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 "pagefrm.hxx"
21 : #include "rootfrm.hxx"
22 : #include "cntfrm.hxx"
23 : #include "viewsh.hxx"
24 : #include "doc.hxx"
25 : #include "docsh.hxx"
26 : #include "viewimp.hxx"
27 : #include "swtable.hxx"
28 : #include "dflyobj.hxx"
29 : #include "flyfrm.hxx"
30 : #include "frmtool.hxx"
31 : #include "frmfmt.hxx"
32 : #include "dcontact.hxx"
33 : #include <anchoreddrawobject.hxx>
34 : #include <fmtanchr.hxx>
35 : #include "viewopt.hxx"
36 : #include "hints.hxx"
37 : #include "dbg_lay.hxx"
38 : #include <ftnidx.hxx>
39 : #include <svl/itemiter.hxx>
40 : #include <docary.hxx>
41 : #include <editeng/keepitem.hxx>
42 : #include <editeng/ulspitem.hxx>
43 : #include <editeng/lrspitem.hxx>
44 : #include <editeng/brushitem.hxx>
45 : #include <editeng/boxitem.hxx>
46 : #include <vcl/outdev.hxx>
47 : #include <fmtlsplt.hxx>
48 : #include <fmtrowsplt.hxx>
49 : #include <fmtsrnd.hxx>
50 : #include <fmtornt.hxx>
51 : #include <fmtpdsc.hxx>
52 : #include <fmtfsize.hxx>
53 : #include <swtblfmt.hxx>
54 : #include <ndtxt.hxx>
55 : #include "tabfrm.hxx"
56 : #include "rowfrm.hxx"
57 : #include "cellfrm.hxx"
58 : #include "flyfrms.hxx"
59 : #include "txtfrm.hxx"
60 : #include "htmltbl.hxx"
61 : #include "sectfrm.hxx"
62 : #include <fmtfollowtextflow.hxx>
63 : #include <sortedobjs.hxx>
64 : #include <objectformatter.hxx>
65 : #include <layouter.hxx>
66 : #include <switerator.hxx>
67 :
68 : extern void AppendObjs( const SwFrmFmts *pTbl, sal_uLong nIndex,
69 : SwFrm *pFrm, SwPageFrm *pPage );
70 :
71 : using namespace ::com::sun::star;
72 :
73 0 : SwTabFrm::SwTabFrm( SwTable &rTab, SwFrm* pSib ):
74 : SwLayoutFrm( rTab.GetFrmFmt(), pSib ),
75 : SwFlowFrm( (SwFrm&)*this ),
76 0 : pTable( &rTab )
77 : {
78 : bComplete = bCalcLowers = bONECalcLowers = bLowersFormatted = bLockBackMove =
79 : bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine =
80 0 : bRestrictTableGrowth = bRemoveFollowFlowLinePending = sal_False;
81 : // #i26945#
82 0 : bConsiderObjsForMinCellHeight = sal_True;
83 0 : bObjsDoesFit = sal_True;
84 0 : mbInRecalcLowerRow = false;
85 0 : mbFixSize = sal_False; //Don't fall for import filter again.
86 0 : mnType = FRMC_TAB;
87 :
88 : //Create the lines and insert them.
89 0 : const SwTableLines &rLines = rTab.GetTabLines();
90 0 : SwFrm *pTmpPrev = 0;
91 0 : for ( sal_uInt16 i = 0; i < rLines.size(); ++i )
92 : {
93 0 : SwRowFrm *pNew = new SwRowFrm( *rLines[i], this );
94 0 : if( pNew->Lower() )
95 : {
96 0 : pNew->InsertBehind( this, pTmpPrev );
97 0 : pTmpPrev = pNew;
98 : }
99 : else
100 0 : delete pNew;
101 : }
102 : OSL_ENSURE( Lower() && Lower()->IsRowFrm(), "SwTabFrm::SwTabFrm: No rows." );
103 0 : }
104 :
105 0 : SwTabFrm::SwTabFrm( SwTabFrm &rTab ) :
106 0 : SwLayoutFrm( rTab.GetFmt(), &rTab ),
107 : SwFlowFrm( (SwFrm&)*this ),
108 0 : pTable( rTab.GetTable() )
109 : {
110 : bComplete = bONECalcLowers = bCalcLowers = bLowersFormatted = bLockBackMove =
111 : bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine =
112 0 : bRestrictTableGrowth = bRemoveFollowFlowLinePending = sal_False;
113 : // #i26945#
114 0 : bConsiderObjsForMinCellHeight = sal_True;
115 0 : bObjsDoesFit = sal_True;
116 0 : mbInRecalcLowerRow = false;
117 0 : mbFixSize = sal_False; //Don't fall for import filter again.
118 0 : mnType = FRMC_TAB;
119 :
120 0 : SetFollow( rTab.GetFollow() );
121 0 : rTab.SetFollow( this );
122 0 : }
123 :
124 : extern const SwTable *pColumnCacheLastTable;
125 : extern const SwTabFrm *pColumnCacheLastTabFrm;
126 : extern const SwFrm *pColumnCacheLastCellFrm;
127 : extern const SwTable *pRowCacheLastTable;
128 : extern const SwTabFrm *pRowCacheLastTabFrm;
129 : extern const SwFrm *pRowCacheLastCellFrm;
130 :
131 : //return the SwTabFrm (if any) that this SwTabFrm is a follow flow line for
132 0 : SwTabFrm* SwTabFrm::GetFollowFlowLineFor()
133 : {
134 0 : SwFlowFrm *pPrec = GetPrecede();
135 0 : if (pPrec && pPrec->GetFrm()->IsTabFrm())
136 : {
137 0 : SwTabFrm *pPrevTabFrm = (SwTabFrm*)pPrec;
138 : assert(this == pPrevTabFrm->GetFollow());
139 0 : if (pPrevTabFrm->HasFollowFlowLine() && pPrevTabFrm->GetFollow() == this)
140 0 : return pPrevTabFrm;
141 : }
142 0 : return NULL;
143 : }
144 :
145 0 : SwTabFrm::~SwTabFrm()
146 : {
147 : //rhbz#907933, we are a follow flow line for something and have been
148 : //deleted, remove ourself as a follow flowline
149 0 : SwTabFrm* pFlowFrameFor = GetFollowFlowLineFor();
150 0 : if (pFlowFrameFor)
151 0 : pFlowFrameFor->RemoveFollowFlowLine();
152 :
153 : // There is some terrible code in fetab.cxx, that
154 : // makes use of these global pointers. Obviously
155 : // this code did not consider that a TabFrm can be
156 : // deleted.
157 0 : if ( this == pColumnCacheLastTabFrm )
158 : {
159 0 : pColumnCacheLastTable = NULL;
160 0 : pColumnCacheLastTabFrm = NULL;
161 0 : pColumnCacheLastCellFrm= NULL;
162 0 : pRowCacheLastTable = NULL;
163 0 : pRowCacheLastTabFrm = NULL;
164 0 : pRowCacheLastCellFrm= NULL;
165 : }
166 0 : }
167 :
168 0 : void SwTabFrm::JoinAndDelFollows()
169 : {
170 0 : SwTabFrm *pFoll = GetFollow();
171 0 : if ( pFoll->HasFollow() )
172 0 : pFoll->JoinAndDelFollows();
173 0 : pFoll->Cut();
174 0 : SetFollow( pFoll->GetFollow() );
175 0 : delete pFoll;
176 0 : }
177 :
178 0 : void SwTabFrm::RegistFlys()
179 : {
180 : OSL_ENSURE( Lower() && Lower()->IsRowFrm(), "No rows." );
181 :
182 0 : SwPageFrm *pPage = FindPageFrm();
183 0 : if ( pPage )
184 : {
185 0 : SwRowFrm *pRow = (SwRowFrm*)Lower();
186 0 : do
187 : {
188 0 : pRow->RegistFlys( pPage );
189 0 : pRow = (SwRowFrm*)pRow->GetNext();
190 : } while ( pRow );
191 : }
192 0 : }
193 :
194 : /*************************************************************************
195 : |* Some prototypes
196 : |*************************************************************************/
197 : void SwInvalidateAll( SwFrm *pFrm, long nBottom );
198 : static void lcl_RecalcRow( SwRowFrm& rRow, long nBottom );
199 : static bool lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, bool bInva );
200 : // #i26945# - add parameter <_bOnlyRowsAndCells> to control
201 : // that only row and cell frames are formatted.
202 : static bool lcl_InnerCalcLayout( SwFrm *pFrm,
203 : long nBottom,
204 : bool _bOnlyRowsAndCells = false );
205 : // OD 2004-02-18 #106629# - correct type of 1st parameter
206 : // #i26945# - add parameter <_bConsiderObjs> in order to
207 : // control, if floating screen objects have to be considered for the minimal
208 : // cell height.
209 : static SwTwips lcl_CalcMinRowHeight( const SwRowFrm *pRow,
210 : const sal_Bool _bConsiderObjs );
211 : static SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm&, const SwBorderAttrs& );
212 :
213 : /*************************************************************************
214 : |* START: local helper functions for repeated headlines
215 : |*************************************************************************/
216 :
217 0 : static SwTwips lcl_GetHeightOfRows( const SwFrm* pStart, long nCount )
218 : {
219 0 : if ( !nCount || !pStart)
220 0 : return 0;
221 :
222 0 : SwTwips nRet = 0;
223 0 : SWRECTFN( pStart )
224 0 : while ( pStart && nCount > 0 )
225 : {
226 0 : nRet += (pStart->Frm().*fnRect->fnGetHeight)();
227 0 : pStart = pStart->GetNext();
228 0 : --nCount;
229 : }
230 :
231 0 : return nRet;
232 : }
233 :
234 : /*************************************************************************
235 : |* END: local helper functions for repeated headlines
236 : |*************************************************************************/
237 :
238 : /*************************************************************************
239 : |* START: local helper functions for splitting row frames
240 : |*************************************************************************/
241 :
242 : // Local helper function to insert a new follow flow line
243 0 : static SwRowFrm* lcl_InsertNewFollowFlowLine( SwTabFrm& rTab, const SwFrm& rTmpRow, bool bRowSpanLine )
244 : {
245 : OSL_ENSURE( rTmpRow.IsRowFrm(), "No row frame to copy for FollowFlowLine" );
246 0 : const SwRowFrm& rRow = (SwRowFrm&)rTmpRow;
247 :
248 0 : rTab.SetFollowFlowLine( sal_True );
249 0 : SwRowFrm *pFollowFlowLine = new SwRowFrm(*rRow.GetTabLine(), &rTab, false );
250 0 : pFollowFlowLine->SetRowSpanLine( bRowSpanLine );
251 0 : SwFrm* pFirstRow = rTab.GetFollow()->GetFirstNonHeadlineRow();
252 0 : pFollowFlowLine->InsertBefore( rTab.GetFollow(), pFirstRow );
253 0 : return pFollowFlowLine;
254 : }
255 :
256 : // #i26945# - local helper function to invalidate all lower
257 : // objects. By parameter <_bMoveObjsOutOfRange> it can be controlled, if
258 : // additionally the objects are moved 'out of range'.
259 0 : static void lcl_InvalidateLowerObjs( SwLayoutFrm& _rLayoutFrm,
260 : const bool _bMoveObjsOutOfRange = false,
261 : SwPageFrm* _pPageFrm = 0L )
262 : {
263 : // determine page frame, if needed
264 0 : if ( !_pPageFrm )
265 : {
266 0 : _pPageFrm = _rLayoutFrm.FindPageFrm();
267 : OSL_ENSURE( _pPageFrm,
268 : "<lcl_InvalidateLowerObjs(..)> - missing page frame -> no move of lower objects out of range" );
269 0 : if ( !_pPageFrm )
270 : {
271 0 : return;
272 : }
273 : }
274 :
275 : // loop on lower frames
276 0 : SwFrm* pLowerFrm = _rLayoutFrm.Lower();
277 0 : while ( pLowerFrm )
278 : {
279 0 : if ( pLowerFrm->IsLayoutFrm() )
280 : {
281 : ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pLowerFrm)),
282 0 : _bMoveObjsOutOfRange, _pPageFrm );
283 : }
284 0 : if ( pLowerFrm->GetDrawObjs() )
285 : {
286 0 : for ( sal_uInt16 i = 0; i < pLowerFrm->GetDrawObjs()->Count(); ++i )
287 : {
288 0 : SwAnchoredObject* pAnchoredObj = (*pLowerFrm->GetDrawObjs())[i];
289 :
290 : // invalidate position of anchored object
291 0 : pAnchoredObj->SetTmpConsiderWrapInfluence( false );
292 0 : pAnchoredObj->SetConsiderForTextWrap( false );
293 0 : pAnchoredObj->UnlockPosition();
294 0 : pAnchoredObj->InvalidateObjPos();
295 :
296 : // move anchored object 'out of range'
297 0 : if ( _bMoveObjsOutOfRange )
298 : {
299 : // indicate, that positioning is progress to avoid
300 : // modification of the anchored object resp. its attributes
301 : // due to the movement
302 0 : SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj );
303 0 : pAnchoredObj->SetObjLeft( _pPageFrm->Frm().Right() );
304 : // #115759# - reset character rectangle,
305 : // top of line and relative position in order to assure,
306 : // that anchored object is correctly positioned.
307 0 : pAnchoredObj->ClearCharRectAndTopOfLine();
308 0 : pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) );
309 0 : if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
310 : == FLY_AS_CHAR )
311 : {
312 0 : pAnchoredObj->AnchorFrm()
313 : ->Prepare( PREP_FLY_ATTR_CHG,
314 0 : &(pAnchoredObj->GetFrmFmt()) );
315 : }
316 0 : if ( pAnchoredObj->ISA(SwFlyFrm) )
317 : {
318 0 : SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
319 0 : pFly->GetVirtDrawObj()->SetRectsDirty();
320 0 : pFly->GetVirtDrawObj()->SetChanged();
321 0 : }
322 : }
323 :
324 : // If anchored object is a fly frame, invalidate its lower objects
325 0 : if ( pAnchoredObj->ISA(SwFlyFrm) )
326 : {
327 0 : SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
328 0 : ::lcl_InvalidateLowerObjs( *pFly, _bMoveObjsOutOfRange, _pPageFrm );
329 : }
330 : }
331 : }
332 0 : pLowerFrm = pLowerFrm->GetNext();
333 : }
334 : }
335 :
336 : // Local helper function to shrink all lowers of rRow to 0 height
337 0 : static void lcl_ShrinkCellsAndAllContent( SwRowFrm& rRow )
338 : {
339 0 : SwCellFrm* pCurrMasterCell = static_cast<SwCellFrm*>(rRow.Lower());
340 0 : SWRECTFN( pCurrMasterCell )
341 :
342 0 : while ( pCurrMasterCell )
343 : {
344 : // NEW TABLES
345 0 : SwCellFrm& rToAdjust = pCurrMasterCell->GetTabBox()->getRowSpan() < 1 ?
346 : const_cast<SwCellFrm&>(pCurrMasterCell->FindStartEndOfRowSpanCell( true, true )) :
347 0 : *pCurrMasterCell;
348 :
349 : // #i26945#
350 : // all lowers should have the correct position
351 : lcl_ArrangeLowers( &rToAdjust,
352 0 : (rToAdjust.*fnRect->fnGetPrtTop)(),
353 0 : false );
354 : // TODO: Optimize number of frames which are set to 0 height
355 : // we have to start with the last lower frame, otherwise
356 : // the shrink will not shrink the current cell
357 0 : SwFrm* pTmp = rToAdjust.GetLastLower();
358 :
359 0 : if ( pTmp && pTmp->IsRowFrm() )
360 : {
361 0 : SwRowFrm* pTmpRow = (SwRowFrm*)pTmp;
362 0 : lcl_ShrinkCellsAndAllContent( *pTmpRow );
363 : }
364 : else
365 : {
366 : // TODO: Optimize number of frames which are set to 0 height
367 0 : while ( pTmp )
368 : {
369 : // the frames have to be shrunk
370 0 : if ( pTmp->IsTabFrm() )
371 : {
372 0 : SwRowFrm* pTmpRow = (SwRowFrm*)((SwTabFrm*)pTmp)->Lower();
373 0 : while ( pTmpRow )
374 : {
375 0 : lcl_ShrinkCellsAndAllContent( *pTmpRow );
376 0 : pTmpRow = (SwRowFrm*)pTmpRow->GetNext();
377 : }
378 : }
379 : else
380 : {
381 0 : pTmp->Shrink( (pTmp->Frm().*fnRect->fnGetHeight)() );
382 0 : (pTmp->Prt().*fnRect->fnSetTop)( 0 );
383 0 : (pTmp->Prt().*fnRect->fnSetHeight)( 0 );
384 : }
385 :
386 0 : pTmp = pTmp->GetPrev();
387 : }
388 :
389 : // all lowers should have the correct position
390 : lcl_ArrangeLowers( &rToAdjust,
391 0 : (rToAdjust.*fnRect->fnGetPrtTop)(),
392 0 : false );
393 : }
394 :
395 0 : pCurrMasterCell = static_cast<SwCellFrm*>(pCurrMasterCell->GetNext());
396 : }
397 0 : }
398 :
399 : // Local helper function to move the content from rSourceLine to rDestLine
400 : // The content is inserted behind the last content in the corresponding
401 : // cell in rDestLine.
402 0 : static void lcl_MoveRowContent( SwRowFrm& rSourceLine, SwRowFrm& rDestLine )
403 : {
404 0 : SwCellFrm* pCurrDestCell = (SwCellFrm*)rDestLine.Lower();
405 0 : SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower();
406 :
407 : // Move content of follow cells into master cells
408 0 : while ( pCurrSourceCell )
409 : {
410 0 : if ( pCurrSourceCell->Lower() && pCurrSourceCell->Lower()->IsRowFrm() )
411 : {
412 0 : SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower();
413 0 : while ( pTmpSourceRow )
414 : {
415 : // #125926# Achtung! It is possible,
416 : // that pTmpSourceRow->IsFollowFlowRow() but pTmpDestRow
417 : // cannot be found. In this case, we have to move the complete
418 : // row.
419 0 : SwRowFrm* pTmpDestRow = (SwRowFrm*)pCurrDestCell->Lower();
420 :
421 0 : if ( pTmpSourceRow->IsFollowFlowRow() && pTmpDestRow )
422 : {
423 : // move content from follow flow row to pTmpDestRow:
424 0 : while ( pTmpDestRow->GetNext() )
425 0 : pTmpDestRow = (SwRowFrm*)pTmpDestRow->GetNext();
426 :
427 : OSL_ENSURE( pTmpDestRow->GetFollowRow() == pTmpSourceRow, "Table contains node" );
428 :
429 0 : lcl_MoveRowContent( *pTmpSourceRow, *pTmpDestRow );
430 0 : pTmpDestRow->SetFollowRow( pTmpSourceRow->GetFollowRow() );
431 0 : pTmpSourceRow->Remove();
432 0 : delete pTmpSourceRow;
433 : }
434 : else
435 : {
436 : // move complete row:
437 0 : pTmpSourceRow->Remove();
438 0 : pTmpSourceRow->InsertBefore( pCurrDestCell, 0 );
439 : }
440 :
441 0 : pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower();
442 : }
443 : }
444 : else
445 : {
446 0 : SwFrm *pTmp = ::SaveCntnt( (SwCellFrm*)pCurrSourceCell );
447 0 : if ( pTmp )
448 : {
449 : // NEW TABLES
450 0 : SwCellFrm* pDestCell = static_cast<SwCellFrm*>(pCurrDestCell);
451 0 : if ( pDestCell->GetTabBox()->getRowSpan() < 1 )
452 0 : pDestCell = & const_cast<SwCellFrm&>(pDestCell->FindStartEndOfRowSpanCell( true, true ));
453 :
454 : // Find last content
455 0 : SwFrm* pFrm = pDestCell->GetLastLower();
456 0 : ::RestoreCntnt( pTmp, pDestCell, pFrm, true );
457 : }
458 : }
459 0 : pCurrDestCell = (SwCellFrm*)pCurrDestCell->GetNext();
460 0 : pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext();
461 : }
462 0 : }
463 :
464 : // Local helper function to move all footnotes in rRowFrm from
465 : // the footnote boss of rSource to the footnote boss of rDest.
466 0 : static void lcl_MoveFootnotes( SwTabFrm& rSource, SwTabFrm& rDest, SwLayoutFrm& rRowFrm )
467 : {
468 0 : if ( !rSource.GetFmt()->GetDoc()->GetFtnIdxs().empty() )
469 : {
470 0 : SwFtnBossFrm* pOldBoss = rSource.FindFtnBossFrm( sal_True );
471 0 : SwFtnBossFrm* pNewBoss = rDest.FindFtnBossFrm( sal_True );
472 0 : rRowFrm.MoveLowerFtns( 0, pOldBoss, pNewBoss, sal_True );
473 : }
474 0 : }
475 :
476 : // Local helper function to handle nested table cells before the split process
477 0 : static void lcl_PreprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine,
478 : SwRowFrm& rFollowFlowLine, SwTwips nRemain )
479 : {
480 0 : SwCellFrm* pCurrLastLineCell = (SwCellFrm*)rLastLine.Lower();
481 0 : SwCellFrm* pCurrFollowFlowLineCell = (SwCellFrm*)rFollowFlowLine.Lower();
482 :
483 0 : SWRECTFN( pCurrLastLineCell )
484 :
485 : // Move content of follow cells into master cells
486 0 : while ( pCurrLastLineCell )
487 : {
488 0 : if ( pCurrLastLineCell->Lower() && pCurrLastLineCell->Lower()->IsRowFrm() )
489 : {
490 0 : SwTwips nTmpCut = nRemain;
491 0 : SwRowFrm* pTmpLastLineRow = (SwRowFrm*)pCurrLastLineCell->Lower();
492 :
493 : // #i26945#
494 : SwTwips nCurrentHeight =
495 : lcl_CalcMinRowHeight( pTmpLastLineRow,
496 0 : rTab.IsConsiderObjsForMinCellHeight() );
497 0 : while ( pTmpLastLineRow && pTmpLastLineRow->GetNext() && nTmpCut > nCurrentHeight )
498 : {
499 0 : nTmpCut -= nCurrentHeight;
500 0 : pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext();
501 : // #i26945#
502 : nCurrentHeight =
503 : lcl_CalcMinRowHeight( pTmpLastLineRow,
504 0 : rTab.IsConsiderObjsForMinCellHeight() );
505 : }
506 :
507 : // pTmpLastLineRow does not fit to the line or it is the last line
508 0 : if ( pTmpLastLineRow )
509 : {
510 : // Check if we can move pTmpLastLineRow to the follow table,
511 : // or if we have to split the line:
512 0 : SwFrm* pCell = pTmpLastLineRow->Lower();
513 0 : bool bTableLayoutToComplex = false;
514 0 : long nMinHeight = 0;
515 :
516 : // We have to take into account:
517 : // 1. The fixed height of the row
518 : // 2. The borders of the cells inside the row
519 : // 3. The minimum height of the row
520 0 : if ( pTmpLastLineRow->HasFixSize() )
521 0 : nMinHeight = (pTmpLastLineRow->Frm().*fnRect->fnGetHeight)();
522 : else
523 : {
524 0 : while ( pCell )
525 : {
526 0 : if ( ((SwCellFrm*)pCell)->Lower() &&
527 0 : ((SwCellFrm*)pCell)->Lower()->IsRowFrm() )
528 : {
529 0 : bTableLayoutToComplex = true;
530 0 : break;
531 : }
532 :
533 0 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCell );
534 0 : const SwBorderAttrs &rAttrs = *aAccess.Get();
535 0 : nMinHeight = std::max( nMinHeight, lcl_CalcTopAndBottomMargin( *(SwLayoutFrm*)pCell, rAttrs ) );
536 0 : pCell = pCell->GetNext();
537 0 : }
538 :
539 0 : const SwFmtFrmSize &rSz = pTmpLastLineRow->GetFmt()->GetFrmSize();
540 0 : if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE )
541 0 : nMinHeight = std::max( nMinHeight, rSz.GetHeight() );
542 : }
543 :
544 : // 1. Case:
545 : // The line completely fits into the master table.
546 : // Nevertheless, we build a follow (otherwise painting problems
547 : // with empty cell).
548 :
549 : // 2. Case:
550 : // The line has to be split, the minimum height still fits into
551 : // the master table, and the table structure is not to complex.
552 0 : if ( nTmpCut > nCurrentHeight ||
553 0 : ( pTmpLastLineRow->IsRowSplitAllowed() &&
554 0 : !bTableLayoutToComplex && nMinHeight < nTmpCut ) )
555 : {
556 : // The line has to be split:
557 0 : SwRowFrm* pNewRow = new SwRowFrm( *pTmpLastLineRow->GetTabLine(), &rTab, false );
558 0 : pNewRow->SetFollowFlowRow( true );
559 0 : pNewRow->SetFollowRow( pTmpLastLineRow->GetFollowRow() );
560 0 : pTmpLastLineRow->SetFollowRow( pNewRow );
561 0 : pNewRow->InsertBehind( pCurrFollowFlowLineCell, 0 );
562 0 : pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext();
563 : }
564 :
565 : // The following lines have to be moved:
566 0 : while ( pTmpLastLineRow )
567 : {
568 0 : SwRowFrm* pTmp = (SwRowFrm*)pTmpLastLineRow->GetNext();
569 0 : lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pTmpLastLineRow );
570 0 : pTmpLastLineRow->Remove();
571 0 : pTmpLastLineRow->InsertBefore( pCurrFollowFlowLineCell, 0 );
572 0 : pTmpLastLineRow->Shrink( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() );
573 0 : pCurrFollowFlowLineCell->Grow( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() );
574 0 : pTmpLastLineRow = pTmp;
575 : }
576 : }
577 : }
578 :
579 0 : pCurrLastLineCell = (SwCellFrm*)pCurrLastLineCell->GetNext();
580 0 : pCurrFollowFlowLineCell = (SwCellFrm*)pCurrFollowFlowLineCell->GetNext();
581 : }
582 0 : }
583 :
584 : // Local helper function to handle nested table cells after the split process
585 0 : static void lcl_PostprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine )
586 : {
587 0 : SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower();
588 0 : while ( pCurrMasterCell )
589 : {
590 0 : if ( pCurrMasterCell->Lower() &&
591 0 : pCurrMasterCell->Lower()->IsRowFrm() )
592 : {
593 0 : SwRowFrm* pRowFrm = static_cast<SwRowFrm*>(pCurrMasterCell->GetLastLower());
594 :
595 0 : if ( NULL != pRowFrm->GetPrev() && !pRowFrm->ContainsCntnt() )
596 : {
597 : OSL_ENSURE( pRowFrm->GetFollowRow(), "Deleting row frame without follow" );
598 :
599 : // The footnotes have to be moved:
600 0 : lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pRowFrm );
601 0 : pRowFrm->Cut();
602 0 : SwRowFrm* pFollowRow = pRowFrm->GetFollowRow();
603 0 : pRowFrm->Paste( pFollowRow->GetUpper(), pFollowRow );
604 0 : pRowFrm->SetFollowRow( pFollowRow->GetFollowRow() );
605 0 : lcl_MoveRowContent( *pFollowRow, *pRowFrm );
606 0 : pFollowRow->Cut();
607 0 : delete pFollowRow;
608 0 : ::SwInvalidateAll( pCurrMasterCell, LONG_MAX );
609 : }
610 : }
611 :
612 0 : pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext();
613 : }
614 0 : }
615 :
616 : // Local helper function to re-calculate the split line.
617 0 : inline void TableSplitRecalcLock( SwFlowFrm *pTab ) { pTab->LockJoin(); }
618 0 : inline void TableSplitRecalcUnlock( SwFlowFrm *pTab ) { pTab->UnlockJoin(); }
619 :
620 0 : static bool lcl_RecalcSplitLine( SwRowFrm& rLastLine, SwRowFrm& rFollowLine,
621 : SwTwips nRemainingSpaceForLastRow )
622 : {
623 0 : bool bRet = true;
624 :
625 0 : SwTabFrm& rTab = (SwTabFrm&)*rLastLine.GetUpper();
626 :
627 : // If there are nested cells in rLastLine, the recalculation of the last
628 : // line needs some preprocessing.
629 0 : lcl_PreprocessRowsInCells( rTab, rLastLine, rFollowLine, nRemainingSpaceForLastRow );
630 :
631 : // Here the recalculation process starts:
632 0 : rTab.SetRebuildLastLine( sal_True );
633 : // #i26945#
634 0 : rTab.SetDoesObjsFit( sal_True );
635 0 : SWRECTFN( rTab.GetUpper() )
636 :
637 : // #i26945# - invalidate and move floating screen
638 : // objects 'out of range'
639 0 : ::lcl_InvalidateLowerObjs( rLastLine, true );
640 :
641 : // manipulate row and cell sizes
642 :
643 : // #i26945# - Do *not* consider floating screen objects
644 : // for the minimal cell height.
645 0 : rTab.SetConsiderObjsForMinCellHeight( sal_False );
646 0 : ::lcl_ShrinkCellsAndAllContent( rLastLine );
647 0 : rTab.SetConsiderObjsForMinCellHeight( sal_True );
648 :
649 : // invalidate last line
650 0 : ::SwInvalidateAll( &rLastLine, LONG_MAX );
651 :
652 : // Lock this tab frame and its follow
653 0 : bool bUnlockMaster = false;
654 0 : bool bUnlockFollow = false;
655 0 : SwTabFrm* pMaster = rTab.IsFollow() ? (SwTabFrm*)rTab.FindMaster() : 0;
656 0 : if ( pMaster && !pMaster->IsJoinLocked() )
657 : {
658 0 : bUnlockMaster = true;
659 0 : ::TableSplitRecalcLock( pMaster );
660 : }
661 0 : if ( !rTab.GetFollow()->IsJoinLocked() )
662 : {
663 0 : bUnlockFollow = true;
664 0 : ::TableSplitRecalcLock( rTab.GetFollow() );
665 : }
666 :
667 : // Do the recalculation
668 0 : lcl_RecalcRow( rLastLine, LONG_MAX );
669 : // #115759# - force a format of the last line in order to
670 : // get the correct height.
671 0 : rLastLine.InvalidateSize();
672 0 : rLastLine.Calc();
673 :
674 : // Unlock this tab frame and its follow
675 0 : if ( bUnlockFollow )
676 0 : ::TableSplitRecalcUnlock( rTab.GetFollow() );
677 0 : if ( bUnlockMaster )
678 0 : ::TableSplitRecalcUnlock( pMaster );
679 :
680 : // If there are nested cells in rLastLine, the recalculation of the last
681 : // line needs some postprocessing.
682 0 : lcl_PostprocessRowsInCells( rTab, rLastLine );
683 :
684 : // Do a couple of checks on the current situation.
685 :
686 : // If we are not happy with the current situation we return false.
687 : // This will start a new try to split the table, this time we do not
688 : // try to split the table rows.
689 :
690 : // 1. Check if table fits to its upper.
691 : // #i26945# - include check, if objects fit
692 : const SwTwips nDistanceToUpperPrtBottom =
693 0 : (rTab.Frm().*fnRect->fnBottomDist)( (rTab.GetUpper()->*fnRect->fnGetPrtBottom)());
694 0 : if ( nDistanceToUpperPrtBottom < 0 || !rTab.DoesObjsFit() )
695 0 : bRet = false;
696 :
697 : // 2. Check if each cell in the last line has at least one content frame.
698 :
699 : // Note: a FollowFlowRow may contains empty cells!
700 0 : if ( bRet )
701 : {
702 0 : if ( !rLastLine.IsInFollowFlowRow() )
703 : {
704 0 : SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower();
705 0 : while ( pCurrMasterCell )
706 : {
707 0 : if ( !pCurrMasterCell->ContainsCntnt() && pCurrMasterCell->GetTabBox()->getRowSpan() >= 1 )
708 : {
709 0 : bRet = false;
710 0 : break;
711 : }
712 0 : pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext();
713 : }
714 : }
715 : }
716 :
717 : // 3. Check if last line does not contain any content:
718 0 : if ( bRet )
719 : {
720 0 : if ( !rLastLine.ContainsCntnt() )
721 : {
722 0 : bRet = false;
723 : }
724 : }
725 :
726 : // 4. Check if follow flow line does not contain content:
727 0 : if ( bRet )
728 : {
729 0 : if ( !rFollowLine.IsRowSpanLine() && !rFollowLine.ContainsCntnt() )
730 : {
731 0 : bRet = false;
732 : }
733 : }
734 :
735 0 : if ( bRet )
736 : {
737 : // Everything looks fine. Splitting seems to be successful. We invalidate
738 : // rFollowLine to force a new formatting.
739 0 : ::SwInvalidateAll( &rFollowLine, LONG_MAX );
740 : }
741 : else
742 : {
743 : // Splitting the table row gave us an unexpected result.
744 : // Everything has to be prepared for a second try to split
745 : // the table, this time without splitting the row.
746 0 : ::SwInvalidateAll( &rLastLine, LONG_MAX );
747 : }
748 :
749 0 : rTab.SetRebuildLastLine( sal_False );
750 : // #i26945#
751 0 : rTab.SetDoesObjsFit( sal_True );
752 :
753 0 : return bRet;
754 : }
755 :
756 : // Sets the correct height for all spanned cells
757 0 : static void lcl_AdjustRowSpanCells( SwRowFrm* pRow )
758 : {
759 0 : SWRECTFN( pRow )
760 0 : SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pRow->GetLower());
761 0 : while ( pCellFrm )
762 : {
763 0 : const long nLayoutRowSpan = pCellFrm->GetLayoutRowSpan();
764 0 : if ( nLayoutRowSpan > 1 )
765 : {
766 : // calculate height of cell:
767 0 : const long nNewCellHeight = lcl_GetHeightOfRows( pRow, nLayoutRowSpan );
768 0 : const long nDiff = nNewCellHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)();
769 0 : if ( nDiff )
770 0 : (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff );
771 : }
772 :
773 0 : pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext());
774 : }
775 0 : }
776 :
777 : // Returns the maximum layout row span of the row
778 : // Looking for the next row that contains no covered cells:
779 0 : static long lcl_GetMaximumLayoutRowSpan( const SwRowFrm& rRow )
780 : {
781 0 : long nRet = 1;
782 :
783 0 : const SwRowFrm* pCurrentRowFrm = static_cast<const SwRowFrm*>(rRow.GetNext());
784 0 : bool bNextRow = false;
785 :
786 0 : while ( pCurrentRowFrm )
787 : {
788 : // if there is any covered cell, we proceed to the next row frame
789 0 : const SwCellFrm* pLower = static_cast<const SwCellFrm*>( pCurrentRowFrm->Lower());
790 0 : while ( pLower )
791 : {
792 0 : if ( pLower->GetTabBox()->getRowSpan() < 0 )
793 : {
794 0 : ++nRet;
795 0 : bNextRow = true;
796 0 : break;
797 : }
798 0 : pLower = static_cast<const SwCellFrm*>(pLower->GetNext());
799 : }
800 : pCurrentRowFrm = bNextRow ?
801 0 : static_cast<const SwRowFrm*>(pCurrentRowFrm->GetNext() ) :
802 0 : 0;
803 : }
804 :
805 0 : return nRet;
806 : }
807 :
808 : /*************************************************************************
809 : |* END: local helper functions for splitting row frames
810 : |*************************************************************************/
811 :
812 : // Function to remove the FollowFlowLine of rTab.
813 : // The content of the FollowFlowLine is moved to the associated line in the
814 : // master table.
815 0 : bool SwTabFrm::RemoveFollowFlowLine()
816 : {
817 : // find FollowFlowLine
818 0 : SwRowFrm* pFollowFlowLine = static_cast<SwRowFrm*>(GetFollow()->GetFirstNonHeadlineRow());
819 :
820 : // find last row in master
821 0 : SwFrm* pLastLine = GetLastLower();
822 :
823 : OSL_ENSURE( HasFollowFlowLine() &&
824 : pFollowFlowLine &&
825 : pLastLine, "There should be a flowline in the follow" );
826 :
827 : // We have to reset the flag here, because lcl_MoveRowContent
828 : // calls a GrowFrm(), which has a different bahavior if
829 : // this flag is set.
830 0 : SetFollowFlowLine( sal_False );
831 :
832 : // #140081# Make code robust.
833 0 : if ( !pFollowFlowLine || !pLastLine )
834 0 : return true;
835 :
836 : // Move content
837 0 : lcl_MoveRowContent( *pFollowFlowLine, *(SwRowFrm*)pLastLine );
838 :
839 : // NEW TABLES
840 : // If a row span follow flow line is removed, we want to move the whole span
841 : // to the master:
842 0 : long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pFollowFlowLine );
843 :
844 0 : if ( nRowsToMove > 1 )
845 : {
846 0 : SWRECTFN( this )
847 0 : SwFrm* pRow = pFollowFlowLine->GetNext();
848 0 : SwFrm* pInsertBehind = GetLastLower();
849 0 : SwTwips nGrow = 0;
850 :
851 0 : while ( pRow && nRowsToMove-- > 1 )
852 : {
853 0 : SwFrm* pNxt = pRow->GetNext();
854 0 : nGrow += (pRow->Frm().*fnRect->fnGetHeight)();
855 :
856 : // The footnotes have to be moved:
857 0 : lcl_MoveFootnotes( *GetFollow(), *this, (SwRowFrm&)*pRow );
858 :
859 0 : pRow->Remove();
860 0 : pRow->InsertBehind( this, pInsertBehind );
861 0 : pRow->_InvalidateAll();
862 0 : pRow->CheckDirChange();
863 0 : pInsertBehind = pRow;
864 0 : pRow = pNxt;
865 : }
866 :
867 0 : SwFrm* pFirstRow = Lower();
868 0 : while ( pFirstRow )
869 : {
870 0 : lcl_AdjustRowSpanCells( static_cast<SwRowFrm*>(pFirstRow) );
871 0 : pFirstRow = pFirstRow->GetNext();
872 : }
873 :
874 0 : Grow( nGrow );
875 0 : GetFollow()->Shrink( nGrow );
876 : }
877 :
878 0 : bool bJoin = !pFollowFlowLine->GetNext();
879 0 : pFollowFlowLine->Cut();
880 0 : delete pFollowFlowLine;
881 :
882 0 : return bJoin;
883 : }
884 :
885 : // #i26945# - Floating screen objects are no longer searched.
886 0 : static bool lcl_FindSectionsInRow( const SwRowFrm& rRow )
887 : {
888 0 : bool bRet = false;
889 0 : SwCellFrm* pLower = (SwCellFrm*)rRow.Lower();
890 0 : while ( pLower )
891 : {
892 0 : if ( pLower->IsVertical() != rRow.IsVertical() )
893 0 : return true;
894 :
895 0 : SwFrm* pTmpFrm = pLower->Lower();
896 0 : while ( pTmpFrm )
897 : {
898 0 : if ( pTmpFrm->IsRowFrm() )
899 : {
900 0 : bRet = lcl_FindSectionsInRow( *(SwRowFrm*)pTmpFrm );
901 : }
902 : else
903 : {
904 : // #i26945# - search only for sections
905 0 : bRet = pTmpFrm->IsSctFrm();
906 : }
907 :
908 0 : if ( bRet )
909 0 : return true;
910 0 : pTmpFrm = pTmpFrm->GetNext();
911 : }
912 :
913 0 : pLower = (SwCellFrm*)pLower->GetNext();
914 : }
915 0 : return bRet;
916 : }
917 :
918 0 : bool SwTabFrm::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep )
919 : {
920 0 : bool bRet = true;
921 :
922 0 : SWRECTFN( this )
923 :
924 : // #i26745# - format row and cell frames of table
925 : {
926 0 : this->Lower()->_InvalidatePos();
927 : // #i43913# - correction
928 : // call method <lcl_InnerCalcLayout> with first lower.
929 0 : lcl_InnerCalcLayout( this->Lower(), LONG_MAX, true );
930 : }
931 :
932 : //In order to be able to compare the positions of the cells whit CutPos,
933 : //they have to be calculated consecutively starting from the table.
934 : //They can definitely be invalid because of position changes of the table.
935 0 : SwRowFrm *pRow = static_cast<SwRowFrm*>(Lower());
936 0 : if( !pRow )
937 0 : return bRet;
938 :
939 0 : const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();
940 0 : sal_uInt16 nRowCount = 0; // pRow currently points to the first row
941 :
942 : SwTwips nRemainingSpaceForLastRow =
943 0 : (*fnRect->fnYDiff)( nCutPos, (Frm().*fnRect->fnGetTop)() );
944 0 : nRemainingSpaceForLastRow -= (this->*fnRect->fnGetTopMargin)();
945 :
946 : // Make pRow point to the line that does not fit anymore:
947 0 : while( pRow->GetNext() &&
948 0 : nRemainingSpaceForLastRow >= ( (pRow->Frm().*fnRect->fnGetHeight)() +
949 0 : (IsCollapsingBorders() ?
950 0 : pRow->GetBottomLineSize() :
951 : 0 ) ) )
952 : {
953 0 : if( bTryToSplit || !pRow->IsRowSpanLine() ||
954 0 : 0 != (pRow->Frm().*fnRect->fnGetHeight)() )
955 0 : ++nRowCount;
956 0 : nRemainingSpaceForLastRow -= (pRow->Frm().*fnRect->fnGetHeight)();
957 0 : pRow = static_cast<SwRowFrm*>(pRow->GetNext());
958 : }
959 :
960 : // bSplitRowAllowed: Row may be split according to its attributes.
961 : // bTryToSplit: Row will never be split if bTryToSplit = false.
962 : // This can either be passed as a parameter, indicating
963 : // that we are currently doing the second try to split the
964 : // table, or it will be set to falseunder certain
965 : // conditions that are not suitable for splitting
966 : // the row.
967 0 : bool bSplitRowAllowed = pRow->IsRowSplitAllowed();
968 :
969 : // #i29438#
970 : // #i26945# - Floating screen objects no longer forbid
971 : // a splitting of the table row.
972 : // Special DoNotSplit case 1:
973 : // Search for sections inside pRow:
974 0 : if ( lcl_FindSectionsInRow( *pRow ) )
975 : {
976 0 : bTryToSplit = false;
977 : }
978 :
979 : // #i29771#
980 : // To avoid loops, we do some checks before actually trying to split
981 : // the row. Maybe we should keep the next row in this table.
982 : // Note: This is only done if we are at the beginning of our upper
983 0 : bool bKeepNextRow = false;
984 0 : if ( nRowCount < nRepeat )
985 : {
986 : // First case: One of the repeated headline does not fit to the page anymore.
987 : // At least one more non-heading row has to stay in this table in
988 : // order to avoid loops:
989 : OSL_ENSURE( !GetIndPrev(), "Table is supposed to be at beginning" );
990 0 : bKeepNextRow = true;
991 : }
992 0 : else if ( !GetIndPrev() && nRepeat == nRowCount )
993 : {
994 : // Second case: The first non-headline row does not fit to the page.
995 : // If it is not allowed to be split, or it contains a sub-row that
996 : // is not allowed to be split, we keep the row in this table:
997 0 : if ( bTryToSplit && bSplitRowAllowed )
998 : {
999 : // Check if there are (first) rows inside this row,
1000 : // which are not allowed to be split.
1001 0 : SwCellFrm* pLowerCell = pRow ? (SwCellFrm*)pRow->Lower() : 0;
1002 0 : while ( pLowerCell )
1003 : {
1004 0 : if ( pLowerCell->Lower() && pLowerCell->Lower()->IsRowFrm() )
1005 : {
1006 0 : const SwRowFrm* pLowerRow = (SwRowFrm*)pLowerCell->Lower();
1007 0 : if ( !pLowerRow->IsRowSplitAllowed() &&
1008 0 : (pLowerRow->Frm().*fnRect->fnGetHeight)() >
1009 : nRemainingSpaceForLastRow )
1010 : {
1011 0 : bKeepNextRow = true;
1012 0 : break;
1013 : }
1014 : }
1015 0 : pLowerCell = (SwCellFrm*)pLowerCell->GetNext();
1016 0 : }
1017 : }
1018 : else
1019 0 : bKeepNextRow = true;
1020 : }
1021 :
1022 : // Better keep the next row in this table:
1023 0 : if ( bKeepNextRow )
1024 : {
1025 0 : pRow = GetFirstNonHeadlineRow();
1026 0 : if( pRow && pRow->IsRowSpanLine() && 0 == (pRow->Frm().*fnRect->fnGetHeight)() )
1027 0 : pRow = static_cast<SwRowFrm*>(pRow->GetNext());
1028 0 : if ( pRow )
1029 : {
1030 0 : pRow = static_cast<SwRowFrm*>(pRow->GetNext());
1031 0 : ++nRowCount;
1032 : }
1033 : }
1034 :
1035 : // No more row to split or to move to follow table:
1036 0 : if ( !pRow )
1037 0 : return bRet;
1038 :
1039 : // We try to split the row if
1040 : // - the attributes of the row are set accordingly and
1041 : // - we are allowed to do so
1042 : // - the it should not keep with the next row
1043 0 : bSplitRowAllowed = bSplitRowAllowed && bTryToSplit &&
1044 0 : ( !bTableRowKeep ||
1045 0 : !pRow->ShouldRowKeepWithNext() );
1046 :
1047 : // Adjust pRow according to the keep-with-next attribute:
1048 0 : if ( !bSplitRowAllowed && bTableRowKeep )
1049 : {
1050 0 : SwRowFrm* pTmpRow = static_cast<SwRowFrm*>(pRow->GetPrev());
1051 0 : SwRowFrm* pOldRow = pRow;
1052 0 : while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() &&
1053 : nRowCount > nRepeat )
1054 : {
1055 0 : pRow = pTmpRow;
1056 0 : --nRowCount;
1057 0 : pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetPrev());
1058 : }
1059 :
1060 : // loop prevention
1061 0 : if ( nRowCount == nRepeat && !GetIndPrev())
1062 : {
1063 0 : pRow = pOldRow;
1064 : }
1065 : }
1066 :
1067 : // If we do not indent to split pRow, we check if we are
1068 : // allowed to move pRow to a follow. Otherwise we return
1069 : // false, indicating an error
1070 0 : if ( !bSplitRowAllowed )
1071 : {
1072 0 : SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow();
1073 0 : if ( pRow == pFirstNonHeadlineRow )
1074 0 : return false;
1075 :
1076 : // #i91764#
1077 : // Ignore row span lines
1078 0 : SwRowFrm* pTmpRow = pFirstNonHeadlineRow;
1079 0 : while ( pTmpRow && pTmpRow->IsRowSpanLine() )
1080 : {
1081 0 : pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetNext());
1082 : }
1083 0 : if ( !pTmpRow || pRow == pTmpRow )
1084 : {
1085 0 : return false;
1086 : }
1087 : }
1088 :
1089 : // Build follow table if not already done:
1090 : bool bNewFollow;
1091 : SwTabFrm *pFoll;
1092 0 : if ( GetFollow() )
1093 : {
1094 0 : pFoll = GetFollow();
1095 0 : bNewFollow = false;
1096 : }
1097 : else
1098 : {
1099 0 : bNewFollow = true;
1100 0 : pFoll = new SwTabFrm( *this );
1101 :
1102 : // We give the follow table an initial width.
1103 0 : (pFoll->Frm().*fnRect->fnAddWidth)( (Frm().*fnRect->fnGetWidth)() );
1104 0 : (pFoll->Prt().*fnRect->fnAddWidth)( (Prt().*fnRect->fnGetWidth)() );
1105 0 : (pFoll->Frm().*fnRect->fnSetLeft)( (Frm().*fnRect->fnGetLeft)() );
1106 :
1107 : // Insert the new follow table
1108 0 : pFoll->InsertBehind( GetUpper(), this );
1109 :
1110 : // Repeat the headlines.
1111 0 : for ( nRowCount = 0; nRowCount < nRepeat; ++nRowCount )
1112 : {
1113 : // Insert new headlines:
1114 0 : bDontCreateObjects = true; //frmtool
1115 : SwRowFrm* pHeadline = new SwRowFrm(
1116 0 : *GetTable()->GetTabLines()[ nRowCount ], this );
1117 0 : pHeadline->SetRepeatedHeadline( true );
1118 0 : bDontCreateObjects = false;
1119 0 : pHeadline->InsertBefore( pFoll, 0 );
1120 :
1121 0 : SwPageFrm *pPage = pHeadline->FindPageFrm();
1122 0 : const SwFrmFmts *pTbl = GetFmt()->GetDoc()->GetSpzFrmFmts();
1123 0 : if( !pTbl->empty() )
1124 : {
1125 : sal_uLong nIndex;
1126 0 : SwCntntFrm* pFrm = pHeadline->ContainsCntnt();
1127 0 : while( pFrm )
1128 : {
1129 0 : nIndex = pFrm->GetNode()->GetIndex();
1130 0 : AppendObjs( pTbl, nIndex, pFrm, pPage );
1131 0 : pFrm = pFrm->GetNextCntntFrm();
1132 0 : if( !pHeadline->IsAnLower( pFrm ) )
1133 0 : break;
1134 : }
1135 : }
1136 : }
1137 : }
1138 :
1139 0 : SwRowFrm* pLastRow = 0; // will point to the last remaining line in master
1140 0 : SwRowFrm* pFollowRow = 0; // points to either the follow flow line of the
1141 : // first regular line in the follow
1142 :
1143 0 : if ( bSplitRowAllowed )
1144 : {
1145 : // If the row that does not fit anymore is allowed
1146 : // to be split, the next row has to be moved to the follow table.
1147 0 : pLastRow = pRow;
1148 0 : pRow = static_cast<SwRowFrm*>(pRow->GetNext());
1149 :
1150 : // new follow flow line for last row of master table
1151 0 : pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, false );
1152 : }
1153 : else
1154 : {
1155 0 : pFollowRow = pRow;
1156 :
1157 : // NEW TABLES
1158 : // check if we will break a row span by moving pFollowRow to the follow:
1159 : // In this case we want to reformat the last line.
1160 0 : const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>(pFollowRow->GetLower());
1161 0 : while ( pCellFrm )
1162 : {
1163 0 : if ( pCellFrm->GetTabBox()->getRowSpan() < 1 )
1164 : {
1165 0 : pLastRow = static_cast<SwRowFrm*>(pRow->GetPrev());
1166 0 : break;
1167 : }
1168 :
1169 0 : pCellFrm = static_cast<const SwCellFrm*>(pCellFrm->GetNext());
1170 : }
1171 :
1172 : // new follow flow line for last row of master table
1173 0 : if ( pLastRow )
1174 0 : pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, true );
1175 : }
1176 :
1177 0 : SwTwips nRet = 0;
1178 :
1179 : //Optimization: There is no paste needed for the new Follow and the
1180 : //optimized insert can be used (big amounts of rows luckily only occurs in
1181 : //such situations).
1182 0 : if ( bNewFollow )
1183 : {
1184 0 : SwFrm* pNxt = 0;
1185 0 : SwFrm* pInsertBehind = pFoll->GetLastLower();
1186 :
1187 0 : while ( pRow )
1188 : {
1189 0 : pNxt = pRow->GetNext();
1190 0 : nRet += (pRow->Frm().*fnRect->fnGetHeight)();
1191 : // The footnotes do not have to be moved, this is done in the
1192 : // MoveFwd of the follow table!!!
1193 0 : pRow->Remove();
1194 0 : pRow->InsertBehind( pFoll, pInsertBehind );
1195 0 : pRow->_InvalidateAll();
1196 0 : pInsertBehind = pRow;
1197 0 : pRow = static_cast<SwRowFrm*>(pNxt);
1198 : }
1199 : }
1200 : else
1201 : {
1202 0 : SwFrm* pNxt = 0;
1203 0 : SwFrm* pPasteBefore = HasFollowFlowLine() ?
1204 0 : pFollowRow->GetNext() :
1205 0 : pFoll->GetFirstNonHeadlineRow();
1206 :
1207 0 : while ( pRow )
1208 : {
1209 0 : pNxt = pRow->GetNext();
1210 0 : nRet += (pRow->Frm().*fnRect->fnGetHeight)();
1211 :
1212 : // The footnotes have to be moved:
1213 0 : lcl_MoveFootnotes( *this, *GetFollow(), *pRow );
1214 :
1215 0 : pRow->Remove();
1216 0 : pRow->Paste( pFoll, pPasteBefore );
1217 :
1218 0 : pRow->CheckDirChange();
1219 0 : pRow = static_cast<SwRowFrm*>(pNxt);
1220 : }
1221 : }
1222 :
1223 0 : Shrink( nRet );
1224 :
1225 : // we rebuild the last line to assure that it will be fully formatted
1226 0 : if ( pLastRow )
1227 : {
1228 : // recalculate the split line
1229 0 : bRet = lcl_RecalcSplitLine( *pLastRow, *pFollowRow, nRemainingSpaceForLastRow );
1230 :
1231 : // NEW TABLES
1232 : // check if each cell in the row span line has a good height
1233 0 : if ( bRet && pFollowRow->IsRowSpanLine() )
1234 0 : lcl_AdjustRowSpanCells( pFollowRow );
1235 :
1236 : // We The RowSplitLine stuff did not work. In this case we conceal the split error:
1237 0 : if ( !bRet && !bSplitRowAllowed )
1238 : {
1239 0 : bRet = true;
1240 : }
1241 : }
1242 :
1243 0 : return bRet;
1244 : }
1245 :
1246 0 : bool SwTabFrm::Join()
1247 : {
1248 : OSL_ENSURE( !HasFollowFlowLine(), "Joining follow flow line" );
1249 :
1250 0 : SwTabFrm *pFoll = GetFollow();
1251 :
1252 0 : if ( !pFoll->IsJoinLocked() )
1253 : {
1254 0 : SWRECTFN( this )
1255 0 : pFoll->Cut(); //Cut out first to avoid unnecessary notifications.
1256 :
1257 0 : SwFrm *pRow = pFoll->GetFirstNonHeadlineRow(),
1258 : *pNxt;
1259 :
1260 0 : SwFrm* pPrv = GetLastLower();
1261 :
1262 0 : SwTwips nHeight = 0; //Total height of the inserted rows as return value.
1263 :
1264 0 : while ( pRow )
1265 : {
1266 0 : pNxt = pRow->GetNext();
1267 0 : nHeight += (pRow->Frm().*fnRect->fnGetHeight)();
1268 0 : pRow->Remove();
1269 0 : pRow->_InvalidateAll();
1270 0 : pRow->InsertBehind( this, pPrv );
1271 0 : pRow->CheckDirChange();
1272 0 : pPrv = pRow;
1273 0 : pRow = pNxt;
1274 : }
1275 :
1276 0 : SetFollow( pFoll->GetFollow() );
1277 0 : SetFollowFlowLine( pFoll->HasFollowFlowLine() );
1278 0 : delete pFoll;
1279 :
1280 0 : Grow( nHeight );
1281 : }
1282 :
1283 0 : return true;
1284 : }
1285 :
1286 0 : void SwInvalidatePositions( SwFrm *pFrm, long nBottom )
1287 : {
1288 : // LONG_MAX == nBottom means we have to calculate all
1289 0 : bool bAll = LONG_MAX == nBottom;
1290 0 : SWRECTFN( pFrm )
1291 0 : do
1292 0 : { pFrm->_InvalidatePos();
1293 0 : pFrm->_InvalidateSize();
1294 0 : if( pFrm->IsLayoutFrm() )
1295 : {
1296 0 : if ( ((SwLayoutFrm*)pFrm)->Lower() )
1297 : {
1298 0 : ::SwInvalidatePositions( ((SwLayoutFrm*)pFrm)->Lower(), nBottom);
1299 : // #i26945#
1300 0 : ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pFrm)) );
1301 : }
1302 : }
1303 : else
1304 0 : pFrm->Prepare( PREP_ADJUST_FRM );
1305 0 : pFrm = pFrm->GetNext();
1306 0 : } while ( pFrm &&
1307 0 : ( bAll ||
1308 0 : (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) );
1309 0 : }
1310 :
1311 0 : void SwInvalidateAll( SwFrm *pFrm, long nBottom )
1312 : {
1313 : // LONG_MAX == nBottom means we have to calculate all
1314 0 : bool bAll = LONG_MAX == nBottom;
1315 0 : SWRECTFN( pFrm )
1316 0 : do
1317 : {
1318 0 : pFrm->_InvalidatePos();
1319 0 : pFrm->_InvalidateSize();
1320 0 : pFrm->_InvalidatePrt();
1321 0 : if( pFrm->IsLayoutFrm() )
1322 : {
1323 : // NEW TABLES
1324 0 : SwLayoutFrm* pToInvalidate = static_cast<SwLayoutFrm*>(pFrm);
1325 0 : SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm);
1326 0 : if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 )
1327 : {
1328 0 : pToInvalidate = & const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true ));
1329 0 : pToInvalidate->_InvalidatePos();
1330 0 : pToInvalidate->_InvalidateSize();
1331 0 : pToInvalidate->_InvalidatePrt();
1332 : }
1333 :
1334 0 : if ( pToInvalidate->Lower() )
1335 0 : ::SwInvalidateAll( pToInvalidate->Lower(), nBottom);
1336 : }
1337 : else
1338 0 : pFrm->Prepare( PREP_CLEAR );
1339 :
1340 0 : pFrm = pFrm->GetNext();
1341 0 : } while ( pFrm &&
1342 0 : ( bAll ||
1343 0 : (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) );
1344 0 : }
1345 :
1346 : // #i29550#
1347 0 : static void lcl_InvalidateAllLowersPrt( SwLayoutFrm* pLayFrm )
1348 : {
1349 0 : pLayFrm->_InvalidatePrt();
1350 0 : pLayFrm->_InvalidateSize();
1351 0 : pLayFrm->SetCompletePaint();
1352 :
1353 0 : SwFrm* pFrm = pLayFrm->Lower();
1354 :
1355 0 : while ( pFrm )
1356 : {
1357 0 : if ( pFrm->IsLayoutFrm() )
1358 0 : lcl_InvalidateAllLowersPrt( (SwLayoutFrm*)pFrm );
1359 : else
1360 : {
1361 0 : pFrm->_InvalidatePrt();
1362 0 : pFrm->_InvalidateSize();
1363 0 : pFrm->SetCompletePaint();
1364 : }
1365 :
1366 0 : pFrm = pFrm->GetNext();
1367 : }
1368 0 : }
1369 :
1370 0 : bool SwCntntFrm::CalcLowers( SwLayoutFrm* pLay, const SwLayoutFrm* pDontLeave,
1371 : long nBottom, bool bSkipRowSpanCells )
1372 : {
1373 0 : if ( !pLay )
1374 0 : return true;
1375 :
1376 : // LONG_MAX == nBottom means we have to calculate all
1377 0 : bool bAll = LONG_MAX == nBottom;
1378 0 : bool bRet = false;
1379 0 : SwCntntFrm *pCnt = pLay->ContainsCntnt();
1380 0 : SWRECTFN( pLay )
1381 :
1382 : // FME 2007-08-30 #i81146# new loop control
1383 0 : sal_uInt16 nLoopControlRuns = 0;
1384 0 : const sal_uInt16 nLoopControlMax = 10;
1385 0 : const SwModify* pLoopControlCond = 0;
1386 :
1387 0 : while ( pCnt && pDontLeave->IsAnLower( pCnt ) )
1388 : {
1389 : // #115759# - check, if a format of content frame is
1390 : // possible. Thus, 'copy' conditions, found at the beginning of
1391 : // <SwCntntFrm::MakeAll(..)>, and check these.
1392 0 : const bool bFormatPossible = !pCnt->IsJoinLocked() &&
1393 0 : ( !pCnt->IsTxtFrm() ||
1394 0 : !static_cast<SwTxtFrm*>(pCnt)->IsLocked() ) &&
1395 0 : ( pCnt->IsFollow() || !StackHack::IsLocked() );
1396 :
1397 : // NEW TABLES
1398 0 : bool bSkipContent = false;
1399 0 : if ( bSkipRowSpanCells && pCnt->IsInTab() )
1400 : {
1401 0 : const SwFrm* pCell = pCnt->GetUpper();
1402 0 : while ( pCell && !pCell->IsCellFrm() )
1403 0 : pCell = pCell->GetUpper();
1404 0 : if ( pCell && 1 != static_cast<const SwCellFrm*>( pCell )->GetLayoutRowSpan() )
1405 0 : bSkipContent = true;
1406 : }
1407 :
1408 0 : if ( bFormatPossible && !bSkipContent )
1409 : {
1410 0 : bRet |= !pCnt->IsValid();
1411 : // #i26945# - no extra invalidation of floating
1412 : // screen objects needed.
1413 : // Thus, delete call of method <SwFrm::InvalidateObjs( true )>
1414 0 : pCnt->Calc();
1415 : // OD 2004-05-11 #i28701# - usage of new method <::FormatObjsAtFrm(..)>
1416 : // to format the floating screen objects
1417 : // #i46941# - frame has to be valid
1418 : // Note: frame could be invalid after calling its format, if it's locked.
1419 : OSL_ENSURE( !pCnt->IsTxtFrm() ||
1420 : pCnt->IsValid() ||
1421 : static_cast<SwTxtFrm*>(pCnt)->IsJoinLocked(),
1422 : "<SwCntntFrm::CalcLowers(..)> - text frame invalid and not locked." );
1423 0 : if ( pCnt->IsTxtFrm() && pCnt->IsValid() )
1424 : {
1425 : // #i23129#, #i36347# - pass correct page frame to
1426 : // the object formatter
1427 0 : if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt,
1428 0 : *(pCnt->FindPageFrm()) ) )
1429 : {
1430 0 : if ( pCnt->GetRegisteredIn() == pLoopControlCond )
1431 0 : ++nLoopControlRuns;
1432 : else
1433 : {
1434 0 : nLoopControlRuns = 0;
1435 0 : pLoopControlCond = pCnt->GetRegisteredIn();
1436 : }
1437 :
1438 0 : if ( nLoopControlRuns < nLoopControlMax )
1439 : {
1440 : // restart format with first content
1441 0 : pCnt = pLay->ContainsCntnt();
1442 0 : continue;
1443 : }
1444 :
1445 : #if OSL_DEBUG_LEVEL > 1
1446 : OSL_FAIL( "LoopControl in SwCntntFrm::CalcLowers" );
1447 : #endif
1448 : }
1449 : }
1450 0 : pCnt->GetUpper()->Calc();
1451 : }
1452 0 : if( ! bAll && (*fnRect->fnYDiff)((pCnt->Frm().*fnRect->fnGetTop)(), nBottom) > 0 )
1453 0 : break;
1454 0 : pCnt = pCnt->GetNextCntntFrm();
1455 : }
1456 0 : return bRet;
1457 : }
1458 :
1459 : // #i26945# - add parameter <_bOnlyRowsAndCells> to control
1460 : // that only row and cell frames are formatted.
1461 0 : static bool lcl_InnerCalcLayout( SwFrm *pFrm,
1462 : long nBottom,
1463 : bool _bOnlyRowsAndCells )
1464 : {
1465 : // LONG_MAX == nBottom means we have to calculate all
1466 0 : bool bAll = LONG_MAX == nBottom;
1467 0 : bool bRet = false;
1468 0 : const SwFrm* pOldUp = pFrm->GetUpper();
1469 0 : SWRECTFN( pFrm )
1470 0 : do
1471 : {
1472 : // #i26945# - parameter <_bOnlyRowsAndCells> controls,
1473 : // if only row and cell frames are formatted.
1474 0 : if ( pFrm->IsLayoutFrm() &&
1475 0 : ( !_bOnlyRowsAndCells || pFrm->IsRowFrm() || pFrm->IsCellFrm() ) )
1476 : {
1477 : // #130744# An invalid locked table frame will
1478 : // not be calculated => It will not become valid =>
1479 : // Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet.
1480 0 : bRet |= !pFrm->IsValid() && ( !pFrm->IsTabFrm() || !static_cast<SwTabFrm*>(pFrm)->IsJoinLocked() );
1481 0 : pFrm->Calc();
1482 0 : if( static_cast<SwLayoutFrm*>(pFrm)->Lower() )
1483 0 : bRet |= lcl_InnerCalcLayout( static_cast<SwLayoutFrm*>(pFrm)->Lower(), nBottom);
1484 :
1485 : // NEW TABLES
1486 0 : SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm);
1487 0 : if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 )
1488 : {
1489 0 : SwCellFrm& rToCalc = const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true ));
1490 0 : bRet |= !rToCalc.IsValid();
1491 0 : rToCalc.Calc();
1492 0 : if ( rToCalc.Lower() )
1493 0 : bRet |= lcl_InnerCalcLayout( rToCalc.Lower(), nBottom);
1494 : }
1495 : }
1496 0 : pFrm = pFrm->GetNext();
1497 0 : } while( pFrm &&
1498 0 : ( bAll ||
1499 0 : (*fnRect->fnYDiff)((pFrm->Frm().*fnRect->fnGetTop)(), nBottom) < 0 )
1500 0 : && pFrm->GetUpper() == pOldUp );
1501 0 : return bRet;
1502 : }
1503 :
1504 0 : static void lcl_RecalcRow( SwRowFrm& rRow, long nBottom )
1505 : {
1506 : // FME 2007-08-30 #i81146# new loop control
1507 0 : sal_uInt16 nLoopControlRuns_1 = 0;
1508 0 : sal_uInt16 nLoopControlStage_1 = 0;
1509 0 : const sal_uInt16 nLoopControlMax = 10;
1510 :
1511 0 : bool bCheck = true;
1512 : do
1513 : {
1514 : // FME 2007-08-30 #i81146# new loop control
1515 0 : sal_uInt16 nLoopControlRuns_2 = 0;
1516 0 : sal_uInt16 nLoopControlStage_2 = 0;
1517 :
1518 0 : while( lcl_InnerCalcLayout( &rRow, nBottom ) )
1519 : {
1520 0 : if ( ++nLoopControlRuns_2 > nLoopControlMax )
1521 : {
1522 : #if OSL_DEBUG_LEVEL > 1
1523 : OSL_ENSURE( 0 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 1!" );
1524 : OSL_ENSURE( 1 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 2!!" );
1525 : OSL_ENSURE( 2 > nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 3!!!" );
1526 : #endif
1527 0 : rRow.ValidateThisAndAllLowers( nLoopControlStage_2++ );
1528 0 : nLoopControlRuns_2 = 0;
1529 0 : if( nLoopControlStage_2 > 2 )
1530 0 : break;
1531 : }
1532 :
1533 0 : bCheck = true;
1534 : }
1535 :
1536 0 : if( bCheck )
1537 : {
1538 : // #115759# - force another format of the
1539 : // lowers, if at least one of it was invalid.
1540 0 : bCheck = SwCntntFrm::CalcLowers( &rRow, rRow.GetUpper(), nBottom, true );
1541 :
1542 : // NEW TABLES
1543 : // First we calculate the cells with row span of < 1, afterwards
1544 : // all cells with row span of > 1:
1545 0 : for ( int i = 0; i < 2; ++i )
1546 : {
1547 0 : SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(rRow.Lower());
1548 0 : while ( pCellFrm )
1549 : {
1550 : const bool bCalc = 0 == i ?
1551 0 : pCellFrm->GetLayoutRowSpan() < 1 :
1552 0 : pCellFrm->GetLayoutRowSpan() > 1;
1553 :
1554 0 : if ( bCalc )
1555 : {
1556 : SwCellFrm& rToRecalc = 0 == i ?
1557 : const_cast<SwCellFrm&>(pCellFrm->FindStartEndOfRowSpanCell( true, true )) :
1558 0 : *pCellFrm;
1559 0 : bCheck |= SwCntntFrm::CalcLowers( &rToRecalc, &rToRecalc, nBottom, false );
1560 : }
1561 :
1562 0 : pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext());
1563 : }
1564 : }
1565 :
1566 0 : if ( bCheck )
1567 : {
1568 0 : if ( ++nLoopControlRuns_1 > nLoopControlMax )
1569 : {
1570 : #if OSL_DEBUG_LEVEL > 1
1571 : OSL_ENSURE( 0 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 1!" );
1572 : OSL_ENSURE( 1 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 2!!" );
1573 : OSL_ENSURE( 2 > nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 3!!!" );
1574 : #endif
1575 0 : rRow.ValidateThisAndAllLowers( nLoopControlStage_1++ );
1576 0 : nLoopControlRuns_1 = 0;
1577 0 : if( nLoopControlStage_1 > 2 )
1578 0 : break;
1579 : }
1580 :
1581 0 : continue;
1582 : }
1583 : }
1584 0 : break;
1585 0 : } while( true );
1586 0 : }
1587 :
1588 0 : static void lcl_RecalcTable( SwTabFrm& rTab,
1589 : SwLayoutFrm *pFirstRow,
1590 : SwLayNotify &rNotify )
1591 : {
1592 0 : if ( rTab.Lower() )
1593 : {
1594 0 : if ( !pFirstRow )
1595 : {
1596 0 : pFirstRow = (SwLayoutFrm*)rTab.Lower();
1597 0 : rNotify.SetLowersComplete( sal_True );
1598 : }
1599 0 : ::SwInvalidatePositions( pFirstRow, LONG_MAX );
1600 0 : lcl_RecalcRow( static_cast<SwRowFrm&>(*pFirstRow), LONG_MAX );
1601 : }
1602 0 : }
1603 :
1604 : // This is a new function to check the first condition whether
1605 : // a tab frame may move backward. It replaces the formerly used
1606 : // GetIndPrev(), which did not work correctly for #i5947#
1607 0 : static bool lcl_NoPrev( const SwFrm& rFrm )
1608 : {
1609 : // #i79774#
1610 : // skip empty sections on investigation of direct previous frame.
1611 : // use information, that at least one empty section is skipped in the following code.
1612 0 : bool bSkippedDirectPrevEmptySection( false );
1613 0 : if ( rFrm.GetPrev() )
1614 : {
1615 0 : const SwFrm* pPrev( rFrm.GetPrev() );
1616 0 : while ( pPrev &&
1617 0 : pPrev->IsSctFrm() &&
1618 0 : !dynamic_cast<const SwSectionFrm*>(pPrev)->GetSection() )
1619 : {
1620 0 : pPrev = pPrev->GetPrev();
1621 0 : bSkippedDirectPrevEmptySection = true;
1622 : }
1623 0 : if ( pPrev )
1624 : {
1625 0 : return false;
1626 : }
1627 : }
1628 :
1629 0 : if ( ( !bSkippedDirectPrevEmptySection && !rFrm.GetIndPrev() ) ||
1630 0 : ( bSkippedDirectPrevEmptySection &&
1631 0 : ( !rFrm.IsInSct() || !rFrm._GetIndPrev() ) ) )
1632 : {
1633 0 : return true;
1634 : }
1635 :
1636 : // I do not have a direct prev, but I have an indirect prev.
1637 : // In section frames I have to check if I'm located inside
1638 : // the first column:
1639 0 : if ( rFrm.IsInSct() )
1640 : {
1641 0 : const SwFrm* pSct = rFrm.GetUpper();
1642 0 : if ( pSct && pSct->IsColBodyFrm() &&
1643 0 : pSct->GetUpper()->GetUpper()->IsSctFrm() )
1644 : {
1645 0 : const SwFrm* pPrevCol = rFrm.GetUpper()->GetUpper()->GetPrev();
1646 0 : if ( pPrevCol )
1647 : // I'm not inside the first column and do not have a direct
1648 : // prev. I can try to go backward.
1649 0 : return true;
1650 : }
1651 : }
1652 :
1653 0 : return false;
1654 : }
1655 :
1656 : #define KEEPTAB ( !GetFollow() && !IsFollow() )
1657 :
1658 : // - helper method to find next content frame of
1659 : // a table frame and format it to assure keep attribute.
1660 : // method return true, if a next content frame is formatted.
1661 : // Precondition: The given table frame hasn't a follow and isn't a follow.
1662 0 : SwFrm* sw_FormatNextCntntForKeep( SwTabFrm* pTabFrm )
1663 : {
1664 : // find next content, table or section
1665 0 : SwFrm* pNxt = pTabFrm->FindNext();
1666 :
1667 : // skip empty sections
1668 0 : while ( pNxt && pNxt->IsSctFrm() &&
1669 0 : !static_cast<SwSectionFrm*>(pNxt)->GetSection() )
1670 : {
1671 0 : pNxt = pNxt->FindNext();
1672 : }
1673 :
1674 : // if found next frame is a section, get its first content.
1675 0 : if ( pNxt && pNxt->IsSctFrm() )
1676 : {
1677 0 : pNxt = static_cast<SwSectionFrm*>(pNxt)->ContainsAny();
1678 : }
1679 :
1680 : // format found next frame.
1681 : // if table frame is inside another table, method <SwFrm::MakeAll()> is
1682 : // called to avoid that the superior table frame is formatted.
1683 0 : if ( pNxt )
1684 : {
1685 0 : if ( pTabFrm->GetUpper()->IsInTab() )
1686 0 : pNxt->MakeAll();
1687 : else
1688 0 : pNxt->Calc();
1689 : }
1690 :
1691 0 : return pNxt;
1692 : }
1693 :
1694 : namespace {
1695 0 : bool AreAllRowsKeepWithNext( const SwRowFrm* pFirstRowFrm )
1696 : {
1697 0 : bool bRet = pFirstRowFrm != 0 &&
1698 0 : pFirstRowFrm->ShouldRowKeepWithNext();
1699 :
1700 0 : while ( bRet && pFirstRowFrm->GetNext() != 0 )
1701 : {
1702 0 : pFirstRowFrm = dynamic_cast<const SwRowFrm*>(pFirstRowFrm->GetNext());
1703 0 : bRet = pFirstRowFrm != 0 &&
1704 0 : pFirstRowFrm->ShouldRowKeepWithNext();
1705 : }
1706 :
1707 0 : return bRet;
1708 : }
1709 : }
1710 0 : void SwTabFrm::MakeAll()
1711 : {
1712 0 : if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 )
1713 0 : return;
1714 :
1715 0 : if ( HasFollow() )
1716 : {
1717 0 : SwTabFrm* pFollowFrm = (SwTabFrm*)GetFollow();
1718 : OSL_ENSURE( !pFollowFrm->IsJoinLocked() || !pFollowFrm->IsRebuildLastLine(),
1719 : "SwTabFrm::MakeAll for master while follow is in RebuildLastLine()" );
1720 0 : if ( pFollowFrm->IsJoinLocked() && pFollowFrm->IsRebuildLastLine() )
1721 0 : return;
1722 : }
1723 :
1724 : PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 )
1725 :
1726 0 : LockJoin(); //I don't want to be destroyed on the way.
1727 0 : SwLayNotify aNotify( this ); //does the notification in the DTor
1728 : // If pos is invalid, we have to call a SetInvaKeep at aNotify.
1729 : // Otherwise the keep attribute would not work in front of a table.
1730 0 : const sal_Bool bOldValidPos = GetValidPosFlag();
1731 :
1732 : //If my neighbour is my Follow at the same time, I'll swallow it up.
1733 : // OD 09.04.2003 #108698# - join all follows, which are placed on the
1734 : // same page/column.
1735 : // OD 29.04.2003 #109213# - join follow, only if join for the follow
1736 : // is not locked. Otherwise, join will not be performed and this loop
1737 : // will be endless.
1738 0 : while ( GetNext() && GetNext() == GetFollow() &&
1739 0 : !GetFollow()->IsJoinLocked()
1740 : )
1741 : {
1742 0 : if ( HasFollowFlowLine() )
1743 0 : RemoveFollowFlowLine();
1744 0 : Join();
1745 : }
1746 :
1747 : // The bRemoveFollowFlowLinePending is set if the split attribute of the
1748 : // last line is set:
1749 0 : if ( IsRemoveFollowFlowLinePending() && HasFollowFlowLine() )
1750 : {
1751 0 : if ( RemoveFollowFlowLine() )
1752 0 : Join();
1753 0 : SetRemoveFollowFlowLinePending( sal_False );
1754 : }
1755 :
1756 0 : if ( bResizeHTMLTable ) //Optimized interplay with grow/shrink of the content
1757 : {
1758 0 : bResizeHTMLTable = sal_False;
1759 0 : SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
1760 0 : if ( pLayout )
1761 : bCalcLowers = pLayout->Resize(
1762 0 : pLayout->GetBrowseWidthByTabFrm( *this ), sal_False );
1763 : }
1764 :
1765 : // as long as bMakePage is true, a new page can be created (exactly once)
1766 0 : bool bMakePage = true;
1767 : // bMovedBwd gets set to true when the frame flows backwards
1768 0 : bool bMovedBwd = false;
1769 : // as long as bMovedFwd is false, the Frm may flow backwards (until
1770 : // it has been moved forward once)
1771 0 : bool bMovedFwd = false;
1772 : // gets set to true when the Frm is split
1773 0 : bool bSplit = false;
1774 0 : const bool bFtnsInDoc = !GetFmt()->GetDoc()->GetFtnIdxs().empty();
1775 : bool bMoveable;
1776 0 : const sal_Bool bFly = IsInFly();
1777 :
1778 0 : SwBorderAttrAccess *pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
1779 0 : const SwBorderAttrs *pAttrs = pAccess->Get();
1780 :
1781 : // The beloved keep attribute
1782 0 : const bool bKeep = IsKeep( pAttrs->GetAttrSet() );
1783 :
1784 : // All rows should keep together
1785 : // OD 2004-05-25 #i21478# - don't split table, if it has to keep with next
1786 0 : const bool bDontSplit = !IsFollow() &&
1787 0 : ( !GetFmt()->GetLayoutSplit().GetValue() || bKeep );
1788 :
1789 : // The number of repeated headlines
1790 0 : const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();
1791 :
1792 : // This flag indicates that we are allowed to try to split the
1793 : // table rows.
1794 0 : bool bTryToSplit = true;
1795 :
1796 : // #131283#
1797 : // Indicates that two individual rows may keep together, based on the keep
1798 : // attribute set at the first paragraph in the first cell.
1799 0 : const bool bTableRowKeep = !bDontSplit && GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP);
1800 :
1801 : // The Magic Move: Used for the table row keep feature.
1802 : // If only the last row of the table wants to keep (implicitely by setting
1803 : // keep for the first paragraph in the first cell), and this table does
1804 : // not have a next, the last line will be cut. Loop prevention: Only
1805 : // one try.
1806 0 : bool bLastRowHasToMoveToFollow = false;
1807 0 : bool bLastRowMoveNoMoreTries = false;
1808 :
1809 : // Join follow table, if this table is not allowed to split:
1810 0 : if ( bDontSplit )
1811 : {
1812 0 : while ( GetFollow() && !GetFollow()->IsJoinLocked() )
1813 : {
1814 0 : if ( HasFollowFlowLine() )
1815 0 : RemoveFollowFlowLine();
1816 0 : Join();
1817 : }
1818 : }
1819 :
1820 : // Join follow table, if this does not have enough (repeated) lines:
1821 0 : if ( nRepeat )
1822 : {
1823 0 : if( GetFollow() && !GetFollow()->IsJoinLocked() &&
1824 0 : 0 == GetFirstNonHeadlineRow() )
1825 : {
1826 0 : if ( HasFollowFlowLine() )
1827 0 : RemoveFollowFlowLine();
1828 0 : Join();
1829 : }
1830 : }
1831 :
1832 : // Join follow table, if last row of this table should keep:
1833 0 : if ( bTableRowKeep && GetFollow() && !GetFollow()->IsJoinLocked() )
1834 : {
1835 0 : const SwRowFrm* pTmpRow = static_cast<const SwRowFrm*>(GetLastLower());
1836 0 : if ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() )
1837 : {
1838 0 : if ( HasFollowFlowLine() )
1839 0 : RemoveFollowFlowLine();
1840 0 : Join();
1841 : }
1842 : }
1843 :
1844 : // a new one is moved forwards immediately
1845 0 : if ( !Frm().Top() && IsFollow() )
1846 : {
1847 0 : SwFrm *pPre = GetPrev();
1848 0 : if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this)
1849 : {
1850 0 : if ( !MoveFwd( bMakePage, sal_False ) )
1851 0 : bMakePage = false;
1852 0 : bMovedFwd = true;
1853 : }
1854 : }
1855 :
1856 0 : int nUnSplitted = 5; // Just another loop control :-(
1857 0 : SWRECTFN( this )
1858 0 : while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
1859 : {
1860 0 : if ( (bMoveable = IsMoveable()) )
1861 0 : if ( CheckMoveFwd( bMakePage, bKeep && KEEPTAB, bMovedBwd ) )
1862 : {
1863 0 : bMovedFwd = true;
1864 0 : bCalcLowers = sal_True;
1865 : // #i99267#
1866 : // reset <bSplit> after forward move to assure that follows
1867 : // can be joined, if further space is available.
1868 0 : bSplit = false;
1869 : }
1870 :
1871 0 : Point aOldPos( (Frm().*fnRect->fnGetPos)() );
1872 0 : MakePos();
1873 :
1874 0 : if ( aOldPos != (Frm().*fnRect->fnGetPos)() )
1875 : {
1876 0 : if ( aOldPos.Y() != (Frm().*fnRect->fnGetTop)() )
1877 : {
1878 0 : SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
1879 0 : if( pLayout )
1880 : {
1881 0 : delete pAccess;
1882 : bCalcLowers |= pLayout->Resize(
1883 0 : pLayout->GetBrowseWidthByTabFrm( *this ), sal_False );
1884 0 : pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this );
1885 0 : pAttrs = pAccess->Get();
1886 : }
1887 :
1888 0 : mbValidPrtArea = sal_False;
1889 0 : aNotify.SetLowersComplete( sal_False );
1890 : }
1891 : SwFrm *pPre;
1892 0 : if ( bKeep || (0 != (pPre = FindPrev()) &&
1893 0 : pPre->GetAttrSet()->GetKeep().GetValue()) )
1894 : {
1895 0 : bCalcLowers = sal_True;
1896 : // #i99267#
1897 : // reset <bSplit> after forward move to assure that follows
1898 : // can be joined, if further space is available.
1899 0 : bSplit = false;
1900 : }
1901 : }
1902 :
1903 : //We need to know the height of the first row, because the master needs
1904 : //to be activated if it shrinks and then absorb the row if necessary.
1905 0 : long n1StLineHeight = 0;
1906 0 : if ( IsFollow() )
1907 : {
1908 0 : SwFrm* pFrm = GetFirstNonHeadlineRow();
1909 0 : if ( pFrm )
1910 0 : n1StLineHeight = (pFrm->Frm().*fnRect->fnGetHeight)();
1911 : }
1912 :
1913 0 : if ( !mbValidSize || !mbValidPrtArea )
1914 : {
1915 0 : const long nOldPrtWidth = (Prt().*fnRect->fnGetWidth)();
1916 0 : const long nOldFrmWidth = (Frm().*fnRect->fnGetWidth)();
1917 0 : const Point aOldPrtPos = (Prt().*fnRect->fnGetPos)();
1918 0 : Format( pAttrs );
1919 :
1920 0 : SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
1921 0 : if ( pLayout &&
1922 0 : ((Prt().*fnRect->fnGetWidth)() != nOldPrtWidth ||
1923 0 : (Frm().*fnRect->fnGetWidth)() != nOldFrmWidth) )
1924 : {
1925 0 : delete pAccess;
1926 : bCalcLowers |= pLayout->Resize(
1927 0 : pLayout->GetBrowseWidthByTabFrm( *this ), sal_False );
1928 0 : pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
1929 0 : pAttrs = pAccess->Get();
1930 : }
1931 0 : if ( aOldPrtPos != (Prt().*fnRect->fnGetPos)() )
1932 0 : aNotify.SetLowersComplete( sal_False );
1933 : }
1934 :
1935 : // If this is the first one in a chain, check if this can flow
1936 : // backwards (if this is movable at all).
1937 : // To prevent oscillations/loops, check that this has not just
1938 : // flowed forwards.
1939 0 : if ( !bMovedFwd && (bMoveable || bFly) && lcl_NoPrev( *this ) )
1940 : {
1941 : // for Follows notify Master.
1942 : // only move Follow if it has to skip empty pages.
1943 0 : if ( IsFollow() )
1944 : {
1945 : // Only if the height of the first line got smaller.
1946 0 : SwFrm *pFrm = GetFirstNonHeadlineRow();
1947 0 : if( pFrm && n1StLineHeight >(pFrm->Frm().*fnRect->fnGetHeight )() )
1948 : {
1949 0 : SwTabFrm *pMaster = (SwTabFrm*)FindMaster();
1950 : bool bDummy;
1951 0 : if ( ShouldBwdMoved( pMaster->GetUpper(), false, bDummy ) )
1952 0 : pMaster->InvalidatePos();
1953 : }
1954 : }
1955 0 : SwFtnBossFrm *pOldBoss = bFtnsInDoc ? FindFtnBossFrm( sal_True ) : 0;
1956 : bool bReformat;
1957 0 : if ( MoveBwd( bReformat ) )
1958 : {
1959 0 : SWREFRESHFN( this )
1960 0 : bMovedBwd = true;
1961 0 : aNotify.SetLowersComplete( sal_False );
1962 0 : if ( bFtnsInDoc )
1963 0 : MoveLowerFtns( 0, pOldBoss, 0, sal_True );
1964 0 : if ( bReformat || bKeep )
1965 : {
1966 0 : long nOldTop = (Frm().*fnRect->fnGetTop)();
1967 0 : MakePos();
1968 0 : if( nOldTop != (Frm().*fnRect->fnGetTop)() )
1969 : {
1970 : SwHTMLTableLayout *pHTMLLayout =
1971 0 : GetTable()->GetHTMLTableLayout();
1972 0 : if( pHTMLLayout )
1973 : {
1974 0 : delete pAccess;
1975 : bCalcLowers |= pHTMLLayout->Resize(
1976 0 : pHTMLLayout->GetBrowseWidthByTabFrm( *this ),
1977 0 : sal_False );
1978 :
1979 0 : pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
1980 0 : pAttrs = pAccess->Get();
1981 : }
1982 :
1983 0 : mbValidPrtArea = sal_False;
1984 0 : Format( pAttrs );
1985 : }
1986 0 : lcl_RecalcTable( *this, 0, aNotify );
1987 0 : bLowersFormatted = sal_True;
1988 0 : if ( bKeep && KEEPTAB )
1989 : {
1990 :
1991 : // Consider case that table is inside another table,
1992 : // because it has to be avoided, that superior table
1993 : // is formatted.
1994 : // Thus, find next content, table or section
1995 : // and, if a section is found, get its first
1996 : // content.
1997 0 : if ( 0 != sw_FormatNextCntntForKeep( this ) && !GetNext() )
1998 : {
1999 0 : mbValidPos = sal_False;
2000 : }
2001 : }
2002 : }
2003 : }
2004 : }
2005 :
2006 : //Again an invalid value? - do it again...
2007 0 : if ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
2008 0 : continue;
2009 :
2010 : // check, if calculation of table frame is ready.
2011 :
2012 : // Local variable <nDistanceToUpperPrtBottom>
2013 : // Introduce local variable and init it with the distance from the
2014 : // table frame bottom to the bottom of the upper printing area.
2015 : // Note: negative values denotes the situation that table frame doesn't fit in its upper.
2016 : SwTwips nDistanceToUpperPrtBottom =
2017 0 : (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)());
2018 :
2019 : /// In online layout try to grow upper of table frame, if table frame doesn't fit in its upper.
2020 0 : const SwViewShell *pSh = getRootFrm()->GetCurrShell();
2021 0 : const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
2022 0 : if ( nDistanceToUpperPrtBottom < 0 && bBrowseMode )
2023 : {
2024 0 : if ( GetUpper()->Grow( -nDistanceToUpperPrtBottom ) )
2025 : {
2026 : // upper is grown --> recalculate <nDistanceToUpperPrtBottom>
2027 0 : nDistanceToUpperPrtBottom = (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)());
2028 : }
2029 : }
2030 :
2031 : // If there is still some space left in the upper, we check if we
2032 : // can join some rows of the follow.
2033 : // Setting bLastRowHasToMoveToFollow to true means we want to force
2034 : // the table to be split! Only skip this if condition once.
2035 0 : if( nDistanceToUpperPrtBottom >= 0 && !bLastRowHasToMoveToFollow )
2036 : {
2037 : // If there is space left in the upper printing area, join as for trial
2038 : // at least one further row of an existing follow.
2039 0 : if ( !bSplit && GetFollow() )
2040 : {
2041 : bool bDummy;
2042 0 : if ( GetFollow()->ShouldBwdMoved( GetUpper(), false, bDummy ) )
2043 : {
2044 0 : SwFrm *pTmp = GetUpper();
2045 0 : SwTwips nDeadLine = (pTmp->*fnRect->fnGetPrtBottom)();
2046 0 : if ( bBrowseMode )
2047 0 : nDeadLine += pTmp->Grow( LONG_MAX, sal_True );
2048 0 : if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 )
2049 : {
2050 : // First, we remove an existing follow flow line.
2051 0 : if ( HasFollowFlowLine() )
2052 : {
2053 0 : SwFrm* pLastLine = const_cast<SwFrm*>(GetLastLower());
2054 0 : RemoveFollowFlowLine();
2055 : // invalidate and rebuild last row
2056 0 : if ( pLastLine )
2057 : {
2058 0 : ::SwInvalidateAll( pLastLine, LONG_MAX );
2059 0 : SetRebuildLastLine( sal_True );
2060 0 : lcl_RecalcRow( static_cast<SwRowFrm&>(*pLastLine), LONG_MAX );
2061 0 : SetRebuildLastLine( sal_False );
2062 : }
2063 :
2064 0 : SwFrm* pRow = GetFollow()->GetFirstNonHeadlineRow();
2065 :
2066 0 : if ( !pRow || !pRow->GetNext() )
2067 : //The follow becomes empty and invalid for this reason.
2068 0 : Join();
2069 :
2070 0 : continue;
2071 : }
2072 :
2073 : // If there is no follow flow line, we move the first
2074 : // row in the follow table to the master table.
2075 0 : SwRowFrm *pRow = GetFollow()->GetFirstNonHeadlineRow();
2076 :
2077 : //The follow becomes empty and invalid for this reason.
2078 0 : if ( !pRow )
2079 : {
2080 0 : Join();
2081 0 : continue;
2082 : }
2083 :
2084 0 : const SwTwips nOld = (Frm().*fnRect->fnGetHeight)();
2085 0 : long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pRow );
2086 0 : SwFrm* pRowToMove = pRow;
2087 :
2088 0 : while ( pRowToMove && nRowsToMove-- > 0 )
2089 : {
2090 0 : const bool bMoveFtns = bFtnsInDoc && !GetFollow()->IsJoinLocked();
2091 :
2092 0 : SwFtnBossFrm *pOldBoss = 0;
2093 0 : if ( bMoveFtns )
2094 0 : pOldBoss = pRowToMove->FindFtnBossFrm( sal_True );
2095 :
2096 0 : SwFrm* pNextRow = pRowToMove->GetNext();
2097 :
2098 0 : if ( !pNextRow )
2099 : {
2100 : //The follow becomes empty and invalid for this reason.
2101 0 : Join();
2102 : }
2103 : else
2104 : {
2105 0 : pRowToMove->Cut();
2106 0 : pRowToMove->Paste( this );
2107 : }
2108 :
2109 : //Displace the footnotes!
2110 0 : if ( bMoveFtns )
2111 0 : if ( ((SwLayoutFrm*)pRowToMove)->MoveLowerFtns( 0, pOldBoss, FindFtnBossFrm( sal_True ), sal_True ) )
2112 0 : GetUpper()->Calc();
2113 :
2114 0 : pRowToMove = pNextRow;
2115 : }
2116 :
2117 0 : if ( nOld != (Frm().*fnRect->fnGetHeight)() )
2118 0 : lcl_RecalcTable( *this, (SwLayoutFrm*)pRow, aNotify );
2119 :
2120 0 : continue;
2121 : }
2122 : }
2123 : }
2124 0 : else if ( KEEPTAB )
2125 : {
2126 0 : bool bFormat = false;
2127 0 : if ( bKeep )
2128 0 : bFormat = true;
2129 0 : else if ( bTableRowKeep && !bLastRowMoveNoMoreTries )
2130 : {
2131 : // We only want to give the last row one chance to move
2132 : // to the follow table. Set the flag as early as possible:
2133 0 : bLastRowMoveNoMoreTries = true;
2134 :
2135 : // The last line of the table has to be cut off if:
2136 : // 1. The table does not want to keep with its next
2137 : // 2. The compatibility option is set and the table is allowed to split
2138 : // 3. We did not already cut off the last row
2139 : // 4. There is not break after attribute set at the table
2140 : // 5. There is no break before attribute set behind the table
2141 : // 6. There is no section change behind the table (see IsKeep)
2142 : // 7. The last table row wants to keep with its next.
2143 0 : const SwRowFrm* pLastRow = static_cast<const SwRowFrm*>(GetLastLower());
2144 0 : if ( pLastRow && IsKeep( pAttrs->GetAttrSet(), true ) &&
2145 0 : pLastRow->ShouldRowKeepWithNext() )
2146 0 : bFormat = true;
2147 : }
2148 :
2149 0 : if ( bFormat )
2150 : {
2151 0 : delete pAccess;
2152 :
2153 : // Consider case that table is inside another table, because
2154 : // it has to be avoided, that superior table is formatted.
2155 : // Thus, find next content, table or section and, if a section
2156 : // is found, get its first content.
2157 0 : const SwFrm* pTmpNxt = sw_FormatNextCntntForKeep( this );
2158 :
2159 0 : pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
2160 0 : pAttrs = pAccess->Get();
2161 :
2162 : // The last row wants to keep with the frame behind the table.
2163 : // Check if the next frame is on a different page and valid.
2164 : // In this case we do a magic trick:
2165 0 : if ( !bKeep && !GetNext() && pTmpNxt && pTmpNxt->IsValid() )
2166 : {
2167 0 : mbValidPos = sal_False;
2168 0 : bLastRowHasToMoveToFollow = true;
2169 : }
2170 : }
2171 : }
2172 :
2173 0 : if ( IsValid() )
2174 : {
2175 0 : if ( bCalcLowers )
2176 : {
2177 0 : lcl_RecalcTable( *this, 0, aNotify );
2178 0 : bLowersFormatted = sal_True;
2179 0 : bCalcLowers = sal_False;
2180 : }
2181 0 : else if ( bONECalcLowers )
2182 : {
2183 0 : lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX );
2184 0 : bONECalcLowers = sal_False;
2185 : }
2186 : }
2187 0 : continue;
2188 : }
2189 :
2190 : //I don't fit in the higher-ranked element anymore, therefore it's the
2191 : //right moment to do some preferably constructive changes.
2192 :
2193 : //If I'm NOT allowed to leave the parent Frm, I've got a problem.
2194 : // Following Artur Dent, we do the only thing that you can do with
2195 : // an unsolvable problem: We ignore it with all our power.
2196 0 : if ( !bMoveable )
2197 : {
2198 0 : if ( bCalcLowers && IsValid() )
2199 : {
2200 0 : lcl_RecalcTable( *this, 0, aNotify );
2201 0 : bLowersFormatted = sal_True;
2202 0 : bCalcLowers = sal_False;
2203 : }
2204 0 : else if ( bONECalcLowers )
2205 : {
2206 0 : lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX );
2207 0 : bONECalcLowers = sal_False;
2208 : }
2209 :
2210 : // It does not make sense to cut off the last line if we are
2211 : // not moveable:
2212 0 : bLastRowHasToMoveToFollow = false;
2213 :
2214 0 : continue;
2215 : }
2216 :
2217 0 : if ( bCalcLowers && IsValid() )
2218 : {
2219 0 : lcl_RecalcTable( *this, 0, aNotify );
2220 0 : bLowersFormatted = sal_True;
2221 0 : bCalcLowers = sal_False;
2222 0 : if( !IsValid() )
2223 0 : continue;
2224 : }
2225 :
2226 : // First try to split the table. Condition:
2227 : // 1. We have at least one non headline row
2228 : // 2. If this row wants to keep, we need an additional row
2229 : // 3. The table is allowed to split or we do not have an pIndPrev:
2230 0 : SwFrm* pIndPrev = GetIndPrev();
2231 0 : const SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow();
2232 : // #i120016# if this row wants to keep, allow split in case that all rows want to keep with next,
2233 : // the table can not move forward as it is the first one and a split is in general allowed.
2234 0 : const bool bAllowSplitOfRow = ( bTableRowKeep &&
2235 0 : AreAllRowsKeepWithNext( pFirstNonHeadlineRow ) ) &&
2236 0 : !pIndPrev &&
2237 0 : !bDontSplit;
2238 :
2239 0 : if ( pFirstNonHeadlineRow && nUnSplitted > 0 &&
2240 0 : ( !bTableRowKeep || pFirstNonHeadlineRow->GetNext() || !pFirstNonHeadlineRow->ShouldRowKeepWithNext() || bAllowSplitOfRow ) &&
2241 0 : ( !bDontSplit || !pIndPrev ) )
2242 : {
2243 : // #i29438#
2244 : // Special DoNotSplit case:
2245 : // We better avoid splitting of a row frame if we are inside a columned
2246 : // section which has a height of 0, because this is not growable and thus
2247 : // all kinds of unexpected things could happen.
2248 0 : if ( IsInSct() &&
2249 0 : (FindSctFrm())->Lower()->IsColumnFrm() &&
2250 0 : 0 == (GetUpper()->Frm().*fnRect->fnGetHeight)() )
2251 : {
2252 0 : bTryToSplit = false;
2253 : }
2254 :
2255 : // 1. Try: bTryToSplit = true => Try to split the row.
2256 : // 2. Try: bTryToSplit = false => Split the table between the rows.
2257 0 : if ( pFirstNonHeadlineRow->GetNext() || bTryToSplit )
2258 : {
2259 0 : SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)();
2260 0 : if( IsInSct() || GetUpper()->IsInTab() ) // TABLE IN TABLE)
2261 : nDeadLine = (*fnRect->fnYInc)( nDeadLine,
2262 0 : GetUpper()->Grow( LONG_MAX, sal_True ) );
2263 :
2264 : {
2265 0 : SetInRecalcLowerRow( true );
2266 0 : ::lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), nDeadLine );
2267 0 : SetInRecalcLowerRow( false );
2268 : }
2269 0 : bLowersFormatted = sal_True;
2270 0 : aNotify.SetLowersComplete( sal_True );
2271 :
2272 : // One more check if its really necessary to split the table.
2273 : // 1. The table either has to exceed the deadline or
2274 : // 2. We explicitly want to cut off the last row.
2275 0 : if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 && !bLastRowHasToMoveToFollow )
2276 : {
2277 0 : continue;
2278 : }
2279 :
2280 : // Set to false again as early as possible.
2281 0 : bLastRowHasToMoveToFollow = false;
2282 :
2283 : // #i52781#
2284 : // YaSC - Yet another special case:
2285 : // If our upper is inside a table cell which is not allowed
2286 : // to split, we do not try to split:
2287 0 : if ( GetUpper()->IsInTab() )
2288 : {
2289 0 : const SwFrm* pTmpRow = GetUpper();
2290 0 : while ( pTmpRow && !pTmpRow->IsRowFrm() )
2291 0 : pTmpRow = pTmpRow->GetUpper();
2292 0 : if ( pTmpRow && !static_cast<const SwRowFrm*>(pTmpRow)->IsRowSplitAllowed() )
2293 0 : continue;
2294 : }
2295 :
2296 0 : sal_uInt16 nMinNumOfLines = nRepeat;
2297 :
2298 0 : if ( bTableRowKeep )
2299 : {
2300 0 : const SwRowFrm* pTmpRow = pFirstNonHeadlineRow;
2301 0 : while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() )
2302 : {
2303 0 : ++nMinNumOfLines;
2304 0 : pTmpRow = static_cast<const SwRowFrm*>(pTmpRow->GetNext());
2305 : }
2306 : }
2307 :
2308 0 : if ( !bTryToSplit )
2309 0 : ++nMinNumOfLines;
2310 :
2311 : const SwTwips nBreakLine = (*fnRect->fnYInc)(
2312 0 : (Frm().*fnRect->fnGetTop)(),
2313 0 : (this->*fnRect->fnGetTopMargin)() +
2314 0 : lcl_GetHeightOfRows( GetLower(), nMinNumOfLines ) );
2315 :
2316 : // Some more checks if we want to call the split algorithm or not:
2317 : // The repeating lines / keeping lines still fit into the upper or
2318 : // if we do not have an (in)direkt Prev, we split anyway.
2319 0 : if( (*fnRect->fnYDiff)(nDeadLine, nBreakLine) >=0 || !pIndPrev )
2320 : {
2321 0 : aNotify.SetLowersComplete( sal_False );
2322 0 : bSplit = true;
2323 :
2324 : // An existing follow flow line has to be removed.
2325 0 : if ( HasFollowFlowLine() )
2326 : {
2327 0 : RemoveFollowFlowLine();
2328 : }
2329 :
2330 0 : const bool bSplitError = !Split( nDeadLine, bTryToSplit, ( bTableRowKeep && !bAllowSplitOfRow ) );
2331 0 : if( !bTryToSplit && !bSplitError && nUnSplitted > 0 )
2332 : {
2333 0 : --nUnSplitted;
2334 : }
2335 :
2336 : // #i29771# Two tries to split the table
2337 : // If an error occurred during splitting. We start a second
2338 : // try, this time without splitting of table rows.
2339 0 : if ( bSplitError )
2340 : {
2341 0 : if ( HasFollowFlowLine() )
2342 0 : RemoveFollowFlowLine();
2343 : }
2344 :
2345 : // #119477#
2346 : // If splitting the table was successful or not,
2347 : // we do not want to have 'empty' follow tables.
2348 0 : if ( GetFollow() && !GetFollow()->GetFirstNonHeadlineRow() )
2349 0 : Join();
2350 :
2351 : // We want to restore the situation before the failed
2352 : // split operation as good as possible. Therefore we
2353 : // do some more calculations. Note: Restricting this
2354 : // to nDeadLine may not be enough.
2355 0 : if ( bSplitError && bTryToSplit ) // no restart if we did not try to split: i72847, i79426
2356 : {
2357 0 : lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX );
2358 0 : mbValidPos = sal_False;
2359 0 : bTryToSplit = false;
2360 0 : continue;
2361 : }
2362 :
2363 0 : bTryToSplit = !bSplitError;
2364 :
2365 : //To avoid oscillations the Follow must become valid now
2366 0 : if ( GetFollow() )
2367 : {
2368 : // #i80924#
2369 : // After a successful split assure that the first row
2370 : // is invalid. When graphics are present, this isn't hold.
2371 : // Note: defect i80924 could also be fixed, if it is
2372 : // assured, that <SwLayNotify::bLowersComplete> is only
2373 : // set, if all lower are valid *and* are correct laid out.
2374 0 : if ( !bSplitError && GetFollow()->GetLower() )
2375 : {
2376 0 : GetFollow()->GetLower()->InvalidatePos();
2377 : }
2378 0 : SWRECTFNX( GetFollow() )
2379 :
2380 : static sal_uInt8 nStack = 0;
2381 0 : if ( !StackHack::IsLocked() && nStack < 4 )
2382 : {
2383 0 : ++nStack;
2384 0 : StackHack aHack;
2385 0 : delete pAccess;
2386 :
2387 0 : GetFollow()->MakeAll();
2388 :
2389 0 : pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
2390 0 : pAttrs = pAccess->Get();
2391 :
2392 0 : ((SwTabFrm*)GetFollow())->SetLowersFormatted(sal_False);
2393 : // #i43913# - lock follow table
2394 : // to avoid its formatting during the format of
2395 : // its content.
2396 0 : const bool bOldJoinLock = GetFollow()->IsJoinLocked();
2397 0 : GetFollow()->LockJoin();
2398 0 : ::lcl_RecalcRow( static_cast<SwRowFrm&>(*GetFollow()->Lower()),
2399 0 : (GetFollow()->GetUpper()->Frm().*fnRectX->fnGetBottom)() );
2400 : // #i43913#
2401 : // #i63632# Do not unlock the
2402 : // follow if it wasn't locked before.
2403 0 : if ( !bOldJoinLock )
2404 0 : GetFollow()->UnlockJoin();
2405 :
2406 0 : if ( !GetFollow()->GetFollow() )
2407 : {
2408 0 : SwFrm* pNxt = ((SwFrm*)GetFollow())->FindNext();
2409 0 : if ( pNxt )
2410 : {
2411 : // #i18103# - no formatting of found next
2412 : // frame, if its a follow section of the
2413 : // 'ColLocked' section, the follow table is
2414 : // in.
2415 0 : bool bCalcNxt = true;
2416 0 : if ( GetFollow()->IsInSct() && pNxt->IsSctFrm() )
2417 : {
2418 0 : SwSectionFrm* pSct = GetFollow()->FindSctFrm();
2419 0 : if ( pSct->IsColLocked() &&
2420 0 : pSct->GetFollow() == pNxt )
2421 : {
2422 0 : bCalcNxt = false;
2423 : }
2424 : }
2425 0 : if ( bCalcNxt )
2426 : {
2427 0 : pNxt->Calc();
2428 : }
2429 : }
2430 : }
2431 0 : --nStack;
2432 : }
2433 0 : else if ( GetFollow() == GetNext() )
2434 0 : ((SwTabFrm*)GetFollow())->MoveFwd( sal_True, sal_False );
2435 : }
2436 0 : continue;
2437 : }
2438 : }
2439 : }
2440 :
2441 : // Set to false again as early as possible.
2442 0 : bLastRowHasToMoveToFollow = false;
2443 :
2444 0 : if( IsInSct() && bMovedFwd && bMakePage && GetUpper()->IsColBodyFrm() &&
2445 0 : GetUpper()->GetUpper()->GetUpper()->IsSctFrm() &&
2446 0 : ( GetUpper()->GetUpper()->GetPrev() || GetIndPrev() ) &&
2447 0 : ((SwSectionFrm*)GetUpper()->GetUpper()->GetUpper())->MoveAllowed(this) )
2448 : {
2449 0 : bMovedFwd = false;
2450 : }
2451 :
2452 : // #i29771# Reset bTryToSplit flag on change of upper
2453 0 : const SwFrm* pOldUpper = GetUpper();
2454 :
2455 : //Let's see if we find some place anywhere...
2456 0 : if ( !bMovedFwd && !MoveFwd( bMakePage, sal_False ) )
2457 0 : bMakePage = false;
2458 :
2459 : // #i29771# Reset bSplitError flag on change of upper
2460 0 : if ( GetUpper() != pOldUpper )
2461 : {
2462 0 : bTryToSplit = true;
2463 0 : nUnSplitted = 5;
2464 : }
2465 :
2466 0 : SWREFRESHFN( this )
2467 0 : bCalcLowers = sal_True;
2468 0 : bMovedFwd = true;
2469 0 : aNotify.SetLowersComplete( sal_False );
2470 0 : if ( IsFollow() )
2471 : {
2472 : //To avoid oscillations now invalid master should drop behind.
2473 0 : SwTabFrm *pTab = FindMaster();
2474 0 : if ( pTab->GetUpper() )
2475 0 : pTab->GetUpper()->Calc();
2476 0 : pTab->Calc();
2477 0 : pTab->SetLowersFormatted( sal_False );
2478 : }
2479 :
2480 : //If my neighbour is my Follow at the same time, I'll swallow it up.
2481 0 : if ( ( GetNext() && GetNext() == GetFollow() ) || !GetLower() )
2482 : {
2483 0 : if ( HasFollowFlowLine() )
2484 0 : RemoveFollowFlowLine();
2485 0 : if ( GetFollow() )
2486 0 : Join();
2487 : }
2488 :
2489 0 : if ( bMovedBwd && GetUpper() )
2490 : {
2491 : //During floating back the upper was animated to do a full repaint,
2492 : //we can now skip this after the whole back and forth floating.
2493 0 : GetUpper()->ResetCompletePaint();
2494 : }
2495 :
2496 0 : if ( bCalcLowers && IsValid() )
2497 : {
2498 : // #i44910# - format of lower frames unnecessary
2499 : // and can cause layout loops, if table doesn't fit and isn't
2500 : // allowed to split.
2501 : SwTwips nDistToUpperPrtBottom =
2502 0 : (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)());
2503 0 : if ( nDistToUpperPrtBottom >= 0 || bTryToSplit )
2504 : {
2505 0 : lcl_RecalcTable( *this, 0, aNotify );
2506 0 : bLowersFormatted = sal_True;
2507 0 : bCalcLowers = sal_False;
2508 : }
2509 : #if OSL_DEBUG_LEVEL > 0
2510 : else
2511 : {
2512 : OSL_FAIL( "debug assertion: <SwTabFrm::MakeAll()> - format of table lowers suppressed by fix i44910" );
2513 : }
2514 : #endif
2515 : }
2516 :
2517 : } //while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
2518 :
2519 : //If my direct predecessor is my master now, it can destroy me during the
2520 : //next best opportunity.
2521 0 : if ( IsFollow() )
2522 : {
2523 0 : SwFrm *pPre = GetPrev();
2524 0 : if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this)
2525 0 : pPre->InvalidatePos();
2526 : }
2527 :
2528 0 : bCalcLowers = bONECalcLowers = sal_False;
2529 0 : delete pAccess;
2530 0 : UnlockJoin();
2531 0 : if ( bMovedFwd || bMovedBwd || !bOldValidPos )
2532 0 : aNotify.SetInvaKeep();
2533 : }
2534 :
2535 : /// Calculate the offsets arising because of FlyFrames
2536 0 : sal_Bool SwTabFrm::CalcFlyOffsets( SwTwips& rUpper,
2537 : long& rLeftOffset,
2538 : long& rRightOffset ) const
2539 : {
2540 0 : sal_Bool bInvalidatePrtArea = sal_False;
2541 0 : const SwPageFrm *pPage = FindPageFrm();
2542 0 : const SwFlyFrm* pMyFly = FindFlyFrm();
2543 :
2544 : // --> #108724# Page header/footer content doesn't have to wrap around
2545 : // floating screen objects
2546 :
2547 0 : const IDocumentSettingAccess* pIDSA = GetFmt()->getIDocumentSettingAccess();
2548 0 : const bool bWrapAllowed = pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ||
2549 0 : ( !IsInFtn() && 0 == FindFooterOrHeader() );
2550 :
2551 0 : if ( pPage->GetSortedObjs() && bWrapAllowed )
2552 : {
2553 0 : SWRECTFN( this )
2554 0 : const bool bConsiderWrapOnObjPos = pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION);
2555 0 : long nPrtPos = (Frm().*fnRect->fnGetTop)();
2556 0 : nPrtPos = (*fnRect->fnYInc)( nPrtPos, rUpper );
2557 0 : SwRect aRect( Frm() );
2558 0 : long nYDiff = (*fnRect->fnYDiff)( (Prt().*fnRect->fnGetTop)(), rUpper );
2559 0 : if( nYDiff > 0 )
2560 0 : (aRect.*fnRect->fnAddBottom)( -nYDiff );
2561 0 : for ( sal_uInt16 i = 0; i < pPage->GetSortedObjs()->Count(); ++i )
2562 : {
2563 0 : SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
2564 0 : if ( pAnchoredObj->ISA(SwFlyFrm) )
2565 : {
2566 0 : SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
2567 0 : const SwRect aFlyRect = pFly->GetObjRectWithSpaces();
2568 : // #i26945# - correction of conditions,
2569 : // if Writer fly frame has to be considered:
2570 : // - no need to check, if top of Writer fly frame differs
2571 : // from FAR_AWAY, because its also check, if the Writer
2572 : // fly frame rectangle overlaps with <aRect>
2573 : // - no check, if bottom of anchor frame is prior the top of
2574 : // the table, because Writer fly frames can be negative positioned.
2575 : // - correct check, if the Writer fly frame is an lower of the
2576 : // table, because table lines/rows can split and a at-character
2577 : // anchored Writer fly frame could be positioned in the follow
2578 : // flow line.
2579 : // - add condition, that an existing anchor character text frame
2580 : // has to be on the same page as the table.
2581 : // E.g., it could happen, that the fly frame is still registered
2582 : // at the page frame, the table is on, but it's anchor character
2583 : // text frame has already changed its page.
2584 0 : const SwTxtFrm* pAnchorCharFrm = pFly->FindAnchorCharFrm();
2585 : bool bConsiderFly =
2586 : // #i46807# - do not consider invalid
2587 : // Writer fly frames.
2588 0 : pFly->IsValid() &&
2589 : // fly anchored at character
2590 0 : pFly->IsFlyAtCntFrm() &&
2591 : // fly overlaps with corresponding table rectangle
2592 0 : aFlyRect.IsOver( aRect ) &&
2593 : // fly isn't lower of table and
2594 : // anchor character frame of fly isn't lower of table
2595 0 : ( !IsAnLower( pFly ) &&
2596 0 : ( !pAnchorCharFrm || !IsAnLower( pAnchorCharFrm ) ) ) &&
2597 : // table isn't lower of fly
2598 0 : !pFly->IsAnLower( this ) &&
2599 : // fly is lower of fly, the table is in
2600 : // #123274# - correction
2601 : // assure that fly isn't a lower of a fly, the table isn't in.
2602 : // E.g., a table in the body doesn't wrap around a graphic,
2603 : // which is inside a frame.
2604 0 : ( ( !pMyFly ||
2605 0 : pMyFly->IsAnLower( pFly ) ) &&
2606 0 : pMyFly == pFly->GetAnchorFrmContainingAnchPos()->FindFlyFrm() ) &&
2607 : // anchor frame not on following page
2608 0 : pPage->GetPhyPageNum() >=
2609 0 : pFly->GetAnchorFrm()->FindPageFrm()->GetPhyPageNum() &&
2610 : // anchor character text frame on same page
2611 0 : ( !pAnchorCharFrm ||
2612 0 : pAnchorCharFrm->FindPageFrm()->GetPhyPageNum() ==
2613 0 : pPage->GetPhyPageNum() );
2614 :
2615 0 : if ( bConsiderFly )
2616 : {
2617 0 : const SwFrm* pFlyHeaderFooterFrm = pFly->GetAnchorFrm()->FindFooterOrHeader();
2618 0 : const SwFrm* pThisHeaderFooterFrm = FindFooterOrHeader();
2619 :
2620 0 : if ( pFlyHeaderFooterFrm != pThisHeaderFooterFrm &&
2621 : // #148493# If bConsiderWrapOnObjPos is set,
2622 : // we want to consider the fly if it is located in the header and
2623 : // the table is located in the body:
2624 0 : ( !bConsiderWrapOnObjPos || 0 != pThisHeaderFooterFrm || !pFlyHeaderFooterFrm->IsHeaderFrm() ) )
2625 0 : bConsiderFly = false;
2626 : }
2627 :
2628 0 : if ( bConsiderFly )
2629 : {
2630 0 : const SwFmtSurround &rSur = pFly->GetFmt()->GetSurround();
2631 0 : const SwFmtHoriOrient &rHori= pFly->GetFmt()->GetHoriOrient();
2632 0 : if ( SURROUND_NONE == rSur.GetSurround() )
2633 : {
2634 0 : long nBottom = (aFlyRect.*fnRect->fnGetBottom)();
2635 0 : if( (*fnRect->fnYDiff)( nPrtPos, nBottom ) < 0 )
2636 0 : nPrtPos = nBottom;
2637 0 : bInvalidatePrtArea = sal_True;
2638 : }
2639 0 : if ( (SURROUND_RIGHT == rSur.GetSurround() ||
2640 0 : SURROUND_PARALLEL == rSur.GetSurround())&&
2641 0 : text::HoriOrientation::LEFT == rHori.GetHoriOrient() )
2642 : {
2643 : const long nWidth = (*fnRect->fnXDiff)(
2644 0 : (aFlyRect.*fnRect->fnGetRight)(),
2645 0 : (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetLeft)() );
2646 0 : rLeftOffset = std::max( rLeftOffset, nWidth );
2647 0 : bInvalidatePrtArea = sal_True;
2648 : }
2649 0 : if ( (SURROUND_LEFT == rSur.GetSurround() ||
2650 0 : SURROUND_PARALLEL == rSur.GetSurround())&&
2651 0 : text::HoriOrientation::RIGHT == rHori.GetHoriOrient() )
2652 : {
2653 : const long nWidth = (*fnRect->fnXDiff)(
2654 0 : (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetRight)(),
2655 0 : (aFlyRect.*fnRect->fnGetLeft)() );
2656 0 : rRightOffset = std::max( rRightOffset, nWidth );
2657 0 : bInvalidatePrtArea = sal_True;
2658 : }
2659 : }
2660 : }
2661 : }
2662 0 : rUpper = (*fnRect->fnYDiff)( nPrtPos, (Frm().*fnRect->fnGetTop)() );
2663 : }
2664 :
2665 0 : return bInvalidatePrtArea;
2666 : }
2667 :
2668 : /// "Formats" the frame; Frm and PrtArea.
2669 : /// The fixed size is not adjusted here.
2670 0 : void SwTabFrm::Format( const SwBorderAttrs *pAttrs )
2671 : {
2672 : OSL_ENSURE( pAttrs, "TabFrm::Format, pAttrs ist 0." );
2673 :
2674 0 : SWRECTFN( this )
2675 0 : if ( !mbValidSize )
2676 : {
2677 0 : long nDiff = (GetUpper()->Prt().*fnRect->fnGetWidth)() -
2678 0 : (Frm().*fnRect->fnGetWidth)();
2679 0 : if( nDiff )
2680 0 : (maFrm.*fnRect->fnAddRight)( nDiff );
2681 : }
2682 :
2683 : //VarSize is always the height.
2684 : //For the upper/lower border the same rules apply as for cntfrms (see
2685 : //MakePrtArea() of those).
2686 :
2687 0 : SwTwips nUpper = CalcUpperSpace( pAttrs );
2688 :
2689 : //We want to dodge the border. Two possibilities:
2690 : //1. There are borders with SurroundNone, dodge them completely
2691 : //2. There are borders which only float on the right or the left side and
2692 : // are right or left aligned, those set the minimum for the borders.
2693 0 : long nTmpRight = -1000000,
2694 0 : nLeftOffset = 0;
2695 0 : if( CalcFlyOffsets( nUpper, nLeftOffset, nTmpRight ) )
2696 0 : mbValidPrtArea = sal_False;
2697 0 : long nRightOffset = std::max( 0L, nTmpRight );
2698 :
2699 0 : SwTwips nLower = pAttrs->CalcBottomLine();
2700 : // #i29550#
2701 0 : if ( IsCollapsingBorders() )
2702 0 : nLower += GetBottomLineSize();
2703 :
2704 0 : if ( !mbValidPrtArea )
2705 0 : { mbValidPrtArea = sal_True;
2706 :
2707 : //The width of the PrtArea is given by the FrmFmt, the borders have to
2708 : //be set accordingly.
2709 : //Minimum borders are determined depending on margins and shadows.
2710 : //The borders are adjusted so that the PrtArea is aligned into the Frm
2711 : //according to the adjustment.
2712 : //If the adjustment is 0, the borders are set according to the border
2713 : //attributes.
2714 :
2715 0 : const SwTwips nOldHeight = (Prt().*fnRect->fnGetHeight)();
2716 0 : const SwTwips nMax = (maFrm.*fnRect->fnGetWidth)();
2717 :
2718 : // OD 14.03.2003 #i9040# - adjust variable names.
2719 0 : const SwTwips nLeftLine = pAttrs->CalcLeftLine();
2720 0 : const SwTwips nRightLine = pAttrs->CalcRightLine();
2721 :
2722 : //The width possibly is a percentage value. If the table is inside
2723 : //something else, the value applies to the surrounding. If it's the body
2724 : //the value applies to the screen width in the BrowseView.
2725 0 : const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize();
2726 : // OD 14.03.2003 #i9040# - adjust variable name.
2727 0 : const SwTwips nWishedTableWidth = CalcRel( rSz, sal_True );
2728 :
2729 0 : bool bCheckBrowseWidth = false;
2730 :
2731 : // OD 14.03.2003 #i9040# - insert new variables for left/right spacing.
2732 0 : SwTwips nLeftSpacing = 0;
2733 0 : SwTwips nRightSpacing = 0;
2734 0 : switch ( GetFmt()->GetHoriOrient().GetHoriOrient() )
2735 : {
2736 : case text::HoriOrientation::LEFT:
2737 : {
2738 : // left indent:
2739 0 : nLeftSpacing = nLeftLine + nLeftOffset;
2740 : // OD 06.03.2003 #i9040# - correct calculation of right indent:
2741 : // - Consider right indent given by right line attributes.
2742 : // - Consider negative right indent.
2743 : // wished right indent determined by wished table width and
2744 : // left offset given by surround fly frames on the left:
2745 0 : const SwTwips nWishRight = nMax - nWishedTableWidth - nLeftOffset;
2746 0 : if ( nRightOffset > 0 )
2747 : {
2748 : // surrounding fly frames on the right
2749 : // -> right indent is maximun of given right offset
2750 : // and wished right offset.
2751 0 : nRightSpacing = nRightLine + std::max( nRightOffset, nWishRight );
2752 : }
2753 : else
2754 : {
2755 : // no surrounding fly frames on the right
2756 : // If intrinsic right indent (intrinsic means not considering
2757 : // determined left indent) is negative,
2758 : // then hold this intrinsic indent,
2759 : // otherwise non negative wished right indent is hold.
2760 0 : nRightSpacing = nRightLine +
2761 0 : ( ( (nWishRight+nLeftOffset) < 0 ) ?
2762 0 : (nWishRight+nLeftOffset) :
2763 0 : std::max( 0L, nWishRight ) );
2764 : }
2765 : }
2766 0 : break;
2767 : case text::HoriOrientation::RIGHT:
2768 : {
2769 : // right indent:
2770 0 : nRightSpacing = nRightLine + nRightOffset;
2771 : // OD 06.03.2003 #i9040# - correct calculation of left indent:
2772 : // - Consider left indent given by left line attributes.
2773 : // - Consider negative left indent.
2774 : // wished left indent determined by wished table width and
2775 : // right offset given by surrounding fyl frames on the right:
2776 0 : const SwTwips nWishLeft = nMax - nWishedTableWidth - nRightOffset;
2777 0 : if ( nLeftOffset > 0 )
2778 : {
2779 : // surrounding fly frames on the left
2780 : // -> right indent is maximun of given left offset
2781 : // and wished left offset.
2782 0 : nLeftSpacing = nLeftLine + std::max( nLeftOffset, nWishLeft );
2783 : }
2784 : else
2785 : {
2786 : // no surrounding fly frames on the left
2787 : // If intrinsic left indent (intrinsic = not considering
2788 : // determined right indent) is negative,
2789 : // then hold this intrinsic indent,
2790 : // otherwise non negative wished left indent is hold.
2791 0 : nLeftSpacing = nLeftLine +
2792 0 : ( ( (nWishLeft+nRightOffset) < 0 ) ?
2793 0 : (nWishLeft+nRightOffset) :
2794 0 : std::max( 0L, nWishLeft ) );
2795 : }
2796 : }
2797 0 : break;
2798 : case text::HoriOrientation::CENTER:
2799 : {
2800 : // OD 07.03.2003 #i9040# - consider left/right line attribute.
2801 : // OD 10.03.2003 #i9040# -
2802 0 : const SwTwips nCenterSpacing = ( nMax - nWishedTableWidth ) / 2;
2803 0 : nLeftSpacing = nLeftLine +
2804 0 : ( (nLeftOffset > 0) ?
2805 0 : std::max( nCenterSpacing, nLeftOffset ) :
2806 0 : nCenterSpacing );
2807 0 : nRightSpacing = nRightLine +
2808 0 : ( (nRightOffset > 0) ?
2809 0 : std::max( nCenterSpacing, nRightOffset ) :
2810 0 : nCenterSpacing );
2811 : }
2812 0 : break;
2813 : case text::HoriOrientation::FULL:
2814 : //This things grows over the whole width.
2815 : //Only the free space needed for the border is taken into
2816 : //account. The attribute values of LRSpace are ignored
2817 : //intentionally.
2818 0 : bCheckBrowseWidth = true;
2819 0 : nLeftSpacing = nLeftLine + nLeftOffset;
2820 0 : nRightSpacing = nRightLine + nRightOffset;
2821 0 : break;
2822 : case text::HoriOrientation::NONE:
2823 : {
2824 : //The border are defined by the border attribute.
2825 0 : nLeftSpacing = pAttrs->CalcLeft( this );
2826 0 : if( nLeftOffset )
2827 : {
2828 : // OD 07.03.2003 #i9040# - surround fly frames only, if
2829 : // they overlap with the table.
2830 : // Thus, take maximun of left spacing and left offset.
2831 : // OD 10.03.2003 #i9040# - consider left line attribute.
2832 0 : nLeftSpacing = std::max( nLeftSpacing, ( nLeftOffset + nLeftLine ) );
2833 : }
2834 : // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
2835 0 : nRightSpacing = pAttrs->CalcRight( this );
2836 0 : if( nRightOffset )
2837 : {
2838 : // OD 07.03.2003 #i9040# - surround fly frames only, if
2839 : // they overlap with the table.
2840 : // Thus, take maximun of right spacing and right offset.
2841 : // OD 10.03.2003 #i9040# - consider right line attribute.
2842 0 : nRightSpacing = std::max( nRightSpacing, ( nRightOffset + nRightLine ) );
2843 : }
2844 : }
2845 0 : break;
2846 : case text::HoriOrientation::LEFT_AND_WIDTH:
2847 : {
2848 : //Linker Rand und die Breite zaehlen (Word-Spezialitaet)
2849 : // OD 10.03.2003 #i9040# - no width alignment in online mode.
2850 : //bCheckBrowseWidth = true;
2851 0 : nLeftSpacing = pAttrs->CalcLeft( this );
2852 0 : if( nLeftOffset )
2853 : {
2854 : // OD 10.03.2003 #i9040# - surround fly frames only, if
2855 : // they overlap with the table.
2856 : // Thus, take maximun of right spacing and right offset.
2857 : // OD 10.03.2003 #i9040# - consider left line attribute.
2858 0 : nLeftSpacing = std::max( nLeftSpacing, ( pAttrs->CalcLeftLine() + nLeftOffset ) );
2859 : }
2860 : // OD 10.03.2003 #i9040# - consider right and left line attribute.
2861 : const SwTwips nWishRight =
2862 0 : nMax - (nLeftSpacing-pAttrs->CalcLeftLine()) - nWishedTableWidth;
2863 0 : nRightSpacing = nRightLine +
2864 0 : ( (nRightOffset > 0) ?
2865 0 : std::max( nWishRight, nRightOffset ) :
2866 0 : nWishRight );
2867 : }
2868 0 : break;
2869 : default:
2870 : OSL_FAIL( "Ungueltige orientation fuer Table." );
2871 : }
2872 :
2873 : // #i26250# - extend bottom printing area, if table
2874 : // is last content inside a table cell.
2875 0 : if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) &&
2876 0 : GetUpper()->IsInTab() && !GetIndNext() )
2877 : {
2878 0 : nLower += pAttrs->GetULSpace().GetLower();
2879 : }
2880 0 : (this->*fnRect->fnSetYMargins)( nUpper, nLower );
2881 0 : if( (nMax - MINLAY) < (nLeftSpacing + nRightSpacing) )
2882 0 : (this->*fnRect->fnSetXMargins)( 0, 0 );
2883 : else
2884 0 : (this->*fnRect->fnSetXMargins)( nLeftSpacing, nRightSpacing );
2885 :
2886 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
2887 0 : if ( bCheckBrowseWidth &&
2888 0 : pSh && pSh->GetViewOptions()->getBrowseMode() &&
2889 0 : GetUpper()->IsPageBodyFrm() && // only PageBodyFrms and not ColBodyFrms
2890 0 : pSh->VisArea().Width() )
2891 : {
2892 : //Don't overlap the edge of the visible area.
2893 : //The page width can be bigger because objects with
2894 : //"over-size" are possible (RootFrm::ImplCalcBrowseWidth())
2895 0 : long nWidth = pSh->GetBrowseWidth();
2896 0 : nWidth -= Prt().Left();
2897 0 : nWidth -= pAttrs->CalcRightLine();
2898 0 : Prt().Width( std::min( nWidth, Prt().Width() ) );
2899 : }
2900 :
2901 0 : if ( nOldHeight != (Prt().*fnRect->fnGetHeight)() )
2902 0 : mbValidSize = sal_False;
2903 : }
2904 :
2905 0 : if ( !mbValidSize )
2906 : {
2907 0 : mbValidSize = sal_True;
2908 :
2909 : //The size is defined by the content plus the borders.
2910 0 : SwTwips nRemaining = 0, nDiff;
2911 0 : SwFrm *pFrm = pLower;
2912 0 : while ( pFrm )
2913 : {
2914 0 : nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)();
2915 0 : pFrm = pFrm->GetNext();
2916 : }
2917 : //And now add the borders
2918 0 : nRemaining += nUpper + nLower;
2919 :
2920 0 : nDiff = (Frm().*fnRect->fnGetHeight)() - nRemaining;
2921 0 : if ( nDiff > 0 )
2922 0 : Shrink( nDiff );
2923 0 : else if ( nDiff < 0 )
2924 0 : Grow( -nDiff );
2925 : }
2926 0 : }
2927 :
2928 0 : SwTwips SwTabFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo )
2929 : {
2930 0 : SWRECTFN( this )
2931 0 : SwTwips nHeight =(Frm().*fnRect->fnGetHeight)();
2932 0 : if( nHeight > 0 && nDist > ( LONG_MAX - nHeight ) )
2933 0 : nDist = LONG_MAX - nHeight;
2934 :
2935 0 : if ( bTst && !IsRestrictTableGrowth() )
2936 0 : return nDist;
2937 :
2938 0 : if ( GetUpper() )
2939 : {
2940 0 : SwRect aOldFrm( Frm() );
2941 :
2942 : //The upper only grows as far as needed. nReal provides the distance
2943 : //which is already available.
2944 0 : SwTwips nReal = (GetUpper()->Prt().*fnRect->fnGetHeight)();
2945 0 : SwFrm *pFrm = GetUpper()->Lower();
2946 0 : while ( pFrm && GetFollow() != pFrm )
2947 : {
2948 0 : nReal -= (pFrm->Frm().*fnRect->fnGetHeight)();
2949 0 : pFrm = pFrm->GetNext();
2950 : }
2951 :
2952 0 : if ( nReal < nDist )
2953 : {
2954 0 : long nTmp = GetUpper()->Grow( nDist - ( nReal > 0 ? nReal : 0), bTst, bInfo );
2955 :
2956 0 : if ( IsRestrictTableGrowth() )
2957 : {
2958 0 : nTmp = std::min( nDist, nReal + nTmp );
2959 0 : nDist = nTmp < 0 ? 0 : nTmp;
2960 : }
2961 : }
2962 :
2963 0 : if ( !bTst )
2964 : {
2965 0 : (Frm().*fnRect->fnAddBottom)( nDist );
2966 :
2967 0 : SwRootFrm *pRootFrm = getRootFrm();
2968 0 : if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
2969 0 : pRootFrm->GetCurrShell() )
2970 : {
2971 0 : pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( this, aOldFrm );
2972 : }
2973 : }
2974 : }
2975 :
2976 0 : if ( !bTst && ( nDist || IsRestrictTableGrowth() ) )
2977 : {
2978 0 : SwPageFrm *pPage = FindPageFrm();
2979 0 : if ( GetNext() )
2980 : {
2981 0 : GetNext()->_InvalidatePos();
2982 0 : if ( GetNext()->IsCntntFrm() )
2983 0 : GetNext()->InvalidatePage( pPage );
2984 : }
2985 : // #i28701# - Due to the new object positioning the
2986 : // frame on the next page/column can flow backward (e.g. it was moved
2987 : // forward due to the positioning of its objects ). Thus, invalivate this
2988 : // next frame, if document compatibility option 'Consider wrapping style
2989 : // influence on object positioning' is ON.
2990 0 : else if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) )
2991 : {
2992 0 : InvalidateNextPos();
2993 : }
2994 0 : _InvalidateAll();
2995 0 : InvalidatePage( pPage );
2996 0 : SetComplete();
2997 :
2998 0 : const SvxGraphicPosition ePos = GetFmt()->GetBackground().GetGraphicPos();
2999 0 : if ( GPOS_NONE != ePos && GPOS_TILED != ePos )
3000 0 : SetCompletePaint();
3001 : }
3002 :
3003 0 : return nDist;
3004 : }
3005 :
3006 0 : void SwTabFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
3007 : {
3008 0 : sal_uInt8 nInvFlags = 0;
3009 0 : bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();
3010 :
3011 0 : if( bAttrSetChg )
3012 : {
3013 0 : SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() );
3014 0 : SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() );
3015 0 : SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld );
3016 0 : SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew );
3017 : while( true )
3018 : {
3019 : _UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(),
3020 : (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags,
3021 0 : &aOldSet, &aNewSet );
3022 0 : if( aNIter.IsAtEnd() )
3023 0 : break;
3024 0 : aNIter.NextItem();
3025 0 : aOIter.NextItem();
3026 : }
3027 0 : if ( aOldSet.Count() || aNewSet.Count() )
3028 0 : SwLayoutFrm::Modify( &aOldSet, &aNewSet );
3029 : }
3030 : else
3031 0 : _UpdateAttr( pOld, pNew, nInvFlags );
3032 :
3033 0 : if ( nInvFlags != 0 )
3034 : {
3035 0 : SwPageFrm *pPage = FindPageFrm();
3036 0 : InvalidatePage( pPage );
3037 0 : if ( nInvFlags & 0x02 )
3038 0 : _InvalidatePrt();
3039 0 : if ( nInvFlags & 0x40 )
3040 0 : _InvalidatePos();
3041 : SwFrm *pTmp;
3042 0 : if ( 0 != (pTmp = GetIndNext()) )
3043 : {
3044 0 : if ( nInvFlags & 0x04 )
3045 : {
3046 0 : pTmp->_InvalidatePrt();
3047 0 : if ( pTmp->IsCntntFrm() )
3048 0 : pTmp->InvalidatePage( pPage );
3049 : }
3050 0 : if ( nInvFlags & 0x10 )
3051 0 : pTmp->SetCompletePaint();
3052 : }
3053 0 : if ( nInvFlags & 0x08 && 0 != (pTmp = GetPrev()) )
3054 : {
3055 0 : pTmp->_InvalidatePrt();
3056 0 : if ( pTmp->IsCntntFrm() )
3057 0 : pTmp->InvalidatePage( pPage );
3058 : }
3059 0 : if ( nInvFlags & 0x20 )
3060 : {
3061 0 : if ( pPage && pPage->GetUpper() && !IsFollow() )
3062 0 : ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth();
3063 : }
3064 0 : if ( nInvFlags & 0x80 )
3065 0 : InvalidateNextPos();
3066 : }
3067 0 : }
3068 :
3069 0 : void SwTabFrm::_UpdateAttr( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
3070 : sal_uInt8 &rInvFlags,
3071 : SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
3072 : {
3073 0 : bool bClear = true;
3074 0 : const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
3075 0 : switch( nWhich )
3076 : {
3077 : case RES_TBLHEADLINECHG:
3078 0 : if ( IsFollow() )
3079 : {
3080 : // Delete remaining headlines:
3081 0 : SwRowFrm* pLowerRow = 0;
3082 0 : while ( 0 != ( pLowerRow = (SwRowFrm*)Lower() ) && pLowerRow->IsRepeatedHeadline() )
3083 : {
3084 0 : pLowerRow->Cut();
3085 0 : delete pLowerRow;
3086 : }
3087 :
3088 : // insert new headlines
3089 0 : const sal_uInt16 nNewRepeat = GetTable()->GetRowsToRepeat();
3090 0 : for ( sal_uInt16 nIdx = 0; nIdx < nNewRepeat; ++nIdx )
3091 : {
3092 0 : bDontCreateObjects = true; //frmtool
3093 0 : SwRowFrm* pHeadline = new SwRowFrm( *GetTable()->GetTabLines()[ nIdx ], this );
3094 0 : pHeadline->SetRepeatedHeadline( true );
3095 0 : bDontCreateObjects = false;
3096 0 : pHeadline->Paste( this, pLowerRow );
3097 : }
3098 : }
3099 0 : rInvFlags |= 0x02;
3100 0 : break;
3101 :
3102 : case RES_FRM_SIZE:
3103 : case RES_HORI_ORIENT:
3104 0 : rInvFlags |= 0x22;
3105 0 : break;
3106 :
3107 : case RES_PAGEDESC: //Attribute changes (on/off)
3108 0 : if ( IsInDocBody() )
3109 : {
3110 0 : rInvFlags |= 0x40;
3111 0 : SwPageFrm *pPage = FindPageFrm();
3112 0 : if ( !GetPrev() )
3113 0 : CheckPageDescs( pPage );
3114 0 : if ( pPage && GetFmt()->GetPageDesc().GetNumOffset() )
3115 0 : ((SwRootFrm*)pPage->GetUpper())->SetVirtPageNum( sal_True );
3116 0 : SwDocPosUpdate aMsgHnt( pPage->Frm().Top() );
3117 0 : GetFmt()->GetDoc()->UpdatePageFlds( &aMsgHnt );
3118 : }
3119 0 : break;
3120 :
3121 : case RES_BREAK:
3122 0 : rInvFlags |= 0xC0;
3123 0 : break;
3124 :
3125 : case RES_LAYOUT_SPLIT:
3126 0 : if ( !IsFollow() )
3127 0 : rInvFlags |= 0x40;
3128 0 : break;
3129 : case RES_FRAMEDIR :
3130 0 : SetDerivedR2L( sal_False );
3131 0 : CheckDirChange();
3132 0 : break;
3133 : case RES_COLLAPSING_BORDERS :
3134 0 : rInvFlags |= 0x02;
3135 0 : lcl_InvalidateAllLowersPrt( this );
3136 0 : break;
3137 : case RES_UL_SPACE:
3138 0 : rInvFlags |= 0x1C;
3139 : /* no break here */
3140 :
3141 : default:
3142 0 : bClear = false;
3143 : }
3144 0 : if ( bClear )
3145 : {
3146 0 : if ( pOldSet || pNewSet )
3147 : {
3148 0 : if ( pOldSet )
3149 0 : pOldSet->ClearItem( nWhich );
3150 0 : if ( pNewSet )
3151 0 : pNewSet->ClearItem( nWhich );
3152 : }
3153 : else
3154 0 : SwLayoutFrm::Modify( pOld, pNew );
3155 : }
3156 0 : }
3157 :
3158 0 : bool SwTabFrm::GetInfo( SfxPoolItem &rHnt ) const
3159 : {
3160 0 : if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && !IsFollow() )
3161 : {
3162 0 : SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt;
3163 0 : const SwPageFrm *pPage = FindPageFrm();
3164 0 : if ( pPage )
3165 : {
3166 0 : if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
3167 : {
3168 : //Here it should be (can temporary be different, should we be
3169 : // concerned about this?)
3170 0 : rInfo.SetInfo( pPage, this );
3171 0 : return false;
3172 : }
3173 0 : if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
3174 0 : (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
3175 : {
3176 : //This could be the one.
3177 0 : rInfo.SetInfo( pPage, this );
3178 : }
3179 : }
3180 : }
3181 0 : return true;
3182 : }
3183 :
3184 0 : SwCntntFrm *SwTabFrm::FindLastCntnt()
3185 : {
3186 0 : SwFrm *pRet = pLower;
3187 :
3188 0 : while ( pRet && !pRet->IsCntntFrm() )
3189 : {
3190 0 : SwFrm *pOld = pRet;
3191 :
3192 0 : SwFrm *pTmp = pRet; // To skip empty section frames
3193 0 : while ( pRet->GetNext() )
3194 : {
3195 0 : pRet = pRet->GetNext();
3196 0 : if( !pRet->IsSctFrm() || ((SwSectionFrm*)pRet)->GetSection() )
3197 0 : pTmp = pRet;
3198 : }
3199 0 : pRet = pTmp;
3200 :
3201 0 : if ( pRet->GetLower() )
3202 0 : pRet = pRet->GetLower();
3203 0 : if ( pRet == pOld )
3204 : {
3205 : // Check all other columns if there is a column based section with
3206 : // an empty last column at the end of the last line - this is done
3207 : // by SwSectionFrm::FindLastCntnt
3208 0 : if( pRet->IsColBodyFrm() )
3209 : {
3210 : #if OSL_DEBUG_LEVEL > 0
3211 : SwSectionFrm* pSect = pRet->FindSctFrm();
3212 : OSL_ENSURE( pSect, "Where does this column come fron?");
3213 : OSL_ENSURE( IsAnLower( pSect ), "Splited cell?" );
3214 : #endif
3215 0 : return pRet->FindSctFrm()->FindLastCntnt();
3216 : }
3217 :
3218 : // pRet may be a cell frame without a lower (cell has been split).
3219 : // We have to find the last content the hard way:
3220 :
3221 : OSL_ENSURE( pRet->IsCellFrm(), "SwTabFrm::FindLastCntnt failed" );
3222 0 : const SwFrm* pRow = pRet->GetUpper();
3223 0 : while ( pRow && !pRow->GetUpper()->IsTabFrm() )
3224 0 : pRow = pRow->GetUpper();
3225 0 : SwCntntFrm* pCntntFrm = pRow ? ((SwLayoutFrm*)pRow)->ContainsCntnt() : NULL;
3226 0 : pRet = 0;
3227 :
3228 0 : while ( pCntntFrm && ((SwLayoutFrm*)pRow)->IsAnLower( pCntntFrm ) )
3229 : {
3230 0 : pRet = pCntntFrm;
3231 0 : pCntntFrm = pCntntFrm->GetNextCntntFrm();
3232 : }
3233 : }
3234 : }
3235 :
3236 : // #112929# There actually is a situation, which results in pRet = 0:
3237 : // Insert frame, insert table via text <-> table. This gives you a frame
3238 : // containing a table without any other content frames. Split the table
3239 : // and undo the splitting. This operation gives us a table frame without
3240 : // a lower.
3241 0 : if ( pRet )
3242 : {
3243 0 : while ( pRet->GetNext() )
3244 0 : pRet = pRet->GetNext();
3245 :
3246 0 : if( pRet->IsSctFrm() )
3247 0 : pRet = ((SwSectionFrm*)pRet)->FindLastCntnt();
3248 : }
3249 :
3250 0 : return (SwCntntFrm*)pRet;
3251 : }
3252 :
3253 : /// Return value defines if the frm needs to be relocated
3254 0 : bool SwTabFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, bool, bool &rReformat )
3255 : {
3256 0 : rReformat = false;
3257 0 : if ( (SwFlowFrm::IsMoveBwdJump() || !IsPrevObjMove()) )
3258 : {
3259 : //Floating back Frm's is quite time consuming unfortunately.
3260 : //Most often the location where the Frm wants to float to has the same
3261 : //FixSize as the Frm itself. In such a situation it's easy to check if
3262 : //the Frm will find enough space for its VarSize, if this is not the
3263 : //case, the relocation can be skipped.
3264 : //Checking if the Frm will find enough space is done by the Frm itself,
3265 : //this also takes the possibility of splitting the Frm into account.
3266 : //If the FixSize is different or Flys are involved (at the old or the
3267 : //new position) the whole checks don't make sense at all, the Frm then
3268 : //needs to be relocated tentatively (if a bit of space is available).
3269 :
3270 : //The FixSize of the surrounding which contain tables is always the
3271 : //width.
3272 :
3273 0 : SwPageFrm *pOldPage = FindPageFrm(),
3274 0 : *pNewPage = pNewUpper->FindPageFrm();
3275 0 : bool bMoveAnyway = false;
3276 0 : SwTwips nSpace = 0;
3277 :
3278 0 : SWRECTFN( this )
3279 0 : if ( !SwFlowFrm::IsMoveBwdJump() )
3280 : {
3281 :
3282 0 : long nOldWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)();
3283 0 : SWRECTFNX( pNewUpper );
3284 0 : long nNewWidth = (pNewUpper->Prt().*fnRectX->fnGetWidth)();
3285 0 : if( std::abs( nNewWidth - nOldWidth ) < 2 )
3286 : {
3287 0 : if( !( bMoveAnyway = (BwdMoveNecessary( pOldPage, Frm() ) > 1) ) )
3288 : {
3289 0 : SwRect aRect( pNewUpper->Prt() );
3290 0 : aRect.Pos() += pNewUpper->Frm().Pos();
3291 0 : const SwFrm *pPrevFrm = pNewUpper->Lower();
3292 0 : while ( pPrevFrm && pPrevFrm != this )
3293 : {
3294 0 : (aRect.*fnRectX->fnSetTop)( (pPrevFrm->Frm().*fnRectX->
3295 0 : fnGetBottom)() );
3296 0 : pPrevFrm = pPrevFrm->GetNext();
3297 : }
3298 0 : bMoveAnyway = BwdMoveNecessary( pNewPage, aRect) > 1;
3299 :
3300 : // #i54861# Due to changes made in PrepareMake,
3301 : // the tabfrm may not have a correct position. Therefore
3302 : // it is possible that pNewUpper->Prt().Height == 0. In this
3303 : // case the above calculation of nSpace might give wrong
3304 : // results and we really do not want to MoveBackwrd into a
3305 : // 0 height frame. If nTmpSpace is already <= 0, we take this
3306 : // value:
3307 0 : const SwTwips nTmpSpace = (aRect.*fnRectX->fnGetHeight)();
3308 0 : if ( (pNewUpper->Prt().*fnRectX->fnGetHeight)() > 0 || nTmpSpace <= 0 )
3309 0 : nSpace = nTmpSpace;
3310 :
3311 0 : const SwViewShell *pSh = getRootFrm()->GetCurrShell();
3312 0 : if( pSh && pSh->GetViewOptions()->getBrowseMode() )
3313 0 : nSpace += pNewUpper->Grow( LONG_MAX, sal_True );
3314 : }
3315 : }
3316 0 : else if( !bLockBackMove )
3317 0 : bMoveAnyway = true;
3318 : }
3319 0 : else if( !bLockBackMove )
3320 0 : bMoveAnyway = true;
3321 :
3322 0 : if ( bMoveAnyway )
3323 : {
3324 0 : rReformat = true;
3325 0 : return true;
3326 : }
3327 0 : if ( !bLockBackMove && nSpace > 0 )
3328 : {
3329 : // #i26945# - check, if follow flow line
3330 : // contains frame, which are moved forward due to its object
3331 : // positioning.
3332 0 : SwRowFrm* pFirstRow = GetFirstNonHeadlineRow();
3333 0 : if ( pFirstRow && pFirstRow->IsInFollowFlowRow() &&
3334 : SwLayouter::DoesRowContainMovedFwdFrm(
3335 0 : *(pFirstRow->GetFmt()->GetDoc()),
3336 0 : *(pFirstRow) ) )
3337 : {
3338 0 : return false;
3339 : }
3340 0 : SwTwips nTmpHeight = CalcHeightOfFirstContentLine();
3341 :
3342 : // #118840#
3343 : // For some mysterious reason, I changed the good old
3344 : // 'return nHeight <= nSpace' to 'return nTmpHeight < nSpace'.
3345 : // This obviously results in problems with table frames in
3346 : // sections. Remember: Every twip is sacred.
3347 0 : return nTmpHeight <= nSpace;
3348 : }
3349 : }
3350 0 : return false;
3351 : }
3352 :
3353 0 : void SwTabFrm::Cut()
3354 : {
3355 : OSL_ENSURE( GetUpper(), "Cut ohne Upper()." );
3356 :
3357 0 : SwPageFrm *pPage = FindPageFrm();
3358 0 : InvalidatePage( pPage );
3359 0 : SwFrm *pFrm = GetNext();
3360 0 : if( pFrm )
3361 : {
3362 : //The old follower eventually calculated a margin to the predecessor
3363 : //which is obsolete now as it became the first one
3364 0 : pFrm->_InvalidatePrt();
3365 0 : pFrm->_InvalidatePos();
3366 0 : if ( pFrm->IsCntntFrm() )
3367 0 : pFrm->InvalidatePage( pPage );
3368 0 : if( IsInSct() && !GetPrev() )
3369 : {
3370 0 : SwSectionFrm* pSct = FindSctFrm();
3371 0 : if( !pSct->IsFollow() )
3372 : {
3373 0 : pSct->_InvalidatePrt();
3374 0 : pSct->InvalidatePage( pPage );
3375 : }
3376 : }
3377 : }
3378 : else
3379 : {
3380 0 : InvalidateNextPos();
3381 : //Someone has to do the retouch: predecessor or upper
3382 0 : if ( 0 != (pFrm = GetPrev()) )
3383 0 : { pFrm->SetRetouche();
3384 0 : pFrm->Prepare( PREP_WIDOWS_ORPHANS );
3385 0 : pFrm->_InvalidatePos();
3386 0 : if ( pFrm->IsCntntFrm() )
3387 0 : pFrm->InvalidatePage( pPage );
3388 : }
3389 : //If I am (was) the only FlowFrm in my own upper, it has to do
3390 : //the retouch. Moreover it has to do the retouch.
3391 : else
3392 0 : { SwRootFrm *pRoot = (SwRootFrm*)pPage->GetUpper();
3393 0 : pRoot->SetSuperfluous();
3394 0 : GetUpper()->SetCompletePaint();
3395 0 : if( IsInSct() )
3396 : {
3397 0 : SwSectionFrm* pSct = FindSctFrm();
3398 0 : if( !pSct->IsFollow() )
3399 : {
3400 0 : pSct->_InvalidatePrt();
3401 0 : pSct->InvalidatePage( pPage );
3402 : }
3403 : }
3404 : }
3405 : }
3406 :
3407 : //First remove, then shrink the upper.
3408 0 : SwLayoutFrm *pUp = GetUpper();
3409 0 : SWRECTFN( this )
3410 0 : Remove();
3411 0 : if ( pUp )
3412 : {
3413 : OSL_ENSURE( !pUp->IsFtnFrm(), "Table in Footnote." );
3414 0 : SwSectionFrm *pSct = 0;
3415 : // #126020# - adjust check for empty section
3416 : // #130797# - correct fix #126020#
3417 0 : if ( !pUp->Lower() && pUp->IsInSct() &&
3418 0 : !(pSct = pUp->FindSctFrm())->ContainsCntnt() &&
3419 0 : !pSct->ContainsAny( true ) )
3420 : {
3421 0 : if ( pUp->GetUpper() )
3422 : {
3423 0 : pSct->DelEmpty( sal_False );
3424 0 : pSct->_InvalidateSize();
3425 : }
3426 : }
3427 0 : else if( (Frm().*fnRect->fnGetHeight)() )
3428 : {
3429 : // OD 26.08.2003 #i18103# - *no* 'ColUnlock' of section -
3430 : // undo changes of fix for #104992#
3431 0 : pUp->Shrink( Frm().Height() );
3432 : }
3433 : }
3434 :
3435 0 : if ( pPage && !IsFollow() && pPage->GetUpper() )
3436 0 : ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth();
3437 0 : }
3438 :
3439 0 : void SwTabFrm::Paste( SwFrm* pParent, SwFrm* pSibling )
3440 : {
3441 : OSL_ENSURE( pParent, "No parent for pasting." );
3442 : OSL_ENSURE( pParent->IsLayoutFrm(), "Parent is CntntFrm." );
3443 : OSL_ENSURE( pParent != this, "I'm the parent myself." );
3444 : OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
3445 : OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
3446 : "I'm still registred somewhere." );
3447 :
3448 : //Insert in the tree.
3449 0 : InsertBefore( (SwLayoutFrm*)pParent, pSibling );
3450 :
3451 0 : _InvalidateAll();
3452 0 : SwPageFrm *pPage = FindPageFrm();
3453 0 : InvalidatePage( pPage );
3454 :
3455 0 : if ( GetNext() )
3456 : {
3457 0 : GetNext()->_InvalidatePos();
3458 0 : GetNext()->_InvalidatePrt();
3459 0 : if ( GetNext()->IsCntntFrm() )
3460 0 : GetNext()->InvalidatePage( pPage );
3461 : }
3462 :
3463 0 : SWRECTFN( this )
3464 0 : if( (Frm().*fnRect->fnGetHeight)() )
3465 0 : pParent->Grow( (Frm().*fnRect->fnGetHeight)() );
3466 :
3467 0 : if( (Frm().*fnRect->fnGetWidth)() != (pParent->Prt().*fnRect->fnGetWidth)() )
3468 0 : Prepare( PREP_FIXSIZE_CHG );
3469 0 : if ( GetPrev() )
3470 : {
3471 0 : if ( !IsFollow() )
3472 : {
3473 0 : GetPrev()->InvalidateSize();
3474 0 : if ( GetPrev()->IsCntntFrm() )
3475 0 : GetPrev()->InvalidatePage( pPage );
3476 : }
3477 : }
3478 0 : else if ( GetNext() )
3479 : //Take the marging into account when dealing with CntntFrm's. There are
3480 : //two situations (both always happen at once):
3481 : //a) The Cntnt becomes the first in a chain
3482 : //b) The new follower was the first in a chain before
3483 0 : GetNext()->_InvalidatePrt();
3484 :
3485 0 : if ( pPage && !IsFollow() )
3486 : {
3487 0 : if ( pPage->GetUpper() )
3488 0 : ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth();
3489 :
3490 0 : if ( !GetPrev() )//At least needed for HTML with a table at the beginning.
3491 : {
3492 0 : const SwPageDesc *pDesc = GetFmt()->GetPageDesc().GetPageDesc();
3493 0 : if ( (pDesc && pDesc != pPage->GetPageDesc()) ||
3494 0 : (!pDesc && pPage->GetPageDesc() != &GetFmt()->GetDoc()->GetPageDesc(0)) )
3495 0 : CheckPageDescs( pPage, sal_True );
3496 : }
3497 : }
3498 0 : }
3499 :
3500 0 : void SwTabFrm::Prepare( const PrepareHint eHint, const void *, bool )
3501 : {
3502 0 : if( PREP_BOSS_CHGD == eHint )
3503 0 : CheckDirChange();
3504 0 : }
3505 :
3506 0 : SwRowFrm::SwRowFrm( const SwTableLine &rLine, SwFrm* pSib, bool bInsertContent ):
3507 : SwLayoutFrm( rLine.GetFrmFmt(), pSib ),
3508 : pTabLine( &rLine ),
3509 : pFollowRow( 0 ),
3510 : // #i29550#
3511 : mnTopMarginForLowers( 0 ),
3512 : mnBottomMarginForLowers( 0 ),
3513 : mnBottomLineSize( 0 ),
3514 : // --> split table rows
3515 : bIsFollowFlowRow( false ),
3516 : // <-- split table rows
3517 : bIsRepeatedHeadline( false ),
3518 0 : mbIsRowSpanLine( false )
3519 : {
3520 0 : mnType = FRMC_ROW;
3521 :
3522 : //Create the boxes and insert them.
3523 0 : const SwTableBoxes &rBoxes = rLine.GetTabBoxes();
3524 0 : SwFrm *pTmpPrev = 0;
3525 0 : for ( sal_uInt16 i = 0; i < rBoxes.size(); ++i )
3526 : {
3527 0 : SwCellFrm *pNew = new SwCellFrm( *rBoxes[i], this, bInsertContent );
3528 0 : pNew->InsertBehind( this, pTmpPrev );
3529 0 : pTmpPrev = pNew;
3530 : }
3531 0 : }
3532 :
3533 0 : SwRowFrm::~SwRowFrm()
3534 : {
3535 0 : SwModify* pMod = GetFmt();
3536 0 : if( pMod )
3537 : {
3538 0 : pMod->Remove( this ); // remove,
3539 0 : if( !pMod->GetDepends() )
3540 0 : delete pMod; // and delete
3541 : }
3542 0 : }
3543 :
3544 0 : void SwRowFrm::RegistFlys( SwPageFrm *pPage )
3545 : {
3546 0 : ::RegistFlys( pPage ? pPage : FindPageFrm(), this );
3547 0 : }
3548 :
3549 0 : void SwRowFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
3550 : {
3551 0 : bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();
3552 0 : const SfxPoolItem *pItem = 0;
3553 :
3554 0 : if( bAttrSetChg )
3555 : {
3556 0 : const SwAttrSet* pChgSet = ((SwAttrSetChg*)pNew)->GetChgSet();
3557 0 : pChgSet->GetItemState( RES_FRM_SIZE, false, &pItem);
3558 0 : if ( !pItem )
3559 0 : pChgSet->GetItemState( RES_ROW_SPLIT, false, &pItem);
3560 : }
3561 0 : else if (pNew && (RES_FRM_SIZE == pNew->Which() || RES_ROW_SPLIT == pNew->Which()))
3562 0 : pItem = pNew;
3563 :
3564 0 : if ( pItem )
3565 : {
3566 0 : SwTabFrm *pTab = FindTabFrm();
3567 0 : if ( pTab )
3568 : {
3569 0 : const bool bInFirstNonHeadlineRow = pTab->IsFollow() &&
3570 0 : this == pTab->GetFirstNonHeadlineRow();
3571 : // #i35063#
3572 : // Invalidation required is pRow is last row
3573 0 : if ( bInFirstNonHeadlineRow || !GetNext() )
3574 : {
3575 0 : if ( bInFirstNonHeadlineRow )
3576 0 : pTab = pTab->FindMaster();
3577 0 : pTab->InvalidatePos();
3578 : }
3579 : }
3580 : }
3581 :
3582 0 : SwLayoutFrm::Modify( pOld, pNew );
3583 0 : }
3584 :
3585 0 : void SwRowFrm::MakeAll()
3586 : {
3587 0 : if ( !GetNext() )
3588 0 : mbValidSize = sal_False;
3589 0 : SwLayoutFrm::MakeAll();
3590 0 : }
3591 :
3592 0 : long CalcHeightWidthFlys( const SwFrm *pFrm )
3593 : {
3594 0 : SWRECTFN( pFrm )
3595 0 : long nHeight = 0;
3596 0 : const SwFrm* pTmp = pFrm->IsSctFrm() ?
3597 0 : ((SwSectionFrm*)pFrm)->ContainsCntnt() : pFrm;
3598 0 : while( pTmp )
3599 : {
3600 : // #i26945# - consider follow text frames
3601 0 : const SwSortedObjs* pObjs( 0L );
3602 0 : bool bIsFollow( false );
3603 0 : if ( pTmp->IsTxtFrm() && static_cast<const SwTxtFrm*>(pTmp)->IsFollow() )
3604 : {
3605 : const SwFrm* pMaster;
3606 : // #i46450# Master does not necessarily have
3607 : // to exist if this function is called from JoinFrm() ->
3608 : // Cut() -> Shrink()
3609 0 : const SwTxtFrm* pTmpFrm = static_cast<const SwTxtFrm*>(pTmp);
3610 0 : if ( pTmpFrm->GetPrev() && pTmpFrm->GetPrev()->IsTxtFrm() &&
3611 0 : static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() &&
3612 0 : static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() != pTmp )
3613 0 : pMaster = 0;
3614 : else
3615 0 : pMaster = pTmpFrm->FindMaster();
3616 :
3617 0 : if ( pMaster )
3618 : {
3619 0 : pObjs = static_cast<const SwTxtFrm*>(pTmp)->FindMaster()->GetDrawObjs();
3620 0 : bIsFollow = true;
3621 : }
3622 : }
3623 : else
3624 : {
3625 0 : pObjs = pTmp->GetDrawObjs();
3626 : }
3627 0 : if ( pObjs )
3628 : {
3629 0 : for ( sal_uInt16 i = 0; i < pObjs->Count(); ++i )
3630 : {
3631 0 : const SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
3632 : // #i26945# - if <pTmp> is follow, the
3633 : // anchor character frame has to be <pTmp>.
3634 0 : if ( bIsFollow &&
3635 0 : const_cast<SwAnchoredObject*>(pAnchoredObj)->FindAnchorCharFrm() != pTmp )
3636 : {
3637 0 : continue;
3638 : }
3639 : // #i26945# - consider also drawing objects
3640 : {
3641 : // OD 30.09.2003 #i18732# - only objects, which follow
3642 : // the text flow have to be considered.
3643 0 : const SwFrmFmt& rFrmFmt = pAnchoredObj->GetFrmFmt();
3644 : const bool bConsiderObj =
3645 0 : (rFrmFmt.GetAnchor().GetAnchorId() != FLY_AS_CHAR) &&
3646 0 : pAnchoredObj->GetObjRect().Top() != FAR_AWAY &&
3647 0 : rFrmFmt.GetFollowTextFlow().GetValue() &&
3648 0 : pAnchoredObj->GetPageFrm() == pTmp->FindPageFrm();
3649 0 : if ( bConsiderObj )
3650 : {
3651 0 : const SwFmtFrmSize &rSz = rFrmFmt.GetFrmSize();
3652 0 : if( !rSz.GetHeightPercent() )
3653 : {
3654 : const SwTwips nDistOfFlyBottomToAnchorTop =
3655 0 : (pAnchoredObj->GetObjRect().*fnRect->fnGetHeight)() +
3656 : ( bVert ?
3657 0 : pAnchoredObj->GetCurrRelPos().X() :
3658 0 : pAnchoredObj->GetCurrRelPos().Y() );
3659 :
3660 : const SwTwips nFrmDiff =
3661 : (*fnRect->fnYDiff)(
3662 0 : (pTmp->Frm().*fnRect->fnGetTop)(),
3663 0 : (pFrm->Frm().*fnRect->fnGetTop)() );
3664 :
3665 0 : nHeight = std::max( nHeight, nDistOfFlyBottomToAnchorTop + nFrmDiff -
3666 0 : (pFrm->Frm().*fnRect->fnGetHeight)() );
3667 :
3668 : // #i56115# The first height calculation
3669 : // gives wrong results if pFrm->Prt().Y() > 0. We do
3670 : // a second calculation based on the actual rectangles of
3671 : // pFrm and pAnchoredObj, and use the maximum of the results.
3672 : // I do not want to remove the first calculation because
3673 : // if clipping has been applied, using the GetCurrRelPos
3674 : // might be the better option to calculate nHeight.
3675 : const SwTwips nDistOfFlyBottomToAnchorTop2 = (*fnRect->fnYDiff)(
3676 0 : (pAnchoredObj->GetObjRect().*fnRect->fnGetBottom)(),
3677 0 : (pFrm->Frm().*fnRect->fnGetBottom)() );
3678 :
3679 0 : nHeight = std::max( nHeight, nDistOfFlyBottomToAnchorTop2 );
3680 : }
3681 : }
3682 : }
3683 : }
3684 : }
3685 0 : if( !pFrm->IsSctFrm() )
3686 0 : break;
3687 0 : pTmp = pTmp->FindNextCnt();
3688 0 : if( !((SwSectionFrm*)pFrm)->IsAnLower( pTmp ) )
3689 0 : break;
3690 : }
3691 0 : return nHeight;
3692 : }
3693 :
3694 0 : static SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm& rCell, const SwBorderAttrs& rAttrs )
3695 : {
3696 0 : const SwTabFrm* pTab = rCell.FindTabFrm();
3697 0 : SwTwips nTopSpace = 0;
3698 0 : SwTwips nBottomSpace = 0;
3699 :
3700 : // #i29550#
3701 0 : if ( pTab->IsCollapsingBorders() && rCell.Lower() && !rCell.Lower()->IsRowFrm() )
3702 : {
3703 0 : nTopSpace = ((SwRowFrm*)rCell.GetUpper())->GetTopMarginForLowers();
3704 0 : nBottomSpace = ((SwRowFrm*)rCell.GetUpper())->GetBottomMarginForLowers();
3705 : }
3706 : else
3707 : {
3708 0 : if ( pTab->IsVertical() != rCell.IsVertical() )
3709 : {
3710 0 : nTopSpace = rAttrs.CalcLeft( &rCell );
3711 0 : nBottomSpace = rAttrs.CalcRight( &rCell );
3712 : }
3713 : else
3714 : {
3715 0 : nTopSpace = rAttrs.CalcTop();
3716 0 : nBottomSpace = rAttrs.CalcBottom();
3717 : }
3718 : }
3719 :
3720 0 : return nTopSpace + nBottomSpace;
3721 : }
3722 :
3723 : // #i26945# - add parameter <_bConsiderObjs> in order to
3724 : // control, if floating screen objects have to be considered for the minimal
3725 : // cell height.
3726 0 : static SwTwips lcl_CalcMinCellHeight( const SwLayoutFrm *_pCell,
3727 : const sal_Bool _bConsiderObjs,
3728 : const SwBorderAttrs *pAttrs = 0 )
3729 : {
3730 0 : SWRECTFN( _pCell )
3731 0 : SwTwips nHeight = 0;
3732 0 : const SwFrm* pLow = _pCell->Lower();
3733 0 : if ( pLow )
3734 : {
3735 0 : long nFlyAdd = 0;
3736 0 : while ( pLow )
3737 : {
3738 : // OD 2004-02-18 #106629# - change condition and switch then-body
3739 : // and else-body
3740 0 : if ( pLow->IsRowFrm() )
3741 : {
3742 : // #i26945#
3743 : nHeight += ::lcl_CalcMinRowHeight( static_cast<const SwRowFrm*>(pLow),
3744 0 : _bConsiderObjs );
3745 : }
3746 : else
3747 : {
3748 0 : long nLowHeight = (pLow->Frm().*fnRect->fnGetHeight)();
3749 0 : nHeight += nLowHeight;
3750 : // #i26945#
3751 0 : if ( _bConsiderObjs )
3752 : {
3753 0 : nFlyAdd = std::max( 0L, nFlyAdd - nLowHeight );
3754 0 : nFlyAdd = std::max( nFlyAdd, ::CalcHeightWidthFlys( pLow ) );
3755 : }
3756 : }
3757 :
3758 0 : pLow = pLow->GetNext();
3759 : }
3760 0 : if ( nFlyAdd )
3761 0 : nHeight += nFlyAdd;
3762 : }
3763 : //The border needs to be considered too, unfortunately it can't be
3764 : //calculated using PrtArea and Frm because those can be invalid in arbitrary
3765 : //combinations.
3766 0 : if ( _pCell->Lower() )
3767 : {
3768 0 : if ( pAttrs )
3769 0 : nHeight += lcl_CalcTopAndBottomMargin( *_pCell, *pAttrs );
3770 : else
3771 : {
3772 0 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), _pCell );
3773 0 : const SwBorderAttrs &rAttrs = *aAccess.Get();
3774 0 : nHeight += lcl_CalcTopAndBottomMargin( *_pCell, rAttrs );
3775 : }
3776 : }
3777 0 : return nHeight;
3778 : }
3779 :
3780 : // OD 2004-02-18 #106629# - correct type of 1st parameter
3781 : // #i26945# - add parameter <_bConsiderObjs> in order to control,
3782 : // if floating screen objects have to be considered for the minimal cell height
3783 0 : static SwTwips lcl_CalcMinRowHeight( const SwRowFrm* _pRow,
3784 : const sal_Bool _bConsiderObjs )
3785 : {
3786 0 : SWRECTFN( _pRow )
3787 :
3788 0 : const SwFmtFrmSize &rSz = _pRow->GetFmt()->GetFrmSize();
3789 :
3790 0 : if ( _pRow->HasFixSize() && !_pRow->IsRowSpanLine() )
3791 : {
3792 : OSL_ENSURE( ATT_FIX_SIZE == rSz.GetHeightSizeType(), "pRow claims to have fixed size" );
3793 0 : return rSz.GetHeight();
3794 : }
3795 :
3796 0 : SwTwips nHeight = 0;
3797 0 : const SwCellFrm* pLow = static_cast<const SwCellFrm*>(_pRow->Lower());
3798 0 : while ( pLow )
3799 : {
3800 0 : SwTwips nTmp = 0;
3801 0 : const long nRowSpan = pLow->GetLayoutRowSpan();
3802 : // --> NEW TABLES
3803 : // Consider height of
3804 : // 1. current cell if RowSpan == 1
3805 : // 2. current cell if cell is "follow" cell of a cell with RowSpan == -1
3806 : // 3. master cell if RowSpan == -1
3807 0 : if ( 1 == nRowSpan )
3808 : {
3809 0 : nTmp = ::lcl_CalcMinCellHeight( pLow, _bConsiderObjs );
3810 : }
3811 0 : else if ( -1 == nRowSpan )
3812 : {
3813 : // Height of the last cell of a row span is height of master cell
3814 : // minus the height of the other rows which are covered by the master
3815 : // cell:
3816 0 : const SwCellFrm& rMaster = pLow->FindStartEndOfRowSpanCell( true, true );
3817 0 : nTmp = ::lcl_CalcMinCellHeight( &rMaster, _bConsiderObjs );
3818 0 : const SwFrm* pMasterRow = rMaster.GetUpper();
3819 0 : while ( pMasterRow && pMasterRow != _pRow )
3820 : {
3821 0 : nTmp -= (pMasterRow->Frm().*fnRect->fnGetHeight)();
3822 0 : pMasterRow = pMasterRow->GetNext();
3823 : }
3824 : }
3825 : // <-- NEW TABLES
3826 :
3827 : // Do not consider rotated cells:
3828 0 : if ( pLow->IsVertical() == bVert && nTmp > nHeight )
3829 0 : nHeight = nTmp;
3830 :
3831 0 : pLow = static_cast<const SwCellFrm*>(pLow->GetNext());
3832 : }
3833 0 : if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE && !_pRow->IsRowSpanLine() )
3834 0 : nHeight = std::max( nHeight, rSz.GetHeight() );
3835 0 : return nHeight;
3836 : }
3837 :
3838 : // #i29550#
3839 :
3840 : // Calculate the maximum of (TopLineSize + TopLineDist) over all lowers:
3841 0 : static sal_uInt16 lcl_GetTopSpace( const SwRowFrm& rRow )
3842 : {
3843 0 : sal_uInt16 nTopSpace = 0;
3844 0 : for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower;
3845 0 : pCurrLower = (SwCellFrm*)pCurrLower->GetNext() )
3846 : {
3847 0 : sal_uInt16 nTmpTopSpace = 0;
3848 0 : if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() )
3849 0 : nTmpTopSpace = lcl_GetTopSpace( *(SwRowFrm*)pCurrLower->Lower() );
3850 : else
3851 : {
3852 0 : const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet();
3853 0 : const SvxBoxItem& rBoxItem = rSet.GetBox();
3854 0 : nTmpTopSpace = rBoxItem.CalcLineSpace( BOX_LINE_TOP, true );
3855 : }
3856 0 : nTopSpace = std::max( nTopSpace, nTmpTopSpace );
3857 : }
3858 0 : return nTopSpace;
3859 : }
3860 :
3861 : // Calculate the maximum of TopLineDist over all lowers:
3862 0 : static sal_uInt16 lcl_GetTopLineDist( const SwRowFrm& rRow )
3863 : {
3864 0 : sal_uInt16 nTopLineDist = 0;
3865 0 : for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower;
3866 0 : pCurrLower = (SwCellFrm*)pCurrLower->GetNext() )
3867 : {
3868 0 : sal_uInt16 nTmpTopLineDist = 0;
3869 0 : if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() )
3870 0 : nTmpTopLineDist = lcl_GetTopLineDist( *(SwRowFrm*)pCurrLower->Lower() );
3871 : else
3872 : {
3873 0 : const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet();
3874 0 : const SvxBoxItem& rBoxItem = rSet.GetBox();
3875 0 : nTmpTopLineDist = rBoxItem.GetDistance( BOX_LINE_TOP );
3876 : }
3877 0 : nTopLineDist = std::max( nTopLineDist, nTmpTopLineDist );
3878 : }
3879 0 : return nTopLineDist;
3880 : }
3881 :
3882 : // Calculate the maximum of BottomLineSize over all lowers:
3883 0 : static sal_uInt16 lcl_GetBottomLineSize( const SwRowFrm& rRow )
3884 : {
3885 0 : sal_uInt16 nBottomLineSize = 0;
3886 0 : for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower;
3887 0 : pCurrLower = (SwCellFrm*)pCurrLower->GetNext() )
3888 : {
3889 0 : sal_uInt16 nTmpBottomLineSize = 0;
3890 0 : if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() )
3891 : {
3892 0 : const SwFrm* pRow = pCurrLower->GetLastLower();
3893 0 : nTmpBottomLineSize = lcl_GetBottomLineSize( *(SwRowFrm*)pRow );
3894 : }
3895 : else
3896 : {
3897 0 : const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet();
3898 0 : const SvxBoxItem& rBoxItem = rSet.GetBox();
3899 0 : nTmpBottomLineSize = rBoxItem.CalcLineSpace( BOX_LINE_BOTTOM, true ) -
3900 0 : rBoxItem.GetDistance( BOX_LINE_BOTTOM );
3901 : }
3902 0 : nBottomLineSize = std::max( nBottomLineSize, nTmpBottomLineSize );
3903 : }
3904 0 : return nBottomLineSize;
3905 : }
3906 :
3907 : // Calculate the maximum of BottomLineDist over all lowers:
3908 0 : static sal_uInt16 lcl_GetBottomLineDist( const SwRowFrm& rRow )
3909 : {
3910 0 : sal_uInt16 nBottomLineDist = 0;
3911 0 : for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower;
3912 0 : pCurrLower = (SwCellFrm*)pCurrLower->GetNext() )
3913 : {
3914 0 : sal_uInt16 nTmpBottomLineDist = 0;
3915 0 : if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() )
3916 : {
3917 0 : const SwFrm* pRow = pCurrLower->GetLastLower();
3918 0 : nTmpBottomLineDist = lcl_GetBottomLineDist( *(SwRowFrm*)pRow );
3919 : }
3920 : else
3921 : {
3922 0 : const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet();
3923 0 : const SvxBoxItem& rBoxItem = rSet.GetBox();
3924 0 : nTmpBottomLineDist = rBoxItem.GetDistance( BOX_LINE_BOTTOM );
3925 : }
3926 0 : nBottomLineDist = std::max( nBottomLineDist, nTmpBottomLineDist );
3927 : }
3928 0 : return nBottomLineDist;
3929 : }
3930 :
3931 0 : void SwRowFrm::Format( const SwBorderAttrs *pAttrs )
3932 : {
3933 0 : SWRECTFN( this )
3934 : OSL_ENSURE( pAttrs, "SwRowFrm::Format without Attrs." );
3935 :
3936 0 : const sal_Bool bFix = mbFixSize;
3937 :
3938 0 : if ( !mbValidPrtArea )
3939 : {
3940 : //RowFrms don't have borders and so on therefore the PrtArea always
3941 : //matches the Frm.
3942 0 : mbValidPrtArea = sal_True;
3943 0 : maPrt.Left( 0 );
3944 0 : maPrt.Top( 0 );
3945 0 : maPrt.Width ( maFrm.Width() );
3946 0 : maPrt.Height( maFrm.Height() );
3947 :
3948 : // #i29550#
3949 : // Here we calculate the top-printing area for the lower cell frames
3950 0 : SwTabFrm* pTabFrm = FindTabFrm();
3951 0 : if ( pTabFrm->IsCollapsingBorders() )
3952 : {
3953 0 : const sal_uInt16 nTopSpace = lcl_GetTopSpace( *this );
3954 0 : const sal_uInt16 nTopLineDist = lcl_GetTopLineDist( *this );
3955 0 : const sal_uInt16 nBottomLineSize = lcl_GetBottomLineSize( *this );
3956 0 : const sal_uInt16 nBottomLineDist = lcl_GetBottomLineDist( *this );
3957 :
3958 0 : const SwRowFrm* pPreviousRow = 0;
3959 :
3960 : // #i32456#
3961 : // In order to calculate the top printing area for the lower cell
3962 : // frames, we have to find the 'previous' row frame and compare
3963 : // the bottom values of the 'previous' row with the 'top' values
3964 : // of this row. The best way to find the 'previous' row is to
3965 : // use the table structure:
3966 0 : const SwTable* pTable = pTabFrm->GetTable();
3967 0 : const SwTableLine* pPrevTabLine = 0;
3968 0 : const SwRowFrm* pTmpRow = this;
3969 :
3970 0 : while ( pTmpRow && !pPrevTabLine )
3971 : {
3972 0 : sal_uInt16 nIdx = 0;
3973 0 : const SwTableLines& rLines = pTmpRow->GetTabLine()->GetUpper() ?
3974 0 : pTmpRow->GetTabLine()->GetUpper()->GetTabLines() :
3975 0 : pTable->GetTabLines();
3976 :
3977 0 : while ( rLines[ nIdx ] != pTmpRow->GetTabLine() )
3978 0 : ++nIdx;
3979 :
3980 0 : if ( nIdx > 0 )
3981 : {
3982 : // pTmpRow has a 'previous' row in the table structure:
3983 0 : pPrevTabLine = rLines[ nIdx - 1 ];
3984 : }
3985 : else
3986 : {
3987 : // pTmpRow is a first row in the table structue.
3988 : // We go up in the table structure:
3989 0 : pTmpRow = pTmpRow->GetUpper()->GetUpper() &&
3990 0 : pTmpRow->GetUpper()->GetUpper()->IsRowFrm() ?
3991 0 : static_cast<const SwRowFrm*>( pTmpRow->GetUpper()->GetUpper() ) :
3992 0 : 0;
3993 : }
3994 : }
3995 :
3996 : // If we found a 'previous' row, we look for the appropriate row frame:
3997 0 : if ( pPrevTabLine )
3998 : {
3999 0 : SwIterator<SwRowFrm,SwFmt> aIter( *pPrevTabLine->GetFrmFmt() );
4000 0 : for ( SwRowFrm* pRow = aIter.First(); pRow; pRow = aIter.Next() )
4001 : {
4002 : // #115759# - do *not* take repeated
4003 : // headlines, because during split of table it can be
4004 : // invalid and thus can't provide correct border values.
4005 0 : if ( pRow->GetTabLine() == pPrevTabLine &&
4006 0 : !pRow->IsRepeatedHeadline() )
4007 : {
4008 0 : pPreviousRow = pRow;
4009 0 : break;
4010 : }
4011 0 : }
4012 : }
4013 :
4014 0 : sal_uInt16 nTopPrtMargin = nTopSpace;
4015 0 : if ( pPreviousRow )
4016 : {
4017 0 : const sal_uInt16 nTmpPrtMargin = pPreviousRow->GetBottomLineSize() + nTopLineDist;
4018 0 : if ( nTmpPrtMargin > nTopPrtMargin )
4019 0 : nTopPrtMargin = nTmpPrtMargin;
4020 : }
4021 :
4022 : // table has to be notified if it has to change its lower
4023 : // margin due to changes of nBottomLineSize:
4024 0 : if ( !GetNext() && nBottomLineSize != GetBottomLineSize() )
4025 0 : pTabFrm->_InvalidatePrt();
4026 :
4027 : // If there are rows nested inside this row, the nested rows
4028 : // may not have been calculated yet. Therefore the
4029 : // ::lcl_CalcMinRowHeight( this ) operation later in this
4030 : // function cannot consider the correct border values. We
4031 : // have to trigger the invalidation of the outer row frame
4032 : // manually:
4033 : // Note: If any further invalidations should be necessary, we
4034 : // should consider moving the invalidation stuff to the
4035 : // appropriate SwNotify object.
4036 0 : if ( GetUpper()->GetUpper()->IsRowFrm() &&
4037 0 : ( nBottomLineDist != GetBottomMarginForLowers() ||
4038 0 : nTopPrtMargin != GetTopMarginForLowers() ) )
4039 0 : GetUpper()->GetUpper()->_InvalidateSize();
4040 :
4041 0 : SetBottomMarginForLowers( nBottomLineDist ); // 3.
4042 0 : SetBottomLineSize( nBottomLineSize ); // 4.
4043 0 : SetTopMarginForLowers( nTopPrtMargin ); // 5.
4044 :
4045 : }
4046 : }
4047 :
4048 0 : while ( !mbValidSize )
4049 : {
4050 0 : mbValidSize = sal_True;
4051 :
4052 : #if OSL_DEBUG_LEVEL > 0
4053 : if ( HasFixSize() )
4054 : {
4055 : const SwFmtFrmSize &rFrmSize = GetFmt()->GetFrmSize();
4056 : OSL_ENSURE( rFrmSize.GetSize().Height() > 0, "Hat ihn" );
4057 : }
4058 : #endif
4059 0 : const SwTwips nDiff = (Frm().*fnRect->fnGetHeight)() -
4060 0 : ( HasFixSize() && !IsRowSpanLine()
4061 0 : ? pAttrs->GetSize().Height()
4062 : // #i26945#
4063 : : ::lcl_CalcMinRowHeight( this,
4064 0 : FindTabFrm()->IsConsiderObjsForMinCellHeight() ) );
4065 0 : if ( nDiff )
4066 : {
4067 0 : mbFixSize = sal_False;
4068 0 : if ( nDiff > 0 )
4069 0 : Shrink( nDiff, sal_False, sal_True );
4070 0 : else if ( nDiff < 0 )
4071 0 : Grow( -nDiff );
4072 0 : mbFixSize = bFix;
4073 : }
4074 : }
4075 :
4076 : // last row will fill the space in its upper.
4077 0 : if ( !GetNext() )
4078 : {
4079 : //The last fills the remaining space in the upper.
4080 0 : SwTwips nDiff = (GetUpper()->Prt().*fnRect->fnGetHeight)();
4081 0 : SwFrm *pSibling = GetUpper()->Lower();
4082 0 : do
4083 0 : { nDiff -= (pSibling->Frm().*fnRect->fnGetHeight)();
4084 0 : pSibling = pSibling->GetNext();
4085 : } while ( pSibling );
4086 0 : if ( nDiff > 0 )
4087 : {
4088 0 : mbFixSize = sal_False;
4089 0 : Grow( nDiff );
4090 0 : mbFixSize = bFix;
4091 0 : mbValidSize = sal_True;
4092 : }
4093 : }
4094 0 : }
4095 :
4096 0 : void SwRowFrm::AdjustCells( const SwTwips nHeight, const sal_Bool bHeight )
4097 : {
4098 0 : SwFrm *pFrm = Lower();
4099 0 : if ( bHeight )
4100 : {
4101 0 : SwRootFrm *pRootFrm = getRootFrm();
4102 0 : SWRECTFN( this )
4103 0 : SwRect aOldFrm;
4104 :
4105 0 : while ( pFrm )
4106 : {
4107 0 : SwFrm* pNotify = 0;
4108 :
4109 0 : SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pFrm);
4110 :
4111 : // NEW TABLES
4112 : // Which cells need to be adjusted if the current row changes
4113 : // its height?
4114 :
4115 : // Current frame is a covered frame:
4116 : // Set new height for covered cell and adjust master cell:
4117 0 : if ( pCellFrm->GetTabBox()->getRowSpan() < 1 )
4118 : {
4119 : // Set height of current (covered) cell to new line height.
4120 0 : const long nDiff = nHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)();
4121 0 : if ( nDiff )
4122 : {
4123 0 : (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff );
4124 0 : pCellFrm->_InvalidatePrt();
4125 : }
4126 : }
4127 :
4128 0 : SwCellFrm* pToAdjust = 0;
4129 0 : SwFrm* pToAdjustRow = 0;
4130 :
4131 : // If current frame is covered frame, we still want to adjust the
4132 : // height of the cell starting the row span
4133 0 : if ( pCellFrm->GetLayoutRowSpan() < 1 )
4134 : {
4135 0 : pToAdjust = const_cast< SwCellFrm*>(&pCellFrm->FindStartEndOfRowSpanCell( true, true ));
4136 0 : pToAdjustRow = pToAdjust->GetUpper();
4137 : }
4138 : else
4139 : {
4140 0 : pToAdjust = pCellFrm;
4141 0 : pToAdjustRow = this;
4142 : }
4143 :
4144 : // Set height of master cell to height of all lines spanned by this line.
4145 0 : long nRowSpan = pToAdjust->GetLayoutRowSpan();
4146 0 : SwTwips nSumRowHeight = 0;
4147 0 : while ( pToAdjustRow )
4148 : {
4149 : // Use new height for the current row:
4150 0 : nSumRowHeight += pToAdjustRow == this ?
4151 : nHeight :
4152 0 : (pToAdjustRow->Frm().*fnRect->fnGetHeight)();
4153 :
4154 0 : if ( nRowSpan-- == 1 )
4155 0 : break;
4156 :
4157 0 : pToAdjustRow = pToAdjustRow->GetNext();
4158 : }
4159 :
4160 0 : if ( pToAdjustRow && pToAdjustRow != this )
4161 0 : pToAdjustRow->_InvalidateSize();
4162 :
4163 0 : const long nDiff = nSumRowHeight - (pToAdjust->Frm().*fnRect->fnGetHeight)();
4164 0 : if ( nDiff )
4165 : {
4166 0 : aOldFrm = pToAdjust->Frm();
4167 0 : (pToAdjust->Frm().*fnRect->fnAddBottom)( nDiff );
4168 0 : pNotify = pToAdjust;
4169 : }
4170 :
4171 0 : if ( pNotify )
4172 : {
4173 0 : if( pRootFrm && pRootFrm->IsAnyShellAccessible() && pRootFrm->GetCurrShell() )
4174 0 : pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( pNotify, aOldFrm );
4175 :
4176 0 : pNotify->_InvalidatePrt();
4177 : }
4178 :
4179 0 : pFrm = pFrm->GetNext();
4180 : }
4181 : }
4182 : else
4183 0 : { while ( pFrm )
4184 : {
4185 0 : pFrm->_InvalidateAll();
4186 0 : pFrm = pFrm->GetNext();
4187 : }
4188 : }
4189 0 : InvalidatePage();
4190 0 : }
4191 :
4192 0 : void SwRowFrm::Cut()
4193 : {
4194 0 : SwTabFrm *pTab = FindTabFrm();
4195 0 : if ( pTab && pTab->IsFollow() && this == pTab->GetFirstNonHeadlineRow() )
4196 : {
4197 0 : pTab->FindMaster()->InvalidatePos();
4198 : }
4199 :
4200 : // #i103961#
4201 : // notification for accessibility
4202 : {
4203 0 : SwRootFrm *pRootFrm = getRootFrm();
4204 0 : if( pRootFrm && pRootFrm->IsAnyShellAccessible() )
4205 : {
4206 0 : SwViewShell* pVSh = pRootFrm->GetCurrShell();
4207 0 : if ( pVSh && pVSh->Imp() )
4208 : {
4209 0 : SwFrm* pCellFrm( GetLower() );
4210 0 : while ( pCellFrm )
4211 : {
4212 : OSL_ENSURE( pCellFrm->IsCellFrm(),
4213 : "<SwRowFrm::Cut()> - unexpected type of SwRowFrm lower." );
4214 0 : pVSh->Imp()->DisposeAccessibleFrm( pCellFrm );
4215 :
4216 0 : pCellFrm = pCellFrm->GetNext();
4217 : }
4218 : }
4219 : }
4220 : }
4221 :
4222 0 : SwLayoutFrm::Cut();
4223 0 : }
4224 :
4225 0 : SwTwips SwRowFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo )
4226 : {
4227 0 : SwTwips nReal = 0;
4228 :
4229 0 : SwTabFrm* pTab = FindTabFrm();
4230 0 : SWRECTFN( pTab )
4231 :
4232 : bool bRestrictTableGrowth;
4233 0 : bool bHasFollowFlowLine = pTab->HasFollowFlowLine();
4234 :
4235 0 : if ( GetUpper()->IsTabFrm() )
4236 : {
4237 0 : const SwRowFrm* pFollowFlowRow = IsInSplitTableRow();
4238 0 : bRestrictTableGrowth = pFollowFlowRow && !pFollowFlowRow->IsRowSpanLine();
4239 : }
4240 : else
4241 : {
4242 : OSL_ENSURE( GetUpper()->IsCellFrm(), "RowFrm->GetUpper neither table nor cell" );
4243 0 : bRestrictTableGrowth = GetFollowRow() && bHasFollowFlowLine;
4244 : OSL_ENSURE( !bRestrictTableGrowth || !GetNext(),
4245 : "GetFollowRow for row frame that has a Next" );
4246 :
4247 : // There may still be some space left in my direct upper:
4248 : const SwTwips nAdditionalSpace =
4249 0 : (Frm().*fnRect->fnBottomDist)( (GetUpper()->GetUpper()->*fnRect->fnGetPrtBottom)() );
4250 0 : if ( bRestrictTableGrowth && nAdditionalSpace > 0 )
4251 : {
4252 0 : nReal = std::min( nAdditionalSpace, nDist );
4253 0 : nDist -= nReal;
4254 0 : if ( !bTst )
4255 0 : (Frm().*fnRect->fnAddBottom)( nReal );
4256 : }
4257 : }
4258 :
4259 0 : if ( bRestrictTableGrowth )
4260 0 : pTab->SetRestrictTableGrowth( sal_True );
4261 : else
4262 : {
4263 : // Ok, this looks like a hack, indeed, it is a hack.
4264 : // If the current row frame is inside another cell frame,
4265 : // and the current row frame has no follow, it should not
4266 : // be allowed to grow. In fact, setting bRestrictTableGrowth
4267 : // to 'false' does not work, because the surrounding RowFrm
4268 : // would set this to 'true'.
4269 0 : pTab->SetFollowFlowLine( sal_False );
4270 : }
4271 :
4272 0 : nReal += SwLayoutFrm::GrowFrm( nDist, bTst, bInfo);
4273 :
4274 0 : pTab->SetRestrictTableGrowth( sal_False );
4275 0 : pTab->SetFollowFlowLine( bHasFollowFlowLine );
4276 :
4277 : //Update the height of the cells to the newest value.
4278 0 : if ( !bTst )
4279 : {
4280 0 : SWRECTFNX( this )
4281 0 : AdjustCells( (Prt().*fnRectX->fnGetHeight)() + nReal, sal_True );
4282 0 : if ( nReal )
4283 0 : SetCompletePaint();
4284 : }
4285 :
4286 0 : return nReal;
4287 : }
4288 :
4289 0 : SwTwips SwRowFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo )
4290 : {
4291 0 : SWRECTFN( this )
4292 0 : if( HasFixSize() )
4293 : {
4294 0 : AdjustCells( (Prt().*fnRect->fnGetHeight)(), sal_True );
4295 0 : return 0L;
4296 : }
4297 :
4298 : // bInfo may be set to sal_True by SwRowFrm::Format; we need to hangle this
4299 : // here accordingly
4300 0 : const sal_Bool bShrinkAnyway = bInfo;
4301 :
4302 : //Only shrink as much as the content of the biggest cell allows.
4303 0 : SwTwips nRealDist = nDist;
4304 : {
4305 0 : const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize();
4306 0 : SwTwips nMinHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ?
4307 : rSz.GetHeight() :
4308 0 : 0;
4309 :
4310 : // Only necessary to calculate minimal row height if height
4311 : // of pRow is at least nMinHeight. Otherwise nMinHeight is the
4312 : // minimum height.
4313 0 : if( nMinHeight < (Frm().*fnRect->fnGetHeight)() )
4314 : {
4315 : // #i26945#
4316 : OSL_ENSURE( FindTabFrm(), "<SwRowFrm::ShrinkFrm(..)> - no table frame -> crash." );
4317 0 : const bool bConsiderObjs( FindTabFrm()->IsConsiderObjsForMinCellHeight() );
4318 0 : nMinHeight = lcl_CalcMinRowHeight( this, bConsiderObjs );
4319 : }
4320 :
4321 0 : if ( ((Frm().*fnRect->fnGetHeight)() - nRealDist) < nMinHeight )
4322 0 : nRealDist = (Frm().*fnRect->fnGetHeight)() - nMinHeight;
4323 : }
4324 0 : if ( nRealDist < 0 )
4325 0 : nRealDist = 0;
4326 :
4327 0 : SwTwips nReal = nRealDist;
4328 0 : if ( nReal )
4329 : {
4330 0 : if ( !bTst )
4331 : {
4332 0 : SwTwips nHeight = (Frm().*fnRect->fnGetHeight)();
4333 0 : (Frm().*fnRect->fnSetHeight)( nHeight - nReal );
4334 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
4335 0 : if( IsVertical() && !IsVertLR() && !bRev )
4336 0 : Frm().Pos().X() += nReal;
4337 : }
4338 :
4339 0 : SwTwips nTmp = GetUpper()->Shrink( nReal, bTst );
4340 0 : if ( !bShrinkAnyway && !GetNext() && nTmp != nReal )
4341 : {
4342 : //The last one gets the leftover in the upper and therefore takes
4343 : //care (otherwise: endless loop)
4344 0 : if ( !bTst )
4345 : {
4346 0 : nReal -= nTmp;
4347 0 : SwTwips nHeight = (Frm().*fnRect->fnGetHeight)();
4348 0 : (Frm().*fnRect->fnSetHeight)( nHeight + nReal );
4349 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
4350 0 : if( IsVertical() && !IsVertLR() && !bRev )
4351 0 : Frm().Pos().X() -= nReal;
4352 : }
4353 0 : nReal = nTmp;
4354 : }
4355 : }
4356 :
4357 : //Invalidate if possible and update the height to the newest value.
4358 0 : if ( !bTst )
4359 : {
4360 0 : if ( nReal )
4361 : {
4362 0 : if ( GetNext() )
4363 0 : GetNext()->_InvalidatePos();
4364 0 : _InvalidateAll();
4365 0 : SetCompletePaint();
4366 :
4367 0 : SwTabFrm *pTab = FindTabFrm();
4368 0 : if ( !pTab->IsRebuildLastLine()
4369 0 : && pTab->IsFollow()
4370 0 : && this == pTab->GetFirstNonHeadlineRow()
4371 0 : && !pTab->IsInRecalcLowerRow() )
4372 : {
4373 0 : SwTabFrm* pMasterTab = const_cast< SwTabFrm* >( pTab->FindMaster() );
4374 0 : pMasterTab->InvalidatePos();
4375 : }
4376 : }
4377 0 : AdjustCells( (Prt().*fnRect->fnGetHeight)() - nReal, sal_True );
4378 : }
4379 0 : return nReal;
4380 : }
4381 :
4382 0 : bool SwRowFrm::IsRowSplitAllowed() const
4383 : {
4384 : // Fixed size rows are never allowed to split:
4385 0 : if ( HasFixSize() )
4386 : {
4387 : OSL_ENSURE( ATT_FIX_SIZE == GetFmt()->GetFrmSize().GetHeightSizeType(), "pRow claims to have fixed size" );
4388 0 : return false;
4389 : }
4390 :
4391 : // Repeated headlines are never allowed to split:
4392 0 : const SwTabFrm* pTabFrm = FindTabFrm();
4393 0 : if ( pTabFrm->GetTable()->GetRowsToRepeat() > 0 &&
4394 0 : pTabFrm->IsInHeadline( *this ) )
4395 0 : return false;
4396 :
4397 0 : const SwTableLineFmt* pFrmFmt = (SwTableLineFmt*)GetTabLine()->GetFrmFmt();
4398 0 : const SwFmtRowSplit& rLP = pFrmFmt->GetRowSplit();
4399 0 : return rLP.GetValue();
4400 : }
4401 :
4402 0 : bool SwRowFrm::ShouldRowKeepWithNext() const
4403 : {
4404 0 : bool bRet = false;
4405 :
4406 0 : const SwCellFrm* pCell = static_cast<const SwCellFrm*>(Lower());
4407 0 : const SwFrm* pTxt = pCell->Lower();
4408 :
4409 0 : if ( pTxt && pTxt->IsTxtFrm() )
4410 : {
4411 0 : bRet = static_cast<const SwTxtFrm*>(pTxt)->GetTxtNode()->GetSwAttrSet().GetKeep().GetValue();
4412 : }
4413 0 : return bRet;
4414 : }
4415 :
4416 0 : SwCellFrm::SwCellFrm( const SwTableBox &rBox, SwFrm* pSib, bool bInsertContent ) :
4417 : SwLayoutFrm( rBox.GetFrmFmt(), pSib ),
4418 0 : pTabBox( &rBox )
4419 : {
4420 0 : mnType = FRMC_CELL;
4421 :
4422 0 : if ( !bInsertContent )
4423 0 : return;
4424 :
4425 : //If a StartIdx is available, CntntFrms are added in the cell, otherwise
4426 : //Rows have to be present and those are added.
4427 0 : if ( rBox.GetSttIdx() )
4428 : {
4429 0 : sal_uLong nIndex = rBox.GetSttIdx();
4430 0 : ::_InsertCnt( this, rBox.GetFrmFmt()->GetDoc(), ++nIndex );
4431 : }
4432 : else
4433 : {
4434 0 : const SwTableLines &rLines = rBox.GetTabLines();
4435 0 : SwFrm *pTmpPrev = 0;
4436 0 : for ( sal_uInt16 i = 0; i < rLines.size(); ++i )
4437 : {
4438 0 : SwRowFrm *pNew = new SwRowFrm( *rLines[i], this, bInsertContent );
4439 0 : pNew->InsertBehind( this, pTmpPrev );
4440 0 : pTmpPrev = pNew;
4441 : }
4442 : }
4443 : }
4444 :
4445 0 : SwCellFrm::~SwCellFrm()
4446 : {
4447 0 : SwModify* pMod = GetFmt();
4448 0 : if( pMod )
4449 : {
4450 : // At this stage the lower frames aren't destroyed already,
4451 : // therefore we have to do a recursive dispose.
4452 0 : SwRootFrm *pRootFrm = getRootFrm();
4453 0 : if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
4454 0 : pRootFrm->GetCurrShell() )
4455 : {
4456 0 : pRootFrm->GetCurrShell()->Imp()->DisposeAccessibleFrm( this, true );
4457 : }
4458 :
4459 0 : pMod->Remove( this ); // remove,
4460 0 : if( !pMod->GetDepends() )
4461 0 : delete pMod; // and delete
4462 : }
4463 0 : }
4464 :
4465 0 : static bool lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, bool bInva )
4466 : {
4467 0 : bool bRet = false;
4468 0 : SwFrm *pFrm = pLay->Lower();
4469 0 : SWRECTFN( pLay )
4470 0 : while ( pFrm )
4471 : {
4472 0 : long nFrmTop = (pFrm->Frm().*fnRect->fnGetTop)();
4473 0 : if( nFrmTop != lYStart )
4474 : {
4475 0 : bRet = true;
4476 0 : const long lDiff = (*fnRect->fnYDiff)( lYStart, nFrmTop );
4477 0 : const long lDiffX = lYStart - nFrmTop;
4478 0 : (pFrm->Frm().*fnRect->fnSubTop)( -lDiff );
4479 0 : (pFrm->Frm().*fnRect->fnAddBottom)( lDiff );
4480 0 : pFrm->SetCompletePaint();
4481 0 : if ( !pFrm->GetNext() )
4482 0 : pFrm->SetRetouche();
4483 0 : if( bInva )
4484 0 : pFrm->Prepare( PREP_POS_CHGD );
4485 0 : if ( pFrm->IsLayoutFrm() && ((SwLayoutFrm*)pFrm)->Lower() )
4486 : lcl_ArrangeLowers( (SwLayoutFrm*)pFrm,
4487 0 : (((SwLayoutFrm*)pFrm)->Lower()->Frm().*fnRect->fnGetTop)()
4488 0 : + lDiffX, bInva );
4489 0 : if ( pFrm->GetDrawObjs() )
4490 : {
4491 0 : for ( sal_uInt16 i = 0; i < pFrm->GetDrawObjs()->Count(); ++i )
4492 : {
4493 0 : SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i];
4494 : // #i26945# - check, if anchored object
4495 : // is lower of layout frame by checking, if the anchor
4496 : // frame, which contains the anchor position, is a lower
4497 : // of the layout frame.
4498 0 : if ( !pLay->IsAnLower( pAnchoredObj->GetAnchorFrmContainingAnchPos() ) )
4499 : {
4500 0 : continue;
4501 : }
4502 : // #i52904# - distinguish between anchored
4503 : // objects, whose vertical position depends on its anchor
4504 : // frame and whose vertical position is independent
4505 : // from its anchor frame.
4506 0 : bool bVertPosDepOnAnchor( true );
4507 : {
4508 0 : SwFmtVertOrient aVert( pAnchoredObj->GetFrmFmt().GetVertOrient() );
4509 0 : switch ( aVert.GetRelationOrient() )
4510 : {
4511 : case text::RelOrientation::PAGE_FRAME:
4512 : case text::RelOrientation::PAGE_PRINT_AREA:
4513 0 : bVertPosDepOnAnchor = false;
4514 0 : break;
4515 0 : default: break;
4516 0 : }
4517 : }
4518 0 : if ( pAnchoredObj->ISA(SwFlyFrm) )
4519 : {
4520 0 : SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
4521 :
4522 : // OD 2004-05-18 #i28701# - no direct move of objects,
4523 : // which are anchored to-paragraph/to-character, if
4524 : // the wrapping style influence has to be considered
4525 : // on the object positioning.
4526 : // #i52904# - no direct move of objects,
4527 : // whose vertical position doesn't depend on anchor frame.
4528 : const bool bDirectMove =
4529 0 : FAR_AWAY != pFly->Frm().Top() &&
4530 0 : bVertPosDepOnAnchor &&
4531 0 : !pFly->ConsiderObjWrapInfluenceOnObjPos();
4532 0 : if ( bDirectMove )
4533 : {
4534 0 : (pFly->Frm().*fnRect->fnSubTop)( -lDiff );
4535 0 : (pFly->Frm().*fnRect->fnAddBottom)( lDiff );
4536 0 : pFly->GetVirtDrawObj()->SetRectsDirty();
4537 : // --> OD 2004-08-17 - also notify view of <SdrObject>
4538 : // instance, which represents the Writer fly frame in
4539 : // the drawing layer
4540 0 : pFly->GetVirtDrawObj()->SetChanged();
4541 : // #i58280#
4542 0 : pFly->InvalidateObjRectWithSpaces();
4543 : }
4544 :
4545 0 : if ( pFly->IsFlyInCntFrm() )
4546 : {
4547 0 : static_cast<SwFlyInCntFrm*>(pFly)->AddRefOfst( lDiff );
4548 : // #115759# - reset current relative
4549 : // position to get re-positioned, if not directly moved.
4550 0 : if ( !bDirectMove )
4551 : {
4552 0 : pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) );
4553 : }
4554 : }
4555 0 : else if( pFly->IsAutoPos() )
4556 : {
4557 0 : pFly->AddLastCharY( lDiff );
4558 : // OD 2004-05-18 #i28701# - follow-up of #i22341#
4559 : // <mnLastTopOfLine> has also been adjusted.
4560 0 : pFly->AddLastTopOfLineY( lDiff );
4561 : }
4562 : // #i26945# - re-registration at
4563 : // page frame of anchor frame, if table frame isn't
4564 : // a follow table and table frame isn't in its
4565 : // rebuild of last line.
4566 0 : const SwTabFrm* pTabFrm = pLay->FindTabFrm();
4567 : // #115759#
4568 : // - save: check, if table frame is found.
4569 0 : if ( pTabFrm &&
4570 0 : !( pTabFrm->IsFollow() &&
4571 0 : pTabFrm->FindMaster()->IsRebuildLastLine() ) &&
4572 0 : pFly->IsFlyFreeFrm() )
4573 : {
4574 0 : SwPageFrm* pPageFrm = pFly->GetPageFrm();
4575 0 : SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm();
4576 0 : if ( pPageFrm != pPageOfAnchor )
4577 : {
4578 0 : pFly->InvalidatePos();
4579 0 : if ( pPageFrm )
4580 0 : pPageFrm->MoveFly( pFly, pPageOfAnchor );
4581 : else
4582 0 : pPageOfAnchor->AppendFlyToPage( pFly );
4583 : }
4584 : }
4585 : // OD 2004-05-11 #i28701# - Because of the introduction
4586 : // of new positionings and alignments (e.g. aligned at
4587 : // page area, but anchored at-character), the position
4588 : // of the Writer fly frame has to be invalidated.
4589 0 : pFly->InvalidatePos();
4590 :
4591 : // #i26945# - follow-up of #i3317#
4592 : // No arrangement of lowers, if Writer fly frame isn't
4593 : // moved
4594 0 : if ( bDirectMove &&
4595 : ::lcl_ArrangeLowers( pFly,
4596 0 : (pFly->*fnRect->fnGetPrtTop)(),
4597 0 : bInva ) )
4598 : {
4599 0 : pFly->SetCompletePaint();
4600 : }
4601 : }
4602 0 : else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) )
4603 : {
4604 : // #i26945#
4605 0 : const SwTabFrm* pTabFrm = pLay->FindTabFrm();
4606 0 : if ( pTabFrm &&
4607 0 : !( pTabFrm->IsFollow() &&
4608 0 : pTabFrm->FindMaster()->IsRebuildLastLine() ) &&
4609 0 : (pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
4610 : != FLY_AS_CHAR))
4611 : {
4612 0 : SwPageFrm* pPageFrm = pAnchoredObj->GetPageFrm();
4613 0 : SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm();
4614 0 : if ( pPageFrm != pPageOfAnchor )
4615 : {
4616 0 : pAnchoredObj->InvalidateObjPos();
4617 0 : if ( pPageFrm )
4618 : {
4619 0 : pPageFrm->RemoveDrawObjFromPage( *pAnchoredObj );
4620 : }
4621 0 : pPageOfAnchor->AppendDrawObjToPage( *pAnchoredObj );
4622 : }
4623 : }
4624 : // #i28701# - adjust last character
4625 : // rectangle and last top of line.
4626 0 : pAnchoredObj->AddLastCharY( lDiff );
4627 0 : pAnchoredObj->AddLastTopOfLineY( lDiff );
4628 : // #i52904# - re-introduce direct move
4629 : // of drawing objects
4630 : const bool bDirectMove =
4631 0 : static_cast<const SwDrawFrmFmt&>(pAnchoredObj->GetFrmFmt()).IsPosAttrSet() &&
4632 0 : bVertPosDepOnAnchor &&
4633 0 : !pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos();
4634 0 : if ( bDirectMove )
4635 : {
4636 0 : SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj );
4637 0 : if ( bVert )
4638 : {
4639 0 : pAnchoredObj->DrawObj()->Move( Size( lDiff, 0 ) );
4640 : }
4641 : else
4642 : {
4643 0 : pAnchoredObj->DrawObj()->Move( Size( 0, lDiff ) );
4644 : }
4645 : // #i58280#
4646 0 : pAnchoredObj->InvalidateObjRectWithSpaces();
4647 : }
4648 0 : pAnchoredObj->InvalidateObjPos();
4649 : }
4650 : else
4651 : {
4652 : OSL_FAIL( "<lcl_ArrangeLowers(..)> - unknown type of anchored object!" );
4653 : }
4654 : }
4655 : }
4656 : }
4657 : // Columns and cells are ordered horizontal, not vertical
4658 0 : if( !pFrm->IsColumnFrm() && !pFrm->IsCellFrm() )
4659 : lYStart = (*fnRect->fnYInc)( lYStart,
4660 0 : (pFrm->Frm().*fnRect->fnGetHeight)() );
4661 :
4662 : // Nowadays, the content inside a cell can flow into the follow table.
4663 : // Thus, the cell may only grow up to the end of the environment.
4664 : // So the content may have grown, but the cell could not grow.
4665 : // Therefore we have to trigger a formatting for the frames, which do
4666 : // not fit into the cell anymore:
4667 : SwTwips nDistanceToUpperPrtBottom =
4668 0 : (pFrm->Frm().*fnRect->fnBottomDist)( (pLay->*fnRect->fnGetPrtBottom)());
4669 : // #i56146# - Revise fix of issue #i26945#
4670 : // do *not* consider content inside fly frames, if it's an undersized paragraph.
4671 : // #i26945# - consider content inside fly frames
4672 0 : if ( nDistanceToUpperPrtBottom < 0 &&
4673 0 : ( ( pFrm->IsInFly() &&
4674 0 : ( !pFrm->IsTxtFrm() ||
4675 0 : !static_cast<SwTxtFrm*>(pFrm)->IsUndersized() ) ) ||
4676 0 : pFrm->IsInSplitTableRow() ) )
4677 : {
4678 0 : pFrm->InvalidatePos();
4679 : }
4680 :
4681 0 : pFrm = pFrm->GetNext();
4682 : }
4683 0 : return bRet;
4684 : }
4685 :
4686 0 : void SwCellFrm::Format( const SwBorderAttrs *pAttrs )
4687 : {
4688 : OSL_ENSURE( pAttrs, "CellFrm::Format, pAttrs ist 0." );
4689 0 : const SwTabFrm* pTab = FindTabFrm();
4690 0 : SWRECTFN( pTab )
4691 :
4692 0 : if ( !mbValidPrtArea )
4693 : {
4694 0 : mbValidPrtArea = sal_True;
4695 :
4696 : //Adjust position.
4697 0 : if ( Lower() )
4698 : {
4699 : SwTwips nTopSpace, nBottomSpace, nLeftSpace, nRightSpace;
4700 : // #i29550#
4701 0 : if ( pTab->IsCollapsingBorders() && !Lower()->IsRowFrm() )
4702 : {
4703 0 : const SvxBoxItem& rBoxItem = pAttrs->GetBox();
4704 0 : nLeftSpace = rBoxItem.GetDistance( BOX_LINE_LEFT );
4705 0 : nRightSpace = rBoxItem.GetDistance( BOX_LINE_RIGHT );
4706 0 : nTopSpace = ((SwRowFrm*)GetUpper())->GetTopMarginForLowers();
4707 0 : nBottomSpace = ((SwRowFrm*)GetUpper())->GetBottomMarginForLowers();
4708 : }
4709 : else
4710 : {
4711 : // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
4712 0 : nLeftSpace = pAttrs->CalcLeft( this );
4713 0 : nRightSpace = pAttrs->CalcRight( this );
4714 0 : nTopSpace = pAttrs->CalcTop();
4715 0 : nBottomSpace = pAttrs->CalcBottom();
4716 : }
4717 0 : (this->*fnRect->fnSetXMargins)( nLeftSpace, nRightSpace );
4718 0 : (this->*fnRect->fnSetYMargins)( nTopSpace, nBottomSpace );
4719 : }
4720 : }
4721 : // #i26945#
4722 0 : long nRemaining = GetTabBox()->getRowSpan() >= 1 ?
4723 0 : ::lcl_CalcMinCellHeight( this, pTab->IsConsiderObjsForMinCellHeight(), pAttrs ) :
4724 0 : 0;
4725 0 : if ( !mbValidSize )
4726 : {
4727 0 : mbValidSize = sal_True;
4728 :
4729 : //The VarSize of the CellFrms is always the width.
4730 : //The width is not variable though, it is defined by the format.
4731 : //This predefined value however does not necessary match the actual
4732 : //width. The width is calculated based on the attribute, the value in
4733 : //the attribute matches the desired value of the TabFrm. Changes which
4734 : //were done there are taken into account here proportionately.
4735 : //If the cell doesn't have a neighbour anymore, it does not take the
4736 : //attribute into account and takes the rest of the upper instead.
4737 : SwTwips nWidth;
4738 0 : if ( GetNext() )
4739 : {
4740 0 : const SwTwips nWish = pTab->GetFmt()->GetFrmSize().GetWidth();
4741 0 : nWidth = pAttrs->GetSize().Width();
4742 :
4743 : OSL_ENSURE( nWish, "Table without width?" );
4744 : OSL_ENSURE( nWidth <= nWish, "Width of cell larger than table." );
4745 : OSL_ENSURE( nWidth > 0, "Box without width" );
4746 :
4747 0 : const long nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
4748 0 : if ( nWish != nPrtWidth )
4749 : {
4750 : // Avoid rounding problems, at least for the new table model
4751 0 : if ( pTab->GetTable()->IsNewModel() )
4752 : {
4753 : // 1. sum of widths of cells up to this cell (in model)
4754 0 : const SwTableLine* pTabLine = GetTabBox()->GetUpper();
4755 0 : const SwTableBoxes& rBoxes = pTabLine->GetTabBoxes();
4756 0 : const SwTableBox* pTmpBox = 0;
4757 :
4758 0 : SwTwips nSumWidth = 0;
4759 0 : sal_uInt16 i = 0;
4760 0 : do
4761 : {
4762 0 : pTmpBox = rBoxes[ i++ ];
4763 0 : nSumWidth += pTmpBox->GetFrmFmt()->GetFrmSize().GetWidth();
4764 : }
4765 0 : while ( pTmpBox != GetTabBox() );
4766 :
4767 : // 2. calculate actual width of cells up to this one
4768 0 : double nTmpWidth = nSumWidth;
4769 0 : nTmpWidth *= nPrtWidth;
4770 0 : nTmpWidth /= nWish;
4771 0 : nWidth = (SwTwips)nTmpWidth;
4772 :
4773 : // 3. calculate frame widths of cells up to this one:
4774 0 : const SwFrm* pTmpCell = static_cast<const SwLayoutFrm*>(GetUpper())->Lower();
4775 0 : SwTwips nSumFrameWidths = 0;
4776 0 : while ( pTmpCell != this )
4777 : {
4778 0 : nSumFrameWidths += (pTmpCell->Frm().*fnRect->fnGetWidth)();
4779 0 : pTmpCell = pTmpCell->GetNext();
4780 : }
4781 :
4782 0 : nWidth = nWidth - nSumFrameWidths;
4783 : }
4784 : else
4785 : {
4786 : // #i12092# use double instead of long,
4787 : // otherwise this could lead to overflows
4788 0 : double nTmpWidth = nWidth;
4789 0 : nTmpWidth *= nPrtWidth;
4790 0 : nTmpWidth /= nWish;
4791 0 : nWidth = (SwTwips)nTmpWidth;
4792 : }
4793 : }
4794 : }
4795 : else
4796 : {
4797 : OSL_ENSURE( pAttrs->GetSize().Width() > 0, "Box without width" );
4798 0 : nWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)();
4799 0 : SwFrm *pPre = GetUpper()->Lower();
4800 0 : while ( pPre != this )
4801 : {
4802 0 : nWidth -= (pPre->Frm().*fnRect->fnGetWidth)();
4803 0 : pPre = pPre->GetNext();
4804 : }
4805 : }
4806 0 : const long nDiff = nWidth - (Frm().*fnRect->fnGetWidth)();
4807 0 : if( IsNeighbourFrm() && IsRightToLeft() )
4808 0 : (Frm().*fnRect->fnSubLeft)( nDiff );
4809 : else
4810 0 : (Frm().*fnRect->fnAddRight)( nDiff );
4811 0 : (Prt().*fnRect->fnAddRight)( nDiff );
4812 :
4813 : //Adjust the height, it's defined through the content and the border.
4814 0 : const long nDiffHeight = nRemaining - (Frm().*fnRect->fnGetHeight)();
4815 0 : if ( nDiffHeight )
4816 : {
4817 0 : if ( nDiffHeight > 0 )
4818 : {
4819 : //Validate again if no growth happened. Invalidation is done
4820 : //through AdjustCells of the row.
4821 0 : if ( !Grow( nDiffHeight ) )
4822 0 : mbValidSize = mbValidPrtArea = sal_True;
4823 : }
4824 : else
4825 : {
4826 : //Only keep invalidated if shrinking was done; this can be
4827 : //dismissed because all adjoined cells have to be the same size.
4828 0 : if ( !Shrink( -nDiffHeight ) )
4829 0 : mbValidSize = mbValidPrtArea = sal_True;
4830 : }
4831 : }
4832 : }
4833 0 : const SwFmtVertOrient &rOri = pAttrs->GetAttrSet().GetVertOrient();
4834 :
4835 0 : if ( !Lower() )
4836 0 : return;
4837 :
4838 : // From now on, all operations are related to the table cell.
4839 0 : SWREFRESHFN( this )
4840 :
4841 0 : SwPageFrm* pPg = 0;
4842 0 : if ( !FindTabFrm()->IsRebuildLastLine() && text::VertOrientation::NONE != rOri.GetVertOrient() &&
4843 : // #158225# no vertical alignment of covered cells
4844 0 : !IsCoveredCell() &&
4845 : // #116532# Do not consider vertical alignment in grid mode
4846 0 : !(pPg = FindPageFrm())->HasGrid() )
4847 : {
4848 0 : if ( !Lower()->IsCntntFrm() && !Lower()->IsSctFrm() && !Lower()->IsTabFrm() )
4849 : {
4850 : // OSL_ENSURE(for HTML-import!
4851 : OSL_ENSURE( !this, "VAlign to cell without content" );
4852 0 : return;
4853 : }
4854 0 : bool bVertDir = true;
4855 : // #i43913# - no vertical alignment, if wrapping
4856 : // style influence is considered on object positioning and
4857 : // an object is anchored inside the cell.
4858 0 : const bool bConsiderWrapOnObjPos( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) );
4859 : //No alignment if border with flow overlaps the cell.
4860 0 : if ( pPg->GetSortedObjs() )
4861 : {
4862 0 : SwRect aRect( Prt() ); aRect += Frm().Pos();
4863 0 : for ( sal_uInt16 i = 0; i < pPg->GetSortedObjs()->Count(); ++i )
4864 : {
4865 0 : const SwAnchoredObject* pAnchoredObj = (*pPg->GetSortedObjs())[i];
4866 0 : SwRect aTmp( pAnchoredObj->GetObjRect() );
4867 0 : if ( aTmp.IsOver( aRect ) )
4868 : {
4869 0 : const SwFrmFmt& rAnchoredObjFrmFmt = pAnchoredObj->GetFrmFmt();
4870 0 : const SwFmtSurround &rSur = rAnchoredObjFrmFmt.GetSurround();
4871 :
4872 0 : if ( SURROUND_THROUGHT != rSur.GetSurround() )
4873 : {
4874 : // frames, which the cell is a lower of, aren't relevant
4875 0 : if ( pAnchoredObj->ISA(SwFlyFrm) )
4876 : {
4877 : const SwFlyFrm *pFly =
4878 0 : static_cast<const SwFlyFrm*>(pAnchoredObj);
4879 0 : if ( pFly->IsAnLower( this ) )
4880 0 : continue;
4881 : }
4882 :
4883 0 : const SwFrm* pAnch = pAnchoredObj->GetAnchorFrm();
4884 : // #i43913#
4885 : // #i52904# - no vertical alignment,
4886 : // if object, anchored inside cell, has temporarly
4887 : // consider its wrapping style on object positioning.
4888 : // #i58806# - no vertical alignment
4889 : // if object does not follow the text flow.
4890 0 : if ( bConsiderWrapOnObjPos ||
4891 0 : !IsAnLower( pAnch ) ||
4892 0 : pAnchoredObj->IsTmpConsiderWrapInfluence() ||
4893 0 : !rAnchoredObjFrmFmt.GetFollowTextFlow().GetValue() )
4894 : {
4895 0 : bVertDir = false;
4896 0 : break;
4897 : }
4898 : }
4899 : }
4900 : }
4901 : }
4902 :
4903 0 : long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
4904 0 : if( ( bVertDir && ( nRemaining -= lcl_CalcTopAndBottomMargin( *this, *pAttrs ) ) < nPrtHeight ) ||
4905 0 : (Lower()->Frm().*fnRect->fnGetTop)() != (this->*fnRect->fnGetPrtTop)() )
4906 : {
4907 0 : long nDiff = (Prt().*fnRect->fnGetHeight)() - nRemaining;
4908 0 : if ( nDiff >= 0 )
4909 : {
4910 0 : long lTopOfst = 0;
4911 0 : if ( bVertDir )
4912 : {
4913 0 : switch ( rOri.GetVertOrient() )
4914 : {
4915 0 : case text::VertOrientation::CENTER: lTopOfst = nDiff / 2; break;
4916 0 : case text::VertOrientation::BOTTOM: lTopOfst = nDiff; break;
4917 0 : default: break;
4918 : };
4919 : }
4920 : long nTmp = (*fnRect->fnYInc)(
4921 0 : (this->*fnRect->fnGetPrtTop)(), lTopOfst );
4922 0 : if ( lcl_ArrangeLowers( this, nTmp, !bVertDir ) )
4923 0 : SetCompletePaint();
4924 : }
4925 : }
4926 : }
4927 : else
4928 : {
4929 : //Was an old alignment taken into account?
4930 0 : if ( Lower()->IsCntntFrm() )
4931 : {
4932 0 : const long lYStart = (this->*fnRect->fnGetPrtTop)();
4933 0 : lcl_ArrangeLowers( this, lYStart, true );
4934 : }
4935 : }
4936 : }
4937 :
4938 0 : void SwCellFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
4939 : {
4940 0 : bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();
4941 0 : const SfxPoolItem *pItem = 0;
4942 :
4943 0 : if( bAttrSetChg )
4944 0 : ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_VERT_ORIENT, false, &pItem);
4945 0 : else if (pNew && RES_VERT_ORIENT == pNew->Which())
4946 0 : pItem = pNew;
4947 :
4948 0 : if ( pItem )
4949 : {
4950 0 : bool bInva = true;
4951 0 : if ( text::VertOrientation::NONE == ((SwFmtVertOrient*)pItem)->GetVertOrient() &&
4952 : // OD 04.11.2003 #112910#
4953 0 : Lower() && Lower()->IsCntntFrm() )
4954 : {
4955 0 : SWRECTFN( this )
4956 0 : const long lYStart = (this->*fnRect->fnGetPrtTop)();
4957 0 : bInva = lcl_ArrangeLowers( this, lYStart, false );
4958 : }
4959 0 : if ( bInva )
4960 : {
4961 0 : SetCompletePaint();
4962 0 : InvalidatePrt();
4963 : }
4964 : }
4965 :
4966 0 : if ( ( bAttrSetChg &&
4967 0 : SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_PROTECT, false ) ) ||
4968 0 : RES_PROTECT == pNew->Which() )
4969 : {
4970 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
4971 0 : if( pSh && pSh->GetLayout()->IsAnyShellAccessible() )
4972 0 : pSh->Imp()->InvalidateAccessibleEditableState( true, this );
4973 : }
4974 :
4975 0 : if ( bAttrSetChg &&
4976 0 : SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_FRAMEDIR, false, &pItem ) )
4977 : {
4978 0 : SetDerivedVert( sal_False );
4979 0 : CheckDirChange();
4980 : }
4981 :
4982 : // #i29550#
4983 0 : if ( bAttrSetChg &&
4984 0 : SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_BOX, false, &pItem ) )
4985 : {
4986 0 : SwFrm* pTmpUpper = GetUpper();
4987 0 : while ( pTmpUpper->GetUpper() && !pTmpUpper->GetUpper()->IsTabFrm() )
4988 0 : pTmpUpper = pTmpUpper->GetUpper();
4989 :
4990 0 : SwTabFrm* pTabFrm = (SwTabFrm*)pTmpUpper->GetUpper();
4991 0 : if ( pTabFrm->IsCollapsingBorders() )
4992 : {
4993 : // Invalidate lowers of this and next row:
4994 0 : lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper );
4995 0 : pTmpUpper = pTmpUpper->GetNext();
4996 0 : if ( pTmpUpper )
4997 0 : lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper );
4998 : else
4999 0 : pTabFrm->InvalidatePrt();
5000 : }
5001 : }
5002 :
5003 0 : SwLayoutFrm::Modify( pOld, pNew );
5004 0 : }
5005 :
5006 0 : long SwCellFrm::GetLayoutRowSpan() const
5007 : {
5008 0 : long nRet = GetTabBox()->getRowSpan();
5009 0 : if ( nRet < 1 )
5010 : {
5011 0 : const SwFrm* pRow = GetUpper();
5012 0 : const SwTabFrm* pTab = static_cast<const SwTabFrm*>(pRow->GetUpper());
5013 :
5014 0 : if ( pTab && pTab->IsFollow() && pRow == pTab->GetFirstNonHeadlineRow() )
5015 0 : nRet = -nRet;
5016 : }
5017 0 : return nRet;
5018 : }
5019 :
5020 : // #i103961#
5021 0 : void SwCellFrm::Cut()
5022 : {
5023 : // notification for accessibility
5024 : {
5025 0 : SwRootFrm *pRootFrm = getRootFrm();
5026 0 : if( pRootFrm && pRootFrm->IsAnyShellAccessible() )
5027 : {
5028 0 : SwViewShell* pVSh = pRootFrm->GetCurrShell();
5029 0 : if ( pVSh && pVSh->Imp() )
5030 : {
5031 0 : pVSh->Imp()->DisposeAccessibleFrm( this );
5032 : }
5033 : }
5034 : }
5035 :
5036 0 : SwLayoutFrm::Cut();
5037 0 : }
5038 :
5039 : // Helper functions for repeated headlines:
5040 :
5041 0 : bool SwTabFrm::IsInHeadline( const SwFrm& rFrm ) const
5042 : {
5043 : OSL_ENSURE( IsAnLower( &rFrm ) && rFrm.IsInTab(),
5044 : "SwTabFrm::IsInHeadline called for frame not lower of table" );
5045 :
5046 0 : const SwFrm* pTmp = &rFrm;
5047 0 : while ( !pTmp->GetUpper()->IsTabFrm() )
5048 0 : pTmp = pTmp->GetUpper();
5049 :
5050 0 : return GetTable()->IsHeadline( *((SwRowFrm*)pTmp)->GetTabLine() );
5051 : }
5052 :
5053 : /*
5054 : * If this is a master table, we can may assume, that there are at least
5055 : * nRepeat lines in the table.
5056 : * If this is a follow table, there are intermediate states for the table
5057 : * layout, e.g., during deletion of rows, which makes it necessary to find
5058 : * the first non-headline row by evaluating the headline flag at the row frame.
5059 : */
5060 0 : SwRowFrm* SwTabFrm::GetFirstNonHeadlineRow() const
5061 : {
5062 0 : SwRowFrm* pRet = (SwRowFrm*)Lower();
5063 0 : if ( pRet )
5064 : {
5065 0 : if ( IsFollow() )
5066 : {
5067 0 : while ( pRet && pRet->IsRepeatedHeadline() )
5068 0 : pRet = (SwRowFrm*)pRet->GetNext();
5069 : }
5070 : else
5071 : {
5072 0 : sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();
5073 0 : while ( pRet && nRepeat > 0 )
5074 : {
5075 0 : pRet = (SwRowFrm*)pRet->GetNext();
5076 0 : --nRepeat;
5077 : }
5078 : }
5079 : }
5080 :
5081 0 : return (SwRowFrm*)pRet;
5082 : }
5083 :
5084 0 : bool SwTable::IsHeadline( const SwTableLine& rLine ) const
5085 : {
5086 0 : for ( sal_uInt16 i = 0; i < GetRowsToRepeat(); ++i )
5087 0 : if ( GetTabLines()[ i ] == &rLine )
5088 0 : return true;
5089 :
5090 0 : return false;
5091 : }
5092 :
5093 0 : bool SwTabFrm::IsLayoutSplitAllowed() const
5094 : {
5095 0 : return GetFmt()->GetLayoutSplit().GetValue();
5096 : }
5097 :
5098 : // #i29550#
5099 :
5100 0 : sal_uInt16 SwTabFrm::GetBottomLineSize() const
5101 : {
5102 : OSL_ENSURE( IsCollapsingBorders(),
5103 : "BottomLineSize only required for collapsing borders" );
5104 :
5105 : OSL_ENSURE( Lower(), "Warning! Trying to prevent a crash, please inform FME" );
5106 :
5107 0 : const SwFrm* pTmp = GetLastLower();
5108 :
5109 : // #124755# Try to make code robust
5110 0 : if ( !pTmp ) return 0;
5111 :
5112 0 : return static_cast<const SwRowFrm*>(pTmp)->GetBottomLineSize();
5113 : }
5114 :
5115 0 : bool SwTabFrm::IsCollapsingBorders() const
5116 : {
5117 0 : return ((SfxBoolItem&)GetFmt()->GetAttrSet().Get( RES_COLLAPSING_BORDERS )).GetValue();
5118 : }
5119 :
5120 : /// Local helper function to calculate height of first text row
5121 0 : static SwTwips lcl_CalcHeightOfFirstContentLine( const SwRowFrm& rSourceLine )
5122 : {
5123 : // Find corresponding split line in master table
5124 0 : const SwTabFrm* pTab = rSourceLine.FindTabFrm();
5125 0 : SWRECTFN( pTab )
5126 0 : const SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower();
5127 :
5128 : // 1. Case: rSourceLine is a follow flow line.
5129 : // In this case we have to return the minimum of the heights
5130 : // of the first lines in rSourceLine.
5131 :
5132 : // 2. Case: rSourceLine is not a follow flow line.
5133 : // In this case we have to return the maximum of the heights
5134 : // of the first lines in rSourceLine.
5135 0 : bool bIsInFollowFlowLine = rSourceLine.IsInFollowFlowRow();
5136 0 : SwTwips nHeight = bIsInFollowFlowLine ? LONG_MAX : 0;
5137 :
5138 0 : while ( pCurrSourceCell )
5139 : {
5140 : // NEW TABLES
5141 : // Skip cells which are not responsible for the height of
5142 : // the follow flow line:
5143 0 : if ( bIsInFollowFlowLine && pCurrSourceCell->GetLayoutRowSpan() > 1 )
5144 : {
5145 0 : pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext();
5146 0 : continue;
5147 : }
5148 :
5149 0 : const SwFrm *pTmp = pCurrSourceCell->Lower();
5150 0 : if ( pTmp )
5151 : {
5152 0 : SwTwips nTmpHeight = USHRT_MAX;
5153 : // #i32456# Consider lower row frames
5154 0 : if ( pTmp->IsRowFrm() )
5155 : {
5156 0 : const SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower();
5157 0 : nTmpHeight = lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow );
5158 : }
5159 0 : if ( pTmp->IsTabFrm() )
5160 : {
5161 0 : nTmpHeight = ((SwTabFrm*)pTmp)->CalcHeightOfFirstContentLine();
5162 : }
5163 0 : else if ( pTmp->IsTxtFrm() )
5164 : {
5165 0 : SwTxtFrm* pTxtFrm = (SwTxtFrm*)pTmp;
5166 0 : pTxtFrm->GetFormatted();
5167 0 : nTmpHeight = pTxtFrm->FirstLineHeight();
5168 : }
5169 :
5170 0 : if ( USHRT_MAX != nTmpHeight )
5171 : {
5172 0 : const SwCellFrm* pPrevCell = pCurrSourceCell->GetPreviousCell();
5173 0 : if ( pPrevCell )
5174 : {
5175 : // If we are in a split row, there may be some space
5176 : // left in the cell frame of the master row.
5177 : // We look for the minimum of all first line heights;
5178 0 : SwTwips nReal = (pPrevCell->Prt().*fnRect->fnGetHeight)();
5179 0 : const SwFrm* pFrm = pPrevCell->Lower();
5180 0 : const SwFrm* pLast = pFrm;
5181 0 : while ( pFrm )
5182 : {
5183 0 : nReal -= (pFrm->Frm().*fnRect->fnGetHeight)();
5184 0 : pLast = pFrm;
5185 0 : pFrm = pFrm->GetNext();
5186 : }
5187 :
5188 : // #i26831#, #i26520#
5189 : // The additional lower space of the current last.
5190 : // #115759# - do *not* consider the
5191 : // additional lower space for 'master' text frames
5192 0 : if ( pLast && pLast->IsFlowFrm() &&
5193 0 : ( !pLast->IsTxtFrm() ||
5194 0 : !static_cast<const SwTxtFrm*>(pLast)->GetFollow() ) )
5195 : {
5196 0 : nReal += SwFlowFrm::CastFlowFrm(pLast)->CalcAddLowerSpaceAsLastInTableCell();
5197 : }
5198 : // Don't forget the upper space and lower space,
5199 : // #115759# - do *not* consider the upper
5200 : // and the lower space for follow text frames.
5201 0 : if ( pTmp->IsFlowFrm() &&
5202 0 : ( !pTmp->IsTxtFrm() ||
5203 0 : !static_cast<const SwTxtFrm*>(pTmp)->IsFollow() ) )
5204 : {
5205 0 : nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace( NULL, pLast);
5206 0 : nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace();
5207 : }
5208 : // #115759# - consider additional lower
5209 : // space of <pTmp>, if contains only one line.
5210 : // In this case it would be the new last text frame, which
5211 : // would have no follow and thus would add this space.
5212 0 : if ( pTmp->IsTxtFrm() &&
5213 : const_cast<SwTxtFrm*>(static_cast<const SwTxtFrm*>(pTmp))
5214 0 : ->GetLineCount( COMPLETE_STRING ) == 1 )
5215 : {
5216 : nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)
5217 0 : ->CalcAddLowerSpaceAsLastInTableCell();
5218 : }
5219 0 : if ( nReal > 0 )
5220 0 : nTmpHeight -= nReal;
5221 : }
5222 : else
5223 : {
5224 : // pFirstRow is not a FollowFlowRow. In this case,
5225 : // we look for the maximum of all first line heights:
5226 0 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCurrSourceCell );
5227 0 : const SwBorderAttrs &rAttrs = *aAccess.Get();
5228 0 : nTmpHeight += rAttrs.CalcTop() + rAttrs.CalcBottom();
5229 : // #i26250#
5230 : // Don't forget the upper space and lower space,
5231 0 : if ( pTmp->IsFlowFrm() )
5232 : {
5233 0 : nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace();
5234 0 : nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace();
5235 0 : }
5236 : }
5237 : }
5238 :
5239 0 : if ( bIsInFollowFlowLine )
5240 : {
5241 : // minimum
5242 0 : if ( nTmpHeight < nHeight )
5243 0 : nHeight = nTmpHeight;
5244 : }
5245 : else
5246 : {
5247 : // maximum
5248 0 : if ( nTmpHeight > nHeight && USHRT_MAX != nTmpHeight )
5249 0 : nHeight = nTmpHeight;
5250 : }
5251 : }
5252 :
5253 0 : pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext();
5254 : }
5255 :
5256 0 : return ( LONG_MAX == nHeight ) ? 0 : nHeight;
5257 : }
5258 :
5259 : /// Function to calculate height of first text row
5260 0 : SwTwips SwTabFrm::CalcHeightOfFirstContentLine() const
5261 : {
5262 0 : SWRECTFN( this )
5263 :
5264 0 : const bool bDontSplit = !IsFollow() && !GetFmt()->GetLayoutSplit().GetValue();
5265 :
5266 0 : if ( bDontSplit )
5267 : {
5268 : // Table is not allowed to split: Take the whole height, that's all
5269 0 : return (Frm().*fnRect->fnGetHeight)();
5270 : }
5271 :
5272 0 : SwTwips nTmpHeight = 0;
5273 :
5274 0 : SwRowFrm* pFirstRow = GetFirstNonHeadlineRow();
5275 : OSL_ENSURE( !IsFollow() || pFirstRow, "FollowTable without Lower" );
5276 :
5277 : // NEW TABLES
5278 0 : if ( pFirstRow && pFirstRow->IsRowSpanLine() && pFirstRow->GetNext() )
5279 0 : pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext());
5280 :
5281 : // Calculate the height of the headlines:
5282 0 : const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();
5283 0 : SwTwips nRepeatHeight = nRepeat ? lcl_GetHeightOfRows( GetLower(), nRepeat ) : 0;
5284 :
5285 : // Calculate the height of the keeping lines
5286 : // (headlines + following keeping lines):
5287 0 : SwTwips nKeepHeight = nRepeatHeight;
5288 0 : if ( GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP) )
5289 : {
5290 0 : sal_uInt16 nKeepRows = nRepeat;
5291 :
5292 : // Check how many rows want to keep together
5293 0 : while ( pFirstRow && pFirstRow->ShouldRowKeepWithNext() )
5294 : {
5295 0 : ++nKeepRows;
5296 0 : pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext());
5297 : }
5298 :
5299 0 : if ( nKeepRows > nRepeat )
5300 0 : nKeepHeight = lcl_GetHeightOfRows( GetLower(), nKeepRows );
5301 : }
5302 :
5303 : // For master tables, the height of the headlines + the height of the
5304 : // keeping lines (if any) has to be considered. For follow tables, we
5305 : // only consider the height of the keeping rows without the repeated lines:
5306 0 : if ( !IsFollow() )
5307 : {
5308 0 : nTmpHeight = nKeepHeight;
5309 : }
5310 : else
5311 : {
5312 0 : nTmpHeight = nKeepHeight - nRepeatHeight;
5313 : }
5314 :
5315 : // pFirstRow row is the first non-heading row.
5316 : // nTmpHeight is the height of the heading row if we are a follow.
5317 0 : if ( pFirstRow )
5318 : {
5319 0 : const bool bSplittable = pFirstRow->IsRowSplitAllowed();
5320 0 : const SwTwips nFirstLineHeight = (pFirstRow->Frm().*fnRect->fnGetHeight)();
5321 :
5322 0 : if ( !bSplittable )
5323 : {
5324 : // pFirstRow is not splittable, but it is still possible that the line height of pFirstRow
5325 : // actually is determined by a lower cell with rowspan = -1. In this case we should not
5326 : // just return the height of the first line. Basically we need to get the height of the
5327 : // line as it would be on the last page. Since this is quite complicated to calculate,
5328 : // we olny calculate the height of the first line.
5329 0 : if ( pFirstRow->GetPrev() &&
5330 0 : static_cast<SwRowFrm*>(pFirstRow->GetPrev())->IsRowSpanLine() )
5331 : {
5332 : // Calculate maximum height of all cells with rowspan = 1:
5333 0 : SwTwips nMaxHeight = 0;
5334 0 : const SwCellFrm* pLower2 = static_cast<const SwCellFrm*>(pFirstRow->Lower());
5335 0 : while ( pLower2 )
5336 : {
5337 0 : if ( 1 == pLower2->GetTabBox()->getRowSpan() )
5338 : {
5339 0 : const SwTwips nCellHeight = lcl_CalcMinCellHeight( pLower2, sal_True );
5340 0 : nMaxHeight = std::max( nCellHeight, nMaxHeight );
5341 : }
5342 0 : pLower2 = static_cast<const SwCellFrm*>(pLower2->GetNext());
5343 : }
5344 0 : nTmpHeight += nMaxHeight;
5345 : }
5346 : else
5347 : {
5348 0 : nTmpHeight += nFirstLineHeight;
5349 : }
5350 : }
5351 :
5352 : // #118411#
5353 : // Optimization: lcl_CalcHeightOfFirstContentLine actually can trigger
5354 : // a formatting of the row frame (via the GetFormatted()). We don't
5355 : // want this formatting if the row does not have a height.
5356 0 : else if ( 0 != nFirstLineHeight )
5357 : {
5358 0 : const bool bOldJoinLock = IsJoinLocked();
5359 0 : ((SwTabFrm*)this)->LockJoin();
5360 0 : const SwTwips nHeightOfFirstContentLine = lcl_CalcHeightOfFirstContentLine( *(SwRowFrm*)pFirstRow );
5361 :
5362 : // Consider minimum row height:
5363 0 : const SwFmtFrmSize &rSz = static_cast<const SwRowFrm*>(pFirstRow)->GetFmt()->GetFrmSize();
5364 0 : const SwTwips nMinRowHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ?
5365 0 : rSz.GetHeight() : 0;
5366 :
5367 0 : nTmpHeight += std::max( nHeightOfFirstContentLine, nMinRowHeight );
5368 :
5369 0 : if ( !bOldJoinLock )
5370 0 : ((SwTabFrm*)this)->UnlockJoin();
5371 : }
5372 : }
5373 :
5374 0 : return nTmpHeight;
5375 : }
5376 :
5377 : // Some more functions for covered/covering cells. This way inclusion of
5378 : // SwCellFrm can be avoided
5379 :
5380 0 : bool SwFrm::IsLeaveUpperAllowed() const
5381 : {
5382 0 : const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this);
5383 0 : return pThisCell && pThisCell->GetLayoutRowSpan() > 1;
5384 : }
5385 :
5386 0 : bool SwFrm::IsCoveredCell() const
5387 : {
5388 0 : const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this);
5389 0 : return pThisCell && pThisCell->GetLayoutRowSpan() < 1;
5390 : }
5391 :
5392 0 : bool SwFrm::IsInCoveredCell() const
5393 : {
5394 0 : bool bRet = false;
5395 :
5396 0 : const SwFrm* pThis = this;
5397 0 : while ( pThis && !pThis->IsCellFrm() )
5398 0 : pThis = pThis->GetUpper();
5399 :
5400 0 : if ( pThis )
5401 0 : bRet = pThis->IsCoveredCell();
5402 :
5403 0 : return bRet;
5404 : }
5405 :
5406 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|