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