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