Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <switerator.hxx>
22 : #include <calbck.hxx>
23 : #include <node.hxx>
24 : #include <ndindex.hxx>
25 : #include <swtable.hxx>
26 : #include <ftnfrm.hxx>
27 : #include <sectfrm.hxx>
28 : #include "frmfmt.hxx"
29 : #include "cntfrm.hxx"
30 : #include "tabfrm.hxx"
31 : #include "frmtool.hxx"
32 : #include "section.hxx"
33 : #include "node2lay.hxx"
34 :
35 : /**
36 : * The SwNode2LayImpl class does the actual work, the SwNode2Layout class is
37 : * just the public interface.
38 : */
39 : class SwNode2LayImpl
40 : {
41 : SwIterator<SwFrm,SwModify>* pIter;
42 : SwModify* pMod;
43 : std::vector<SwFrm*>* pUpperFrms; // To collect the Upper
44 : sal_uLong nIndex; // The Index of the to-be-inserted Nodes
45 : bool bMaster : 1; // true => only Master, false => only Frames without Follow
46 : bool bInit : 1; // Did we already call First() at SwClient?
47 : public:
48 : SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, bool bSearch );
49 55 : ~SwNode2LayImpl() { delete pIter; delete pUpperFrms; }
50 : SwFrm* NextFrm(); // Returns the next "useful" Frame
51 : SwLayoutFrm* UpperFrm( SwFrm* &rpFrm, const SwNode &rNode );
52 : void SaveUpperFrms(); // Saves (and locks if needed) the pUpper
53 : // Inserts a Frame under every pUpper of the array
54 : void RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd );
55 :
56 : SwFrm* GetFrm( const Point* pDocPos = 0,
57 : const SwPosition *pPos = 0,
58 : const sal_Bool bCalcFrm = sal_True ) const;
59 : };
60 :
61 : /**
62 : * The main purpose of this ctor is to find the right SwModify to iterate over.
63 : *
64 : * @param bSearch sal_True: find the next Content or TableNode which contains
65 : * Frames (to collect the pUpper).
66 : * Else we assume that rNode points already to such a
67 : * Content or TableNode.
68 : * We insert before or after it.
69 : */
70 46 : SwNode* GoNextWithFrm(const SwNodes& rNodes, SwNodeIndex *pIdx)
71 : {
72 46 : if( pIdx->GetIndex() >= rNodes.Count() - 1 )
73 0 : return 0;
74 :
75 46 : SwNodeIndex aTmp(*pIdx, +1);
76 46 : SwNode* pNd = 0;
77 441 : while( aTmp < rNodes.Count()-1 )
78 : {
79 352 : pNd = &aTmp.GetNode();
80 352 : bool bFound = false;
81 352 : if ( pNd->IsCntntNode() )
82 347 : bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0);
83 5 : else if ( pNd->IsTableNode() )
84 1 : bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 );
85 4 : else if( pNd->IsEndNode() && !pNd->StartOfSectionNode()->IsSectionNode() )
86 : {
87 3 : pNd = 0;
88 3 : break;
89 : }
90 349 : if ( bFound )
91 0 : break;
92 349 : ++aTmp;
93 : }
94 :
95 46 : if( aTmp == rNodes.Count()-1 )
96 43 : pNd = 0;
97 3 : else if( pNd )
98 0 : (*pIdx) = aTmp;
99 46 : return pNd;
100 : }
101 :
102 0 : SwNode* GoPreviousWithFrm(SwNodeIndex *pIdx)
103 : {
104 0 : if( !pIdx->GetIndex() )
105 0 : return 0;
106 :
107 0 : SwNodeIndex aTmp( *pIdx, -1 );
108 0 : SwNode* pNd(0);
109 0 : while( aTmp.GetIndex() )
110 : {
111 0 : pNd = &aTmp.GetNode();
112 0 : bool bFound = false;
113 0 : if ( pNd->IsCntntNode() )
114 0 : bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0);
115 0 : else if ( pNd->IsTableNode() )
116 0 : bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 );
117 0 : else if( pNd->IsStartNode() && !pNd->IsSectionNode() )
118 : {
119 0 : pNd = 0;
120 0 : break;
121 : }
122 0 : if ( bFound )
123 0 : break;
124 0 : aTmp--;
125 : }
126 :
127 0 : if( !aTmp.GetIndex() )
128 0 : pNd = 0;
129 0 : else if( pNd )
130 0 : (*pIdx) = aTmp;
131 0 : return pNd;
132 : }
133 :
134 :
135 55 : SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, bool bSearch )
136 55 : : pUpperFrms( NULL ), nIndex( nIdx ), bInit( false )
137 : {
138 : const SwNode* pNd;
139 55 : if( bSearch || rNode.IsSectionNode() )
140 : {
141 : // Find the next Cntnt/TableNode that contains a Frame, so that we can add
142 : // ourselves before/after it
143 46 : if( !bSearch && rNode.GetIndex() < nIndex )
144 : {
145 0 : SwNodeIndex aTmp( *rNode.EndOfSectionNode(), +1 );
146 0 : pNd = GoPreviousWithFrm( &aTmp );
147 0 : if( !bSearch && pNd && rNode.GetIndex() > pNd->GetIndex() )
148 0 : pNd = NULL; // Do not go over the limits
149 0 : bMaster = false;
150 : }
151 : else
152 : {
153 46 : SwNodeIndex aTmp( rNode, -1 );
154 46 : pNd = GoNextWithFrm( rNode.GetNodes(), &aTmp );
155 46 : bMaster = true;
156 46 : if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() )
157 0 : pNd = NULL; // Do not go over the limits
158 : }
159 : }
160 : else
161 : {
162 9 : pNd = &rNode;
163 9 : bMaster = nIndex < rNode.GetIndex();
164 : }
165 55 : if( pNd )
166 : {
167 9 : if( pNd->IsCntntNode() )
168 9 : pMod = (SwModify*)pNd->GetCntntNode();
169 : else
170 : {
171 : OSL_ENSURE( pNd->IsTableNode(), "For Tablenodes only" );
172 0 : pMod = pNd->GetTableNode()->GetTable().GetFrmFmt();
173 : }
174 9 : pIter = new SwIterator<SwFrm,SwModify>( *pMod );
175 : }
176 : else
177 : {
178 46 : pIter = NULL;
179 46 : pMod = 0;
180 : }
181 55 : }
182 :
183 : /**
184 : * Returns the next "useful" Frame.
185 : *
186 : * When calling this method for the first time, a First is triggered at the
187 : * actual Iterator. The result is check for suitability: Follows are not
188 : * accepted, a Master is accepted when collecting the pUpper and when
189 : * inserting before it.
190 : * When inserting after it, we find and return the last Follow starting
191 : * from the Master.
192 : *
193 : * If the Frame is located in a SectionFrm, we check to see whether the
194 : * SectionFrame is the suitable return value (instead of the Frame itself).
195 : * This is the case if the to-be-inserted Node is outside of the Section.
196 : */
197 55 : SwFrm* SwNode2LayImpl::NextFrm()
198 : {
199 : SwFrm* pRet;
200 55 : if( !pIter )
201 46 : return NULL;
202 9 : if( !bInit )
203 : {
204 9 : pRet = pIter->First();
205 9 : bInit = true;
206 : }
207 : else
208 0 : pRet = pIter->Next();
209 18 : while( pRet )
210 : {
211 0 : SwFlowFrm* pFlow = SwFlowFrm::CastFlowFrm( pRet );
212 : OSL_ENSURE( pFlow, "Cntnt or Table expected?!" );
213 : // Follows are pretty volatile, thus we ignore them.
214 : // Even if we insert after the Frame, we start from the Master
215 : // and iterate through it until the last Follow
216 0 : if( !pFlow->IsFollow() )
217 : {
218 0 : if( !bMaster )
219 : {
220 0 : while( pFlow->HasFollow() )
221 0 : pFlow = pFlow->GetFollow();
222 0 : pRet = pFlow->GetFrm();
223 : }
224 0 : if( pRet->IsInSct() )
225 : {
226 0 : SwSectionFrm* pSct = pRet->FindSctFrm();
227 : // ATTENTION: If we are in a Footnote, from a Layout point of view
228 : // it could be located in a Section with columns, although it
229 : // should be outside of it when looking at the Nodes.
230 : // Thus, when dealing with Footnotes, we need to check whether the
231 : // SectionFrm is also located within the Footnote and not outside of it.
232 0 : if( !pRet->IsInFtn() || pSct->IsInFtn() )
233 : {
234 : OSL_ENSURE( pSct && pSct->GetSection(), "Where's my section?" );
235 0 : SwSectionNode* pNd = pSct->GetSection()->GetFmt()->GetSectionNode();
236 : OSL_ENSURE( pNd, "Lost SectionNode" );
237 : // If the result Frame is located within a Section Frame
238 : // whose Section does not contain the Node, we return with
239 : // the SectionFrm, else we return with the Cntnt/TabFrm
240 0 : if( bMaster )
241 : {
242 0 : if( pNd->GetIndex() >= nIndex )
243 0 : pRet = pSct;
244 : }
245 0 : else if( pNd->EndOfSectionIndex() < nIndex )
246 0 : pRet = pSct;
247 : }
248 : }
249 0 : return pRet;
250 : }
251 0 : pRet = pIter->Next();
252 : }
253 9 : return NULL;
254 : }
255 :
256 46 : void SwNode2LayImpl::SaveUpperFrms()
257 : {
258 46 : pUpperFrms = new std::vector<SwFrm*>;
259 : SwFrm* pFrm;
260 92 : while( 0 != (pFrm = NextFrm()) )
261 : {
262 0 : SwFrm* pPrv = pFrm->GetPrev();
263 0 : pFrm = pFrm->GetUpper();
264 0 : if( pFrm )
265 : {
266 0 : if( pFrm->IsFtnFrm() )
267 0 : ((SwFtnFrm*)pFrm)->ColLock();
268 0 : else if( pFrm->IsInSct() )
269 0 : pFrm->FindSctFrm()->ColLock();
270 0 : if( pPrv && pPrv->IsSctFrm() )
271 0 : ((SwSectionFrm*)pPrv)->LockJoin();
272 0 : pUpperFrms->push_back( pPrv );
273 0 : pUpperFrms->push_back( pFrm );
274 : }
275 : }
276 46 : delete pIter;
277 46 : pIter = NULL;
278 46 : pMod = 0;
279 46 : }
280 :
281 9 : SwLayoutFrm* SwNode2LayImpl::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
282 : {
283 9 : rpFrm = NextFrm();
284 9 : if( !rpFrm )
285 9 : return NULL;
286 0 : SwLayoutFrm* pUpper = rpFrm->GetUpper();
287 0 : if( rpFrm->IsSctFrm() )
288 : {
289 0 : const SwNode* pNode = rNode.StartOfSectionNode();
290 0 : if( pNode->IsSectionNode() )
291 : {
292 0 : SwFrm* pFrm = bMaster ? rpFrm->FindPrev() : rpFrm->FindNext();
293 0 : if( pFrm && pFrm->IsSctFrm() )
294 : {
295 : // pFrm could be a "dummy"-section
296 0 : if( ((SwSectionFrm*)pFrm)->GetSection() &&
297 0 : (&((SwSectionNode*)pNode)->GetSection() ==
298 0 : ((SwSectionFrm*)pFrm)->GetSection()) )
299 : {
300 : // #i22922# - consider columned sections
301 : // 'Go down' the section frame as long as the layout frame
302 : // is found, which would contain content.
303 0 : while ( pFrm->IsLayoutFrm() &&
304 0 : static_cast<SwLayoutFrm*>(pFrm)->Lower() &&
305 0 : !static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsFlowFrm() &&
306 0 : static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsLayoutFrm() )
307 : {
308 0 : pFrm = static_cast<SwLayoutFrm*>(pFrm)->Lower();
309 : }
310 : OSL_ENSURE( pFrm->IsLayoutFrm(),
311 : "<SwNode2LayImpl::UpperFrm(..)> - expected upper frame isn't a layout frame." );
312 : rpFrm = bMaster ? NULL
313 0 : : static_cast<SwLayoutFrm*>(pFrm)->Lower();
314 : OSL_ENSURE( !rpFrm || rpFrm->IsFlowFrm(),
315 : "<SwNode2LayImpl::UpperFrm(..)> - expected sibling isn't a flow frame." );
316 0 : return static_cast<SwLayoutFrm*>(pFrm);
317 : }
318 :
319 0 : pUpper = new SwSectionFrm(((SwSectionNode*)pNode)->GetSection(), rpFrm);
320 0 : pUpper->Paste( rpFrm->GetUpper(),
321 0 : bMaster ? rpFrm : rpFrm->GetNext() );
322 0 : static_cast<SwSectionFrm*>(pUpper)->Init();
323 0 : rpFrm = NULL;
324 : // 'Go down' the section frame as long as the layout frame
325 : // is found, which would contain content.
326 0 : while ( pUpper->Lower() &&
327 0 : !pUpper->Lower()->IsFlowFrm() &&
328 0 : pUpper->Lower()->IsLayoutFrm() )
329 : {
330 0 : pUpper = static_cast<SwLayoutFrm*>(pUpper->Lower());
331 : }
332 0 : return pUpper;
333 : }
334 : }
335 : };
336 0 : if( !bMaster )
337 0 : rpFrm = rpFrm->GetNext();
338 0 : return pUpper;
339 : }
340 :
341 46 : void SwNode2LayImpl::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd )
342 : {
343 : OSL_ENSURE( pUpperFrms, "RestoreUpper without SaveUpper?" );
344 : SwNode* pNd;
345 46 : SwDoc *pDoc = rNds.GetDoc();
346 46 : bool bFirst = true;
347 92 : for( ; nStt < nEnd; ++nStt )
348 : {
349 46 : SwFrm* pNew = 0;
350 : SwFrm* pNxt;
351 : SwLayoutFrm* pUp;
352 46 : if( (pNd = rNds[nStt])->IsCntntNode() )
353 0 : for( sal_uInt16 n = 0; n < pUpperFrms->size(); )
354 : {
355 0 : pNxt = (*pUpperFrms)[n++];
356 0 : if( bFirst && pNxt && pNxt->IsSctFrm() )
357 0 : ((SwSectionFrm*)pNxt)->UnlockJoin();
358 0 : pUp = (SwLayoutFrm*)(*pUpperFrms)[n++];
359 0 : if( pNxt )
360 0 : pNxt = pNxt->GetNext();
361 : else
362 0 : pNxt = pUp->Lower();
363 0 : pNew = ((SwCntntNode*)pNd)->MakeFrm( pUp );
364 0 : pNew->Paste( pUp, pNxt );
365 0 : (*pUpperFrms)[n-2] = pNew;
366 : }
367 46 : else if( pNd->IsTableNode() )
368 92 : for( sal_uInt16 x = 0; x < pUpperFrms->size(); )
369 : {
370 0 : pNxt = (*pUpperFrms)[x++];
371 0 : if( bFirst && pNxt && pNxt->IsSctFrm() )
372 0 : ((SwSectionFrm*)pNxt)->UnlockJoin();
373 0 : pUp = (SwLayoutFrm*)(*pUpperFrms)[x++];
374 0 : if( pNxt )
375 0 : pNxt = pNxt->GetNext();
376 : else
377 0 : pNxt = pUp->Lower();
378 0 : pNew = ((SwTableNode*)pNd)->MakeFrm( pUp );
379 : OSL_ENSURE( pNew->IsTabFrm(), "Table expected" );
380 0 : pNew->Paste( pUp, pNxt );
381 0 : ((SwTabFrm*)pNew)->RegistFlys();
382 0 : (*pUpperFrms)[x-2] = pNew;
383 : }
384 0 : else if( pNd->IsSectionNode() )
385 : {
386 0 : nStt = pNd->EndOfSectionIndex();
387 0 : for( sal_uInt16 x = 0; x < pUpperFrms->size(); )
388 : {
389 0 : pNxt = (*pUpperFrms)[x++];
390 0 : if( bFirst && pNxt && pNxt->IsSctFrm() )
391 0 : ((SwSectionFrm*)pNxt)->UnlockJoin();
392 0 : pUp = (SwLayoutFrm*)(*pUpperFrms)[x++];
393 : OSL_ENSURE( pUp->GetUpper() || pUp->IsFlyFrm(), "Lost Upper" );
394 0 : ::_InsertCnt( pUp, pDoc, pNd->GetIndex(), sal_False, nStt+1, pNxt );
395 0 : pNxt = pUp->GetLastLower();
396 0 : (*pUpperFrms)[x-2] = pNxt;
397 : }
398 : }
399 46 : bFirst = false;
400 : }
401 46 : for( sal_uInt16 x = 0; x < pUpperFrms->size(); ++x )
402 : {
403 0 : SwFrm* pTmp = (*pUpperFrms)[++x];
404 0 : if( pTmp->IsFtnFrm() )
405 0 : ((SwFtnFrm*)pTmp)->ColUnlock();
406 0 : else if ( pTmp->IsInSct() )
407 : {
408 0 : SwSectionFrm* pSctFrm = pTmp->FindSctFrm();
409 0 : pSctFrm->ColUnlock();
410 : // #i18103# - invalidate size of section in order to
411 : // assure, that the section is formatted, unless it was 'Collocked'
412 : // from its 'collection' until its 'restoration'.
413 0 : pSctFrm->_InvalidateSize();
414 : }
415 : }
416 46 : }
417 :
418 0 : SwFrm* SwNode2LayImpl::GetFrm( const Point* pDocPos,
419 : const SwPosition *pPos,
420 : const sal_Bool bCalcFrm ) const
421 : {
422 : // test if change of member pIter -> pMod broke anything
423 0 : return pMod ? ::GetFrmOfModify( 0, *pMod, USHRT_MAX, pDocPos, pPos, bCalcFrm ) : 0;
424 : }
425 :
426 9 : SwNode2Layout::SwNode2Layout( const SwNode& rNd, sal_uLong nIdx )
427 : {
428 9 : pImpl = new SwNode2LayImpl( rNd, nIdx, false );
429 9 : }
430 :
431 46 : SwNode2Layout::SwNode2Layout( const SwNode& rNd )
432 : {
433 46 : pImpl = new SwNode2LayImpl( rNd, rNd.GetIndex(), true );
434 46 : pImpl->SaveUpperFrms();
435 46 : }
436 :
437 46 : void SwNode2Layout::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd )
438 : {
439 : OSL_ENSURE( pImpl, "RestoreUpperFrms without SaveUpperFrms" );
440 46 : pImpl->RestoreUpperFrms( rNds, nStt, nEnd );
441 46 : }
442 :
443 0 : SwFrm* SwNode2Layout::NextFrm()
444 : {
445 0 : return pImpl->NextFrm();
446 : }
447 :
448 9 : SwLayoutFrm* SwNode2Layout::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
449 : {
450 9 : return pImpl->UpperFrm( rpFrm, rNode );
451 : }
452 :
453 55 : SwNode2Layout::~SwNode2Layout()
454 : {
455 55 : delete pImpl;
456 55 : }
457 :
458 0 : SwFrm* SwNode2Layout::GetFrm( const Point* pDocPos,
459 : const SwPosition *pPos,
460 : const sal_Bool bCalcFrm ) const
461 : {
462 0 : return pImpl->GetFrm( pDocPos, pPos, bCalcFrm );
463 : }
464 :
465 :
466 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|