xref: /trunk/main/sw/source/core/docnode/node2lay.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <switerator.hxx>
32 #include <calbck.hxx>
33 #include <node.hxx>
34 #include <ndindex.hxx>
35 #include <swtable.hxx>
36 #include <ftnfrm.hxx>
37 #include <sectfrm.hxx>
38 #include "frmfmt.hxx"
39 #include "cntfrm.hxx"
40 #include "tabfrm.hxx"
41 #include "frmtool.hxx"
42 #include "section.hxx"
43 #include "node2lay.hxx"
44 
45 /* -----------------25.02.99 10:31-------------------
46  * Die SwNode2LayImpl-Klasse erledigt die eigentliche Arbeit,
47  * die SwNode2Layout-Klasse ist nur die der Oefffentlichkeit bekannte Schnittstelle
48  * --------------------------------------------------*/
49 class SwNode2LayImpl
50 {
51     SwIterator<SwFrm,SwModify>* pIter;
52     SwModify* pMod;
53     SvPtrarr *pUpperFrms;// Zum Einsammeln der Upper
54     sal_uLong nIndex;        // Der Index des einzufuegenden Nodes
55     sal_Bool bMaster    : 1; // sal_True => nur Master , sal_False => nur Frames ohne Follow
56     sal_Bool bInit      : 1; // Ist am SwClient bereits ein First()-Aufruf erfolgt?
57 public:
58     SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch );
59     ~SwNode2LayImpl() { delete pIter; delete pUpperFrms; }
60     SwFrm* NextFrm(); // liefert den naechsten "sinnvollen" Frame
61     SwLayoutFrm* UpperFrm( SwFrm* &rpFrm, const SwNode &rNode );
62     void SaveUpperFrms(); // Speichert (und lockt ggf.) die pUpper
63     // Fuegt unter jeden pUpper des Arrays einen Frame ein.
64     void RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd );
65 
66     SwFrm* GetFrm( const Point* pDocPos = 0,
67                     const SwPosition *pPos = 0,
68                     const sal_Bool bCalcFrm = sal_True ) const;
69 };
70 
71 /* -----------------25.02.99 10:38-------------------
72  * Hauptaufgabe des Ctor: Das richtige SwModify zu ermitteln,
73  * ueber das iteriert wird.
74  * Uebergibt man bSearch == sal_True, so wird der naechste Cntnt- oder TableNode
75  * gesucht, der Frames besitzt ( zum Einsammeln der pUpper ), ansonsten wird
76  * erwartet, das rNode bereits auf einem solchen Cntnt- oder TableNode sitzt,
77  * vor oder hinter den eingefuegt werden soll.
78  * --------------------------------------------------*/
79 
80 SwNode* GoNextWithFrm(const SwNodes& rNodes, SwNodeIndex *pIdx)
81 {
82     if( pIdx->GetIndex() >= rNodes.Count() - 1 )
83         return 0;
84 
85     SwNodeIndex aTmp(*pIdx, +1);
86     SwNode* pNd = 0;
87     while( aTmp < rNodes.Count()-1 )
88     {
89         pNd = &aTmp.GetNode();
90         bool bFound = false;
91         if ( pNd->IsCntntNode() )
92             bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0);
93         else if ( pNd->IsTableNode() )
94             bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 );
95         else if( pNd->IsEndNode() && !pNd->StartOfSectionNode()->IsSectionNode() )
96         {
97             pNd = 0;
98             break;
99         }
100         if ( bFound )
101                 break;
102         aTmp++;
103     }
104 
105     if( aTmp == rNodes.Count()-1 )
106         pNd = 0;
107     else if( pNd )
108         (*pIdx) = aTmp;
109     return pNd;
110 }
111 
112 SwNode* GoPreviousWithFrm(SwNodeIndex *pIdx)
113 {
114     if( !pIdx->GetIndex() )
115         return 0;
116 
117     SwNodeIndex aTmp( *pIdx, -1 );
118     SwNode* pNd(0);
119     while( aTmp.GetIndex() )
120     {
121         pNd = &aTmp.GetNode();
122         bool bFound = false;
123         if ( pNd->IsCntntNode() )
124             bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0);
125         else if ( pNd->IsTableNode() )
126             bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 );
127         else if( pNd->IsStartNode() && !pNd->IsSectionNode() )
128         {
129             pNd = 0;
130             break;
131         }
132         if ( bFound )
133                 break;
134         aTmp--;
135     }
136 
137     if( !aTmp.GetIndex() )
138         pNd = 0;
139     else if( pNd )
140         (*pIdx) = aTmp;
141     return pNd;
142 }
143 
144 
145 SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch )
146     : pUpperFrms( NULL ), nIndex( nIdx ), bInit( sal_False )
147 {
148     const SwNode* pNd;
149     if( bSearch || rNode.IsSectionNode() )
150     {
151         // Suche den naechsten Cntnt/TblNode, der einen Frame besitzt,
152         // damit wir uns vor/hinter ihn haengen koennen
153         if( !bSearch && rNode.GetIndex() < nIndex )
154         {
155             SwNodeIndex aTmp( *rNode.EndOfSectionNode(), +1 );
156             pNd = GoPreviousWithFrm( &aTmp );
157             if( !bSearch && pNd && rNode.GetIndex() > pNd->GetIndex() )
158                 pNd = NULL; // Nicht ueber den Bereich hinausschiessen
159             bMaster = sal_False;
160         }
161         else
162         {
163             SwNodeIndex aTmp( rNode, -1 );
164             pNd = GoNextWithFrm( rNode.GetNodes(), &aTmp );
165             bMaster = sal_True;
166             if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() )
167                 pNd = NULL; // Nicht ueber den Bereich hinausschiessen
168         }
169     }
170     else
171     {
172         pNd = &rNode;
173         bMaster = nIndex < rNode.GetIndex();
174     }
175     if( pNd )
176     {
177         if( pNd->IsCntntNode() )
178             pMod = (SwModify*)pNd->GetCntntNode();
179         else
180         {
181             ASSERT( pNd->IsTableNode(), "For Tablenodes only" );
182             pMod = pNd->GetTableNode()->GetTable().GetFrmFmt();
183         }
184         pIter = new SwIterator<SwFrm,SwModify>( *pMod );
185     }
186     else
187     {
188         pIter = NULL;
189         pMod = 0;
190     }
191 }
192 
193 /* -----------------25.02.99 10:41-------------------
194  * SwNode2LayImpl::NextFrm() liefert den naechsten "sinnvollen" Frame,
195  * beim ersten Aufruf wird am eigentlichen Iterator ein First gerufen,
196  * danach die Next-Methode. Das Ergebnis wird auf Brauchbarkeit untersucht,
197  * so werden keine Follows akzeptiert, ein Master wird beim Einsammeln der
198  * pUpper und beim Einfuegen vor ihm akzeptiert. Beim Einfuegen dahinter
199  * wird vom Master ausgehend der letzte Follow gesucht und zurueckgegeben.
200  * Wenn der Frame innerhalb eines SectionFrms liegt, wird noch festgestellt,
201  * ob statt des Frames der SectionFrm der geeignete Rueckgabewert ist, dies
202  * ist der Fall, wenn der neu einzufuegende Node ausserhalb des Bereichs liegt.
203  * --------------------------------------------------*/
204 SwFrm* SwNode2LayImpl::NextFrm()
205 {
206     SwFrm* pRet;
207     if( !pIter )
208         return sal_False;
209     if( !bInit )
210     {
211          pRet = pIter->First();
212          bInit = sal_True;
213     }
214     else
215         pRet = pIter->Next();
216     while( pRet )
217     {
218         SwFlowFrm* pFlow = SwFlowFrm::CastFlowFrm( pRet );
219         ASSERT( pFlow, "Cntnt or Table expected?!" );
220         // Follows sind fluechtige Gestalten, deshalb werden sie ignoriert.
221         // Auch wenn wir hinter dem Frame eingefuegt werden sollen, nehmen wir
222         // zunaechst den Master, hangeln uns dann aber zum letzten Follow durch.
223         if( !pFlow->IsFollow() )
224         {
225             if( !bMaster )
226             {
227                 while( pFlow->HasFollow() )
228                     pFlow = pFlow->GetFollow();
229                 pRet = pFlow->GetFrm();
230             }
231             if( pRet->IsInSct() )
232             {
233                 SwSectionFrm* pSct = pRet->FindSctFrm();
234                 // Vorsicht: Wenn wir in einer Fussnote sind, so kann diese
235                 // Layoutmaessig in einem spaltigen Bereich liegen, obwohl
236                 // sie nodemaessig ausserhalb liegt. Deshalb muss bei Fussnoten
237                 // ueberprueft werden, ob auch der SectionFrm in der Fussnote
238                 // und nicht ausserhalb liegt.
239                 if( !pRet->IsInFtn() || pSct->IsInFtn() )
240                 {
241                     ASSERT( pSct && pSct->GetSection(), "Where's my section?" );
242                     SwSectionNode* pNd = pSct->GetSection()->GetFmt()->GetSectionNode();
243                     ASSERT( pNd, "Lost SectionNode" );
244                     // Wenn der erhaltene Frame in einem Bereichsframe steht,
245                     // dessen Bereich den Ausgangsnode nicht umfasst, so kehren
246                     // wir mit dem SectionFrm zurueck, sonst mit dem Cntnt/TabFrm
247                     if( bMaster )
248                     {
249                         if( pNd->GetIndex() >= nIndex )
250                             pRet = pSct;
251                     }
252                     else if( pNd->EndOfSectionIndex() < nIndex )
253                         pRet = pSct;
254                 }
255             }
256             return pRet;
257         }
258         pRet = pIter->Next();
259     }
260     return NULL;
261 }
262 
263 void SwNode2LayImpl::SaveUpperFrms()
264 {
265     pUpperFrms = new SvPtrarr( 0, 20 );
266     SwFrm* pFrm;
267     while( 0 != (pFrm = NextFrm()) )
268     {
269         SwFrm* pPrv = pFrm->GetPrev();
270         pFrm = pFrm->GetUpper();
271         if( pFrm )
272         {
273             if( pFrm->IsFtnFrm() )
274                 ((SwFtnFrm*)pFrm)->ColLock();
275             else if( pFrm->IsInSct() )
276                 pFrm->FindSctFrm()->ColLock();
277             if( pPrv && pPrv->IsSctFrm() )
278                 ((SwSectionFrm*)pPrv)->LockJoin();
279             pUpperFrms->Insert( (void*)pPrv, pUpperFrms->Count() );
280             pUpperFrms->Insert( (void*)pFrm, pUpperFrms->Count() );
281         }
282     }
283     delete pIter;
284     pIter = NULL;
285     pMod = 0;
286 }
287 
288 SwLayoutFrm* SwNode2LayImpl::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
289 {
290     rpFrm = NextFrm();
291     if( !rpFrm )
292         return NULL;
293     SwLayoutFrm* pUpper = rpFrm->GetUpper();
294     if( rpFrm->IsSctFrm() )
295     {
296         const SwNode* pNode = rNode.StartOfSectionNode();
297         if( pNode->IsSectionNode() )
298         {
299             SwFrm* pFrm = bMaster ? rpFrm->FindPrev() : rpFrm->FindNext();
300             if( pFrm && pFrm->IsSctFrm() )
301             {
302                 // #137684#: pFrm could be a "dummy"-section
303                 if( ((SwSectionFrm*)pFrm)->GetSection() &&
304                     (&((SwSectionNode*)pNode)->GetSection() ==
305                      ((SwSectionFrm*)pFrm)->GetSection()) )
306                 {
307                     // OD 2004-06-02 #i22922# - consider columned sections
308                     // 'Go down' the section frame as long as the layout frame
309                     // is found, which would contain content.
310                     while ( pFrm->IsLayoutFrm() &&
311                             static_cast<SwLayoutFrm*>(pFrm)->Lower() &&
312                             !static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsFlowFrm() &&
313                             static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsLayoutFrm() )
314                     {
315                         pFrm = static_cast<SwLayoutFrm*>(pFrm)->Lower();
316                     }
317                     ASSERT( pFrm->IsLayoutFrm(),
318                             "<SwNode2LayImpl::UpperFrm(..)> - expected upper frame isn't a layout frame." );
319                     rpFrm = bMaster ? NULL
320                                     : static_cast<SwLayoutFrm*>(pFrm)->Lower();
321                     ASSERT( !rpFrm || rpFrm->IsFlowFrm(),
322                             "<SwNode2LayImpl::UpperFrm(..)> - expected sibling isn't a flow frame." );
323                     return static_cast<SwLayoutFrm*>(pFrm);
324                 }
325 
326                 pUpper = new SwSectionFrm(((SwSectionNode*)pNode)->GetSection(), rpFrm);
327                 pUpper->Paste( rpFrm->GetUpper(),
328                                bMaster ? rpFrm : rpFrm->GetNext() );
329                 static_cast<SwSectionFrm*>(pUpper)->Init();
330                 rpFrm = NULL;
331                 // 'Go down' the section frame as long as the layout frame
332                 // is found, which would contain content.
333                 while ( pUpper->Lower() &&
334                         !pUpper->Lower()->IsFlowFrm() &&
335                         pUpper->Lower()->IsLayoutFrm() )
336                 {
337                     pUpper = static_cast<SwLayoutFrm*>(pUpper->Lower());
338                 }
339                 return pUpper;
340             }
341         }
342     };
343     if( !bMaster )
344         rpFrm = rpFrm->GetNext();
345     return pUpper;
346 }
347 
348 void SwNode2LayImpl::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd )
349 {
350     ASSERT( pUpperFrms, "RestoreUpper without SaveUpper?" )
351     SwNode* pNd;
352     SwDoc *pDoc = rNds.GetDoc();
353     sal_Bool bFirst = sal_True;
354     for( ; nStt < nEnd; ++nStt )
355     {
356         SwFrm* pNew = 0;
357         SwFrm* pNxt;
358         SwLayoutFrm* pUp;
359         if( (pNd = rNds[nStt])->IsCntntNode() )
360             for( sal_uInt16 n = 0; n < pUpperFrms->Count(); )
361             {
362                 pNxt = (SwFrm*)(*pUpperFrms)[n++];
363                 if( bFirst && pNxt && pNxt->IsSctFrm() )
364                     ((SwSectionFrm*)pNxt)->UnlockJoin();
365                 pUp = (SwLayoutFrm*)(*pUpperFrms)[n++];
366                 if( pNxt )
367                     pNxt = pNxt->GetNext();
368                 else
369                     pNxt = pUp->Lower();
370                 pNew = ((SwCntntNode*)pNd)->MakeFrm( pUp );
371                 pNew->Paste( pUp, pNxt );
372                 (*pUpperFrms)[n-2] = pNew;
373             }
374         else if( pNd->IsTableNode() )
375             for( sal_uInt16 x = 0; x < pUpperFrms->Count(); )
376             {
377                 pNxt = (SwFrm*)(*pUpperFrms)[x++];
378                 if( bFirst && pNxt && pNxt->IsSctFrm() )
379                     ((SwSectionFrm*)pNxt)->UnlockJoin();
380                 pUp = (SwLayoutFrm*)(*pUpperFrms)[x++];
381                 if( pNxt )
382                     pNxt = pNxt->GetNext();
383                 else
384                     pNxt = pUp->Lower();
385                 pNew = ((SwTableNode*)pNd)->MakeFrm( pUp );
386                 ASSERT( pNew->IsTabFrm(), "Table exspected" );
387                 pNew->Paste( pUp, pNxt );
388                 ((SwTabFrm*)pNew)->RegistFlys();
389                 (*pUpperFrms)[x-2] = pNew;
390             }
391         else if( pNd->IsSectionNode() )
392         {
393             nStt = pNd->EndOfSectionIndex();
394             for( sal_uInt16 x = 0; x < pUpperFrms->Count(); )
395             {
396                 pNxt = (SwFrm*)(*pUpperFrms)[x++];
397                 if( bFirst && pNxt && pNxt->IsSctFrm() )
398                     ((SwSectionFrm*)pNxt)->UnlockJoin();
399                 pUp = (SwLayoutFrm*)(*pUpperFrms)[x++];
400                 ASSERT( pUp->GetUpper() || pUp->IsFlyFrm(), "Lost Upper" );
401                 ::_InsertCnt( pUp, pDoc, pNd->GetIndex(), sal_False, nStt+1, pNxt );
402                 pNxt = pUp->GetLastLower();
403                 (*pUpperFrms)[x-2] = pNxt;
404             }
405         }
406         bFirst = sal_False;
407     }
408     for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ++x )
409     {
410         SwFrm* pTmp = (SwFrm*)(*pUpperFrms)[++x];
411         if( pTmp->IsFtnFrm() )
412             ((SwFtnFrm*)pTmp)->ColUnlock();
413         else if ( pTmp->IsInSct() )
414         {
415             SwSectionFrm* pSctFrm = pTmp->FindSctFrm();
416             pSctFrm->ColUnlock();
417             // OD 26.08.2003 #i18103# - invalidate size of section in order to
418             // assure, that the section is formatted, unless it was 'Collocked'
419             // from its 'collection' until its 'restoration'.
420             pSctFrm->_InvalidateSize();
421         }
422     }
423 }
424 
425 SwFrm* SwNode2LayImpl::GetFrm( const Point* pDocPos,
426                                 const SwPosition *pPos,
427                                 const sal_Bool bCalcFrm ) const
428 {
429     // mba: test if change of member pIter -> pMod broke anything
430     return pMod ? ::GetFrmOfModify( 0, *pMod, USHRT_MAX, pDocPos, pPos, bCalcFrm ) : 0;
431 }
432 
433 SwNode2Layout::SwNode2Layout( const SwNode& rNd, sal_uLong nIdx )
434 {
435     pImpl = new SwNode2LayImpl( rNd, nIdx, sal_False );
436 }
437 
438 SwNode2Layout::SwNode2Layout( const SwNode& rNd )
439 {
440     pImpl = new SwNode2LayImpl( rNd, rNd.GetIndex(), sal_True );
441     pImpl->SaveUpperFrms();
442 }
443 
444 void SwNode2Layout::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd )
445 {
446     ASSERT( pImpl, "RestoreUpperFrms without SaveUpperFrms" );
447     pImpl->RestoreUpperFrms( rNds, nStt, nEnd );
448 }
449 
450 SwFrm* SwNode2Layout::NextFrm()
451 {
452     return pImpl->NextFrm();
453 }
454 
455 SwLayoutFrm* SwNode2Layout::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
456 {
457     return pImpl->UpperFrm( rpFrm, rNode );
458 }
459 
460 SwNode2Layout::~SwNode2Layout()
461 {
462     delete pImpl;
463 }
464 
465 SwFrm* SwNode2Layout::GetFrm( const Point* pDocPos,
466                                 const SwPosition *pPos,
467                                 const sal_Bool bCalcFrm ) const
468 {
469     return pImpl->GetFrm( pDocPos, pPos, bCalcFrm );
470 }
471 
472 
473