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