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 <calbck.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 2999 : ~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 bool bCalcFrm = true ) const;
58 : };
59 :
60 614 : SwNode* GoNextWithFrm(const SwNodes& rNodes, SwNodeIndex *pIdx)
61 : {
62 614 : if( pIdx->GetIndex() >= rNodes.Count() - 1 )
63 0 : return 0;
64 :
65 614 : SwNodeIndex aTmp(*pIdx, +1);
66 614 : SwNode* pNd = 0;
67 11581 : while( aTmp < rNodes.Count()-1 )
68 : {
69 10505 : pNd = &aTmp.GetNode();
70 10505 : bool bFound = false;
71 10505 : if ( pNd->IsContentNode() )
72 10261 : bFound = SwIterator<SwFrm,SwContentNode>(*static_cast<SwContentNode*>(pNd)).First();
73 244 : else if ( pNd->IsTableNode() )
74 49 : bFound = SwIterator<SwFrm,SwFormat>(*static_cast<SwTableNode*>(pNd)->GetTable().GetFrameFormat()).First() ;
75 195 : else if( pNd->IsEndNode() && !pNd->StartOfSectionNode()->IsSectionNode() )
76 : {
77 141 : pNd = 0;
78 141 : break;
79 : }
80 10364 : if ( bFound )
81 11 : break;
82 10353 : ++aTmp;
83 : }
84 :
85 614 : if( aTmp == rNodes.Count()-1 )
86 462 : pNd = 0;
87 152 : else if( pNd )
88 11 : (*pIdx) = aTmp;
89 614 : 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->IsContentNode() )
104 0 : bFound = SwIterator<SwFrm,SwContentNode>(*static_cast<SwContentNode*>(pNd)).First();
105 0 : else if ( pNd->IsTableNode() )
106 0 : bFound = SwIterator<SwFrm,SwFormat>(*static_cast<SwTableNode*>(pNd)->GetTable().GetFrameFormat()).First();
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 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 2999 : SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, bool bSearch )
134 2999 : : pUpperFrms( NULL ), nIndex( nIdx ), bInit( false )
135 : {
136 : const SwNode* pNd;
137 2999 : if( bSearch || rNode.IsSectionNode() )
138 : {
139 : // Find the next Content/TableNode that contains a Frame, so that we can add
140 : // ourselves before/after it
141 614 : 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 614 : SwNodeIndex aTmp( rNode, -1 );
152 614 : pNd = GoNextWithFrm( rNode.GetNodes(), &aTmp );
153 614 : bMaster = true;
154 614 : if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() )
155 0 : pNd = NULL; // Do not go over the limits
156 : }
157 : }
158 : else
159 : {
160 2385 : pNd = &rNode;
161 2385 : bMaster = nIndex < rNode.GetIndex();
162 : }
163 2999 : if( pNd )
164 : {
165 2396 : if( pNd->IsContentNode() )
166 2388 : pMod = const_cast<SwModify*>(static_cast<SwModify const *>(pNd->GetContentNode()));
167 : else
168 : {
169 : OSL_ENSURE( pNd->IsTableNode(), "For Tablenodes only" );
170 8 : pMod = pNd->GetTableNode()->GetTable().GetFrameFormat();
171 : }
172 2396 : pIter = new SwIterator<SwFrm,SwModify>( *pMod );
173 : }
174 : else
175 : {
176 603 : pIter = NULL;
177 603 : pMod = 0;
178 : }
179 2999 : }
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 5284 : SwFrm* SwNode2LayImpl::NextFrm()
196 : {
197 : SwFrm* pRet;
198 5284 : if( !pIter )
199 603 : return NULL;
200 4681 : if( !bInit )
201 : {
202 2396 : pRet = pIter->First();
203 2396 : bInit = true;
204 : }
205 : else
206 2285 : pRet = pIter->Next();
207 9375 : while( pRet )
208 : {
209 2298 : SwFlowFrm* pFlow = SwFlowFrm::CastFlowFrm( pRet );
210 : OSL_ENSURE( pFlow, "Content 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 2298 : if( !pFlow->IsFollow() )
215 : {
216 2285 : if( !bMaster )
217 : {
218 3603 : while( pFlow->HasFollow() )
219 1 : pFlow = pFlow->GetFollow();
220 1801 : pRet = &(pFlow->GetFrm());
221 : }
222 2285 : if( pRet->IsInSct() )
223 : {
224 198 : 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 198 : if( !pRet->IsInFootnote() || pSct->IsInFootnote() )
231 : {
232 : OSL_ENSURE( pSct && pSct->GetSection(), "Where's my section?" );
233 198 : SwSectionNode* pNd = pSct->GetSection()->GetFormat()->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 Content/TabFrm
238 198 : if( bMaster )
239 : {
240 19 : if( pNd->GetIndex() >= nIndex )
241 6 : pRet = pSct;
242 : }
243 179 : else if( pNd->EndOfSectionIndex() < nIndex )
244 12 : pRet = pSct;
245 : }
246 : }
247 2285 : return pRet;
248 : }
249 13 : pRet = pIter->Next();
250 : }
251 2396 : return NULL;
252 : }
253 :
254 612 : void SwNode2LayImpl::SaveUpperFrms()
255 : {
256 612 : pUpperFrms = new std::vector<SwFrm*>;
257 : SwFrm* pFrm;
258 1233 : while( 0 != (pFrm = NextFrm()) )
259 : {
260 9 : SwFrm* pPrv = pFrm->GetPrev();
261 9 : pFrm = pFrm->GetUpper();
262 9 : if( pFrm )
263 : {
264 9 : if( pFrm->IsFootnoteFrm() )
265 0 : static_cast<SwFootnoteFrm*>(pFrm)->ColLock();
266 9 : else if( pFrm->IsInSct() )
267 0 : pFrm->FindSctFrm()->ColLock();
268 9 : if( pPrv && pPrv->IsSctFrm() )
269 0 : static_cast<SwSectionFrm*>(pPrv)->LockJoin();
270 9 : pUpperFrms->push_back( pPrv );
271 9 : pUpperFrms->push_back( pFrm );
272 : }
273 : }
274 612 : delete pIter;
275 612 : pIter = NULL;
276 612 : pMod = 0;
277 612 : }
278 :
279 4611 : SwLayoutFrm* SwNode2LayImpl::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
280 : {
281 4611 : rpFrm = NextFrm();
282 4611 : if( !rpFrm )
283 2360 : return NULL;
284 2251 : SwLayoutFrm* pUpper = rpFrm->GetUpper();
285 2251 : if( rpFrm->IsSctFrm() )
286 : {
287 9 : const SwNode* pNode = rNode.StartOfSectionNode();
288 9 : 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( static_cast<SwSectionFrm*>(pFrm)->GetSection() &&
295 0 : (&static_cast<const SwSectionNode*>(pNode)->GetSection() ==
296 0 : static_cast<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(const_cast<SwSectionNode*>(static_cast<const 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 2251 : if( !bMaster )
335 1789 : rpFrm = rpFrm->GetNext();
336 2251 : return pUpper;
337 : }
338 :
339 612 : void SwNode2LayImpl::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd )
340 : {
341 : OSL_ENSURE( pUpperFrms, "RestoreUpper without SaveUpper?" );
342 : SwNode* pNd;
343 612 : SwDoc *pDoc = rNds.GetDoc();
344 612 : bool bFirst = true;
345 1224 : for( ; nStt < nEnd; ++nStt )
346 : {
347 612 : SwFrm* pNew = 0;
348 : SwFrm* pNxt;
349 : SwLayoutFrm* pUp;
350 612 : if( (pNd = rNds[nStt])->IsContentNode() )
351 0 : for( std::vector<SwFrm*>::size_type n = 0; n < pUpperFrms->size(); )
352 : {
353 0 : pNxt = (*pUpperFrms)[n++];
354 0 : if( bFirst && pNxt && pNxt->IsSctFrm() )
355 0 : static_cast<SwSectionFrm*>(pNxt)->UnlockJoin();
356 0 : pUp = static_cast<SwLayoutFrm*>((*pUpperFrms)[n++]);
357 0 : if( pNxt )
358 0 : pNxt = pNxt->GetNext();
359 : else
360 0 : pNxt = pUp->Lower();
361 0 : pNew = static_cast<SwContentNode*>(pNd)->MakeFrm( pUp );
362 0 : pNew->Paste( pUp, pNxt );
363 0 : (*pUpperFrms)[n-2] = pNew;
364 : }
365 612 : else if( pNd->IsTableNode() )
366 1218 : for( std::vector<SwFrm*>::size_type x = 0; x < pUpperFrms->size(); )
367 : {
368 4 : pNxt = (*pUpperFrms)[x++];
369 4 : if( bFirst && pNxt && pNxt->IsSctFrm() )
370 0 : static_cast<SwSectionFrm*>(pNxt)->UnlockJoin();
371 4 : pUp = static_cast<SwLayoutFrm*>((*pUpperFrms)[x++]);
372 4 : if( pNxt )
373 0 : pNxt = pNxt->GetNext();
374 : else
375 4 : pNxt = pUp->Lower();
376 4 : pNew = static_cast<SwTableNode*>(pNd)->MakeFrm( pUp );
377 : OSL_ENSURE( pNew->IsTabFrm(), "Table expected" );
378 4 : pNew->Paste( pUp, pNxt );
379 4 : static_cast<SwTabFrm*>(pNew)->RegistFlys();
380 4 : (*pUpperFrms)[x-2] = pNew;
381 : }
382 5 : else if( pNd->IsSectionNode() )
383 : {
384 5 : nStt = pNd->EndOfSectionIndex();
385 15 : for( std::vector<SwFrm*>::size_type x = 0; x < pUpperFrms->size(); )
386 : {
387 5 : pNxt = (*pUpperFrms)[x++];
388 5 : if( bFirst && pNxt && pNxt->IsSctFrm() )
389 0 : static_cast<SwSectionFrm*>(pNxt)->UnlockJoin();
390 5 : pUp = static_cast<SwLayoutFrm*>((*pUpperFrms)[x++]);
391 : OSL_ENSURE( pUp->GetUpper() || pUp->IsFlyFrm(), "Lost Upper" );
392 5 : ::_InsertCnt( pUp, pDoc, pNd->GetIndex(), false, nStt+1, pNxt );
393 5 : pNxt = pUp->GetLastLower();
394 5 : (*pUpperFrms)[x-2] = pNxt;
395 : }
396 : }
397 612 : bFirst = false;
398 : }
399 621 : for( std::vector<SwFrm*>::size_type x = 0; x < pUpperFrms->size(); ++x )
400 : {
401 9 : SwFrm* pTmp = (*pUpperFrms)[++x];
402 9 : if( pTmp->IsFootnoteFrm() )
403 0 : static_cast<SwFootnoteFrm*>(pTmp)->ColUnlock();
404 9 : 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 612 : }
415 :
416 0 : SwFrm* SwNode2LayImpl::GetFrm( const Point* pDocPos,
417 : const SwPosition *pPos,
418 : const 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 2387 : SwNode2Layout::SwNode2Layout( const SwNode& rNd, sal_uLong nIdx )
425 : {
426 2387 : pImpl = new SwNode2LayImpl( rNd, nIdx, false );
427 2387 : }
428 :
429 612 : SwNode2Layout::SwNode2Layout( const SwNode& rNd )
430 : {
431 612 : pImpl = new SwNode2LayImpl( rNd, rNd.GetIndex(), true );
432 612 : pImpl->SaveUpperFrms();
433 612 : }
434 :
435 612 : void SwNode2Layout::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd )
436 : {
437 : OSL_ENSURE( pImpl, "RestoreUpperFrms without SaveUpperFrms" );
438 612 : pImpl->RestoreUpperFrms( rNds, nStt, nEnd );
439 612 : }
440 :
441 52 : SwFrm* SwNode2Layout::NextFrm()
442 : {
443 52 : return pImpl->NextFrm();
444 : }
445 :
446 4611 : SwLayoutFrm* SwNode2Layout::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
447 : {
448 4611 : return pImpl->UpperFrm( rpFrm, rNode );
449 : }
450 :
451 2999 : SwNode2Layout::~SwNode2Layout()
452 : {
453 2999 : delete pImpl;
454 2999 : }
455 :
456 0 : SwFrm* SwNode2Layout::GetFrm( const Point* pDocPos,
457 : const SwPosition *pPos,
458 : const bool bCalcFrm ) const
459 : {
460 0 : return pImpl->GetFrm( pDocPos, pPos, bCalcFrm );
461 177 : }
462 :
463 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|