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 <sal/config.h>
21 :
22 : #include <bodyfrm.hxx>
23 : #include "swtable.hxx"
24 : #include "rootfrm.hxx"
25 : #include "pagefrm.hxx"
26 : #include "viewimp.hxx"
27 : #include "viewopt.hxx"
28 : #include "frmtool.hxx"
29 : #include <IDocumentFieldsAccess.hxx>
30 : #include "dcontact.hxx"
31 : #include <editeng/formatbreakitem.hxx>
32 : #include <editeng/keepitem.hxx>
33 : #include <fmtsrnd.hxx>
34 : #include <fmtpdsc.hxx>
35 : #include <editeng/ulspitem.hxx>
36 : #include <tgrditem.hxx>
37 : #include <txtftn.hxx>
38 : #include <fmtftn.hxx>
39 : #include <editeng/pgrditem.hxx>
40 : #include <paratr.hxx>
41 : #include "ftnfrm.hxx"
42 : #include "txtfrm.hxx"
43 : #include "tabfrm.hxx"
44 : #include "pagedesc.hxx"
45 : #include "layact.hxx"
46 : #include "flyfrms.hxx"
47 : #include "sectfrm.hxx"
48 : #include "section.hxx"
49 : #include "dbg_lay.hxx"
50 : #include "lineinfo.hxx"
51 : #include <fmtclbl.hxx>
52 : #include <sortedobjs.hxx>
53 : #include <layouter.hxx>
54 : #include <fmtfollowtextflow.hxx>
55 : #include <calbck.hxx>
56 : #include <IDocumentSettingAccess.hxx>
57 : #include <IDocumentDrawModelAccess.hxx>
58 :
59 : bool SwFlowFrm::m_bMoveBwdJump = false;
60 :
61 39592 : SwFlowFrm::SwFlowFrm( SwFrm &rFrm ) :
62 : m_rThis( rFrm ),
63 : m_pFollow( 0 ),
64 : m_pPrecede( 0 ),
65 : m_bLockJoin( false ),
66 : m_bUndersized( false ),
67 39592 : m_bFlyLock( false )
68 39592 : {}
69 :
70 38766 : SwFlowFrm::~SwFlowFrm()
71 : {
72 38766 : if (m_pFollow)
73 : {
74 276 : m_pFollow->m_pPrecede = 0;
75 : }
76 38766 : if (m_pPrecede)
77 : {
78 0 : m_pPrecede->m_pFollow = 0;
79 : }
80 38766 : }
81 :
82 3447 : void SwFlowFrm::SetFollow(SwFlowFrm *const pFollow)
83 : {
84 3447 : if (m_pFollow)
85 : {
86 : assert(this == m_pFollow->m_pPrecede);
87 770 : m_pFollow->m_pPrecede = 0;
88 : }
89 3447 : m_pFollow = pFollow;
90 3447 : if (m_pFollow != NULL)
91 : {
92 1135 : if (m_pFollow->m_pPrecede) // re-chaining pFollow?
93 : {
94 : assert(m_pFollow == m_pFollow->m_pPrecede->m_pFollow);
95 84 : m_pFollow->m_pPrecede->m_pFollow = 0;
96 : }
97 1135 : m_pFollow->m_pPrecede = this;
98 : }
99 3447 : }
100 :
101 : /// @return true if any follow has the JoinLocked flag
102 4970 : bool SwFlowFrm::HasLockedFollow() const
103 : {
104 4970 : const SwFlowFrm* pFrm = GetFollow();
105 9941 : while( pFrm )
106 : {
107 1 : if( pFrm->IsJoinLocked() )
108 0 : return true;
109 1 : pFrm = pFrm->GetFollow();
110 : }
111 4970 : return false;
112 : }
113 :
114 107 : bool SwFlowFrm::IsKeepFwdMoveAllowed()
115 : {
116 : // If all the predecessors up to the first of the chain have
117 : // the 'keep' attribute set, and the first of the chain's
118 : // IsFwdMoveAllowed returns false, then we're not allowed to move.
119 107 : SwFrm *pFrm = &m_rThis;
120 107 : if ( !pFrm->IsInFootnote() )
121 491 : do
122 532 : { if ( pFrm->GetAttrSet()->GetKeep().GetValue() )
123 491 : pFrm = pFrm->GetIndPrev();
124 : else
125 41 : return true;
126 : } while ( pFrm );
127 :
128 : //See IsFwdMoveAllowed()
129 66 : bool bRet = false;
130 66 : if ( pFrm && pFrm->GetIndPrev() )
131 0 : bRet = true;
132 66 : return bRet;
133 : }
134 :
135 18551 : void SwFlowFrm::CheckKeep()
136 : {
137 : // Kick off the "last" predecessor with a 'keep' attribute, because
138 : // it's possible for the whole troop to move back.
139 18551 : SwFrm *pPre = m_rThis.GetIndPrev();
140 18551 : if( pPre->IsSctFrm() )
141 : {
142 306 : SwFrm *pLast = static_cast<SwSectionFrm*>(pPre)->FindLastContent();
143 306 : if( pLast && pLast->FindSctFrm() == pPre )
144 262 : pPre = pLast;
145 : else
146 18595 : return;
147 : }
148 : SwFrm* pTmp;
149 : bool bKeep;
150 39680 : while ( (bKeep = pPre->GetAttrSet()->GetKeep().GetValue()) &&
151 : 0 != ( pTmp = pPre->GetIndPrev() ) )
152 : {
153 2666 : if( pTmp->IsSctFrm() )
154 : {
155 17 : SwFrm *pLast = static_cast<SwSectionFrm*>(pTmp)->FindLastContent();
156 17 : if( pLast && pLast->FindSctFrm() == pTmp )
157 17 : pTmp = pLast;
158 : else
159 0 : break;
160 : }
161 2666 : pPre = pTmp;
162 : }
163 18507 : if ( bKeep )
164 705 : pPre->InvalidatePos();
165 : }
166 :
167 80248 : bool SwFlowFrm::IsKeep( const SwAttrSet& rAttrs, bool bCheckIfLastRowShouldKeep ) const
168 : {
169 : // 1. The keep attribute is ignored inside footnotes
170 : // 2. For compatibility reasons, the keep attribute is
171 : // ignored for frames inside table cells
172 : // 3. If bBreakCheck is set to true, this function only checks
173 : // if there are any break after attributes set at rAttrs
174 : // or break before attributes set for the next content (or next table)
175 163113 : bool bKeep = bCheckIfLastRowShouldKeep ||
176 154694 : ( !m_rThis.IsInFootnote() &&
177 158755 : ( !m_rThis.IsInTab() || m_rThis.IsTabFrm() ) &&
178 138259 : rAttrs.GetKeep().GetValue() );
179 :
180 : OSL_ENSURE( !bCheckIfLastRowShouldKeep || m_rThis.IsTabFrm(),
181 : "IsKeep with bCheckIfLastRowShouldKeep should only be used for tabfrms" );
182 :
183 : // Ignore keep attribute if there are break situations:
184 80248 : if ( bKeep )
185 : {
186 5287 : switch ( rAttrs.GetBreak().GetBreak() )
187 : {
188 : case SVX_BREAK_COLUMN_AFTER:
189 : case SVX_BREAK_COLUMN_BOTH:
190 : case SVX_BREAK_PAGE_AFTER:
191 : case SVX_BREAK_PAGE_BOTH:
192 : {
193 34 : bKeep = false;
194 : }
195 5287 : default: break;
196 : }
197 5287 : if ( bKeep )
198 : {
199 : SwFrm *pNxt;
200 15319 : if( 0 != (pNxt = m_rThis.FindNextCnt()) &&
201 5033 : (!m_pFollow || pNxt != &m_pFollow->GetFrm()))
202 : {
203 : // #135914#
204 : // The last row of a table only keeps with the next content
205 : // it they are in the same section:
206 5033 : if ( bCheckIfLastRowShouldKeep )
207 : {
208 2595 : const SwSection* pThisSection = 0;
209 2595 : const SwSection* pNextSection = 0;
210 2595 : const SwSectionFrm* pThisSectionFrm = m_rThis.FindSctFrm();
211 2595 : const SwSectionFrm* pNextSectionFrm = pNxt->FindSctFrm();
212 :
213 2595 : if ( pThisSectionFrm )
214 155 : pThisSection = pThisSectionFrm->GetSection();
215 :
216 2595 : if ( pNextSectionFrm )
217 176 : pNextSection = pNextSectionFrm->GetSection();
218 :
219 2595 : if ( pThisSection != pNextSection )
220 21 : bKeep = false;
221 : }
222 :
223 5033 : if ( bKeep )
224 : {
225 5012 : const SwAttrSet* pSet = NULL;
226 :
227 5012 : if ( pNxt->IsInTab() )
228 : {
229 295 : SwTabFrm* pTab = pNxt->FindTabFrm();
230 295 : if ( ! m_rThis.IsInTab() || m_rThis.FindTabFrm() != pTab )
231 295 : pSet = &pTab->GetFormat()->GetAttrSet();
232 : }
233 :
234 5012 : if ( ! pSet )
235 4717 : pSet = pNxt->GetAttrSet();
236 :
237 : assert(pSet && "No AttrSet to check keep attribute");
238 :
239 5012 : if ( pSet->GetPageDesc().GetPageDesc() )
240 73 : bKeep = false;
241 4939 : else switch ( pSet->GetBreak().GetBreak() )
242 : {
243 : case SVX_BREAK_COLUMN_BEFORE:
244 : case SVX_BREAK_COLUMN_BOTH:
245 : case SVX_BREAK_PAGE_BEFORE:
246 : case SVX_BREAK_PAGE_BOTH:
247 111 : bKeep = false;
248 4939 : default: break;
249 : }
250 : }
251 : }
252 : }
253 : }
254 80248 : return bKeep;
255 : }
256 :
257 9110 : sal_uInt8 SwFlowFrm::BwdMoveNecessary( const SwPageFrm *pPage, const SwRect &rRect )
258 : {
259 : // The return value helps deciding whether we need to flow back (3),
260 : // or whether we can use the good old WouldFit (0, 1), or if
261 : // it's reasonable to relocate and test-format (2).
262 :
263 : // Bit 1 in this case means that there are objects anchored to myself,
264 : // bit 2 means that I have to evade other objects.
265 :
266 : // If a SurroundObj that desires to be wrapped around overlaps with the
267 : // Rect, it's required to flow (because we can't guess the relationships).
268 : // However it's possible for a test formatting to happen.
269 : // If the SurroundObj is a Fly and I'm a Lower, or the Fly is a Lower of
270 : // mine, then it doesn't matter.
271 : // If the SurroundObj is anchored in a character bound Fly, and I'm not
272 : // a Lower of that character bound Fly myself, then the Fly doesn't matter.
273 :
274 : // #32639# If the object is anchored with me, i can ignore it, because
275 : // it's likely that it will follow me with the flow. A test formatting is
276 : // not allowed in that case, however!
277 9110 : sal_uInt8 nRet = 0;
278 9110 : SwFlowFrm *pTmp = this;
279 14149 : do
280 : { // If there are objects hanging either on me or on a follow, we can't
281 : // do a test formatting, because paragraph bound objects wouldn't
282 : // be properly considered, and character bound objects shouldn't
283 : // be test formatted at all.
284 14149 : if( pTmp->GetFrm().GetDrawObjs() )
285 49 : nRet = 1;
286 14149 : pTmp = pTmp->GetFollow();
287 14100 : } while ( !nRet && pTmp );
288 9110 : if ( pPage->GetSortedObjs() )
289 : {
290 : // #i28701# - new type <SwSortedObjs>
291 2335 : const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
292 2335 : sal_uLong nIndex = ULONG_MAX;
293 9088 : for ( size_t i = 0; nRet < 3 && i < rObjs.size(); ++i )
294 : {
295 : // #i28701# - consider changed type of
296 : // <SwSortedObjs> entries.
297 6753 : SwAnchoredObject* pObj = rObjs[i];
298 6753 : const SwFrameFormat& rFormat = pObj->GetFrameFormat();
299 6753 : const SwRect aRect( pObj->GetObjRect() );
300 7453 : if ( aRect.IsOver( rRect ) &&
301 700 : rFormat.GetSurround().GetSurround() != SURROUND_THROUGHT )
302 : {
303 45 : if( m_rThis.IsLayoutFrm() && //Fly Lower of This?
304 2 : Is_Lower_Of( &m_rThis, pObj->GetDrawObj() ) )
305 8 : continue;
306 43 : if( pObj->ISA(SwFlyFrm) )
307 : {
308 9 : const SwFlyFrm *pFly = static_cast<const SwFlyFrm*>(pObj);
309 9 : if ( pFly->IsAnLower( &m_rThis ) )//This Lower of Fly?
310 0 : continue;
311 : }
312 :
313 43 : const SwFrm* pAnchor = pObj->GetAnchorFrm();
314 43 : if ( pAnchor == &m_rThis )
315 : {
316 5 : nRet |= 1;
317 5 : continue;
318 : }
319 :
320 : // Don't do this if the object is anchored behind me in the text
321 : // flow, because then I wouldn't evade it.
322 38 : if ( ::IsFrmInSameKontext( pAnchor, &m_rThis ) )
323 : {
324 38 : if ( rFormat.GetAnchor().GetAnchorId() == FLY_AT_PARA )
325 : {
326 : // The index of the other one can be retrieved using the anchor attribute.
327 30 : sal_uLong nTmpIndex = rFormat.GetAnchor().GetContentAnchor()->nNode.GetIndex();
328 : // Now we're going to check whether the current paragraph before
329 : // the anchor of the displacing object sits in the text. If this
330 : // is the case, we don't try to evade it.
331 : // The index is being determined via SwFormatAnchor, because it's
332 : // getting quite expensive otherwise.
333 30 : if( ULONG_MAX == nIndex )
334 : {
335 : const SwNode *pNode;
336 30 : if ( m_rThis.IsContentFrm() )
337 28 : pNode = static_cast<SwContentFrm&>(m_rThis).GetNode();
338 2 : else if( m_rThis.IsSctFrm() )
339 : pNode = static_cast<SwSectionFormat*>(static_cast<SwSectionFrm&>(m_rThis).
340 0 : GetFormat())->GetSectionNode();
341 : else
342 : {
343 : OSL_ENSURE( m_rThis.IsTabFrm(), "new FowFrm?" );
344 : pNode = static_cast<SwTabFrm&>(m_rThis).GetTable()->
345 2 : GetTabSortBoxes()[0]->GetSttNd()->FindTableNode();
346 : }
347 30 : nIndex = pNode->GetIndex();
348 : }
349 30 : if( nIndex < nTmpIndex )
350 3 : continue;
351 : }
352 : }
353 : else
354 0 : continue;
355 :
356 35 : nRet |= 2;
357 : }
358 : }
359 : }
360 9110 : return nRet;
361 : }
362 :
363 : /// A specialized form of Cut(), which relocates a whole chain (this and the following,
364 : /// in particular). During this process, only the minimum operations and notifications are done.
365 2115 : SwLayoutFrm *SwFlowFrm::CutTree( SwFrm *pStart )
366 : {
367 : // Cut the Start and all the neighbours; they are chained together and
368 : // a handle to the first one is returned. Residuals are invalidated
369 : // as appropriate.
370 :
371 2115 : SwLayoutFrm *pLay = pStart->GetUpper();
372 2115 : if ( pLay->IsInFootnote() )
373 18 : pLay = pLay->FindFootnoteFrm();
374 :
375 : // #i58846#
376 : // <pPrepare( PREP_QUOVADIS )> only for frames in footnotes
377 2115 : if( pStart->IsInFootnote() )
378 : {
379 18 : SwFrm* pTmp = pStart->GetIndPrev();
380 18 : if( pTmp )
381 18 : pTmp->Prepare( PREP_QUOVADIS );
382 : }
383 :
384 : // Just cut quickly and take care that we don't cause problems with the
385 : // left-behinds. The pointers of the chain being cut can point who-knows where.
386 2115 : if ( pStart == pStart->GetUpper()->Lower() )
387 415 : pStart->GetUpper()->m_pLower = nullptr;
388 2115 : if ( pStart->GetPrev() )
389 : {
390 1700 : pStart->GetPrev()->mpNext = 0;
391 1700 : pStart->mpPrev = 0;
392 : }
393 :
394 2115 : if ( pLay->IsFootnoteFrm() )
395 : {
396 18 : if ( !pLay->Lower() && !pLay->IsColLocked() &&
397 0 : !static_cast<SwFootnoteFrm*>(pLay)->IsBackMoveLocked() )
398 : {
399 0 : pLay->Cut();
400 0 : SwFrm::DestroyFrm(pLay);
401 : }
402 : else
403 : {
404 18 : bool bUnlock = !static_cast<SwFootnoteFrm*>(pLay)->IsBackMoveLocked();
405 18 : static_cast<SwFootnoteFrm*>(pLay)->LockBackMove();
406 18 : pLay->InvalidateSize();
407 18 : pLay->Calc();
408 18 : SwContentFrm *pCnt = pLay->ContainsContent();
409 194 : while ( pCnt && pLay->IsAnLower( pCnt ) )
410 : {
411 : // It's possible for the CntFrm to be locked, and we don't want
412 : // to end up in an endless page migration, so we're not even
413 : // going to call Calc!
414 : OSL_ENSURE( pCnt->IsTextFrm(), "The Graphic has landed." );
415 324 : if ( static_cast<SwTextFrm*>(pCnt)->IsLocked() ||
416 158 : static_cast<SwTextFrm*>(pCnt)->GetFollow() == pStart )
417 8 : break;
418 158 : pCnt->Calc();
419 158 : pCnt = pCnt->GetNextContentFrm();
420 : }
421 18 : if( bUnlock )
422 13 : static_cast<SwFootnoteFrm*>(pLay)->UnlockBackMove();
423 : }
424 18 : pLay = 0;
425 : }
426 2115 : return pLay;
427 : }
428 :
429 : /// A specialized form of Paste(), which relocates a whole chain (this and the following,
430 : /// in particular). During this process, only the minimum operations and notifications are done.
431 2115 : bool SwFlowFrm::PasteTree( SwFrm *pStart, SwLayoutFrm *pParent, SwFrm *pSibling,
432 : SwFrm *pOldParent )
433 : {
434 : // returns true if there's a LayoutFrm in the chain.
435 2115 : bool bRet = false;
436 :
437 : // The chain beginning with pStart is inserted before pSibling
438 : // under the parent. We take care to invalidate as required.
439 :
440 : // I'm receiving a finished chain. We need to update the pointers for
441 : // the beginning of the chain, then all the uppers and finally the end.
442 : // On the way there, we invalidate as required.
443 2115 : if ( pSibling )
444 : {
445 630 : if ( 0 != (pStart->mpPrev = pSibling->GetPrev()) )
446 8 : pStart->GetPrev()->mpNext = pStart;
447 : else
448 622 : pParent->m_pLower = pStart;
449 630 : pSibling->_InvalidatePos();
450 630 : pSibling->_InvalidatePrt();
451 : }
452 : else
453 : {
454 1485 : if ( 0 == (pStart->mpPrev = pParent->Lower()) )
455 1459 : pParent->m_pLower = pStart;
456 : else
457 : //Modified for #i100782#,04/03/2009
458 : //If the pParent has more than 1 child nodes, former design will
459 : //ignore them directly without any collection work. It will make some
460 : //dangling pointers. This lead the crash...
461 : //The new design will find the last child of pParent in loop way, and
462 : //add the pStart after the last child.
463 : // pParent->Lower()->pNext = pStart;
464 : {
465 26 : SwFrm* pTemp = pParent->m_pLower;
466 80 : while (pTemp)
467 : {
468 54 : if (pTemp->mpNext)
469 28 : pTemp = pTemp->mpNext;
470 : else
471 : {
472 26 : pStart->mpPrev = pTemp;
473 26 : pTemp->mpNext = pStart;
474 26 : break;
475 : }
476 : }
477 : }
478 : //End modification for #i100782#,04/03/2009
479 :
480 : // #i27145#
481 1485 : if ( pParent->IsSctFrm() )
482 : {
483 : // We have no sibling because pParent is a section frame and
484 : // has just been created to contain some content. The printing
485 : // area of the frame behind pParent has to be invalidated, so
486 : // that the correct distance between pParent and the next frame
487 : // can be calculated.
488 27 : pParent->InvalidateNextPrtArea();
489 : }
490 : }
491 2115 : SwFrm *pFloat = pStart;
492 2115 : SwFrm *pLst = 0;
493 2115 : SWRECTFN( pParent )
494 2115 : SwTwips nGrowVal = 0;
495 12140 : do
496 12140 : { pFloat->mpUpper = pParent;
497 12140 : pFloat->_InvalidateAll();
498 12140 : pFloat->CheckDirChange();
499 :
500 : // I'm a friend of the TextFrm and thus am allowed to do many things.
501 : // The CacheIdx idea seems to be a bit risky!
502 12140 : if ( pFloat->IsTextFrm() )
503 : {
504 11911 : if ( static_cast<SwTextFrm*>(pFloat)->GetCacheIdx() != USHRT_MAX )
505 2238 : static_cast<SwTextFrm*>(pFloat)->Init(); // I'm his friend.
506 : }
507 : else
508 229 : bRet = true;
509 :
510 12140 : nGrowVal += (pFloat->Frm().*fnRect->fnGetHeight)();
511 12140 : if ( pFloat->GetNext() )
512 10025 : pFloat = pFloat->GetNext();
513 : else
514 : {
515 2115 : pLst = pFloat;
516 2115 : pFloat = 0;
517 : }
518 : } while ( pFloat );
519 :
520 2115 : if ( pSibling )
521 : {
522 630 : pLst->mpNext = pSibling;
523 630 : pSibling->mpPrev = pLst;
524 630 : if( pSibling->IsInFootnote() )
525 : {
526 3 : if( pSibling->IsSctFrm() )
527 2 : pSibling = static_cast<SwSectionFrm*>(pSibling)->ContainsAny();
528 3 : if( pSibling )
529 1 : pSibling->Prepare( PREP_ERGOSUM );
530 : }
531 : }
532 2115 : if ( nGrowVal )
533 : {
534 1627 : if ( pOldParent && pOldParent->IsBodyFrm() ) // For variable page height while browsing
535 1519 : pOldParent->Shrink( nGrowVal );
536 1627 : pParent->Grow( nGrowVal );
537 : }
538 :
539 2115 : if ( pParent->IsFootnoteFrm() )
540 11 : static_cast<SwFootnoteFrm*>(pParent)->InvalidateNxtFootnoteCnts( pParent->FindPageFrm() );
541 2115 : return bRet;
542 : }
543 :
544 2115 : void SwFlowFrm::MoveSubTree( SwLayoutFrm* pParent, SwFrm* pSibling )
545 : {
546 : OSL_ENSURE( pParent, "No parent given." );
547 : OSL_ENSURE( m_rThis.GetUpper(), "Where are we coming from?" );
548 :
549 : // Be economical with notifications if an action is running.
550 2115 : SwViewShell *pSh = m_rThis.getRootFrm()->GetCurrShell();
551 2115 : const SwViewShellImp *pImp = pSh ? pSh->Imp() : 0;
552 2115 : const bool bComplete = pImp && pImp->IsAction() && pImp->GetLayAction().IsComplete();
553 :
554 2115 : if ( !bComplete )
555 : {
556 1634 : SwFrm *pPre = m_rThis.GetIndPrev();
557 1634 : if ( pPre )
558 : {
559 1388 : pPre->SetRetouche();
560 : // #115759# - follow-up of #i26250#
561 : // invalidate printing area of previous frame, if it's in a table
562 1388 : if ( pPre->GetUpper()->IsInTab() )
563 : {
564 61 : pPre->_InvalidatePrt();
565 : }
566 1388 : pPre->InvalidatePage();
567 : }
568 : else
569 : {
570 246 : m_rThis.GetUpper()->SetCompletePaint();
571 246 : m_rThis.GetUpper()->InvalidatePage();
572 : }
573 : }
574 :
575 2115 : SwPageFrm *pOldPage = m_rThis.FindPageFrm();
576 :
577 : SwLayoutFrm *pOldParent;
578 : bool bInvaLay;
579 :
580 : {
581 : //JoinLock pParent for the lifetime of the Cut/Paste call to avoid
582 : //SwSectionFrm::MergeNext removing the pParent we're trying to reparent
583 : //into
584 2115 : FlowFrmJoinLockGuard aJoinGuard(pParent);
585 2115 : pOldParent = CutTree( &m_rThis );
586 2115 : bInvaLay = PasteTree( &m_rThis, pParent, pSibling, pOldParent );
587 : }
588 :
589 : // If, by cutting & pasting, an empty SectionFrm came into existence, it should
590 : // disappear automatically.
591 : SwSectionFrm *pSct;
592 : // #126020# - adjust check for empty section
593 : // #130797# - correct fix #126020#
594 2586 : if ( pOldParent && !pOldParent->Lower() &&
595 1162 : ( pOldParent->IsInSct() &&
596 809 : !(pSct = pOldParent->FindSctFrm())->ContainsContent() &&
597 59 : !pSct->ContainsAny( true ) ) )
598 : {
599 59 : pSct->DelEmpty( false );
600 : }
601 :
602 : // If we're in a column section, we'd rather not call Calc "from below"
603 3550 : if( !m_rThis.IsInSct() &&
604 948 : ( !m_rThis.IsInTab() || ( m_rThis.IsTabFrm() && !m_rThis.GetUpper()->IsInTab() ) ) )
605 661 : m_rThis.GetUpper()->Calc();
606 1454 : else if( m_rThis.GetUpper()->IsSctFrm() )
607 : {
608 38 : SwSectionFrm* pTmpSct = static_cast<SwSectionFrm*>(m_rThis.GetUpper());
609 38 : bool bOld = pTmpSct->IsContentLocked();
610 38 : pTmpSct->SetContentLock( true );
611 38 : pTmpSct->Calc();
612 38 : if( !bOld )
613 38 : pTmpSct->SetContentLock( false );
614 : }
615 2115 : SwPageFrm *pPage = m_rThis.FindPageFrm();
616 :
617 2115 : if ( pOldPage != pPage )
618 : {
619 932 : m_rThis.InvalidatePage( pPage );
620 932 : if ( m_rThis.IsLayoutFrm() )
621 : {
622 85 : SwContentFrm *pCnt = static_cast<SwLayoutFrm*>(&m_rThis)->ContainsContent();
623 85 : if ( pCnt )
624 84 : pCnt->InvalidatePage( pPage );
625 : }
626 1694 : else if ( pSh && pSh->GetDoc()->GetLineNumberInfo().IsRestartEachPage()
627 847 : && pPage->FindFirstBodyContent() == &m_rThis )
628 : {
629 0 : m_rThis._InvalidateLineNum();
630 : }
631 : }
632 2115 : if ( bInvaLay || (pSibling && pSibling->IsLayoutFrm()) )
633 150 : m_rThis.GetUpper()->InvalidatePage( pPage );
634 2115 : }
635 :
636 4842 : bool SwFlowFrm::IsAnFollow( const SwFlowFrm *pAssumed ) const
637 : {
638 4842 : const SwFlowFrm *pFoll = this;
639 4857 : do
640 5835 : { if ( pAssumed == pFoll )
641 978 : return true;
642 4857 : pFoll = pFoll->GetFollow();
643 : } while ( pFoll );
644 3864 : return false;
645 : }
646 :
647 41014 : SwTextFrm* SwContentFrm::FindMaster() const
648 : {
649 : OSL_ENSURE( IsFollow(), "SwContentFrm::FindMaster(): !IsFollow" );
650 :
651 41014 : const SwContentFrm* pPrec = GetPrecede();
652 :
653 41014 : if ( pPrec && pPrec->HasFollow() && pPrec->GetFollow() == this )
654 : {
655 : OSL_ENSURE( pPrec->IsTextFrm(), "NoTextFrm with follow found" );
656 41014 : return const_cast<SwTextFrm*>(static_cast< const SwTextFrm* >(pPrec));
657 : }
658 :
659 : OSL_FAIL( "Follow ist lost in Space." );
660 0 : return 0;
661 : }
662 :
663 296 : SwSectionFrm* SwSectionFrm::FindMaster() const
664 : {
665 : OSL_ENSURE( IsFollow(), "SwSectionFrm::FindMaster(): !IsFollow" );
666 :
667 296 : SwIterator<SwSectionFrm,SwFormat> aIter( *pSection->GetFormat() );
668 296 : SwSectionFrm* pSect = aIter.First();
669 1279 : while ( pSect )
670 : {
671 983 : if( pSect->GetFollow() == this )
672 296 : return pSect;
673 687 : pSect = aIter.Next();
674 : }
675 :
676 : OSL_FAIL( "Follow ist lost in Space." );
677 0 : return 0;
678 : }
679 :
680 4637 : SwTabFrm* SwTabFrm::FindMaster( bool bFirstMaster ) const
681 : {
682 : OSL_ENSURE( IsFollow(), "SwTabFrm::FindMaster(): !IsFollow" );
683 :
684 4637 : SwIterator<SwTabFrm,SwFormat> aIter( *GetTable()->GetFrameFormat() );
685 4637 : SwTabFrm* pTab = aIter.First();
686 21520 : while ( pTab )
687 : {
688 16883 : if ( bFirstMaster )
689 : {
690 : // Optimization. This makes code like this obsolete:
691 : // while ( pTab->IsFollow() )
692 : // pTab = pTab->FindMaster();
693 :
694 0 : if ( !pTab->IsFollow() )
695 : {
696 0 : SwTabFrm* pNxt = pTab;
697 0 : while ( pNxt )
698 : {
699 0 : if ( pNxt->GetFollow() == this )
700 0 : return pTab;
701 0 : pNxt = pNxt->GetFollow();
702 : }
703 : }
704 : }
705 : else
706 : {
707 16883 : if ( pTab->GetFollow() == this )
708 4637 : return pTab;
709 : }
710 :
711 12246 : pTab = aIter.Next();
712 : }
713 :
714 : OSL_FAIL( "Follow ist lost in Space." );
715 0 : return 0;
716 : }
717 :
718 : /**
719 : * Returns the next/previous Layout leaf that's NOT below this (or even is this itself).
720 : * Also, that leaf must be in the same text flow as the pAnch origin frame (Body, Footnote)
721 : */
722 2 : const SwLayoutFrm *SwFrm::GetLeaf( MakePageType eMakePage, bool bFwd,
723 : const SwFrm *pAnch ) const
724 : {
725 : // No flow, no joy...
726 2 : if ( !(IsInDocBody() || IsInFootnote() || IsInFly()) )
727 0 : return 0;
728 :
729 2 : const SwFrm *pLeaf = this;
730 2 : bool bFound = false;
731 :
732 2 : do
733 2 : { pLeaf = const_cast<SwFrm*>(pLeaf)->GetLeaf( eMakePage, bFwd );
734 :
735 6 : if ( pLeaf &&
736 4 : (!IsLayoutFrm() || !static_cast<const SwLayoutFrm*>(this)->IsAnLower( pLeaf )))
737 : {
738 4 : if ( pAnch->IsInDocBody() == pLeaf->IsInDocBody() &&
739 2 : pAnch->IsInFootnote() == pLeaf->IsInFootnote() )
740 : {
741 2 : bFound = true;
742 : }
743 : }
744 2 : } while ( !bFound && pLeaf );
745 :
746 2 : return static_cast<const SwLayoutFrm*>(pLeaf);
747 : }
748 :
749 27810 : SwLayoutFrm *SwFrm::GetLeaf( MakePageType eMakePage, bool bFwd )
750 : {
751 27810 : if ( IsInFootnote() )
752 73 : return bFwd ? GetNextFootnoteLeaf( eMakePage ) : GetPrevFootnoteLeaf( eMakePage );
753 :
754 : // #i53323#
755 : // A frame could be inside a table AND inside a section.
756 : // Thus, it has to be determined, which is the first parent.
757 27737 : bool bInTab( IsInTab() );
758 27737 : bool bInSct( IsInSct() );
759 27737 : if ( bInTab && bInSct )
760 : {
761 111 : const SwFrm* pUpperFrm( GetUpper() );
762 374 : while ( pUpperFrm )
763 : {
764 263 : if ( pUpperFrm->IsTabFrm() )
765 : {
766 : // the table is the first.
767 76 : bInSct = false;
768 76 : break;
769 : }
770 187 : else if ( pUpperFrm->IsSctFrm() )
771 : {
772 : // the section is the first.
773 35 : bInTab = false;
774 35 : break;
775 : }
776 :
777 152 : pUpperFrm = pUpperFrm->GetUpper();
778 : }
779 : }
780 :
781 27737 : if ( bInTab && ( !IsTabFrm() || GetUpper()->IsCellFrm() ) ) // TABLE IN TABLE
782 463 : return bFwd ? GetNextCellLeaf( eMakePage ) : GetPrevCellLeaf( eMakePage );
783 :
784 27274 : if ( bInSct )
785 3588 : return bFwd ? GetNextSctLeaf( eMakePage ) : GetPrevSctLeaf( eMakePage );
786 :
787 23686 : return bFwd ? GetNextLeaf( eMakePage ) : GetPrevLeaf( eMakePage );
788 : }
789 :
790 1077 : bool SwFrm::WrongPageDesc( SwPageFrm* pNew )
791 : {
792 : // Now it's getting a bit complicated:
793 :
794 : // Maybe i'm bringing a Pagedesc myself; in that case,
795 : // the pagedesc of the next page needs to correspond.
796 : // Otherwise, I'll have to dig a bit deeper to see where
797 : // the following Pagedesc is coming from.
798 : // If the following page itself tells me that it's pagedesc
799 : // is wrong, I can happily exchange it.
800 : // If the page however thinks that it's pagedesc is correct,
801 : // this doesn't mean it's useful to me:
802 : // If the first BodyContent asks for a PageDesc or a PageBreak,
803 : // I'll have to insert a new page - except the desired page is
804 : // the correct one.
805 : // If I inserted a new page, the problems only get started:
806 : // because then it's likely for the next page to have been
807 : // wrong and having been swapped because of that.
808 : // This in turn means that I have a new (and correct) page,
809 : // but the conditions to swap still apply.
810 : // Way out of the situation: Try to preliminarily insert a
811 : // new page once (empty pages are already inserted by InsertPage()
812 : // if required)
813 1077 : const SwFormatPageDesc &rFormatDesc = GetAttrSet()->GetPageDesc();
814 :
815 : //My Pagedesc doesn't count if I'm a follow!
816 1077 : SwPageDesc *pDesc = 0;
817 1077 : int nTmp = 0;
818 1077 : SwFlowFrm *pFlow = SwFlowFrm::CastFlowFrm( this );
819 1077 : if ( !pFlow || !pFlow->IsFollow() )
820 : {
821 726 : pDesc = const_cast<SwPageDesc*>(rFormatDesc.GetPageDesc());
822 726 : if( pDesc )
823 : {
824 70 : if( !pDesc->GetRightFormat() )
825 0 : nTmp = 2;
826 70 : else if( !pDesc->GetLeftFormat() )
827 0 : nTmp = 1;
828 70 : else if( rFormatDesc.GetNumOffset() )
829 46 : nTmp = rFormatDesc.GetNumOffset().get();
830 : }
831 : }
832 :
833 : // Does the Content bring a Pagedesc or do we need the
834 : // virtual page number of the new layout leaf?
835 : // PageDesc isn't allowed with Follows
836 1077 : const bool bOdd = nTmp ? (nTmp % 2) !=0 : pNew->OnRightPage();
837 1077 : if ( !pDesc )
838 1007 : pDesc = pNew->FindPageDesc();
839 :
840 1077 : bool bFirst = pNew->OnFirstPage();
841 :
842 1077 : const SwFlowFrm *pNewFlow = pNew->FindFirstBodyContent();
843 : // Did we find ourselves?
844 1077 : if( pNewFlow == pFlow )
845 0 : pNewFlow = NULL;
846 1077 : if ( pNewFlow && pNewFlow->GetFrm().IsInTab() )
847 11 : pNewFlow = pNewFlow->GetFrm().FindTabFrm();
848 428 : const SwPageDesc *pNewDesc= ( pNewFlow && !pNewFlow->IsFollow() )
849 1394 : ? pNewFlow->GetFrm().GetAttrSet()->GetPageDesc().GetPageDesc() : 0;
850 :
851 1077 : return (pNew->GetPageDesc() != pDesc) // own desc ?
852 2120 : || (pNew->GetFormat() !=
853 1060 : (bOdd ? pDesc->GetRightFormat(bFirst) : pDesc->GetLeftFormat(bFirst)))
854 2123 : || (pNewDesc && pNewDesc == pDesc);
855 : }
856 :
857 : /// Returns the next layout leaf in which we can move the frame.
858 845 : SwLayoutFrm *SwFrm::GetNextLeaf( MakePageType eMakePage )
859 : {
860 : OSL_ENSURE( !IsInFootnote(), "GetNextLeaf(), don't call me for Footnote." );
861 : OSL_ENSURE( !IsInSct(), "GetNextLeaf(), don't call me for Sections." );
862 :
863 845 : const bool bBody = IsInDocBody(); // If I'm coming from the DocBody,
864 : // I want to end up in the body.
865 :
866 : // It doesn't make sense to insert pages, as we only want to search the
867 : // chain.
868 845 : if( IsInFly() )
869 27 : eMakePage = MAKEPAGE_NONE;
870 :
871 : // For tables, we just take the big leap. A simple GetNext would
872 : // iterate through the first cells and, in turn, all other cells.
873 845 : SwLayoutFrm *pLayLeaf = 0;
874 845 : if ( IsTabFrm() )
875 : {
876 61 : SwContentFrm* pTmp = static_cast<SwTabFrm*>(this)->FindLastContent();
877 61 : if ( pTmp )
878 61 : pLayLeaf = pTmp->GetUpper();
879 : }
880 845 : if ( !pLayLeaf )
881 784 : pLayLeaf = GetNextLayoutLeaf();
882 :
883 845 : SwLayoutFrm *pOldLayLeaf = 0; // Make sure that we don't have to
884 : // start searching from top when we
885 : // have a freshly created page.
886 845 : bool bNewPg = false; // Only insert a new page once.
887 :
888 : while ( true )
889 : {
890 5784 : if ( pLayLeaf )
891 : {
892 : // There's yet another LayoutFrm. Let's see if it's ready to host
893 : // me as well.
894 : // It only needs to be of the same kind like my starting point
895 : // (DocBody or Footnote respectively)
896 5512 : if ( pLayLeaf->FindPageFrm()->IsFootnotePage() )
897 : { // If I ended up at the end note pages, we're done.
898 0 : pLayLeaf = 0;
899 0 : continue;
900 : }
901 10973 : if ( (bBody && !pLayLeaf->IsInDocBody()) || pLayLeaf->IsInTab()
902 6478 : || pLayLeaf->IsInSct() )
903 : {
904 : // They don't want me! Try again
905 4671 : pOldLayLeaf = pLayLeaf;
906 4671 : pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
907 4671 : continue;
908 : }
909 :
910 : // I'm wanted, therefore I'm done. However, it may still be that,
911 : // during a page break, the page type isn't the desired one. In that
912 : // case we have to insert a page of the correct type.
913 :
914 1012 : if( !IsFlowFrm() && ( eMakePage == MAKEPAGE_NONE ||
915 0 : eMakePage==MAKEPAGE_APPEND || eMakePage==MAKEPAGE_NOSECTION ) )
916 171 : return pLayLeaf;
917 :
918 670 : SwPageFrm *pNew = pLayLeaf->FindPageFrm();
919 670 : const SwViewShell *pSh = getRootFrm()->GetCurrShell();
920 : // #111704# The pagedesc check does not make sense for frames in fly frames
921 1313 : if ( pNew != FindPageFrm() && !bNewPg && !IsInFly() &&
922 : // #i46683#
923 : // Do not consider page descriptions in browse mode (since
924 : // MoveBwd ignored them)
925 643 : !(pSh && pSh->GetViewOptions()->getBrowseMode() ) )
926 : {
927 643 : if( WrongPageDesc( pNew ) )
928 : {
929 20 : SwFootnoteContFrm *pCont = pNew->FindFootnoteCont();
930 20 : if( pCont )
931 : {
932 : // If the reference of the first footnote of this page
933 : // lies before the page, we'd rather not insert a new page.
934 : // (Bug #55620#)
935 0 : SwFootnoteFrm *pFootnote = static_cast<SwFootnoteFrm*>(pCont->Lower());
936 0 : if( pFootnote && pFootnote->GetRef() )
937 : {
938 0 : const sal_uInt16 nRefNum = pNew->GetPhyPageNum();
939 0 : if( pFootnote->GetRef()->GetPhyPageNum() < nRefNum )
940 0 : break;
941 : }
942 : }
943 : //Gotcha! The following page is wrong, therefore we need to
944 : //insert a new one.
945 20 : if ( eMakePage == MAKEPAGE_INSERT )
946 : {
947 20 : bNewPg = true;
948 :
949 : SwPageFrm *pPg = pOldLayLeaf ?
950 20 : pOldLayLeaf->FindPageFrm() : 0;
951 20 : if ( pPg && pPg->IsEmptyPage() )
952 : // Don't insert behind. Insert before the EmptyPage.
953 0 : pPg = static_cast<SwPageFrm*>(pPg->GetPrev());
954 :
955 20 : if ( !pPg || pPg == pNew )
956 17 : pPg = FindPageFrm();
957 :
958 20 : InsertPage( pPg, false );
959 20 : pLayLeaf = GetNextLayoutLeaf();
960 20 : pOldLayLeaf = 0;
961 20 : continue;
962 : }
963 : else
964 0 : pLayLeaf = 0;
965 : }
966 : }
967 650 : break;
968 : }
969 : else
970 : {
971 : // There's no other matching LayoutFrm, so we have to insert
972 : // a new page.
973 272 : if ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT )
974 : {
975 : InsertPage(
976 67 : pOldLayLeaf ? pOldLayLeaf->FindPageFrm() : FindPageFrm(),
977 315 : false );
978 :
979 : // And again from the start.
980 248 : pLayLeaf = pOldLayLeaf ? pOldLayLeaf : GetNextLayoutLeaf();
981 : }
982 : else
983 : break;
984 : }
985 : }
986 4939 : return pLayLeaf;
987 : }
988 :
989 : /// Returns the previous layout leaf where we can move the frame.
990 22865 : SwLayoutFrm *SwFrm::GetPrevLeaf( MakePageType )
991 : {
992 : OSL_ENSURE( !IsInFootnote(), "GetPrevLeaf(), don't call me for Footnote." );
993 :
994 22865 : const bool bBody = IsInDocBody(); // If I'm coming from the DocBody,
995 : // I want to end up in the body.
996 22865 : const bool bFly = IsInFly();
997 :
998 22865 : SwLayoutFrm *pLayLeaf = GetPrevLayoutLeaf();
999 22865 : SwLayoutFrm *pPrevLeaf = 0;
1000 :
1001 90823 : while ( pLayLeaf )
1002 : {
1003 104342 : if ( pLayLeaf->IsInTab() || // Never go into tables.
1004 52171 : pLayLeaf->IsInSct() ) // Same goes for sections!
1005 121 : pLayLeaf = pLayLeaf->GetPrevLayoutLeaf();
1006 52050 : else if ( bBody && pLayLeaf->IsInDocBody() )
1007 : {
1008 18654 : if ( pLayLeaf->Lower() )
1009 7077 : break;
1010 11577 : pPrevLeaf = pLayLeaf;
1011 11577 : pLayLeaf = pLayLeaf->GetPrevLayoutLeaf();
1012 11577 : if ( pLayLeaf )
1013 11577 : SwFlowFrm::SetMoveBwdJump( true );
1014 : }
1015 33396 : else if ( bFly )
1016 1 : break; //Contents in Flys should accept any layout leaf.
1017 : else
1018 33395 : pLayLeaf = pLayLeaf->GetPrevLayoutLeaf();
1019 : }
1020 22865 : return pLayLeaf ? pLayLeaf : pPrevLeaf;
1021 : }
1022 :
1023 40445 : bool SwFlowFrm::IsPrevObjMove() const
1024 : {
1025 : // true: The FlowFrm must respect the a border of the predecessor, also needs
1026 : // to insert a break if required.
1027 :
1028 : //!!!!!!!!!!!Hack!!!!!!!!!!!
1029 40445 : const SwViewShell *pSh = m_rThis.getRootFrm()->GetCurrShell();
1030 40445 : if( pSh && pSh->GetViewOptions()->getBrowseMode() )
1031 24 : return false;
1032 :
1033 40421 : SwFrm *pPre = m_rThis.FindPrev();
1034 :
1035 40421 : if ( pPre && pPre->GetDrawObjs() )
1036 : {
1037 : OSL_ENSURE( SwFlowFrm::CastFlowFrm( pPre ), "new flowfrm?" );
1038 2054 : if( SwFlowFrm::CastFlowFrm( pPre )->IsAnFollow( this ) )
1039 0 : return false;
1040 2054 : SwLayoutFrm* pPreUp = pPre->GetUpper();
1041 : // If the upper is a SectionFrm, or a column of a SectionFrm, we're
1042 : // allowed to protrude out of it. However, we need to respect the
1043 : // Upper of the SectionFrm.
1044 2054 : if( pPreUp->IsInSct() )
1045 : {
1046 185 : if( pPreUp->IsSctFrm() )
1047 80 : pPreUp = pPreUp->GetUpper();
1048 210 : else if( pPreUp->IsColBodyFrm() &&
1049 105 : pPreUp->GetUpper()->GetUpper()->IsSctFrm() )
1050 105 : pPreUp = pPreUp->GetUpper()->GetUpper()->GetUpper();
1051 : }
1052 : // #i26945# - re-factoring
1053 : // use <GetVertPosOrientFrm()> to determine, if object has followed the
1054 : // text flow to the next layout frame
1055 5664 : for ( size_t i = 0; i < pPre->GetDrawObjs()->size(); ++i )
1056 : {
1057 : // #i28701# - consider changed type of
1058 : // <SwSortedObjs> entries.
1059 3612 : const SwAnchoredObject* pObj = (*pPre->GetDrawObjs())[i];
1060 : // OD 2004-01-20 #110582# - do not consider hidden objects
1061 : // #i26945# - do not consider object, which
1062 : // doesn't follow the text flow.
1063 10836 : if ( pObj->GetFrameFormat().GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(
1064 18060 : pObj->GetDrawObj()->GetLayer() ) &&
1065 3612 : pObj->GetFrameFormat().GetFollowTextFlow().GetValue() )
1066 : {
1067 61 : const SwLayoutFrm* pVertPosOrientFrm = pObj->GetVertPosOrientFrm();
1068 84 : if ( pVertPosOrientFrm &&
1069 63 : pPreUp != pVertPosOrientFrm &&
1070 2 : !pPreUp->IsAnLower( pVertPosOrientFrm ) )
1071 : {
1072 2 : return true;
1073 : }
1074 : }
1075 : }
1076 : }
1077 40419 : return false;
1078 : }
1079 :
1080 : /**
1081 : |* If there's a hard page break before the Frm AND there's a
1082 : |* predecessor on the same page, true is returned (we need to create a
1083 : |* new PageBreak). Otherwise, returns false.
1084 : |* If bAct is set to true, this function returns true if
1085 : |* there's a PageBreak.
1086 : |* Of course, we don't evaluate the hard page break for follows.
1087 : |* The page break is in it's own FrameFormat (BEFORE) or in the FrameFormat of the
1088 : |* predecessor (AFTER). If there's no predecessor on the page, we don't
1089 : |* need to think further.
1090 : |* Also, a page break (or the need for one) is also present if
1091 : |* the FrameFormat contains a PageDesc.
1092 : |* The implementation works only on ContentFrms! - the definition
1093 : |* of the predecessor is not clear for LayoutFrms.
1094 : |*/
1095 91580 : bool SwFlowFrm::IsPageBreak( bool bAct ) const
1096 : {
1097 257486 : if ( !IsFollow() && m_rThis.IsInDocBody() &&
1098 90905 : ( !m_rThis.IsInTab() || ( m_rThis.IsTabFrm() && !m_rThis.GetUpper()->IsInTab() ) ) ) // i66968
1099 : {
1100 82424 : const SwViewShell *pSh = m_rThis.getRootFrm()->GetCurrShell();
1101 82424 : if( pSh && pSh->GetViewOptions()->getBrowseMode() )
1102 185 : return false;
1103 82239 : const SwAttrSet *pSet = m_rThis.GetAttrSet();
1104 :
1105 : // Determine predecessor
1106 82239 : const SwFrm *pPrev = m_rThis.FindPrev();
1107 217542 : while ( pPrev && ( !pPrev->IsInDocBody() ||
1108 104745 : ( pPrev->IsTextFrm() && static_cast<const SwTextFrm*>(pPrev)->IsHiddenNow() ) ) )
1109 15 : pPrev = pPrev->FindPrev();
1110 :
1111 82239 : if ( pPrev )
1112 : {
1113 : OSL_ENSURE( pPrev->IsInDocBody(), "IsPageBreak: Not in DocBody?" );
1114 53019 : if ( bAct )
1115 16941 : { if ( m_rThis.FindPageFrm() == pPrev->FindPageFrm() )
1116 1056 : return false;
1117 : }
1118 : else
1119 36078 : { if ( m_rThis.FindPageFrm() != pPrev->FindPageFrm() )
1120 34 : return false;
1121 : }
1122 :
1123 51929 : const SvxBreak eBreak = pSet->GetBreak().GetBreak();
1124 51929 : if ( eBreak == SVX_BREAK_PAGE_BEFORE || eBreak == SVX_BREAK_PAGE_BOTH )
1125 2186 : return true;
1126 : else
1127 : {
1128 49743 : const SvxBreak &ePrB = pPrev->GetAttrSet()->GetBreak().GetBreak();
1129 149229 : if ( ePrB == SVX_BREAK_PAGE_AFTER ||
1130 99486 : ePrB == SVX_BREAK_PAGE_BOTH ||
1131 49743 : pSet->GetPageDesc().GetPageDesc() )
1132 925 : return true;
1133 : }
1134 : }
1135 : }
1136 87194 : return false;
1137 : }
1138 :
1139 : /**
1140 : |* If there's a hard column break before the Frm AND there is
1141 : |* a predecessor in the same column, we return true (we need to create
1142 : |* a ColBreak). Otherwise, we return false.
1143 : |* If bAct is set to true, we return true if there's a ColBreak.
1144 : |* Of course, we don't evaluate the hard column break for follows.
1145 : |*
1146 : |* The column break is in it's own FrameFormat (BEFORE) or in the FrameFormat of the
1147 : |* predecessor (AFTER). If there's no predecessor in the column, we don't
1148 : |* need to think further.
1149 : |* The implementation works only on ContentFrms! - the definition
1150 : |* of the predecessor is not clear for LayoutFrms.
1151 : |*/
1152 64583 : bool SwFlowFrm::IsColBreak( bool bAct ) const
1153 : {
1154 64583 : if ( !IsFollow() && (m_rThis.IsMoveable() || bAct) )
1155 : {
1156 62401 : const SwFrm *pCol = m_rThis.FindColFrm();
1157 62401 : if ( pCol )
1158 : {
1159 : // Determine predecessor
1160 7070 : const SwFrm *pPrev = m_rThis.FindPrev();
1161 21022 : while( pPrev && ( ( !pPrev->IsInDocBody() && !m_rThis.IsInFly() ) ||
1162 13726 : ( pPrev->IsTextFrm() && static_cast<const SwTextFrm*>(pPrev)->IsHiddenNow() ) ) )
1163 0 : pPrev = pPrev->FindPrev();
1164 :
1165 7070 : if ( pPrev )
1166 : {
1167 6882 : if ( bAct )
1168 2866 : { if ( pCol == pPrev->FindColFrm() )
1169 0 : return false;
1170 : }
1171 : else
1172 4016 : { if ( pCol != pPrev->FindColFrm() )
1173 837 : return false;
1174 : }
1175 :
1176 6045 : const SvxBreak eBreak = m_rThis.GetAttrSet()->GetBreak().GetBreak();
1177 6045 : if ( eBreak == SVX_BREAK_COLUMN_BEFORE ||
1178 : eBreak == SVX_BREAK_COLUMN_BOTH )
1179 875 : return true;
1180 : else
1181 : {
1182 5170 : const SvxBreak &ePrB = pPrev->GetAttrSet()->GetBreak().GetBreak();
1183 10340 : if ( ePrB == SVX_BREAK_COLUMN_AFTER ||
1184 5170 : ePrB == SVX_BREAK_COLUMN_BOTH )
1185 0 : return true;
1186 : }
1187 : }
1188 : }
1189 : }
1190 62871 : return false;
1191 : }
1192 :
1193 51427 : bool SwFlowFrm::HasParaSpaceAtPages( bool bSct ) const
1194 : {
1195 51427 : if( m_rThis.IsInSct() )
1196 : {
1197 6531 : const SwFrm* pTmp = m_rThis.GetUpper();
1198 18768 : while( pTmp )
1199 : {
1200 46860 : if( pTmp->IsCellFrm() || pTmp->IsFlyFrm() ||
1201 46851 : pTmp->IsFooterFrm() || pTmp->IsHeaderFrm() ||
1202 11193 : ( pTmp->IsFootnoteFrm() && !static_cast<const SwFootnoteFrm*>(pTmp)->GetMaster() ) )
1203 1062 : return true;
1204 11175 : if( pTmp->IsPageFrm() )
1205 433 : return !( pTmp->GetPrev() && !IsPageBreak(true) );
1206 10742 : if( pTmp->IsColumnFrm() && pTmp->GetPrev() )
1207 2025 : return IsColBreak( true );
1208 8717 : if( pTmp->IsSctFrm() && ( !bSct || pTmp->GetPrev() ) )
1209 3011 : return false;
1210 5706 : pTmp = pTmp->GetUpper();
1211 : }
1212 : OSL_FAIL( "HasParaSpaceAtPages: Where's my page?" );
1213 0 : return false;
1214 : }
1215 140300 : if( !m_rThis.IsInDocBody() || ( m_rThis.IsInTab() && !m_rThis.IsTabFrm()) ||
1216 76970 : IsPageBreak( true ) || ( m_rThis.FindColFrm() && IsColBreak( true ) ) )
1217 29523 : return true;
1218 15373 : const SwFrm* pTmp = m_rThis.FindColFrm();
1219 15373 : if( pTmp )
1220 : {
1221 24 : if( pTmp->GetPrev() )
1222 4 : return false;
1223 : }
1224 : else
1225 15349 : pTmp = &m_rThis;
1226 15369 : pTmp = pTmp->FindPageFrm();
1227 15369 : return pTmp && !pTmp->GetPrev();
1228 : }
1229 :
1230 : /** helper method to determine previous frame for calculation of the
1231 : upper space
1232 :
1233 : OD 2004-03-10 #i11860#
1234 : */
1235 118356 : const SwFrm* SwFlowFrm::_GetPrevFrmForUpperSpaceCalc( const SwFrm* _pProposedPrevFrm ) const
1236 : {
1237 : const SwFrm* pPrevFrm = _pProposedPrevFrm
1238 : ? _pProposedPrevFrm
1239 118356 : : m_rThis.GetPrev();
1240 :
1241 : // Skip hidden paragraphs and empty sections
1242 286373 : while ( pPrevFrm &&
1243 95323 : ( ( pPrevFrm->IsTextFrm() &&
1244 95313 : static_cast<const SwTextFrm*>(pPrevFrm)->IsHiddenNow() ) ||
1245 49871 : ( pPrevFrm->IsSctFrm() &&
1246 974 : !static_cast<const SwSectionFrm*>(pPrevFrm)->GetSection() ) ) )
1247 : {
1248 377 : pPrevFrm = pPrevFrm->GetPrev();
1249 : }
1250 :
1251 : // Special case: no direct previous frame is found but frame is in footnote
1252 : // Search for a previous frame in previous footnote,
1253 : // if frame isn't in a section, which is also in the footnote
1254 118899 : if ( !pPrevFrm && m_rThis.IsInFootnote() &&
1255 562 : ( m_rThis.IsSctFrm() ||
1256 344 : !m_rThis.IsInSct() || !m_rThis.FindSctFrm()->IsInFootnote() ) )
1257 : {
1258 : const SwFootnoteFrm* pPrevFootnoteFrm =
1259 256 : static_cast<const SwFootnoteFrm*>(m_rThis.FindFootnoteFrm()->GetPrev());
1260 256 : if ( pPrevFootnoteFrm )
1261 : {
1262 45 : pPrevFrm = pPrevFootnoteFrm->GetLastLower();
1263 :
1264 : // Skip hidden paragraphs and empty sections
1265 135 : while ( pPrevFrm &&
1266 90 : ( ( pPrevFrm->IsTextFrm() &&
1267 90 : static_cast<const SwTextFrm*>(pPrevFrm)->IsHiddenNow() ) ||
1268 45 : ( pPrevFrm->IsSctFrm() &&
1269 0 : !static_cast<const SwSectionFrm*>(pPrevFrm)->GetSection() ) ) )
1270 : {
1271 0 : pPrevFrm = pPrevFrm->GetPrev();
1272 : }
1273 : }
1274 : }
1275 : // Special case: found previous frame is a section
1276 : // Search for the last content in the section
1277 118356 : if( pPrevFrm && pPrevFrm->IsSctFrm() )
1278 : {
1279 : const SwSectionFrm* pPrevSectFrm =
1280 607 : static_cast<const SwSectionFrm*>(pPrevFrm);
1281 607 : pPrevFrm = pPrevSectFrm->FindLastContent();
1282 : // If the last content is in a table _inside_ the section,
1283 : // take the table herself.
1284 : // OD 2004-02-18 #106629# - correction:
1285 : // Check directly, if table is inside table, instead of indirectly
1286 : // by checking, if section isn't inside a table
1287 607 : if ( pPrevFrm && pPrevFrm->IsInTab() )
1288 : {
1289 4 : const SwTabFrm* pTableFrm = pPrevFrm->FindTabFrm();
1290 4 : if ( pPrevSectFrm->IsAnLower( pTableFrm ) )
1291 : {
1292 0 : pPrevFrm = pTableFrm;
1293 : }
1294 : }
1295 : // OD 2004-02-18 #106629# correction: skip hidden text frames
1296 1819 : while ( pPrevFrm &&
1297 1212 : pPrevFrm->IsTextFrm() &&
1298 605 : static_cast<const SwTextFrm*>(pPrevFrm)->IsHiddenNow() )
1299 : {
1300 0 : pPrevFrm = pPrevFrm->GetPrev();
1301 : }
1302 : }
1303 :
1304 118356 : return pPrevFrm;
1305 : }
1306 :
1307 : /// Compare styles attached to these text frames.
1308 342 : static bool lcl_IdenticalStyles(const SwFrm* pPrevFrm, const SwFrm* pFrm)
1309 : {
1310 342 : SwTextFormatColl *pPrevFormatColl = 0;
1311 342 : if (pPrevFrm && pPrevFrm->IsTextFrm())
1312 : {
1313 342 : const SwTextFrm *pTextFrm = static_cast< const SwTextFrm * >( pPrevFrm );
1314 342 : pPrevFormatColl = dynamic_cast<SwTextFormatColl*>(pTextFrm->GetTextNode()->GetFormatColl());
1315 : }
1316 :
1317 342 : bool bIdenticalStyles = false;
1318 342 : if (pFrm && pFrm->IsTextFrm())
1319 : {
1320 342 : const SwTextFrm *pTextFrm = static_cast< const SwTextFrm * >( pFrm );
1321 342 : SwTextFormatColl *pFormatColl = dynamic_cast<SwTextFormatColl*>(pTextFrm->GetTextNode()->GetFormatColl());
1322 342 : bIdenticalStyles = pPrevFormatColl == pFormatColl;
1323 : }
1324 342 : return bIdenticalStyles;
1325 : }
1326 :
1327 419 : static bool lcl_getContextualSpacing(const SwFrm* pPrevFrm)
1328 : {
1329 : bool bRet;
1330 419 : SwBorderAttrAccess *pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), pPrevFrm );
1331 419 : const SwBorderAttrs *pAttrs = pAccess->Get();
1332 :
1333 419 : bRet = pAttrs->GetULSpace().GetContext();
1334 :
1335 419 : delete pAccess;
1336 419 : return bRet;
1337 : }
1338 :
1339 : // OD 2004-03-12 #i11860# - add 3rd parameter <_bConsiderGrid>
1340 92655 : SwTwips SwFlowFrm::CalcUpperSpace( const SwBorderAttrs *pAttrs,
1341 : const SwFrm* pPr,
1342 : const bool _bConsiderGrid ) const
1343 : {
1344 : // OD 2004-03-10 #i11860# - use new method <GetPrevFrmForUpperSpaceCalc(..)>
1345 92655 : const SwFrm* pPrevFrm = _GetPrevFrmForUpperSpaceCalc( pPr );
1346 :
1347 : SwBorderAttrAccess *pAccess;
1348 : SwFrm* pOwn;
1349 92655 : if( !pAttrs )
1350 : {
1351 5801 : if( m_rThis.IsSctFrm() )
1352 : {
1353 1143 : SwSectionFrm* pFoll = &static_cast<SwSectionFrm&>(m_rThis);
1354 1217 : do
1355 1217 : pOwn = pFoll->ContainsAny();
1356 1217 : while( !pOwn && 0 != ( pFoll = pFoll->GetFollow() ) );
1357 1143 : if( !pOwn )
1358 18 : return 0;
1359 : }
1360 : else
1361 4658 : pOwn = &m_rThis;
1362 5783 : pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), pOwn );
1363 5783 : pAttrs = pAccess->Get();
1364 : }
1365 : else
1366 : {
1367 86854 : pAccess = NULL;
1368 86854 : pOwn = &m_rThis;
1369 : }
1370 92637 : SwTwips nUpper = 0;
1371 : // OD 06.01.2004 #i11859#
1372 : {
1373 92637 : const IDocumentSettingAccess* pIDSA = m_rThis.GetUpper()->GetFormat()->getIDocumentSettingAccess();
1374 92637 : const bool bUseFormerLineSpacing = pIDSA->get(DocumentSettingId::OLD_LINE_SPACING);
1375 92637 : if( pPrevFrm )
1376 : {
1377 : // OD 2004-03-10 #i11860# - use new method to determine needed spacing
1378 : // values of found previous frame and use these values.
1379 40987 : SwTwips nPrevLowerSpace = 0;
1380 40987 : SwTwips nPrevLineSpacing = 0;
1381 : // #i102458#
1382 40987 : bool bPrevLineSpacingPorportional = false;
1383 : GetSpacingValuesOfFrm( (*pPrevFrm),
1384 : nPrevLowerSpace, nPrevLineSpacing,
1385 40987 : bPrevLineSpacingPorportional );
1386 40987 : if( pIDSA->get(DocumentSettingId::PARA_SPACE_MAX) )
1387 : {
1388 8791 : nUpper = nPrevLowerSpace + pAttrs->GetULSpace().GetUpper();
1389 8791 : SwTwips nAdd = nPrevLineSpacing;
1390 : // OD 07.01.2004 #i11859# - consideration of the line spacing
1391 : // for the upper spacing of a text frame
1392 8791 : if ( bUseFormerLineSpacing )
1393 : {
1394 : // former consideration
1395 2 : if ( pOwn->IsTextFrm() )
1396 : {
1397 2 : nAdd = std::max( nAdd, static_cast<SwTextFrm*>(pOwn)->GetLineSpace() );
1398 : }
1399 2 : nUpper += nAdd;
1400 : }
1401 : else
1402 : {
1403 : // new consideration:
1404 : // Only the proportional line spacing of the previous
1405 : // text frame is considered for the upper spacing and
1406 : // the line spacing values are add up instead of
1407 : // building its maximum.
1408 8789 : if ( pOwn->IsTextFrm() )
1409 : {
1410 : // #i102458#
1411 : // Correction:
1412 : // A proportional line spacing of the previous text frame
1413 : // is added up to a own leading line spacing.
1414 : // Otherwise, the maximum of the leading line spacing
1415 : // of the previous text frame and the own leading line
1416 : // spacing is built.
1417 8340 : if ( bPrevLineSpacingPorportional )
1418 : {
1419 221 : nAdd += static_cast<SwTextFrm*>(pOwn)->GetLineSpace( true );
1420 : }
1421 : else
1422 : {
1423 8119 : nAdd = std::max( nAdd, static_cast<SwTextFrm*>(pOwn)->GetLineSpace( true ) );
1424 : }
1425 : }
1426 8789 : nUpper += nAdd;
1427 : }
1428 : }
1429 : else
1430 : {
1431 : nUpper = std::max( static_cast<long>(nPrevLowerSpace),
1432 32196 : static_cast<long>(pAttrs->GetULSpace().GetUpper()) );
1433 : // OD 07.01.2004 #i11859# - consideration of the line spacing
1434 : // for the upper spacing of a text frame
1435 32196 : if ( bUseFormerLineSpacing )
1436 : {
1437 : // former consideration
1438 288 : if ( pOwn->IsTextFrm() )
1439 284 : nUpper = std::max( nUpper, static_cast<SwTextFrm*>(pOwn)->GetLineSpace() );
1440 288 : if ( nPrevLineSpacing != 0 )
1441 : {
1442 0 : nUpper = std::max( nUpper, nPrevLineSpacing );
1443 : }
1444 : }
1445 : else
1446 : {
1447 : // new consideration:
1448 : // Only the proportional line spacing of the previous
1449 : // text frame is considered for the upper spacing and
1450 : // the line spacing values are add up and added to
1451 : // the paragraph spacing instead of building the
1452 : // maximum of the line spacings and the paragraph spacing.
1453 31908 : SwTwips nAdd = nPrevLineSpacing;
1454 31908 : if ( pOwn->IsTextFrm() )
1455 : {
1456 : // #i102458#
1457 : // Correction:
1458 : // A proportional line spacing of the previous text frame
1459 : // is added up to a own leading line spacing.
1460 : // Otherwise, the maximum of the leading line spacing
1461 : // of the previous text frame and the own leading line
1462 : // spacing is built.
1463 30485 : if ( bPrevLineSpacingPorportional )
1464 : {
1465 6017 : nAdd += static_cast<SwTextFrm*>(pOwn)->GetLineSpace( true );
1466 : }
1467 : else
1468 : {
1469 24468 : nAdd = std::max( nAdd, static_cast<SwTextFrm*>(pOwn)->GetLineSpace( true ) );
1470 : }
1471 : }
1472 31908 : nUpper += nAdd;
1473 : }
1474 : }
1475 : }
1476 103077 : else if ( pIDSA->get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES) &&
1477 51427 : CastFlowFrm( pOwn )->HasParaSpaceAtPages( m_rThis.IsSctFrm() ) )
1478 : {
1479 39881 : nUpper = pAttrs->GetULSpace().GetUpper();
1480 : }
1481 : }
1482 :
1483 : // OD 2004-02-26 #i25029# - pass previous frame <pPrevFrm>
1484 : // to method <GetTopLine(..)>, if parameter <pPr> is set.
1485 : // Note: parameter <pPr> is set, if method is called from <SwTextFrm::WouldFit(..)>
1486 92637 : nUpper += pAttrs->GetTopLine( m_rThis, (pPr ? pPrevFrm : 0L) );
1487 :
1488 : // OD 2004-03-12 #i11860# - consider value of new parameter <_bConsiderGrid>
1489 : // and use new method <GetUpperSpaceAmountConsideredForPageGrid(..)>
1490 :
1491 : //consider grid in square page mode
1492 92637 : if ( _bConsiderGrid && m_rThis.GetUpper()->GetFormat()->GetDoc()->IsSquaredPageMode() )
1493 : {
1494 19738 : nUpper += _GetUpperSpaceAmountConsideredForPageGrid( nUpper );
1495 : }
1496 :
1497 92637 : bool bContextualSpacing = pAttrs->GetULSpace().GetContext();
1498 92637 : delete pAccess;
1499 :
1500 94163 : if (bContextualSpacing && pPrevFrm && lcl_getContextualSpacing(pPrevFrm)
1501 92979 : && lcl_IdenticalStyles(pPrevFrm, &m_rThis))
1502 : {
1503 336 : return 0;
1504 : }
1505 : else
1506 92301 : return nUpper;
1507 : }
1508 :
1509 : /** method to detemine the upper space amount, which is considered for
1510 : the page grid
1511 :
1512 : OD 2004-03-12 #i11860#
1513 : Precondition: Position of frame is valid.
1514 : */
1515 22017 : SwTwips SwFlowFrm::_GetUpperSpaceAmountConsideredForPageGrid(
1516 : const SwTwips _nUpperSpaceWithoutGrid ) const
1517 : {
1518 22017 : SwTwips nUpperSpaceAmountConsideredForPageGrid = 0;
1519 :
1520 22017 : if ( m_rThis.IsInDocBody() && m_rThis.GetAttrSet()->GetParaGrid().GetValue() )
1521 : {
1522 19992 : const SwPageFrm* pPageFrm = m_rThis.FindPageFrm();
1523 19992 : SwTextGridItem const*const pGrid(GetGridItem(pPageFrm));
1524 19992 : if( pGrid )
1525 : {
1526 0 : const SwFrm* pBodyFrm = pPageFrm->FindBodyCont();
1527 0 : if ( pBodyFrm )
1528 : {
1529 : const long nGridLineHeight =
1530 0 : pGrid->GetBaseHeight() + pGrid->GetRubyHeight();
1531 :
1532 0 : SWRECTFN( (&m_rThis) )
1533 0 : const SwTwips nBodyPrtTop = (pBodyFrm->*fnRect->fnGetPrtTop)();
1534 : const SwTwips nProposedPrtTop =
1535 0 : (*fnRect->fnYInc)( (m_rThis.Frm().*fnRect->fnGetTop)(),
1536 0 : _nUpperSpaceWithoutGrid );
1537 :
1538 : const SwTwips nSpaceAbovePrtTop =
1539 0 : (*fnRect->fnYDiff)( nProposedPrtTop, nBodyPrtTop );
1540 : const SwTwips nSpaceOfCompleteLinesAbove =
1541 0 : nGridLineHeight * ( nSpaceAbovePrtTop / nGridLineHeight );
1542 : SwTwips nNewPrtTop =
1543 0 : (*fnRect->fnYInc)( nBodyPrtTop, nSpaceOfCompleteLinesAbove );
1544 0 : if ( (*fnRect->fnYDiff)( nProposedPrtTop, nNewPrtTop ) > 0 )
1545 : {
1546 0 : nNewPrtTop = (*fnRect->fnYInc)( nNewPrtTop, nGridLineHeight );
1547 : }
1548 :
1549 : const SwTwips nNewUpperSpace =
1550 : (*fnRect->fnYDiff)( nNewPrtTop,
1551 0 : (m_rThis.Frm().*fnRect->fnGetTop)() );
1552 :
1553 : nUpperSpaceAmountConsideredForPageGrid =
1554 0 : nNewUpperSpace - _nUpperSpaceWithoutGrid;
1555 :
1556 : OSL_ENSURE( nUpperSpaceAmountConsideredForPageGrid >= 0,
1557 : "<SwFlowFrm::GetUpperSpaceAmountConsideredForPageGrid(..)> - negative space considered for page grid!" );
1558 : }
1559 : }
1560 : }
1561 22017 : return nUpperSpaceAmountConsideredForPageGrid;
1562 : }
1563 :
1564 : /** method to determent the upper space amount, which is considered for
1565 : the previous frame
1566 :
1567 : OD 2004-03-11 #i11860#
1568 : */
1569 25701 : SwTwips SwFlowFrm::_GetUpperSpaceAmountConsideredForPrevFrm() const
1570 : {
1571 25701 : SwTwips nUpperSpaceAmountOfPrevFrm = 0;
1572 :
1573 25701 : const SwFrm* pPrevFrm = _GetPrevFrmForUpperSpaceCalc();
1574 25701 : if ( pPrevFrm )
1575 : {
1576 7568 : SwTwips nPrevLowerSpace = 0;
1577 7568 : SwTwips nPrevLineSpacing = 0;
1578 : // #i102458#
1579 7568 : bool bDummy = false;
1580 7568 : GetSpacingValuesOfFrm( (*pPrevFrm), nPrevLowerSpace, nPrevLineSpacing, bDummy );
1581 7568 : if ( nPrevLowerSpace > 0 || nPrevLineSpacing > 0 )
1582 : {
1583 4013 : const IDocumentSettingAccess* pIDSA = m_rThis.GetUpper()->GetFormat()->getIDocumentSettingAccess();
1584 7965 : if ( pIDSA->get(DocumentSettingId::PARA_SPACE_MAX) ||
1585 3952 : !pIDSA->get(DocumentSettingId::OLD_LINE_SPACING) )
1586 : {
1587 4013 : nUpperSpaceAmountOfPrevFrm = nPrevLowerSpace + nPrevLineSpacing;
1588 : }
1589 : else
1590 : {
1591 0 : nUpperSpaceAmountOfPrevFrm = std::max( nPrevLowerSpace, nPrevLineSpacing );
1592 : }
1593 : }
1594 : }
1595 :
1596 25701 : return nUpperSpaceAmountOfPrevFrm;
1597 : }
1598 :
1599 : /** method to determine the upper space amount, which is considered for
1600 : the previous frame and the page grid, if option 'Use former object
1601 : positioning' is OFF
1602 :
1603 : OD 2004-03-18 #i11860#
1604 : */
1605 25706 : SwTwips SwFlowFrm::GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() const
1606 : {
1607 25706 : SwTwips nUpperSpaceAmountConsideredForPrevFrmAndPageGrid = 0;
1608 :
1609 25706 : if ( !m_rThis.GetUpper()->GetFormat()->getIDocumentSettingAccess()->get(DocumentSettingId::USE_FORMER_OBJECT_POS) )
1610 : {
1611 : nUpperSpaceAmountConsideredForPrevFrmAndPageGrid =
1612 53681 : _GetUpperSpaceAmountConsideredForPrevFrm() +
1613 25701 : ( m_rThis.GetUpper()->GetFormat()->GetDoc()->IsSquaredPageMode()
1614 2279 : ? _GetUpperSpaceAmountConsideredForPageGrid( CalcUpperSpace( 0, 0, false ) )
1615 25701 : : 0 );
1616 : }
1617 :
1618 25706 : return nUpperSpaceAmountConsideredForPrevFrmAndPageGrid;
1619 : }
1620 :
1621 : /** calculation of lower space
1622 :
1623 : OD 2004-03-02 #106629#
1624 : */
1625 81985 : SwTwips SwFlowFrm::CalcLowerSpace( const SwBorderAttrs* _pAttrs ) const
1626 : {
1627 81985 : SwTwips nLowerSpace = 0;
1628 :
1629 81985 : SwBorderAttrAccess* pAttrAccess = 0L;
1630 81985 : if ( !_pAttrs )
1631 : {
1632 13 : pAttrAccess = new SwBorderAttrAccess( SwFrm::GetCache(), &m_rThis );
1633 13 : _pAttrs = pAttrAccess->Get();
1634 : }
1635 :
1636 81985 : bool bCommonBorder = true;
1637 81985 : if ( m_rThis.IsInSct() && m_rThis.GetUpper()->IsColBodyFrm() )
1638 : {
1639 6111 : const SwSectionFrm* pSectFrm = m_rThis.FindSctFrm();
1640 6111 : bCommonBorder = pSectFrm->GetFormat()->GetBalancedColumns().GetValue();
1641 : }
1642 : nLowerSpace = bCommonBorder ?
1643 76619 : _pAttrs->GetBottomLine( m_rThis ) :
1644 158604 : _pAttrs->CalcBottomLine();
1645 :
1646 : // #i26250#
1647 : // - correct consideration of table frames
1648 : // - use new method <CalcAddLowerSpaceAsLastInTableCell(..)>
1649 245955 : if ( ( ( m_rThis.IsTabFrm() && m_rThis.GetUpper()->IsInTab() ) ||
1650 : // #115759# - no lower spacing, if frame has a follow
1651 209629 : ( m_rThis.IsInTab() && !GetFollow() ) ) &&
1652 22767 : !m_rThis.GetIndNext() )
1653 : {
1654 19681 : nLowerSpace += CalcAddLowerSpaceAsLastInTableCell( _pAttrs );
1655 : }
1656 :
1657 81985 : delete pAttrAccess;
1658 :
1659 81985 : return nLowerSpace;
1660 : }
1661 :
1662 : /** calculation of the additional space to be considered, if flow frame
1663 : is the last inside a table cell
1664 :
1665 : OD 2004-07-16 #i26250#
1666 : */
1667 19700 : SwTwips SwFlowFrm::CalcAddLowerSpaceAsLastInTableCell(
1668 : const SwBorderAttrs* _pAttrs ) const
1669 : {
1670 19700 : SwTwips nAdditionalLowerSpace = 0;
1671 :
1672 19700 : if ( m_rThis.GetUpper()->GetFormat()->getIDocumentSettingAccess()->get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) )
1673 : {
1674 19662 : const SwFrm* pFrm = &m_rThis;
1675 19662 : if ( pFrm->IsSctFrm() )
1676 : {
1677 0 : const SwSectionFrm* pSectFrm = static_cast<const SwSectionFrm*>(pFrm);
1678 0 : pFrm = pSectFrm->FindLastContent();
1679 0 : if ( pFrm && pFrm->IsInTab() )
1680 : {
1681 0 : const SwTabFrm* pTableFrm = pFrm->FindTabFrm();
1682 0 : if ( pSectFrm->IsAnLower( pTableFrm ) )
1683 : {
1684 0 : pFrm = pTableFrm;
1685 : }
1686 : }
1687 : }
1688 :
1689 19662 : SwBorderAttrAccess* pAttrAccess = NULL;
1690 19662 : if (pFrm && (!_pAttrs || pFrm != &m_rThis))
1691 : {
1692 19 : pAttrAccess = new SwBorderAttrAccess( SwFrm::GetCache(), pFrm );
1693 19 : _pAttrs = pAttrAccess->Get();
1694 : }
1695 :
1696 19662 : if (_pAttrs)
1697 19662 : nAdditionalLowerSpace += _pAttrs->GetULSpace().GetLower();
1698 :
1699 19662 : delete pAttrAccess;
1700 : }
1701 :
1702 19700 : return nAdditionalLowerSpace;
1703 : }
1704 :
1705 : /// Moves the Frm forward if it seems necessary regarding the current conditions and attributes.
1706 63355 : bool SwFlowFrm::CheckMoveFwd( bool& rbMakePage, bool bKeep, bool )
1707 : {
1708 63355 : const SwFrm* pNxt = m_rThis.GetIndNext();
1709 :
1710 66347 : if ( bKeep && //!bMovedBwd &&
1711 2992 : ( !pNxt || ( pNxt->IsTextFrm() && static_cast<const SwTextFrm*>(pNxt)->IsEmptyMaster() ) ) &&
1712 63773 : ( 0 != (pNxt = m_rThis.FindNext()) ) && IsKeepFwdMoveAllowed() )
1713 : {
1714 41 : if( pNxt->IsSctFrm() )
1715 : { // Don't get fooled by empty SectionFrms
1716 15 : const SwFrm* pTmp = NULL;
1717 45 : while( pNxt && pNxt->IsSctFrm() &&
1718 30 : ( !static_cast<const SwSectionFrm*>(pNxt)->GetSection() ||
1719 15 : 0 == ( pTmp = static_cast<const SwSectionFrm*>(pNxt)->ContainsAny() ) ) )
1720 : {
1721 0 : pNxt = pNxt->FindNext();
1722 0 : pTmp = NULL;
1723 : }
1724 15 : if( pTmp )
1725 15 : pNxt = pTmp; // the content of the next notempty sectionfrm
1726 : }
1727 41 : if( pNxt && pNxt->GetValidPosFlag() )
1728 : {
1729 38 : bool bMove = false;
1730 38 : const SwSectionFrm *pSct = m_rThis.FindSctFrm();
1731 38 : if( pSct && !pSct->GetValidSizeFlag() )
1732 : {
1733 2 : const SwSectionFrm* pNxtSct = pNxt->FindSctFrm();
1734 2 : if( pNxtSct && pSct->IsAnFollow( pNxtSct ) )
1735 2 : bMove = true;
1736 : }
1737 : else
1738 36 : bMove = true;
1739 38 : if( bMove )
1740 : {
1741 : //Keep together with the following frame
1742 38 : MoveFwd( rbMakePage, false );
1743 38 : return true;
1744 : }
1745 : }
1746 : }
1747 :
1748 63317 : bool bMovedFwd = false;
1749 :
1750 63317 : if ( m_rThis.GetIndPrev() )
1751 : {
1752 37137 : if ( IsPrevObjMove() ) // Should we care about objects of the Prev?
1753 : {
1754 2 : bMovedFwd = true;
1755 2 : if ( !MoveFwd( rbMakePage, false ) )
1756 2 : rbMakePage = false;
1757 : }
1758 : else
1759 : {
1760 37135 : if ( IsPageBreak( false ) )
1761 : {
1762 143 : while ( MoveFwd( rbMakePage, true ) )
1763 : /* do nothing */;
1764 143 : rbMakePage = false;
1765 143 : bMovedFwd = true;
1766 : }
1767 36992 : else if ( IsColBreak ( false ) )
1768 : {
1769 161 : const SwPageFrm *pPage = m_rThis.FindPageFrm();
1770 161 : SwFrm *pCol = m_rThis.FindColFrm();
1771 161 : do
1772 161 : { MoveFwd( rbMakePage, false );
1773 161 : SwFrm *pTmp = m_rThis.FindColFrm();
1774 161 : if( pTmp != pCol )
1775 : {
1776 161 : bMovedFwd = true;
1777 161 : pCol = pTmp;
1778 : }
1779 : else
1780 0 : break;
1781 : } while ( IsColBreak( false ) );
1782 161 : if ( pPage != m_rThis.FindPageFrm() )
1783 23 : rbMakePage = false;
1784 : }
1785 : }
1786 : }
1787 63317 : return bMovedFwd;
1788 : }
1789 :
1790 : /// Return value tells us whether the Frm has changed the page.
1791 2125 : bool SwFlowFrm::MoveFwd( bool bMakePage, bool bPageBreak, bool bMoveAlways )
1792 : {
1793 : //!!!!MoveFootnoteCntFwd might need to be updated as well.
1794 2125 : SwFootnoteBossFrm *pOldBoss = m_rThis.FindFootnoteBossFrm();
1795 2125 : if (m_rThis.IsInFootnote())
1796 : {
1797 12 : if (!m_rThis.IsContentFrm())
1798 : {
1799 : SAL_WARN("sw.core", "Tables in footnotes are not truly supported");
1800 0 : return false;
1801 : }
1802 12 : return static_cast<SwContentFrm&>(m_rThis).MoveFootnoteCntFwd( bMakePage, pOldBoss );
1803 : }
1804 :
1805 2113 : if( !IsFwdMoveAllowed() && !bMoveAlways )
1806 : {
1807 308 : bool bNoFwd = true;
1808 308 : if( m_rThis.IsInSct() )
1809 : {
1810 256 : SwFootnoteBossFrm* pBoss = m_rThis.FindFootnoteBossFrm();
1811 497 : bNoFwd = !pBoss->IsInSct() || ( !pBoss->Lower()->GetNext() &&
1812 497 : !pBoss->GetPrev() );
1813 : }
1814 :
1815 : // Allow the MoveFwd even if we do not have an IndPrev in these cases:
1816 672 : if ( m_rThis.IsInTab() &&
1817 60 : ( !m_rThis.IsTabFrm() ||
1818 8 : ( m_rThis.GetUpper()->IsInTab() &&
1819 364 : m_rThis.GetUpper()->FindTabFrm()->IsFwdMoveAllowed() ) ) &&
1820 52 : 0 != const_cast<SwFrm&>(m_rThis).GetNextCellLeaf( MAKEPAGE_NONE ) )
1821 : {
1822 52 : bNoFwd = false;
1823 : }
1824 :
1825 308 : if( bNoFwd )
1826 : {
1827 : // It's allowed to move PageBreaks if the Frm isn't the first
1828 : // one on the page.
1829 44 : if ( !bPageBreak )
1830 44 : return false;
1831 :
1832 0 : const SwFrm *pCol = m_rThis.FindColFrm();
1833 0 : if ( !pCol || !pCol->GetPrev() )
1834 0 : return false;
1835 : }
1836 : }
1837 :
1838 2069 : bool bSamePage = true;
1839 : SwLayoutFrm *pNewUpper =
1840 2069 : m_rThis.GetLeaf( bMakePage ? MAKEPAGE_INSERT : MAKEPAGE_NONE, true );
1841 :
1842 2069 : if ( pNewUpper )
1843 : {
1844 : PROTOCOL_ENTER( &m_rThis, PROT_MOVE_FWD, 0, 0 );
1845 2069 : SwPageFrm *pOldPage = pOldBoss->FindPageFrm();
1846 : // We move ourself and all the direct successors before the
1847 : // first ContentFrm below the new Upper.
1848 :
1849 : // If our NewUpper lies in a SectionFrm, we need to make sure
1850 : // that it won't destroy itself in Calc.
1851 2069 : SwSectionFrm* pSect = pNewUpper->FindSctFrm();
1852 2069 : if( pSect )
1853 : {
1854 : // If we only switch column within our SectionFrm, we better don't
1855 : // call Calc, as this would format the SectionFrm, which in turn would
1856 : // call us again, etc.
1857 1310 : if( pSect != m_rThis.FindSctFrm() )
1858 : {
1859 251 : bool bUnlock = !pSect->IsColLocked();
1860 251 : pSect->ColLock();
1861 251 : pNewUpper->Calc();
1862 251 : if( bUnlock )
1863 251 : pSect->ColUnlock();
1864 : }
1865 : }
1866 : // Do not calculate split cell frames.
1867 759 : else if ( !pNewUpper->IsCellFrm() || static_cast<SwLayoutFrm*>(pNewUpper)->Lower() )
1868 657 : pNewUpper->Calc();
1869 :
1870 2069 : SwFootnoteBossFrm *pNewBoss = pNewUpper->FindFootnoteBossFrm();
1871 2069 : bool bBossChg = pNewBoss != pOldBoss;
1872 2069 : pNewBoss = pNewBoss->FindFootnoteBossFrm( true );
1873 2069 : pOldBoss = pOldBoss->FindFootnoteBossFrm( true );
1874 2069 : SwPageFrm* pNewPage = pOldPage;
1875 :
1876 : // First, we move the footnotes.
1877 2069 : bool bFootnoteMoved = false;
1878 :
1879 : // #i26831#
1880 : // If pSect has just been created, the printing area of pSect has
1881 : // been calculated based on the first content of its follow.
1882 : // In this case we prefer to call a SimpleFormat for this new
1883 : // section after we inserted the contents. Otherwise the section
1884 : // frame will invalidate its lowers, if its printing area changes
1885 : // in SwSectionFrm::Format, which can cause loops.
1886 2270 : const bool bForceSimpleFormat = pSect && pSect->HasFollow() &&
1887 2270 : !pSect->ContainsAny();
1888 :
1889 2069 : if ( pNewBoss != pOldBoss )
1890 : {
1891 1931 : pNewPage = pNewBoss->FindPageFrm();
1892 1931 : bSamePage = pNewPage == pOldPage;
1893 : // Set deadline, so the footnotes don't think up
1894 : // silly things...
1895 1931 : SWRECTFN( pOldBoss )
1896 : SwSaveFootnoteHeight aHeight( pOldBoss,
1897 1931 : (pOldBoss->Frm().*fnRect->fnGetBottom)() );
1898 1931 : SwContentFrm* pStart = m_rThis.IsContentFrm() ?
1899 1931 : static_cast<SwContentFrm*>(&m_rThis) : static_cast<SwLayoutFrm&>(m_rThis).ContainsContent();
1900 : OSL_ENSURE( pStart || ( m_rThis.IsTabFrm() && !static_cast<SwTabFrm&>(m_rThis).Lower() ),
1901 : "MoveFwd: Missing Content" );
1902 1931 : SwLayoutFrm* pBody = pStart ? ( pStart->IsTextFrm() ?
1903 3862 : const_cast<SwBodyFrm *>(static_cast<SwTextFrm*>(pStart)->FindBodyFrm()) : 0 ) : 0;
1904 1931 : if( pBody )
1905 : bFootnoteMoved = pBody->MoveLowerFootnotes( pStart, pOldBoss, pNewBoss,
1906 1929 : false);
1907 : }
1908 : // It's possible when dealing with SectionFrms that we have been moved
1909 : // by pNewUpper->Calc(), for instance into the pNewUpper.
1910 : // MoveSubTree or PasteTree respectively is not prepared to handle such a
1911 : // situation.
1912 2069 : if( pNewUpper != m_rThis.GetUpper() )
1913 : {
1914 : // #i27145#
1915 2069 : SwSectionFrm* pOldSct = 0;
1916 2069 : if ( m_rThis.GetUpper()->IsSctFrm() )
1917 : {
1918 31 : pOldSct = static_cast<SwSectionFrm*>(m_rThis.GetUpper());
1919 : }
1920 :
1921 2069 : MoveSubTree( pNewUpper, pNewUpper->Lower() );
1922 :
1923 : // #i27145#
1924 2069 : if ( pOldSct && pOldSct->GetSection() )
1925 : {
1926 : // Prevent loops by setting the new height at
1927 : // the section frame if footnotes have been moved.
1928 : // Otherwise the call of SwLayNotify::~SwLayNotify() for
1929 : // the (invalid) section frame will invalidate the first
1930 : // lower of its follow, because it grows due to the removed
1931 : // footnotes.
1932 : // Note: If pOldSct has become empty during MoveSubTree, it
1933 : // has already been scheduled for removal. No SimpleFormat
1934 : // for these.
1935 27 : pOldSct->SimpleFormat();
1936 : }
1937 :
1938 : // #i26831#
1939 2069 : if ( bForceSimpleFormat )
1940 : {
1941 9 : pSect->SimpleFormat();
1942 : }
1943 :
1944 2069 : if ( bFootnoteMoved && !bSamePage )
1945 : {
1946 0 : pOldPage->UpdateFootnoteNum();
1947 0 : pNewPage->UpdateFootnoteNum();
1948 : }
1949 :
1950 2069 : if( bBossChg )
1951 : {
1952 1931 : m_rThis.Prepare( PREP_BOSS_CHGD, 0, false );
1953 1931 : if( !bSamePage )
1954 : {
1955 890 : SwViewShell *pSh = m_rThis.getRootFrm()->GetCurrShell();
1956 890 : if ( pSh && !pSh->Imp()->IsUpdateExpFields() )
1957 603 : pSh->GetDoc()->getIDocumentFieldsAccess().SetNewFieldLst(true); // Will be done by CalcLayout() later on!
1958 :
1959 890 : pNewPage->InvalidateSpelling();
1960 890 : pNewPage->InvalidateSmartTags();
1961 890 : pNewPage->InvalidateAutoCompleteWords();
1962 890 : pNewPage->InvalidateWordCount();
1963 : }
1964 : }
1965 : }
1966 : // OD 30.10.2002 #97265# - no <CheckPageDesc(..)> in online layout
1967 2069 : const SwViewShell *pSh = m_rThis.getRootFrm()->GetCurrShell();
1968 :
1969 2069 : if ( !( pSh && pSh->GetViewOptions()->getBrowseMode() ) )
1970 : {
1971 : // #i106452#
1972 : // check page description not only in situation with sections.
1973 3092 : if ( !bSamePage &&
1974 1647 : ( m_rThis.GetAttrSet()->GetPageDesc().GetPageDesc() ||
1975 757 : pOldPage->GetPageDesc()->GetFollow() != pNewPage->GetPageDesc() ) )
1976 : {
1977 133 : SwFrm::CheckPageDescs( pNewPage, false );
1978 : }
1979 : }
1980 : }
1981 2069 : return bSamePage;
1982 : }
1983 :
1984 : /** Return value tells whether the Frm should change the page.
1985 : *
1986 : * @note This should be called by derived classes.
1987 : * @note The actual moving must be implemented in the subclasses.
1988 : */
1989 27152 : bool SwFlowFrm::MoveBwd( bool &rbReformat )
1990 : {
1991 27152 : SwFlowFrm::SetMoveBwdJump( false );
1992 :
1993 27152 : SwFootnoteFrm* pFootnote = m_rThis.FindFootnoteFrm();
1994 27152 : if ( pFootnote && pFootnote->IsBackMoveLocked() )
1995 80 : return false;
1996 :
1997 : // #115759# - text frames, which are directly inside
1998 : // tables aren't allowed to move backward.
1999 27072 : if ( m_rThis.IsTextFrm() && m_rThis.IsInTab() )
2000 : {
2001 296 : const SwLayoutFrm* pUpperFrm = m_rThis.GetUpper();
2002 1184 : while ( pUpperFrm )
2003 : {
2004 888 : if ( pUpperFrm->IsTabFrm() )
2005 : {
2006 296 : return false;
2007 : }
2008 592 : if ( pUpperFrm->IsColumnFrm() && pUpperFrm->IsInSct() )
2009 : {
2010 0 : break;
2011 : }
2012 592 : pUpperFrm = pUpperFrm->GetUpper();
2013 : }
2014 : }
2015 :
2016 26776 : SwFootnoteBossFrm * pOldBoss = m_rThis.FindFootnoteBossFrm();
2017 26776 : SwPageFrm * const pOldPage = pOldBoss->FindPageFrm();
2018 26776 : SwLayoutFrm *pNewUpper = 0;
2019 26776 : bool bCheckPageDescs = false;
2020 26776 : bool bCheckPageDescOfNextPage = false;
2021 :
2022 26776 : if ( pFootnote )
2023 : {
2024 : // If the footnote already sits on the same page/column as the reference,
2025 : // we can't flow back. The breaks don't need to be checked for footnotes.
2026 :
2027 : // #i37084# FindLastContent does not necessarily
2028 : // have to have a result != 0
2029 272 : SwFrm* pRef = 0;
2030 272 : const bool bEndnote = pFootnote->GetAttr()->GetFootnote().IsEndNote();
2031 272 : if( bEndnote && pFootnote->IsInSct() )
2032 : {
2033 28 : SwSectionFrm* pSect = pFootnote->FindSctFrm();
2034 28 : if( pSect->IsEndnAtEnd() )
2035 28 : pRef = pSect->FindLastContent( FINDMODE_LASTCNT );
2036 : }
2037 272 : if( !pRef )
2038 244 : pRef = pFootnote->GetRef();
2039 :
2040 : OSL_ENSURE( pRef, "MoveBwd: Endnote for an empty section?" );
2041 :
2042 272 : if( !bEndnote )
2043 189 : pOldBoss = pOldBoss->FindFootnoteBossFrm( true );
2044 272 : SwFootnoteBossFrm *pRefBoss = pRef->FindFootnoteBossFrm( !bEndnote );
2045 394 : if ( pOldBoss != pRefBoss &&
2046 : // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)>
2047 120 : ( !bEndnote ||
2048 59 : pRefBoss->IsBefore( pOldBoss ) )
2049 : )
2050 61 : pNewUpper = m_rThis.GetLeaf( MAKEPAGE_FTN, false );
2051 : }
2052 26504 : else if ( IsPageBreak( true ) ) // Do we have to respect a PageBreak?
2053 : {
2054 : // If the previous page doesn't have an Frm in the body,
2055 : // flowing back makes sense despite the PageBreak (otherwise,
2056 : // we'd get an empty page).
2057 : // Of course we need to overlook empty pages!
2058 1187 : const SwFrm *pFlow = &m_rThis;
2059 1187 : do
2060 : {
2061 1187 : pFlow = pFlow->FindPrev();
2062 2374 : } while ( pFlow &&
2063 2374 : ( pFlow->FindPageFrm() == pOldPage ||
2064 1187 : !pFlow->IsInDocBody() ) );
2065 1187 : if ( pFlow )
2066 : {
2067 1187 : long nDiff = pOldPage->GetPhyPageNum() - pFlow->GetPhyPageNum();
2068 1187 : if ( nDiff > 1 )
2069 : {
2070 227 : if ( static_cast<SwPageFrm*>(pOldPage->GetPrev())->IsEmptyPage() )
2071 56 : nDiff -= 1;
2072 227 : if ( nDiff > 1 )
2073 : {
2074 173 : pNewUpper = m_rThis.GetLeaf( MAKEPAGE_NONE, false );
2075 : // #i53139#
2076 : // Now <pNewUpper> is a previous layout frame, which contains
2077 : // content. But the new upper layout frame has to be the next one.
2078 : // Thus, hack for issue i14206 no longer needed, but fix for issue 114442
2079 : // #136024# - correct fix for i53139
2080 : // Check for wrong page description before using next new upper.
2081 : // #i66051# - further correction of fix for i53139
2082 : // Check for correct type of new next upper layout frame
2083 : // #136538# - another correction of fix for i53139
2084 : // Assumption, that in all cases <pNewUpper> is a previous
2085 : // layout frame, which contains content, is wrong.
2086 : // #136538# - another correction of fix for i53139
2087 : // Beside type check, check also, if proposed new next upper
2088 : // frame is inside the same frame types.
2089 : // #i73194# - and yet another correction
2090 : // of fix for i53139:
2091 : // Assure that the new next upper layout frame doesn't
2092 : // equal the current one.
2093 : // E.g.: content is on page 3, on page 2 is only a 'ghost'
2094 : // section and on page 1 is normal content. Method <FindPrev(..)>
2095 : // will find the last content of page 1, but <GetLeaf(..)>
2096 : // returns new upper on page 2.
2097 173 : if (pNewUpper && pNewUpper->Lower())
2098 : {
2099 172 : SwLayoutFrm* pNewNextUpper = pNewUpper->GetLeaf( MAKEPAGE_NONE, true );
2100 344 : if ( pNewNextUpper &&
2101 341 : pNewNextUpper != m_rThis.GetUpper() &&
2102 338 : pNewNextUpper->GetType() == pNewUpper->GetType() &&
2103 338 : pNewNextUpper->IsInDocBody() == pNewUpper->IsInDocBody() &&
2104 338 : pNewNextUpper->IsInFootnote() == pNewUpper->IsInFootnote() &&
2105 338 : pNewNextUpper->IsInTab() == pNewUpper->IsInTab() &&
2106 510 : pNewNextUpper->IsInSct() == pNewUpper->IsInSct() &&
2107 169 : !m_rThis.WrongPageDesc( pNewNextUpper->FindPageFrm() ) )
2108 : {
2109 160 : pNewUpper = pNewNextUpper;
2110 160 : bCheckPageDescOfNextPage = true;
2111 : }
2112 : }
2113 :
2114 173 : bCheckPageDescs = true;
2115 : }
2116 : }
2117 : }
2118 : }
2119 25317 : else if ( IsColBreak( true ) )
2120 : {
2121 : // If the previous column doesn't contain a ContentFrm, flowing back
2122 : // makes sense despite the ColumnBreak, as otherwise we'd get
2123 : // an empty column.
2124 272 : if( m_rThis.IsInSct() )
2125 : {
2126 272 : pNewUpper = m_rThis.GetLeaf( MAKEPAGE_NONE, false );
2127 632 : if( pNewUpper && !SwFlowFrm::IsMoveBwdJump() &&
2128 180 : ( pNewUpper->ContainsContent() ||
2129 0 : ( ( !pNewUpper->IsColBodyFrm() ||
2130 0 : !pNewUpper->GetUpper()->GetPrev() ) &&
2131 0 : !pNewUpper->FindSctFrm()->GetPrev() ) ) )
2132 : {
2133 180 : pNewUpper = 0;
2134 : }
2135 : // #i53139#
2136 : // #i69409# - check <pNewUpper>
2137 : // #i71065# - check <SwFlowFrm::IsMoveBwdJump()>
2138 92 : else if ( pNewUpper && !SwFlowFrm::IsMoveBwdJump() )
2139 : {
2140 : // Now <pNewUpper> is a previous layout frame, which
2141 : // contains content. But the new upper layout frame
2142 : // has to be the next one.
2143 : // #136024# - correct fix for i53139
2144 : // Check for wrong page description before using next new upper.
2145 : // #i66051# - further correction of fix for i53139
2146 : // Check for correct type of new next upper layout frame
2147 : // #136538# - another correction of fix for i53139
2148 : // Beside type check, check also, if proposed new next upper
2149 : // frame is inside the same frame types.
2150 0 : SwLayoutFrm* pNewNextUpper = pNewUpper->GetLeaf( MAKEPAGE_NOSECTION, true );
2151 0 : if ( pNewNextUpper &&
2152 0 : pNewNextUpper->GetType() == pNewUpper->GetType() &&
2153 0 : pNewNextUpper->IsInDocBody() == pNewUpper->IsInDocBody() &&
2154 0 : pNewNextUpper->IsInFootnote() == pNewUpper->IsInFootnote() &&
2155 0 : pNewNextUpper->IsInTab() == pNewUpper->IsInTab() &&
2156 0 : pNewNextUpper->IsInSct() == pNewUpper->IsInSct() &&
2157 0 : !m_rThis.WrongPageDesc( pNewNextUpper->FindPageFrm() ) )
2158 : {
2159 0 : pNewUpper = pNewNextUpper;
2160 : }
2161 : }
2162 : }
2163 : else
2164 : {
2165 0 : const SwFrm *pCol = m_rThis.FindColFrm();
2166 0 : bool bGoOn = true;
2167 0 : bool bJump = false;
2168 0 : do
2169 : {
2170 0 : if ( pCol->GetPrev() )
2171 0 : pCol = pCol->GetPrev();
2172 : else
2173 : {
2174 0 : bGoOn = false;
2175 0 : pCol = m_rThis.GetLeaf( MAKEPAGE_NONE, false );
2176 : }
2177 0 : if ( pCol )
2178 : {
2179 : // ColumnFrms now with BodyFrm
2180 0 : SwLayoutFrm* pColBody = pCol->IsColumnFrm() ?
2181 : const_cast<SwLayoutFrm*>(static_cast<const SwLayoutFrm*>(static_cast<const SwLayoutFrm*>(pCol)->Lower())) :
2182 0 : const_cast<SwLayoutFrm*>(static_cast<const SwLayoutFrm*>(pCol));
2183 0 : if ( pColBody->ContainsContent() )
2184 : {
2185 0 : bGoOn = false; // We have content here! we accept this
2186 : // only if GetLeaf() has set the MoveBwdJump.
2187 0 : if( SwFlowFrm::IsMoveBwdJump() )
2188 : {
2189 0 : pNewUpper = pColBody;
2190 : // #i53139#
2191 : // Now <pNewUpper> is a previous layout frame, which
2192 : // contains content. But the new upper layout frame
2193 : // has to be the next one.
2194 : // #136024# - correct fix for i53139
2195 : // Check for wrong page description before using next new upper.
2196 : // #i66051# - further correction of fix for i53139
2197 : // Check for correct type of new next upper layout frame
2198 : // #136538# - another correction of fix for i53139
2199 : // Beside type check, check also, if proposed new next upper
2200 : // frame is inside the same frame types.
2201 : // #i71065#
2202 : // Check that the proposed new next upper layout
2203 : // frame isn't the current one.
2204 0 : SwLayoutFrm* pNewNextUpper = pNewUpper->GetLeaf( MAKEPAGE_NONE, true );
2205 0 : if ( pNewNextUpper &&
2206 0 : pNewNextUpper != m_rThis.GetUpper() &&
2207 0 : pNewNextUpper->GetType() == pNewUpper->GetType() &&
2208 0 : pNewNextUpper->IsInDocBody() == pNewUpper->IsInDocBody() &&
2209 0 : pNewNextUpper->IsInFootnote() == pNewUpper->IsInFootnote() &&
2210 0 : pNewNextUpper->IsInTab() == pNewUpper->IsInTab() &&
2211 0 : pNewNextUpper->IsInSct() == pNewUpper->IsInSct() &&
2212 0 : !m_rThis.WrongPageDesc( pNewNextUpper->FindPageFrm() ) )
2213 : {
2214 0 : pNewUpper = pNewNextUpper;
2215 : }
2216 : }
2217 : }
2218 : else
2219 : {
2220 0 : if( pNewUpper ) // We already had an empty column, in other
2221 0 : bJump = true; // words we skipped one.
2222 0 : pNewUpper = pColBody; // this empty column could be considered,
2223 : // but we continue searching nevertheless.
2224 : }
2225 : }
2226 : } while( bGoOn );
2227 0 : if( bJump )
2228 0 : SwFlowFrm::SetMoveBwdJump( true );
2229 : }
2230 : }
2231 : else // No breaks - we can flow back.
2232 25045 : pNewUpper = m_rThis.GetLeaf( MAKEPAGE_NONE, false );
2233 :
2234 : // #i27801# - no move backward of 'master' text frame,
2235 : // if - due to its object positioning - it isn't allowed to be on the new page frame
2236 : // #i44049# - add another condition for not moving backward
2237 : // If one of its objects has restarted the layout process, moving backward
2238 : // isn't sensible either.
2239 : // #i47697# - refine condition made for issue i44049
2240 : // - allow move backward as long as the anchored object is only temporarily
2241 : // positions considering its wrapping style.
2242 35207 : if ( pNewUpper &&
2243 35025 : m_rThis.IsTextFrm() && !IsFollow() )
2244 : {
2245 6875 : sal_uInt32 nToPageNum( 0L );
2246 : const bool bMoveFwdByObjPos = SwLayouter::FrmMovedFwdByObjPos(
2247 6875 : *(pOldPage->GetFormat()->GetDoc()),
2248 : static_cast<SwTextFrm&>(m_rThis),
2249 13750 : nToPageNum );
2250 6883 : if ( bMoveFwdByObjPos &&
2251 8 : pNewUpper->FindPageFrm()->GetPhyPageNum() < nToPageNum )
2252 : {
2253 8 : pNewUpper = 0;
2254 : }
2255 : // #i44049# - check, if one of its anchored objects
2256 : // has restarted the layout process.
2257 6867 : else if ( m_rThis.GetDrawObjs() )
2258 : {
2259 105 : for ( size_t i = 0; i < m_rThis.GetDrawObjs()->size(); ++i )
2260 : {
2261 61 : SwAnchoredObject* pAnchoredObj = (*m_rThis.GetDrawObjs())[i];
2262 : // #i47697# - refine condition - see above
2263 62 : if ( pAnchoredObj->RestartLayoutProcess() &&
2264 1 : !pAnchoredObj->IsTmpConsiderWrapInfluence() )
2265 : {
2266 1 : pNewUpper = 0;
2267 1 : break;
2268 : }
2269 : }
2270 : }
2271 : }
2272 :
2273 : // With Follows, it's only allowed to flow back if there's no neighbor
2274 : // in the new environment (because that would be the Master).
2275 : // (6677) If however we skipped empty pages, we still have to move.
2276 26776 : if ( pNewUpper && IsFollow() && pNewUpper->Lower() )
2277 : {
2278 : // #i79774#
2279 : // neglect empty sections in proposed new upper frame
2280 1503 : bool bProposedNewUpperContainsOnlyEmptySections( true );
2281 : {
2282 1503 : const SwFrm* pLower( pNewUpper->Lower() );
2283 1503 : while ( pLower )
2284 : {
2285 1503 : if ( pLower->IsSctFrm() &&
2286 0 : !dynamic_cast<const SwSectionFrm*>(pLower)->GetSection() )
2287 : {
2288 0 : pLower = pLower->GetNext();
2289 0 : continue;
2290 : }
2291 : else
2292 : {
2293 1503 : bProposedNewUpperContainsOnlyEmptySections = false;
2294 1503 : break;
2295 : }
2296 : }
2297 : }
2298 1503 : if ( !bProposedNewUpperContainsOnlyEmptySections )
2299 : {
2300 1503 : if ( SwFlowFrm::IsMoveBwdJump() )
2301 : {
2302 : // Don't move after the Master, but into the next empty page.
2303 4 : SwFrm *pFrm = pNewUpper->Lower();
2304 17 : while ( pFrm->GetNext() )
2305 9 : pFrm = pFrm->GetNext();
2306 4 : pNewUpper = pFrm->GetLeaf( MAKEPAGE_INSERT, true );
2307 4 : if( pNewUpper == m_rThis.GetUpper() ) // Did we end up in the same place?
2308 0 : pNewUpper = NULL; // If so, moving is not needed.
2309 : }
2310 : else
2311 1499 : pNewUpper = 0;
2312 : }
2313 : }
2314 26776 : if ( pNewUpper && !ShouldBwdMoved( pNewUpper, true, rbReformat ) )
2315 : {
2316 122 : if( !pNewUpper->Lower() )
2317 : {
2318 0 : if( pNewUpper->IsFootnoteContFrm() )
2319 : {
2320 0 : pNewUpper->Cut();
2321 0 : SwFrm::DestroyFrm(pNewUpper);
2322 : }
2323 : else
2324 : {
2325 0 : SwSectionFrm* pSectFrm = pNewUpper->FindSctFrm();
2326 : // #126020# - adjust check for empty section
2327 : // #130797# - correct fix #126020#
2328 0 : if ( pSectFrm && !pSectFrm->IsColLocked() &&
2329 0 : !pSectFrm->ContainsContent() && !pSectFrm->ContainsAny( true ) )
2330 : {
2331 0 : pSectFrm->DelEmpty( true );
2332 0 : SwFrm::DestroyFrm(pSectFrm);
2333 0 : m_rThis.mbValidPos = true;
2334 : }
2335 : }
2336 : }
2337 122 : pNewUpper = 0;
2338 : }
2339 :
2340 : // OD 2004-05-26 #i21478# - don't move backward, if flow frame wants to
2341 : // keep with next frame and next frame is locked.
2342 : // #i38232# - If next frame is a table, do *not* check,
2343 : // if it's locked.
2344 40374 : if ( pNewUpper && !IsFollow() &&
2345 34014 : m_rThis.GetAttrSet()->GetKeep().GetValue() && m_rThis.GetIndNext() )
2346 : {
2347 407 : SwFrm* pIndNext = m_rThis.GetIndNext();
2348 : // #i38232#
2349 407 : if ( !pIndNext->IsTabFrm() )
2350 : {
2351 : // get first content of section, while empty sections are skipped
2352 808 : while ( pIndNext && pIndNext->IsSctFrm() )
2353 : {
2354 3 : if( static_cast<SwSectionFrm*>(pIndNext)->GetSection() )
2355 : {
2356 3 : SwFrm* pTmp = static_cast<SwSectionFrm*>(pIndNext)->ContainsAny();
2357 3 : if ( pTmp )
2358 : {
2359 3 : pIndNext = pTmp;
2360 3 : break;
2361 : }
2362 : }
2363 0 : pIndNext = pIndNext->GetIndNext();
2364 : }
2365 : OSL_ENSURE( !pIndNext || pIndNext->ISA(SwTextFrm),
2366 : "<SwFlowFrm::MovedBwd(..)> - incorrect next found." );
2367 808 : if ( pIndNext && pIndNext->IsFlowFrm() &&
2368 404 : SwFlowFrm::CastFlowFrm(pIndNext)->IsJoinLocked() )
2369 : {
2370 0 : pNewUpper = 0L;
2371 : }
2372 : }
2373 : }
2374 :
2375 : // #i65250#
2376 : // layout loop control for flowing content again and again moving
2377 : // backward under the same layout condition.
2378 40374 : if ( pNewUpper && !IsFollow() &&
2379 40370 : pNewUpper != m_rThis.GetUpper() &&
2380 6797 : SwLayouter::MoveBwdSuppressed( *(pOldPage->GetFormat()->GetDoc()),
2381 6797 : *this, *pNewUpper ) )
2382 : {
2383 : SwLayoutFrm* pNextNewUpper = pNewUpper->GetLeaf(
2384 0 : ( !m_rThis.IsSctFrm() && m_rThis.IsInSct() )
2385 : ? MAKEPAGE_NOSECTION
2386 : : MAKEPAGE_NONE,
2387 0 : true );
2388 : // #i73194# - make code robust
2389 : OSL_ENSURE( pNextNewUpper, "<SwFlowFrm::MoveBwd(..)> - missing next new upper" );
2390 0 : if ( pNextNewUpper &&
2391 0 : ( pNextNewUpper == m_rThis.GetUpper() ||
2392 0 : pNextNewUpper->GetType() != m_rThis.GetUpper()->GetType() ) )
2393 : {
2394 0 : pNewUpper = 0L;
2395 : OSL_FAIL( "<SwFlowFrm::MoveBwd(..)> - layout loop control for layout action <Move Backward> applied!" );
2396 : }
2397 : }
2398 :
2399 : OSL_ENSURE( pNewUpper != m_rThis.GetUpper(),
2400 : "<SwFlowFrm::MoveBwd(..)> - moving backward to the current upper frame!? -> Please inform OD." );
2401 26776 : if ( pNewUpper )
2402 : {
2403 : PROTOCOL_ENTER( &m_rThis, PROT_MOVE_BWD, 0, 0 );
2404 6801 : if ( pNewUpper->IsFootnoteContFrm() )
2405 : {
2406 : // I may have gotten a Container
2407 0 : SwFootnoteFrm *pOld = m_rThis.FindFootnoteFrm();
2408 0 : SwFootnoteFrm *pNew = new SwFootnoteFrm( pOld->GetFormat(), pOld,
2409 0 : pOld->GetRef(), pOld->GetAttr() );
2410 0 : if ( pOld->GetMaster() )
2411 : {
2412 0 : pNew->SetMaster( pOld->GetMaster() );
2413 0 : pOld->GetMaster()->SetFollow( pNew );
2414 : }
2415 0 : pNew->SetFollow( pOld );
2416 0 : pOld->SetMaster( pNew );
2417 0 : pNew->Paste( pNewUpper );
2418 0 : pNewUpper = pNew;
2419 : }
2420 6801 : if( pNewUpper->IsFootnoteFrm() && m_rThis.IsInSct() )
2421 : {
2422 3 : SwSectionFrm* pSct = m_rThis.FindSctFrm();
2423 : // If we're in a section of a footnote, we may need to create
2424 : // a SwSectionFrm in the new upper
2425 3 : if( pSct->IsInFootnote() )
2426 : {
2427 3 : SwFrm* pTmp = pNewUpper->Lower();
2428 3 : if( pTmp )
2429 : {
2430 18 : while( pTmp->GetNext() )
2431 12 : pTmp = pTmp->GetNext();
2432 6 : if( !pTmp->IsSctFrm() ||
2433 3 : static_cast<SwSectionFrm*>(pTmp)->GetFollow() != pSct )
2434 0 : pTmp = NULL;
2435 : }
2436 3 : if( pTmp )
2437 3 : pNewUpper = static_cast<SwSectionFrm*>(pTmp);
2438 : else
2439 : {
2440 0 : pSct = new SwSectionFrm( *pSct, true );
2441 0 : pSct->Paste( pNewUpper );
2442 0 : pSct->Init();
2443 0 : pNewUpper = pSct;
2444 0 : pSct->SimpleFormat();
2445 : }
2446 : }
2447 : }
2448 6801 : bool bUnlock = false;
2449 6801 : bool bFollow = false;
2450 : // Lock section. Otherwise, it could get destroyed if the only Content
2451 : // moves e.g. from the second into the first column.
2452 6801 : SwSectionFrm* pSect = pNewUpper->FindSctFrm();
2453 6801 : if( pSect )
2454 : {
2455 1117 : bUnlock = !pSect->IsColLocked();
2456 1117 : pSect->ColLock();
2457 1117 : bFollow = pSect->HasFollow();
2458 : }
2459 6801 : pNewUpper->Calc();
2460 6801 : m_rThis.Cut();
2461 :
2462 : // optimization: format section, if its size is invalidated and if it's
2463 : // the new parent of moved backward frame.
2464 6801 : bool bFormatSect( false );
2465 6801 : if( bUnlock )
2466 : {
2467 515 : pSect->ColUnlock();
2468 515 : if( pSect->HasFollow() != bFollow )
2469 : {
2470 64 : pSect->InvalidateSize();
2471 : // - optimization
2472 64 : if ( pSect == pNewUpper )
2473 64 : bFormatSect = true;
2474 : }
2475 : }
2476 :
2477 6801 : m_rThis.Paste( pNewUpper );
2478 : // - optimization
2479 6801 : if ( bFormatSect )
2480 64 : pSect->Calc();
2481 :
2482 6801 : SwPageFrm *pNewPage = m_rThis.FindPageFrm();
2483 6801 : if( pNewPage != pOldPage )
2484 : {
2485 6538 : m_rThis.Prepare( PREP_BOSS_CHGD, static_cast<const void*>(pOldPage), false );
2486 6538 : SwViewShell *pSh = m_rThis.getRootFrm()->GetCurrShell();
2487 6538 : if ( pSh && !pSh->Imp()->IsUpdateExpFields() )
2488 1091 : pSh->GetDoc()->getIDocumentFieldsAccess().SetNewFieldLst(true); // Will be done by CalcLayout() later on
2489 :
2490 6538 : pNewPage->InvalidateSpelling();
2491 6538 : pNewPage->InvalidateSmartTags();
2492 6538 : pNewPage->InvalidateAutoCompleteWords();
2493 6538 : pNewPage->InvalidateWordCount();
2494 :
2495 : // OD 30.10.2002 #97265# - no <CheckPageDesc(..)> in online layout
2496 6538 : if ( !( pSh && pSh->GetViewOptions()->getBrowseMode() ) )
2497 : {
2498 6538 : if ( bCheckPageDescs && pNewPage->GetNext() )
2499 : {
2500 : SwPageFrm* pStartPage = bCheckPageDescOfNextPage ?
2501 : pNewPage :
2502 173 : static_cast<SwPageFrm*>(pNewPage->GetNext());
2503 173 : SwFrm::CheckPageDescs( pStartPage, false);
2504 : }
2505 6365 : else if ( m_rThis.GetAttrSet()->GetPageDesc().GetPageDesc() )
2506 : {
2507 : // First page could get empty for example by disabling
2508 : // a section
2509 0 : SwFrm::CheckPageDescs( pNewPage, false);
2510 : }
2511 : }
2512 : }
2513 : }
2514 26776 : return pNewUpper != 0;
2515 : }
2516 :
2517 898053 : SwFlowFrm *SwFlowFrm::CastFlowFrm( SwFrm *pFrm )
2518 : {
2519 898053 : if ( pFrm->IsContentFrm() )
2520 824077 : return static_cast<SwContentFrm*>(pFrm);
2521 73976 : if ( pFrm->IsTabFrm() )
2522 9815 : return static_cast<SwTabFrm*>(pFrm);
2523 64161 : if ( pFrm->IsSctFrm() )
2524 2858 : return static_cast<SwSectionFrm*>(pFrm);
2525 61303 : return 0;
2526 : }
2527 :
2528 2584 : const SwFlowFrm *SwFlowFrm::CastFlowFrm( const SwFrm *pFrm )
2529 : {
2530 2584 : if ( pFrm->IsContentFrm() )
2531 2514 : return static_cast<const SwContentFrm*>(pFrm);
2532 70 : if ( pFrm->IsTabFrm() )
2533 70 : return static_cast<const SwTabFrm*>(pFrm);
2534 0 : if ( pFrm->IsSctFrm() )
2535 0 : return static_cast<const SwSectionFrm*>(pFrm);
2536 0 : return 0;
2537 177 : }
2538 :
2539 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|