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