merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / docnode / node2lay.cxx
blob3208873a4e749e7aa901557a60582994515a604b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: node2lay.cxx,v $
10 * $Revision: 1.10 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <calbck.hxx> // SwClientIter
36 #include <node.hxx>
37 #include <ndindex.hxx>
38 #include <swtable.hxx>
39 #include <ftnfrm.hxx>
40 #include <sectfrm.hxx>
41 #include "frmfmt.hxx"
42 #include "cntfrm.hxx"
43 #include "tabfrm.hxx"
44 #include "frmtool.hxx"
45 #include "section.hxx"
46 #include "node2lay.hxx"
49 /* -----------------25.02.99 10:31-------------------
50 * Die SwNode2LayImpl-Klasse erledigt die eigentliche Arbeit,
51 * die SwNode2Layout-Klasse ist nur die der Oefffentlichkeit bekannte Schnittstelle
52 * --------------------------------------------------*/
53 class SwNode2LayImpl
55 SwClientIter *pIter; // Der eigentliche Iterator
56 SvPtrarr *pUpperFrms;// Zum Einsammeln der Upper
57 ULONG nIndex; // Der Index des einzufuegenden Nodes
58 BOOL bMaster : 1; // TRUE => nur Master , FALSE => nur Frames ohne Follow
59 BOOL bInit : 1; // Ist am SwClient bereits ein First()-Aufruf erfolgt?
60 public:
61 SwNode2LayImpl( const SwNode& rNode, ULONG nIdx, BOOL bSearch );
62 ~SwNode2LayImpl() { delete pIter; delete pUpperFrms; }
63 SwFrm* NextFrm(); // liefert den naechsten "sinnvollen" Frame
64 SwLayoutFrm* UpperFrm( SwFrm* &rpFrm, const SwNode &rNode );
65 void SaveUpperFrms(); // Speichert (und lockt ggf.) die pUpper
66 // Fuegt unter jeden pUpper des Arrays einen Frame ein.
67 void RestoreUpperFrms( SwNodes& rNds, ULONG nStt, ULONG nEnd );
69 SwFrm* GetFrm( const Point* pDocPos = 0,
70 const SwPosition *pPos = 0,
71 const BOOL bCalcFrm = TRUE ) const;
74 /* -----------------25.02.99 10:38-------------------
75 * Hauptaufgabe des Ctor: Das richtige SwModify zu ermitteln,
76 * ueber das iteriert wird.
77 * Uebergibt man bSearch == TRUE, so wird der naechste Cntnt- oder TableNode
78 * gesucht, der Frames besitzt ( zum Einsammeln der pUpper ), ansonsten wird
79 * erwartet, das rNode bereits auf einem solchen Cntnt- oder TableNode sitzt,
80 * vor oder hinter den eingefuegt werden soll.
81 * --------------------------------------------------*/
83 SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, ULONG nIdx, BOOL bSearch )
84 : pUpperFrms( NULL ), nIndex( nIdx ), bInit( FALSE )
86 const SwNode* pNd;
87 if( bSearch || rNode.IsSectionNode() )
89 // Suche den naechsten Cntnt/TblNode, der einen Frame besitzt,
90 // damit wir uns vor/hinter ihn haengen koennen
91 if( !bSearch && rNode.GetIndex() < nIndex )
93 SwNodeIndex aTmp( *rNode.EndOfSectionNode(), +1 );
94 pNd = rNode.GetNodes().GoPreviousWithFrm( &aTmp );
95 if( !bSearch && pNd && rNode.GetIndex() > pNd->GetIndex() )
96 pNd = NULL; // Nicht ueber den Bereich hinausschiessen
97 bMaster = FALSE;
99 else
101 SwNodeIndex aTmp( rNode, -1 );
102 pNd = rNode.GetNodes().GoNextWithFrm( &aTmp );
103 bMaster = TRUE;
104 if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() )
105 pNd = NULL; // Nicht ueber den Bereich hinausschiessen
108 else
110 pNd = &rNode;
111 bMaster = nIndex < rNode.GetIndex();
113 if( pNd )
115 SwModify *pMod;
116 if( pNd->IsCntntNode() )
117 pMod = (SwModify*)pNd->GetCntntNode();
118 else
120 ASSERT( pNd->IsTableNode(), "For Tablenodes only" );
121 pMod = pNd->GetTableNode()->GetTable().GetFrmFmt();
123 pIter = new SwClientIter( *pMod );
125 else
126 pIter = NULL;
129 /* -----------------25.02.99 10:41-------------------
130 * SwNode2LayImpl::NextFrm() liefert den naechsten "sinnvollen" Frame,
131 * beim ersten Aufruf wird am eigentlichen Iterator ein First gerufen,
132 * danach die Next-Methode. Das Ergebnis wird auf Brauchbarkeit untersucht,
133 * so werden keine Follows akzeptiert, ein Master wird beim Einsammeln der
134 * pUpper und beim Einfuegen vor ihm akzeptiert. Beim Einfuegen dahinter
135 * wird vom Master ausgehend der letzte Follow gesucht und zurueckgegeben.
136 * Wenn der Frame innerhalb eines SectionFrms liegt, wird noch festgestellt,
137 * ob statt des Frames der SectionFrm der geeignete Rueckgabewert ist, dies
138 * ist der Fall, wenn der neu einzufuegende Node ausserhalb des Bereichs liegt.
139 * --------------------------------------------------*/
140 SwFrm* SwNode2LayImpl::NextFrm()
142 SwFrm* pRet;
143 if( !pIter )
144 return FALSE;
145 if( !bInit )
147 pRet = (SwFrm*)pIter->First(TYPE(SwFrm));
148 bInit = TRUE;
150 else
151 pRet = (SwFrm*)pIter->Next();
152 while( pRet )
154 SwFlowFrm* pFlow = SwFlowFrm::CastFlowFrm( pRet );
155 ASSERT( pFlow, "Cntnt or Table expected?!" );
156 // Follows sind fluechtige Gestalten, deshalb werden sie ignoriert.
157 // Auch wenn wir hinter dem Frame eingefuegt werden sollen, nehmen wir
158 // zunaechst den Master, hangeln uns dann aber zum letzten Follow durch.
159 if( !pFlow->IsFollow() )
161 if( !bMaster )
163 while( pFlow->HasFollow() )
164 pFlow = pFlow->GetFollow();
165 pRet = pFlow->GetFrm();
167 if( pRet->IsInSct() )
169 SwSectionFrm* pSct = pRet->FindSctFrm();
170 // Vorsicht: Wenn wir in einer Fussnote sind, so kann diese
171 // Layoutmaessig in einem spaltigen Bereich liegen, obwohl
172 // sie nodemaessig ausserhalb liegt. Deshalb muss bei Fussnoten
173 // ueberprueft werden, ob auch der SectionFrm in der Fussnote
174 // und nicht ausserhalb liegt.
175 if( !pRet->IsInFtn() || pSct->IsInFtn() )
177 ASSERT( pSct && pSct->GetSection(), "Where's my section?" );
178 SwSectionNode* pNd = pSct->GetSection()->GetFmt()->GetSectionNode();
179 ASSERT( pNd, "Lost SectionNode" );
180 // Wenn der erhaltene Frame in einem Bereichsframe steht,
181 // dessen Bereich den Ausgangsnode nicht umfasst, so kehren
182 // wir mit dem SectionFrm zurueck, sonst mit dem Cntnt/TabFrm
183 if( bMaster )
185 if( pNd->GetIndex() >= nIndex )
186 pRet = pSct;
188 else if( pNd->EndOfSectionIndex() < nIndex )
189 pRet = pSct;
192 return pRet;
194 pRet = (SwFrm*)pIter->Next();
196 return NULL;
199 void SwNode2LayImpl::SaveUpperFrms()
201 pUpperFrms = new SvPtrarr( 0, 20 );
202 SwFrm* pFrm;
203 while( 0 != (pFrm = NextFrm()) )
205 SwFrm* pPrv = pFrm->GetPrev();
206 pFrm = pFrm->GetUpper();
207 if( pFrm )
209 if( pFrm->IsFtnFrm() )
210 ((SwFtnFrm*)pFrm)->ColLock();
211 else if( pFrm->IsInSct() )
212 pFrm->FindSctFrm()->ColLock();
213 if( pPrv && pPrv->IsSctFrm() )
214 ((SwSectionFrm*)pPrv)->LockJoin();
215 pUpperFrms->Insert( (void*)pPrv, pUpperFrms->Count() );
216 pUpperFrms->Insert( (void*)pFrm, pUpperFrms->Count() );
219 delete pIter;
220 pIter = NULL;
223 SwLayoutFrm* SwNode2LayImpl::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
225 rpFrm = NextFrm();
226 if( !rpFrm )
227 return NULL;
228 SwLayoutFrm* pUpper = rpFrm->GetUpper();
229 if( rpFrm->IsSctFrm() )
231 const SwNode* pNode = rNode.StartOfSectionNode();
232 if( pNode->IsSectionNode() )
234 SwFrm* pFrm = bMaster ? rpFrm->FindPrev() : rpFrm->FindNext();
235 if( pFrm && pFrm->IsSctFrm() )
237 // #137684#: pFrm could be a "dummy"-section
238 if( ((SwSectionFrm*)pFrm)->GetSection() &&
239 ((SwSectionNode*)pNode)->GetSection() ==
240 *((SwSectionFrm*)pFrm)->GetSection() )
242 // OD 2004-06-02 #i22922# - consider columned sections
243 // 'Go down' the section frame as long as the layout frame
244 // is found, which would contain content.
245 while ( pFrm->IsLayoutFrm() &&
246 static_cast<SwLayoutFrm*>(pFrm)->Lower() &&
247 !static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsFlowFrm() &&
248 static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsLayoutFrm() )
250 pFrm = static_cast<SwLayoutFrm*>(pFrm)->Lower();
252 ASSERT( pFrm->IsLayoutFrm(),
253 "<SwNode2LayImpl::UpperFrm(..)> - expected upper frame isn't a layout frame." );
254 rpFrm = bMaster ? NULL
255 : static_cast<SwLayoutFrm*>(pFrm)->Lower();
256 ASSERT( !rpFrm || rpFrm->IsFlowFrm(),
257 "<SwNode2LayImpl::UpperFrm(..)> - expected sibling isn't a flow frame." );
258 return static_cast<SwLayoutFrm*>(pFrm);
261 pUpper = new SwSectionFrm(((SwSectionNode*)pNode)->GetSection());
262 pUpper->Paste( rpFrm->GetUpper(),
263 bMaster ? rpFrm : rpFrm->GetNext() );
264 static_cast<SwSectionFrm*>(pUpper)->Init();
265 rpFrm = NULL;
266 // 'Go down' the section frame as long as the layout frame
267 // is found, which would contain content.
268 while ( pUpper->Lower() &&
269 !pUpper->Lower()->IsFlowFrm() &&
270 pUpper->Lower()->IsLayoutFrm() )
272 pUpper = static_cast<SwLayoutFrm*>(pUpper->Lower());
274 return pUpper;
278 if( !bMaster )
279 rpFrm = rpFrm->GetNext();
280 return pUpper;
283 void SwNode2LayImpl::RestoreUpperFrms( SwNodes& rNds, ULONG nStt, ULONG nEnd )
285 ASSERT( pUpperFrms, "RestoreUpper without SaveUpper?" )
286 SwNode* pNd;
287 SwDoc *pDoc = rNds.GetDoc();
288 BOOL bFirst = TRUE;
289 for( ; nStt < nEnd; ++nStt )
291 SwFrm* pNew = 0;
292 SwFrm* pNxt;
293 SwLayoutFrm* pUp;
294 if( (pNd = rNds[nStt])->IsCntntNode() )
295 for( USHORT n = 0; n < pUpperFrms->Count(); )
297 pNxt = (SwFrm*)(*pUpperFrms)[n++];
298 if( bFirst && pNxt && pNxt->IsSctFrm() )
299 ((SwSectionFrm*)pNxt)->UnlockJoin();
300 pUp = (SwLayoutFrm*)(*pUpperFrms)[n++];
301 if( pNxt )
302 pNxt = pNxt->GetNext();
303 else
304 pNxt = pUp->Lower();
305 pNew = ((SwCntntNode*)pNd)->MakeFrm();
306 pNew->Paste( pUp, pNxt );
307 (*pUpperFrms)[n-2] = pNew;
309 else if( pNd->IsTableNode() )
310 for( USHORT x = 0; x < pUpperFrms->Count(); )
312 pNxt = (SwFrm*)(*pUpperFrms)[x++];
313 if( bFirst && pNxt && pNxt->IsSctFrm() )
314 ((SwSectionFrm*)pNxt)->UnlockJoin();
315 pUp = (SwLayoutFrm*)(*pUpperFrms)[x++];
316 if( pNxt )
317 pNxt = pNxt->GetNext();
318 else
319 pNxt = pUp->Lower();
320 pNew = ((SwTableNode*)pNd)->MakeFrm();
321 ASSERT( pNew->IsTabFrm(), "Table exspected" );
322 pNew->Paste( pUp, pNxt );
323 ((SwTabFrm*)pNew)->RegistFlys();
324 (*pUpperFrms)[x-2] = pNew;
326 else if( pNd->IsSectionNode() )
328 nStt = pNd->EndOfSectionIndex();
329 for( USHORT x = 0; x < pUpperFrms->Count(); )
331 pNxt = (SwFrm*)(*pUpperFrms)[x++];
332 if( bFirst && pNxt && pNxt->IsSctFrm() )
333 ((SwSectionFrm*)pNxt)->UnlockJoin();
334 pUp = (SwLayoutFrm*)(*pUpperFrms)[x++];
335 ASSERT( pUp->GetUpper() || pUp->IsFlyFrm(), "Lost Upper" );
336 ::_InsertCnt( pUp, pDoc, pNd->GetIndex(), FALSE, nStt+1, pNxt );
337 pNxt = pUp->GetLastLower();
338 (*pUpperFrms)[x-2] = pNxt;
341 bFirst = FALSE;
343 for( USHORT x = 0; x < pUpperFrms->Count(); ++x )
345 SwFrm* pTmp = (SwFrm*)(*pUpperFrms)[++x];
346 if( pTmp->IsFtnFrm() )
347 ((SwFtnFrm*)pTmp)->ColUnlock();
348 else if ( pTmp->IsInSct() )
350 SwSectionFrm* pSctFrm = pTmp->FindSctFrm();
351 pSctFrm->ColUnlock();
352 // OD 26.08.2003 #i18103# - invalidate size of section in order to
353 // assure, that the section is formatted, unless it was 'Collocked'
354 // from its 'collection' until its 'restoration'.
355 pSctFrm->_InvalidateSize();
360 SwFrm* SwNode2LayImpl::GetFrm( const Point* pDocPos,
361 const SwPosition *pPos,
362 const BOOL bCalcFrm ) const
364 return pIter ? ::GetFrmOfModify( pIter->GetModify(), USHRT_MAX,
365 pDocPos, pPos, bCalcFrm )
366 : 0;
369 SwNode2Layout::SwNode2Layout( const SwNode& rNd, ULONG nIdx )
371 pImpl = new SwNode2LayImpl( rNd, nIdx, FALSE );
374 SwNode2Layout::SwNode2Layout( const SwNode& rNd )
376 pImpl = new SwNode2LayImpl( rNd, rNd.GetIndex(), TRUE );
377 pImpl->SaveUpperFrms();
380 void SwNode2Layout::RestoreUpperFrms( SwNodes& rNds, ULONG nStt, ULONG nEnd )
382 ASSERT( pImpl, "RestoreUpperFrms without SaveUpperFrms" );
383 pImpl->RestoreUpperFrms( rNds, nStt, nEnd );
386 SwFrm* SwNode2Layout::NextFrm()
388 return pImpl->NextFrm();
391 SwLayoutFrm* SwNode2Layout::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
393 return pImpl->UpperFrm( rpFrm, rNode );
396 SwNode2Layout::~SwNode2Layout()
398 delete pImpl;
401 SwFrm* SwNode2Layout::GetFrm( const Point* pDocPos,
402 const SwPosition *pPos,
403 const BOOL bCalcFrm ) const
405 return pImpl->GetFrm( pDocPos, pPos, bCalcFrm );