1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: node2lay.cxx,v $
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
37 #include <ndindex.hxx>
38 #include <swtable.hxx>
40 #include <sectfrm.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 * --------------------------------------------------*/
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?
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
)
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
101 SwNodeIndex
aTmp( rNode
, -1 );
102 pNd
= rNode
.GetNodes().GoNextWithFrm( &aTmp
);
104 if( !bSearch
&& pNd
&& rNode
.EndOfSectionIndex() < pNd
->GetIndex() )
105 pNd
= NULL
; // Nicht ueber den Bereich hinausschiessen
111 bMaster
= nIndex
< rNode
.GetIndex();
116 if( pNd
->IsCntntNode() )
117 pMod
= (SwModify
*)pNd
->GetCntntNode();
120 ASSERT( pNd
->IsTableNode(), "For Tablenodes only" );
121 pMod
= pNd
->GetTableNode()->GetTable().GetFrmFmt();
123 pIter
= new SwClientIter( *pMod
);
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()
147 pRet
= (SwFrm
*)pIter
->First(TYPE(SwFrm
));
151 pRet
= (SwFrm
*)pIter
->Next();
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() )
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
185 if( pNd
->GetIndex() >= nIndex
)
188 else if( pNd
->EndOfSectionIndex() < nIndex
)
194 pRet
= (SwFrm
*)pIter
->Next();
199 void SwNode2LayImpl::SaveUpperFrms()
201 pUpperFrms
= new SvPtrarr( 0, 20 );
203 while( 0 != (pFrm
= NextFrm()) )
205 SwFrm
* pPrv
= pFrm
->GetPrev();
206 pFrm
= pFrm
->GetUpper();
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() );
223 SwLayoutFrm
* SwNode2LayImpl::UpperFrm( SwFrm
* &rpFrm
, const SwNode
&rNode
)
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();
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());
279 rpFrm
= rpFrm
->GetNext();
283 void SwNode2LayImpl::RestoreUpperFrms( SwNodes
& rNds
, ULONG nStt
, ULONG nEnd
)
285 ASSERT( pUpperFrms
, "RestoreUpper without SaveUpper?" )
287 SwDoc
*pDoc
= rNds
.GetDoc();
289 for( ; nStt
< nEnd
; ++nStt
)
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
++];
302 pNxt
= pNxt
->GetNext();
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
++];
317 pNxt
= pNxt
->GetNext();
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
;
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
)
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()
401 SwFrm
* SwNode2Layout::GetFrm( const Point
* pDocPos
,
402 const SwPosition
*pPos
,
403 const BOOL bCalcFrm
) const
405 return pImpl
->GetFrm( pDocPos
, pPos
, bCalcFrm
);