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