1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: swnewtable.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
34 #include <swtable.hxx>
36 #include <tblrwcl.hxx>
42 #include <cellfrm.hxx>
43 #include <fmtfsize.hxx>
49 #include <svx/boxitem.hxx>
50 #include <svx/protitem.hxx>
51 #include <swtblfmt.hxx>
54 #define CHECK_TABLE(t)
57 #define CHECK_TABLE(t) (t).CheckConsistency();
59 #define CHECK_TABLE(t)
63 // ---------------------------------------------------------------
65 /** SwBoxSelection is a small helperclass (structure) to handle selections
66 of cells (boxes) between table functions
68 It contains an "array" of table boxes, a rectangulare selection of table boxes.
69 To be more specific, it contains a vector of box selections,
70 every box selection (SwSelBoxes) contains the selected boxes inside one row.
71 The member mnMergeWidth contains the width of the selected boxes
77 std::vector
<const SwSelBoxes
*> aBoxes
;
79 SwBoxSelection() : mnMergeWidth(0) {}
80 bool isEmpty() const { return aBoxes
.size() == 0; }
81 void insertBoxes( const SwSelBoxes
* pNew
){ aBoxes
.insert( aBoxes
.end(), pNew
); }
84 /** NewMerge(..) removes the superfluous cells after cell merge
86 SwTable::NewMerge(..) does some cleaning up,
87 it simply deletes the superfluous cells ("cell span")
88 and notifies the Undo about it.
89 The main work has been done by SwTable::PrepareMerge(..) already.
95 the undo object to notify, maybe empty
97 @return TRUE for compatibility reasons with OldMerge(..)
100 BOOL
SwTable::NewMerge( SwDoc
* pDoc
, const SwSelBoxes
& rBoxes
,
101 const SwSelBoxes
& rMerged
, SwTableBox
*, SwUndoTblMerge
* pUndo
)
104 pUndo
->SetSelBoxes( rBoxes
);
105 DeleteSel( pDoc
, rBoxes
, &rMerged
, 0, TRUE
, TRUE
);
111 /** lcl_CheckMinMax helps evaluating (horizontal) min/max of boxes
113 lcl_CheckMinMax(..) compares the left border and the right border
114 of a given cell with the given range and sets it accordingly.
117 will be decremented if necessary to the left border of the cell
120 will be incremented if necessary to the right border of the cell
123 the row (table line) of the interesting box
126 the index of the box in the table box array of the given row
129 if bSet is false, rMin and rMax will be manipulated if necessary
130 if bSet is true, rMin and rMax will be set to the left and right border of the box
134 void lcl_CheckMinMax( long& rMin
, long& rMax
, const SwTableLine
& rLine
, USHORT nCheck
, bool bSet
)
137 if( rLine
.GetTabBoxes().Count() < nCheck
)
139 ASSERT( false, "Box out of table line" );
140 nCheck
= rLine
.GetTabBoxes().Count();
143 long nNew
= 0; // will be the right border of the current box
144 long nWidth
= 0; // the width of the current box
145 for( USHORT nCurrBox
= 0; nCurrBox
< nCheck
; ++nCurrBox
)
147 SwTableBox
* pBox
= rLine
.GetTabBoxes()[nCurrBox
];
148 ASSERT( pBox
, "Missing table box" );
149 nWidth
= pBox
->GetFrmFmt()->GetFrmSize().GetWidth();
152 // nNew is the right border of the wished box
153 if( bSet
|| nNew
> rMax
)
155 nNew
-= nWidth
; // nNew becomes the left border of the wished box
156 if( bSet
|| nNew
< rMin
)
160 /** lcl_Box2LeftBorder(..) delivers the left (logical) border of a table box
162 The left logical border of a table box is the sum of the cell width before this
166 is the requested table box
168 @return is the left logical border (long, even it cannot be negative)
172 long lcl_Box2LeftBorder( const SwTableBox
& rBox
)
174 if( !rBox
.GetUpper() )
177 const SwTableLine
&rLine
= *rBox
.GetUpper();
178 USHORT nCount
= rLine
.GetTabBoxes().Count();
179 for( USHORT nCurrBox
= 0; nCurrBox
< nCount
; ++nCurrBox
)
181 SwTableBox
* pBox
= rLine
.GetTabBoxes()[nCurrBox
];
182 ASSERT( pBox
, "Missing table box" );
185 nLeft
+= pBox
->GetFrmFmt()->GetFrmSize().GetWidth();
187 ASSERT( false, "Box not found in own upper?" );
191 /** lcl_LeftBorder2Box delivers the box to a given left border
193 It's used to find the master/follow table boxes in previous/next rows.
194 Don't call this function to check if there is such a box,
195 call it if you know there has to be such box.
198 the left border (logical x-value) of the demanded box
201 the row (table line) to be scanned
203 @return a pointer to the table box inside the given row with the wished left border
207 SwTableBox
* lcl_LeftBorder2Box( long nLeft
, const SwTableLine
* pLine
)
212 USHORT nCount
= pLine
->GetTabBoxes().Count();
213 for( USHORT nCurrBox
= 0; nCurrBox
< nCount
; ++nCurrBox
)
215 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCurrBox
];
216 ASSERT( pBox
, "Missing table box" );
217 if( nCurrLeft
>= nLeft
&& pBox
->GetFrmFmt()->GetFrmSize().GetWidth() )
219 ASSERT( nCurrLeft
== nLeft
, "Wrong box found" );
222 nCurrLeft
+= pBox
->GetFrmFmt()->GetFrmSize().GetWidth();
224 ASSERT( false, "Didn't found wished box" );
228 /** lcl_ChangeRowSpan corrects row span after insertion/deletion of rows
230 lcl_ChangeRowSpan(..) has to be called after an insertion or deletion of rows
231 to adjust the row spans of previous rows accordingly.
232 If rows are deleted, the previous rows with row spans into the deleted area
233 have to be decremented by the number of _overlapped_ inserted rows.
234 If rows are inserted, the previous rows with row span into the inserted area
235 have to be incremented by the number of inserted rows.
236 For those row spans which ends exactly above the inserted area it has to be
237 decided by the parameter bSingle if they have to be expanded or not.
240 the table to manipulate (has to be a new model table)
243 the number of rows which has been inserted (nDiff > 0) or deleted (nDiff < 0)
246 the index of the first row which has to be checked
249 true if the new inserted row should not extend row spans which ends in the row above
250 this is for rows inserted by UI "insert row"
251 false if all cells of an inserted row has to be overlapped by the previous row
252 this is for rows inserted by "split row"
253 false is also needed for deleted rows
257 void lcl_ChangeRowSpan( const SwTable
& rTable
, const long nDiff
,
258 USHORT nRowIdx
, const bool bSingle
)
260 if( !nDiff
|| nRowIdx
>= rTable
.GetTabLines().Count() )
262 ASSERT( !bSingle
|| nDiff
> 0, "Don't set bSingle when deleting lines!" );
264 // nDistance is the distance between the current row and the critical row,
265 // e.g. the deleted rows or the inserted rows.
266 // If the row span is lower than the distance there is nothing to do
267 // because the row span ends before the critical area.
268 // When the inserted rows should not be overlapped by row spans which ends
269 // exactly in the row above, the trick is to start with a distance of 1.
270 long nDistance
= bSingle
? 1 : 0;
273 bGoOn
= false; // will be set to true if we found a non-master cell
274 // which has to be manipulated => we have to chekc the previous row, too.
275 const SwTableLine
* pLine
= rTable
.GetTabLines()[ nRowIdx
];
276 USHORT nBoxCount
= pLine
->GetTabBoxes().Count();
277 for( USHORT nCurrBox
= 0; nCurrBox
< nBoxCount
; ++nCurrBox
)
279 long nRowSpan
= pLine
->GetTabBoxes()[nCurrBox
]->getRowSpan();
280 long nAbsSpan
= nRowSpan
> 0 ? nRowSpan
: -nRowSpan
;
281 // Check if the last overlapped cell is above or below
283 if( nAbsSpan
> nDistance
)
288 nRowSpan
+= nDiff
; // increment row span of master cell
291 nRowSpan
-= nDiff
; // increment row span of non-master cell
299 // end of row span behind the deleted area ..
300 if( nRowSpan
- nDistance
> -nDiff
)
302 else // .. or inside the deleted area
303 nRowSpan
= nDistance
+ 1;
306 { // Same for a non-master cell
307 if( nRowSpan
+ nDistance
< nDiff
)
310 nRowSpan
= -nDistance
- 1;
311 bGoOn
= true; // We have to continue
314 pLine
->GetTabBoxes()[ nCurrBox
]->setRowSpan( nRowSpan
);
321 bGoOn
= false; //robust
325 /** CollectBoxSelection(..) create a rectangulare selection based on the given SwPaM
326 and prepares the selected cells for merging
329 SwBoxSelection
* SwTable::CollectBoxSelection( const SwPaM
& rPam
) const
331 ASSERT( bNewModel
, "Don't call me for old tables" );
332 if( !aLines
.Count() )
334 const SwNode
* pStartNd
= rPam
.Start()->nNode
.GetNode().FindTableBoxStartNode();
335 const SwNode
* pEndNd
= rPam
.End()->nNode
.GetNode().FindTableBoxStartNode();
336 if( !pStartNd
|| !pEndNd
|| pStartNd
== pEndNd
)
339 USHORT nLines
= aLines
.Count();
340 USHORT nTop
= 0, nBottom
= 0;
341 long nMin
= 0, nMax
= 0;
343 for( USHORT nRow
= 0; nFound
< 2 && nRow
< nLines
; ++nRow
)
345 SwTableLine
* pLine
= aLines
[nRow
];
346 ASSERT( pLine
, "Missing table line" );
347 USHORT nCols
= pLine
->GetTabBoxes().Count();
348 for( USHORT nCol
= 0; nCol
< nCols
; ++nCol
)
350 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCol
];
351 ASSERT( pBox
, "Missing table box" );
354 if( pBox
->GetSttNd() == pEndNd
)
357 lcl_CheckMinMax( nMin
, nMax
, *pLine
, nCol
, false );
362 else if( pBox
->GetSttNd() == pStartNd
)
365 lcl_CheckMinMax( nMin
, nMax
, *pLine
, nCol
, true );
374 long nMid
= ( nMin
+ nMax
) / 2;
376 SwBoxSelection
* pRet
= new SwBoxSelection();
377 std::list
< std::pair
< SwTableBox
*, long > > aNewWidthList
;
378 USHORT nCheckBottom
= nBottom
;
381 long nLeftSpanCnt
= 0;
382 long nRightSpanCnt
= 0;
383 for( USHORT nRow
= nTop
; nRow
<= nBottom
&& bOkay
; ++nRow
)
385 SwTableLine
* pLine
= aLines
[nRow
];
386 ASSERT( pLine
, "Missing table line" );
387 SwSelBoxes
*pBoxes
= new SwSelBoxes();
391 USHORT nCount
= pLine
->GetTabBoxes().Count();
392 for( USHORT nCurrBox
= 0; nCurrBox
< nCount
; ++nCurrBox
)
394 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCurrBox
];
395 ASSERT( pBox
, "Missing table box" );
397 nRight
+= pBox
->GetFrmFmt()->GetFrmSize().GetWidth();
398 nRowSpan
= pBox
->getRowSpan();
401 if( nRight
== nMin
&& nLeftSpanCnt
)
405 SwTableBox
* pInnerBox
= 0;
406 SwTableBox
* pLeftBox
= 0;
407 SwTableBox
* pRightBox
= 0;
412 if( nRight
>= nMid
|| nRight
+ nLeft
>= nMin
+ nMin
)
416 pBoxes
->Insert( pBox
);
418 pLeftBox
= pLine
->GetTabBoxes()[nCurrBox
-1];
419 nDiff
= nMin
- nLeft
;
422 if( nCurrBox
+1 < nCount
)
424 pRightBox
= pLine
->GetTabBoxes()[nCurrBox
+1];
425 nDiff2
= nRight
- nMax
;
430 else if( nRightSpanCnt
&& nRight
== nMax
)
436 else if( nCurrBox
+1 < nCount
)
439 pInnerBox
= pLine
->GetTabBoxes()[nCurrBox
+1];
440 nDiff
= nMin
- nRight
;
445 else if( nRight
<= nMax
)
447 pBoxes
->Insert( pBox
);
448 if( nRow
== nTop
&& nRowSpan
< 0 )
453 if( nRowSpan
> 1 && nRow
+ nRowSpan
- 1 > nBottom
)
454 nBottom
= nRow
+ (USHORT
)nRowSpan
- 1;
455 if( nRowSpan
< -1 && nRow
- nRowSpan
- 1 > nBottom
)
456 nBottom
= (USHORT
)(nRow
- nRowSpan
- 1);
457 if( nRightSpanCnt
&& nRight
== nMax
)
460 else if( nLeft
< nMax
)
462 if( nLeft
<= nMid
|| nRight
+ nLeft
<= nMax
)
464 if( nCurrBox
+1 < nCount
)
466 pBoxes
->Insert( pBox
);
468 pRightBox
= pLine
->GetTabBoxes()[nCurrBox
+1];
469 nDiff
= nRight
- nMax
;
477 pInnerBox
= pLine
->GetTabBoxes()[nCurrBox
-1];
478 nDiff
= nLeft
- nMax
;
487 if( nRow
== nBottom
)
489 long nTmpSpan
= pInnerBox
->getRowSpan();
491 nBottom
+= (USHORT
)nTmpSpan
- 1;
492 else if( nTmpSpan
< -1 )
493 nBottom
= (USHORT
)( nBottom
- nTmpSpan
- 1 );
495 SwTableBox
* pOuterBox
= pLeftBox
;
500 long nOutSpan
= pOuterBox
->getRowSpan();
503 USHORT nCheck
= nRow
;
506 const SwTableBox
& rBox
=
507 pOuterBox
->FindStartOfRowSpan( *this, USHRT_MAX
);
508 nOutSpan
= rBox
.getRowSpan();
509 const SwTableLine
* pTmpL
= rBox
.GetUpper();
510 nCheck
= GetTabLines().C40_GETPOS( SwTableLine
, pTmpL
);
513 if( pOuterBox
== pLeftBox
)
515 if( !nLeftSpanCnt
|| nMin
- nDiff
!= nLeftSpan
)
520 if( !nRightSpanCnt
|| nMax
+ nDiff
!= nRightSpan
)
526 if( pOuterBox
== pLeftBox
)
530 nLeftSpan
= nMin
- nDiff
;
531 nLeftSpanCnt
= nOutSpan
;
537 nRightSpan
= nMax
+ nDiff
;
538 nRightSpanCnt
= nOutSpan
;
541 nCheck
+= (USHORT
)nOutSpan
- 1;
542 if( nCheck
> nCheckBottom
)
543 nCheckBottom
= nCheck
;
545 else if( ( nLeftSpanCnt
&& pLeftBox
== pOuterBox
) ||
546 ( nRightSpanCnt
&& pRightBox
== pOuterBox
) )
548 std::pair
< SwTableBox
*, long > aTmp
;
549 aTmp
.first
= pInnerBox
;
550 aTmp
.second
= -nDiff
;
551 aNewWidthList
.push_back( aTmp
);
552 aTmp
.first
= pOuterBox
;
554 aNewWidthList
.push_back( aTmp
);
556 pOuterBox
= pOuterBox
== pRightBox
? 0 : pRightBox
;
559 } while( pOuterBox
);
566 pRet
->insertBoxes( pBoxes
);
568 pRet
->mnMergeWidth
= nMax
- nMin
;
569 if( nCheckBottom
> nBottom
)
573 std::list
< std::pair
< SwTableBox
*, long > >::iterator
574 pCurr
= aNewWidthList
.begin();
575 while( pCurr
!= aNewWidthList
.end() )
577 SwFrmFmt
* pFmt
= pCurr
->first
->ClaimFrmFmt();
578 long nNewWidth
= pFmt
->GetFrmSize().GetWidth() + pCurr
->second
;
579 pFmt
->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE
, nNewWidth
, 0 ) );
591 /** lcl_InvalidateCellFrm(..) invalidates all layout representations of a given cell
592 to initiate a reformatting
595 void lcl_InvalidateCellFrm( const SwTableBox
& rBox
)
597 SwClientIter
aIter( *rBox
.GetFrmFmt() );
599 for( pLast
= aIter
.First( TYPE( SwFrm
) ); pLast
; pLast
= aIter
.Next() )
601 SwCellFrm
*pCell
= (SwCellFrm
*)pLast
;
602 if( pCell
->GetTabBox() == &rBox
)
604 pCell
->InvalidateSize();
605 SwFrm
* pLower
= pCell
->GetLower();
607 pLower
->_InvalidateSize();
612 /** lcl_InsertPosition(..) evaluates the insert positions in every table line,
613 when a selection of cells is given and returns the average cell widths
616 long lcl_InsertPosition( SwTable
&rTable
, std::vector
<USHORT
>& rInsPos
,
617 const SwSelBoxes
& rBoxes
, BOOL bBehind
)
619 sal_Int32 nAddWidth
= 0;
621 for( USHORT j
= 0; j
< rBoxes
.Count(); ++j
)
623 SwTableBox
*pBox
= rBoxes
[j
];
624 SwTableLine
* pLine
= pBox
->GetUpper();
625 long nWidth
= rBoxes
[j
]->GetFrmFmt()->GetFrmSize().GetWidth();
627 USHORT nCurrBox
= pLine
->GetTabBoxes().C40_GETPOS(SwTableBox
, pBox
);
628 USHORT nCurrLine
= rTable
.GetTabLines().C40_GETPOS(SwTableLine
, pLine
);
629 ASSERT( nCurrLine
!= USHRT_MAX
, "Time to say Good-Bye.." );
630 if( rInsPos
[ nCurrLine
] == USHRT_MAX
)
632 rInsPos
[ nCurrLine
] = nCurrBox
;
635 else if( ( rInsPos
[ nCurrLine
] > nCurrBox
) == !bBehind
)
636 rInsPos
[ nCurrLine
] = nCurrBox
;
643 /** SwTable::NewInsertCol(..) insert new column(s) into a table
653 the number of columns to insert
656 insertion behind (true) or before (false) the selected boxes
658 @return true, if any insertion has been done successfully
662 BOOL
SwTable::NewInsertCol( SwDoc
* pDoc
, const SwSelBoxes
& rBoxes
,
663 USHORT nCnt
, BOOL bBehind
)
665 if( !aLines
.Count() || !nCnt
)
669 long nNewBoxWidth
= 0;
670 std::vector
< USHORT
> aInsPos( aLines
.Count(), USHRT_MAX
);
671 { // Calculation of the insert positions and the width of the new boxes
672 sal_uInt64 nTableWidth
= 0;
673 for( USHORT i
= 0; i
< aLines
[0]->GetTabBoxes().Count(); ++i
)
674 nTableWidth
+= aLines
[0]->GetTabBoxes()[i
]->GetFrmFmt()->GetFrmSize().GetWidth();
676 // Fill the vector of insert positions and the (average) width to insert
677 sal_uInt64 nAddWidth
= lcl_InsertPosition( *this, aInsPos
, rBoxes
, bBehind
);
679 // Given is the (average) width of the selected boxes, if we would
680 // insert nCnt of columns the table would grow
681 // So we will shrink the table first, then insert the new boxes and
682 // get a table with the same width than before.
683 // But we will not shrink the table by the full already calculated value,
684 // we will reduce this value proportional to the old table width
685 nAddWidth
*= nCnt
; // we have to insert nCnt boxes per line
686 sal_uInt64 nResultingWidth
= nAddWidth
+ nTableWidth
;
687 if( !nResultingWidth
)
689 nAddWidth
= (nAddWidth
* nTableWidth
) / nResultingWidth
;
690 nNewBoxWidth
= long( nAddWidth
/ nCnt
); // Rounding
691 nAddWidth
= nNewBoxWidth
* nCnt
; // Rounding
692 if( !nAddWidth
|| nAddWidth
>= nTableWidth
)
694 AdjustWidths( static_cast< long >(nTableWidth
), static_cast< long >(nTableWidth
- nAddWidth
) );
697 _FndBox
aFndBox( 0, 0 );
698 aFndBox
.SetTableLines( rBoxes
, *this );
699 aFndBox
.DelFrms( *this );
700 // aFndBox.SaveChartData( *this );
702 SwTableNode
* pTblNd
= GetTableNode();
703 std::vector
<SwTableBoxFmt
*> aInsFormat( nCnt
, 0 );
704 USHORT nLastLine
= USHRT_MAX
;
705 long nLastRowSpan
= 1;
707 for( USHORT i
= 0; i
< aLines
.Count(); ++i
)
709 SwTableLine
* pLine
= aLines
[ i
];
710 USHORT nInsPos
= aInsPos
[i
];
711 ASSERT( nInsPos
!= USHRT_MAX
, "Didn't found insert position" );
712 SwTableBox
* pBox
= pLine
->GetTabBoxes()[ nInsPos
];
715 SwTableBoxFmt
* pBoxFrmFmt
= (SwTableBoxFmt
*)pBox
->GetFrmFmt();
716 ::_InsTblBox( pDoc
, pTblNd
, pLine
, pBoxFrmFmt
, pBox
, nInsPos
, nCnt
);
717 long nRowSpan
= pBox
->getRowSpan();
718 long nDiff
= i
- nLastLine
;
719 bool bNewSpan
= false;
720 if( nLastLine
!= USHRT_MAX
&& nDiff
<= nLastRowSpan
&&
721 nRowSpan
!= nDiff
- nLastRowSpan
)
724 while( nLastLine
< i
)
726 SwTableLine
* pTmpLine
= aLines
[ nLastLine
];
727 USHORT nTmpPos
= aInsPos
[nLastLine
];
730 for( USHORT j
= 0; j
< nCnt
; ++j
)
731 pTmpLine
->GetTabBoxes()[nTmpPos
+j
]->setRowSpan( nDiff
);
744 nLastRowSpan
= -nRowSpan
;
746 nLastRowSpan
= nRowSpan
;
748 const SvxBoxItem
& aSelBoxItem
= pBoxFrmFmt
->GetBox();
749 SvxBoxItem
* pNoRightBorder
= 0;
750 if( aSelBoxItem
.GetRight() )
752 pNoRightBorder
= new SvxBoxItem( aSelBoxItem
);
753 pNoRightBorder
->SetLine( 0, BOX_LINE_RIGHT
);
755 for( USHORT j
= 0; j
< nCnt
; ++j
)
757 SwTableBox
*pCurrBox
= pLine
->GetTabBoxes()[nInsPos
+j
];
760 pCurrBox
->setRowSpan( nLastRowSpan
);
761 SwFrmFmt
* pFrmFmt
= pCurrBox
->ClaimFrmFmt();
762 SwFmtFrmSize
aFrmSz( pFrmFmt
->GetFrmSize() );
763 aFrmSz
.SetWidth( nNewBoxWidth
);
764 pFrmFmt
->SetFmtAttr( aFrmSz
);
765 if( pNoRightBorder
&& ( !bBehind
|| j
+1 < nCnt
) )
766 pFrmFmt
->SetFmtAttr( *pNoRightBorder
);
767 aInsFormat
[j
] = (SwTableBoxFmt
*)pFrmFmt
;
770 pCurrBox
->ChgFrmFmt( aInsFormat
[j
] );
772 if( bBehind
&& pNoRightBorder
)
774 SwFrmFmt
* pFrmFmt
= pBox
->ClaimFrmFmt();
775 pFrmFmt
->SetFmtAttr( *pNoRightBorder
);
777 delete pNoRightBorder
;
780 aFndBox
.MakeFrms( *this );
781 // aFndBox.RestoreChartData( *this );
784 const SwTableBoxes
&rTabBoxes
= aLines
[0]->GetTabBoxes();
786 for( USHORT i
= 0; i
< rTabBoxes
.Count(); ++i
)
787 nNewWidth
+= rTabBoxes
[i
]->GetFrmFmt()->GetFrmSize().GetWidth();
788 ASSERT( nNewWidth
> 0, "Very small" );
796 /** SwTable::PrepareMerge(..) some preparation for the coming Merge(..)
798 For the old table model, ::GetMergeSel(..) is called only,
799 for the new table model, PrepareMerge does the main work.
800 It modifices all cells to merge (width, border, rowspan etc.) and collects
801 the cells which have to be deleted by Merge(..) afterwards.
802 If there are superfluous rows, these cells are put into the deletion list as well.
805 the selection to merge
808 should be empty at the beginning, at the end it is filled with boxes to delete.
811 will be set to the master cell box
814 the undo object to record all changes
815 can be Null, e.g. when called by Redo(..)
821 bool SwTable::PrepareMerge( const SwPaM
& rPam
, SwSelBoxes
& rBoxes
,
822 SwSelBoxes
& rMerged
, SwTableBox
** ppMergeBox
, SwUndoTblMerge
* pUndo
)
826 ::GetMergeSel( rPam
, rBoxes
, ppMergeBox
, pUndo
);
827 return rBoxes
.Count() > 1;
830 // We have to assert a "rectangular" box selection before we start to merge
831 std::auto_ptr
< SwBoxSelection
> pSel( CollectBoxSelection( rPam
) );
832 if( !pSel
.get() || pSel
->isEmpty() )
834 // Now we should have a rectangle of boxes,
835 // i.e. contiguous cells in contiguous rows
836 bool bMerge
= false; // will be set if any content is transferred from
837 // a "not already overlapped" cell into the new master cell.
838 SwTableBox
*pMergeBox
= (*pSel
->aBoxes
[0])[0]; // the master cell box
841 (*ppMergeBox
) = pMergeBox
;
842 // The new master box will get the left and the top border of the top-left
843 // box of the selection and because the new master cell _is_ the top-left
844 // box, the left and right border does not need to be changed.
845 // The right and bottom border instead has to be derived from the right-
846 // bottom box of the selection. If this is a overlapped cell,
847 // the appropiate master box.
848 SwTableBox
* pLastBox
= 0; // the right-bottom (master) cell
849 SwDoc
* pDoc
= GetFrmFmt()->GetDoc();
850 SwPosition
aInsPos( *pMergeBox
->GetSttNd()->EndOfSectionNode() );
851 SwPaM
aChkPam( aInsPos
);
852 // The number of lines in the selection rectangle: nLineCount
853 const USHORT nLineCount
= USHORT(pSel
->aBoxes
.size());
854 // BTW: nLineCount is the rowspan of the new master cell
855 long nRowSpan
= nLineCount
;
856 // We will need the first and last line of the selection
857 // to check if there any superfluous row after merging
858 SwTableLine
* pFirstLn
= 0;
859 SwTableLine
* pLastLn
= 0;
860 // Iteration over the lines of the selection...
861 for( USHORT nCurrLine
= 0; nCurrLine
< nLineCount
; ++nCurrLine
)
863 // The selected boxes in the current line
864 const SwSelBoxes
* pBoxes
= pSel
->aBoxes
[ nCurrLine
];
865 USHORT nColCount
= pBoxes
->Count();
866 // Iteration over the selected cell in the current row
867 for( USHORT nCurrCol
= 0; nCurrCol
< nColCount
; ++nCurrCol
)
869 SwTableBox
* pBox
= (*pBoxes
)[nCurrCol
];
870 rMerged
.Insert( pBox
);
871 // Only the first selected cell in every row will be alive,
872 // the other will be deleted => put into rBoxes
874 rBoxes
.Insert( pBox
);
878 pFirstLn
= pBox
->GetUpper(); // we need this line later on
879 if( nCurrLine
+ 1 == nLineCount
)
880 pLastLn
= pBox
->GetUpper(); // and this one, too.
882 // A box has to be merged if it's not the master box itself,
883 // but an already overlapped cell must not be merged as well.
884 bool bDoMerge
= pBox
!= pMergeBox
&& pBox
->getRowSpan() > 0;
885 // The last box has to be in the last "column" of the selection
886 // and it has to be a master cell
887 if( nCurrCol
+1 == nColCount
&& pBox
->getRowSpan() > 0 )
892 // If the cell to merge contains only one empty paragraph,
893 // we do not transfer this paragraph.
894 if( !IsEmptyBox( *pBox
, aChkPam
) )
896 SwNodeIndex
& rInsPosNd
= aInsPos
.nNode
;
897 SwPaM
aPam( aInsPos
);
898 aPam
.GetPoint()->nNode
.Assign( *pBox
->GetSttNd()->EndOfSectionNode(), -1 );
899 SwCntntNode
* pCNd
= aPam
.GetCntntNode();
900 USHORT nL
= pCNd
? pCNd
->Len() : 0;
901 aPam
.GetPoint()->nContent
.Assign( pCNd
, nL
);
902 SwNodeIndex
aSttNdIdx( *pBox
->GetSttNd(), 1 );
904 pDoc
->DoUndo( FALSE
);
905 pDoc
->AppendTxtNode( *aPam
.GetPoint() );
907 pDoc
->DoUndo( TRUE
);
908 SwNodeRange
aRg( aSttNdIdx
, aPam
.GetPoint()->nNode
);
910 pUndo
->MoveBoxCntnt( pDoc
, aRg
, rInsPosNd
);
913 pDoc
->MoveNodeRange( aRg
, rInsPosNd
,
914 IDocumentContentOperations::DOC_NO_DELFRMS
);
918 // Only the cell of the first selected column will stay alive
919 // and got a new row span
921 pBox
->setRowSpan( nRowSpan
);
923 if( nRowSpan
> 0 ) // the master cell is done, from now on we set
924 nRowSpan
= -nRowSpan
; // negative row spans
925 ++nRowSpan
; // ... -3, -2, -1
929 // A row containing overlapped cells is superfluous,
930 // these cells can be put into rBoxes for deletion
931 _FindSuperfluousRows( rBoxes
, pFirstLn
, pLastLn
);
932 // pNewFmt will be set to the new master box and the overlapped cells
933 SwFrmFmt
* pNewFmt
= pMergeBox
->ClaimFrmFmt();
934 pNewFmt
->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE
, pSel
->mnMergeWidth
, 0 ) );
935 for( USHORT nCurrLine
= 0; nCurrLine
< nLineCount
; ++nCurrLine
)
937 const SwSelBoxes
* pBoxes
= pSel
->aBoxes
[ nCurrLine
];
938 USHORT nColCount
= pBoxes
->Count();
939 for( USHORT nCurrCol
= 0; nCurrCol
< nColCount
; ++nCurrCol
)
941 SwTableBox
* pBox
= (*pBoxes
)[nCurrCol
];
944 // Even this box will be deleted soon,
945 // we have to correct the width to avoid side effects
946 SwFrmFmt
* pFmt
= pBox
->ClaimFrmFmt();
947 pFmt
->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE
, 0, 0 ) );
950 pBox
->ChgFrmFmt( (SwTableBoxFmt
*)pNewFmt
);
953 if( pLastBox
) // Robust
955 // The new borders of the master cell...
956 SvxBoxItem
aBox( pMergeBox
->GetFrmFmt()->GetBox() );
957 bool bOld
= aBox
.GetRight() || aBox
.GetBottom();
958 const SvxBoxItem
& rBox
= pLastBox
->GetFrmFmt()->GetBox();
959 aBox
.SetLine( rBox
.GetRight(), BOX_LINE_RIGHT
);
960 aBox
.SetLine( rBox
.GetBottom(), BOX_LINE_BOTTOM
);
961 if( bOld
|| aBox
.GetLeft() || aBox
.GetTop() || aBox
.GetRight() || aBox
.GetBottom() )
962 (*ppMergeBox
)->GetFrmFmt()->SetFmtAttr( aBox
);
966 pUndo
->AddNewBox( pMergeBox
->GetSttIdx() );
971 /** SwTable::_FindSuperfluousRows(..) is looking for superfluous rows, i.e. rows
972 containing overlapped cells only.
975 void SwTable::_FindSuperfluousRows( SwSelBoxes
& rBoxes
,
976 SwTableLine
* pFirstLn
, SwTableLine
* pLastLn
)
978 if( !pFirstLn
|| !pLastLn
)
980 if( !rBoxes
.Count() )
982 pFirstLn
= rBoxes
[0]->GetUpper();
983 pLastLn
= rBoxes
[ rBoxes
.Count() - 1 ]->GetUpper();
985 USHORT nFirstLn
= GetTabLines().C40_GETPOS(SwTableLine
, pFirstLn
);
986 USHORT nLastLn
= GetTabLines().C40_GETPOS(SwTableLine
, pLastLn
);
987 for( USHORT nRow
= nFirstLn
; nRow
<= nLastLn
; ++nRow
)
989 SwTableLine
* pLine
= aLines
[nRow
];
990 ASSERT( pLine
, "Missing table line" );
991 USHORT nCols
= pLine
->GetTabBoxes().Count();
992 bool bSuperfl
= true;
993 for( USHORT nCol
= 0; nCol
< nCols
; ++nCol
)
995 SwTableBox
*pBox
= pLine
->GetTabBoxes()[nCol
];
996 if( pBox
->getRowSpan() > 0 &&
997 USHRT_MAX
== rBoxes
.GetPos( pBox
) )
1005 for( USHORT nCol
= 0; nCol
< nCols
; ++nCol
)
1007 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCol
];
1008 rBoxes
.Insert( pBox
);
1014 /** SwTableBox::FindStartOfRowSpan(..) retruns the "master" cell, the cell which
1015 overlaps the given cell, it maybe the cell itself.
1018 SwTableBox
& SwTableBox::FindStartOfRowSpan( const SwTable
& rTable
, USHORT nMaxStep
)
1020 if( getRowSpan() > 0 || !nMaxStep
)
1023 long nLeftBorder
= lcl_Box2LeftBorder( *this );
1024 SwTableBox
* pBox
= this;
1025 const SwTableLine
* pMyUpper
= GetUpper();
1026 USHORT nLine
= rTable
.GetTabLines().C40_GETPOS(SwTableLine
, pMyUpper
);
1027 if( nLine
&& nLine
< rTable
.GetTabLines().Count() )
1032 pNext
= lcl_LeftBorder2Box( nLeftBorder
, rTable
.GetTabLines()[--nLine
] );
1035 } while( nLine
&& --nMaxStep
&& pNext
&& pBox
->getRowSpan() < 1 );
1041 /** SwTableBox::FindEndOfRowSpan(..) returns the last overlapped cell if there is
1042 any. Otherwise the cell itself will returned.
1045 SwTableBox
& SwTableBox::FindEndOfRowSpan( const SwTable
& rTable
, USHORT nMaxStep
)
1047 long nAbsSpan
= getRowSpan();
1049 nAbsSpan
= -nAbsSpan
;
1050 if( nAbsSpan
== 1 || !nMaxStep
)
1053 if( nMaxStep
> --nAbsSpan
)
1054 nMaxStep
= (USHORT
)nAbsSpan
;
1055 const SwTableLine
* pMyUpper
= GetUpper();
1056 USHORT nLine
= rTable
.GetTabLines().C40_GETPOS(SwTableLine
, pMyUpper
);
1057 nMaxStep
= nLine
+ nMaxStep
;
1058 if( nMaxStep
>= rTable
.GetTabLines().Count() )
1059 nMaxStep
= rTable
.GetTabLines().Count() - 1;
1060 long nLeftBorder
= lcl_Box2LeftBorder( *this );
1062 lcl_LeftBorder2Box( nLeftBorder
, rTable
.GetTabLines()[ nMaxStep
] );
1069 /** lcl_getAllMergedBoxes(..) collects all overlapped boxes to a given (master) box
1072 void lcl_getAllMergedBoxes( const SwTable
& rTable
, SwSelBoxes
& rBoxes
, SwTableBox
& rBox
)
1074 SwTableBox
* pBox
= &rBox
;
1075 ASSERT( pBox
== &rBox
.FindStartOfRowSpan( rTable
, USHRT_MAX
), "Not a master box" );
1076 rBoxes
.Insert( pBox
);
1077 if( pBox
->getRowSpan() == 1 )
1079 const SwTableLine
* pMyUpper
= pBox
->GetUpper();
1080 USHORT nLine
= rTable
.GetTabLines().C40_GETPOS(SwTableLine
, pMyUpper
);
1081 long nLeftBorder
= lcl_Box2LeftBorder( *pBox
);
1082 USHORT nCount
= rTable
.GetTabLines().Count();
1083 while( ++nLine
< nCount
&& pBox
&& pBox
->getRowSpan() != -1 )
1085 pBox
= lcl_LeftBorder2Box( nLeftBorder
, rTable
.GetTabLines()[nLine
] );
1087 rBoxes
.Insert( pBox
);
1091 /** lcl_UnMerge(..) manipulates the row span attribute of a given master cell
1092 and its overlapped cells to split them into several pieces.
1095 void lcl_UnMerge( const SwTable
& rTable
, SwTableBox
& rBox
, USHORT nCnt
,
1099 lcl_getAllMergedBoxes( rTable
, aBoxes
, rBox
);
1100 USHORT nCount
= aBoxes
.Count();
1105 USHORT
*pSplitIdx
= new USHORT
[ nCnt
];
1108 SwTwips
*pHeights
= new SwTwips
[ nCount
];
1109 SwTwips nHeight
= 0;
1110 for( USHORT i
= 0; i
< nCount
; ++i
)
1112 SwTableLine
* pLine
= aBoxes
[ i
]->GetUpper();
1113 SwFrmFmt
*pRowFmt
= pLine
->GetFrmFmt();
1114 pHeights
[ i
] = pRowFmt
->GetFrmSize().GetHeight();
1115 nHeight
+= pHeights
[ i
];
1119 for( USHORT i
= 1; i
<= nCnt
; ++i
)
1121 SwTwips nSplit
= ( i
* nHeight
) / nCnt
;
1122 while( nSumH
< nSplit
&& nIdx
< nCount
)
1123 nSumH
+= pHeights
[ nIdx
++ ];
1124 pSplitIdx
[ i
- 1 ] = nIdx
;
1130 for( long i
= 1; i
<= nCnt
; ++i
)
1131 pSplitIdx
[ i
- 1 ] = (USHORT
)( ( i
* nCount
) / nCnt
);
1134 for( long i
= 0; i
< nCnt
; ++i
)
1136 USHORT nNextIdx
= pSplitIdx
[ i
];
1137 aBoxes
[ nIdx
]->setRowSpan( nNextIdx
- nIdx
);
1138 lcl_InvalidateCellFrm( *aBoxes
[ nIdx
] );
1139 while( ++nIdx
< nNextIdx
)
1140 aBoxes
[ nIdx
]->setRowSpan( nIdx
- nNextIdx
);
1145 /** lcl_FillSelBoxes(..) puts all boxes of a given line into the selection structure
1148 void lcl_FillSelBoxes( SwSelBoxes
&rBoxes
, SwTableLine
&rLine
)
1150 USHORT nBoxCount
= rLine
.GetTabBoxes().Count();
1152 for( nCurrBox
= 0; nCurrBox
< nBoxCount
; ++nCurrBox
)
1153 rBoxes
.Insert( rLine
.GetTabBoxes()[nCurrBox
] );
1156 /** SwTable::InsertSpannedRow(..) inserts "superfluous" rows, i.e. rows containig
1157 overlapped cells only. This is a preparation for an upcoming split.
1160 void SwTable::InsertSpannedRow( SwDoc
* pDoc
, USHORT nRowIdx
, USHORT nCnt
)
1162 CHECK_TABLE( *this )
1163 ASSERT( nCnt
&& nRowIdx
< GetTabLines().Count(), "Wrong call of InsertSpannedRow" );
1165 SwTableLine
& rLine
= *GetTabLines()[ nRowIdx
];
1166 lcl_FillSelBoxes( aBoxes
, rLine
);
1167 SwFmtFrmSize
aFSz( rLine
.GetFrmFmt()->GetFrmSize() );
1168 if( ATT_VAR_SIZE
!= aFSz
.GetHeightSizeType() )
1170 SwFrmFmt
* pFrmFmt
= rLine
.ClaimFrmFmt();
1171 long nNewHeight
= aFSz
.GetHeight() / ( nCnt
+ 1 );
1174 aFSz
.SetHeight( nNewHeight
);
1175 pFrmFmt
->SetFmtAttr( aFSz
);
1177 _InsertRow( pDoc
, aBoxes
, nCnt
, TRUE
);
1178 USHORT nBoxCount
= rLine
.GetTabBoxes().Count();
1179 for( USHORT n
= 0; n
< nCnt
; ++n
)
1181 SwTableLine
*pNewLine
= GetTabLines()[ nRowIdx
+ nCnt
- n
];
1182 for( USHORT nCurrBox
= 0; nCurrBox
< nBoxCount
; ++nCurrBox
)
1184 long nRowSpan
= rLine
.GetTabBoxes()[nCurrBox
]->getRowSpan();
1186 nRowSpan
= - nRowSpan
;
1187 pNewLine
->GetTabBoxes()[ nCurrBox
]->setRowSpan( nRowSpan
- n
);
1190 lcl_ChangeRowSpan( *this, nCnt
, nRowIdx
, false );
1191 CHECK_TABLE( *this )
1194 typedef std::pair
< USHORT
, USHORT
> SwLineOffset
;
1195 typedef std::list
< SwLineOffset
> SwLineOffsetArray
;
1197 /******************************************************************************
1198 When a couple of table boxes has to be split,
1199 lcl_SophisticatedFillLineIndices delivers the information where and how many
1200 rows have to be inserted.
1202 rTable: the table to manipulate
1203 rBoxes: an array of boxes to split
1204 nCnt: how many parts are wanted
1206 rArr: a list of pairs ( line index, number of lines to insert )
1208 ******************************************************************************/
1210 void lcl_SophisticatedFillLineIndices( SwLineOffsetArray
&rArr
,
1211 const SwTable
& rTable
, const SwSelBoxes
& rBoxes
, USHORT nCnt
)
1213 std::list
< SwLineOffset
> aBoxes
;
1214 SwLineOffset
aLnOfs( USHRT_MAX
, USHRT_MAX
);
1215 for( USHORT i
= 0; i
< rBoxes
.Count(); ++i
)
1216 { // Collect all end line indices and the row spans
1217 const SwTableBox
&rBox
= rBoxes
[ i
]->FindStartOfRowSpan( rTable
);
1218 ASSERT( rBox
.getRowSpan() > 0, "Didn't I say 'StartOfRowSpan' ??" )
1219 if( nCnt
> rBox
.getRowSpan() )
1221 const SwTableLine
*pLine
= rBox
.GetUpper();
1222 const USHORT nEnd
= USHORT( rBox
.getRowSpan() +
1223 rTable
.GetTabLines().C40_GETPOS( SwTableLine
, pLine
) );
1224 // The next if statement is a small optimization
1225 if( aLnOfs
.first
!= nEnd
|| aLnOfs
.second
!= rBox
.getRowSpan() )
1227 aLnOfs
.first
= nEnd
; // ok, this is the line behind the box
1228 aLnOfs
.second
= USHORT( rBox
.getRowSpan() ); // the row span
1229 aBoxes
.insert( aBoxes
.end(), aLnOfs
);
1233 // As I said, I noted the line index _behind_ the last line of the boxes
1234 // in the resulting array the index has to be _on_ the line
1235 // nSum is to evaluate the wished value
1237 while( aBoxes
.size() )
1240 // Looking for the "smallest" line end with the smallest row span
1241 std::list
< SwLineOffset
>::iterator pCurr
= aBoxes
.begin();
1242 aLnOfs
= *pCurr
; // the line end and row span of the first box
1243 while( ++pCurr
!= aBoxes
.end() )
1245 if( aLnOfs
.first
> pCurr
->first
)
1246 { // Found a smaller line end
1247 aLnOfs
.first
= pCurr
->first
;
1248 aLnOfs
.second
= pCurr
->second
; // row span
1250 else if( aLnOfs
.first
== pCurr
->first
&&
1251 aLnOfs
.second
< pCurr
->second
)
1252 aLnOfs
.second
= pCurr
->second
; // Found a smaller row span
1254 ASSERT( aLnOfs
.second
< nCnt
, "Clean-up failed" )
1255 aLnOfs
.second
= nCnt
- aLnOfs
.second
; // the number of rows to insert
1256 rArr
.insert( rArr
.end(),
1257 SwLineOffset( aLnOfs
.first
- nSum
, aLnOfs
.second
) );
1258 // the correction has to be incremented because in the following
1259 // loops the line ends were manipulated
1260 nSum
= nSum
+ aLnOfs
.second
;
1262 pCurr
= aBoxes
.begin();
1263 while( pCurr
!= aBoxes
.end() )
1265 if( pCurr
->first
== aLnOfs
.first
)
1266 { // These boxes can be removed because the last insertion
1267 // of rows will expand their row span above the needed value
1268 std::list
< SwLineOffset
>::iterator pDel
= pCurr
;
1270 aBoxes
.erase( pDel
);
1274 bool bBefore
= ( pCurr
->first
- pCurr
->second
< aLnOfs
.first
);
1275 // Manipulation of the end line indices as if the rows are
1277 pCurr
->first
= pCurr
->first
+ aLnOfs
.second
;
1279 { // If the insertion is inside the box,
1280 // its row span has to be incremented
1281 pCurr
->second
= pCurr
->second
+ aLnOfs
.second
;
1282 if( pCurr
->second
>= nCnt
)
1283 { // if the row span is bigger than the split factor
1285 std::list
< SwLineOffset
>::iterator pDel
= pCurr
;
1287 aBoxes
.erase( pDel
);
1299 typedef std::set
< SwTwips
> SwSplitLines
;
1301 /** lcl_CalculateSplitLineHeights(..) delivers all y-positions where table rows have
1302 to be splitted to fulfill the requested "split same height"
1305 USHORT
lcl_CalculateSplitLineHeights( SwSplitLines
&rCurr
, SwSplitLines
&rNew
,
1306 const SwTable
& rTable
, const SwSelBoxes
& rBoxes
, USHORT nCnt
)
1310 std::list
< SwLineOffset
> aBoxes
;
1311 SwLineOffset
aLnOfs( USHRT_MAX
, USHRT_MAX
);
1312 USHORT nFirst
= USHRT_MAX
; // becomes the index of the first line
1313 USHORT nLast
= 0; // becomes the index of the last line of the splitting
1314 for( USHORT i
= 0; i
< rBoxes
.Count(); ++i
)
1315 { // Collect all pairs (start+end) of line indices to split
1316 const SwTableBox
&rBox
= rBoxes
[ i
]->FindStartOfRowSpan( rTable
);
1317 ASSERT( rBox
.getRowSpan() > 0, "Didn't I say 'StartOfRowSpan' ??" )
1318 const SwTableLine
*pLine
= rBox
.GetUpper();
1319 const USHORT nStart
= rTable
.GetTabLines().C40_GETPOS( SwTableLine
, pLine
);
1320 const USHORT nEnd
= USHORT( rBox
.getRowSpan() + nStart
- 1 );
1321 // The next if statement is a small optimization
1322 if( aLnOfs
.first
!= nStart
|| aLnOfs
.second
!= nEnd
)
1324 aLnOfs
.first
= nStart
;
1325 aLnOfs
.second
= nEnd
;
1326 aBoxes
.insert( aBoxes
.end(), aLnOfs
);
1327 if( nStart
< nFirst
)
1334 if( aBoxes
.empty() )
1336 SwTwips nHeight
= 0;
1337 SwTwips
* pLines
= new SwTwips
[ nLast
+ 1 - nFirst
];
1338 for( USHORT i
= nFirst
; i
<= nLast
; ++i
)
1340 bool bLayoutAvailable
= false;
1341 nHeight
+= rTable
.GetTabLines()[ i
]->GetTableLineHeight( bLayoutAvailable
);
1342 rCurr
.insert( rCurr
.end(), nHeight
);
1343 pLines
[ i
- nFirst
] = nHeight
;
1345 std::list
< SwLineOffset
>::iterator pSplit
= aBoxes
.begin();
1346 while( pSplit
!= aBoxes
.end() )
1348 SwTwips nBase
= pSplit
->first
<= nFirst
? 0 :
1349 pLines
[ pSplit
->first
- nFirst
- 1 ];
1350 SwTwips nDiff
= pLines
[ pSplit
->second
- nFirst
] - nBase
;
1351 for( USHORT i
= 1; i
< nCnt
; ++i
)
1353 SwTwips nSplit
= nBase
+ ( i
* nDiff
) / nCnt
;
1354 rNew
.insert( nSplit
);
1362 /** lcl_LineIndex(..) delivers the line index of the line behind or above
1366 USHORT
lcl_LineIndex( const SwTable
& rTable
, const SwSelBoxes
& rBoxes
,
1369 USHORT nDirect
= USHRT_MAX
;
1370 USHORT nSpan
= USHRT_MAX
;
1371 for( USHORT i
= 0; i
< rBoxes
.Count(); ++i
)
1373 SwTableBox
*pBox
= rBoxes
[i
];
1374 const SwTableLine
* pLine
= rBoxes
[i
]->GetUpper();
1375 USHORT nPos
= rTable
.GetTabLines().C40_GETPOS( SwTableLine
, pLine
);
1376 if( USHRT_MAX
!= nPos
)
1380 if( nPos
> nDirect
|| nDirect
== USHRT_MAX
)
1382 long nRowSpan
= pBox
->getRowSpan();
1387 USHORT nEndOfRowSpan
= (USHORT
)(nPos
+ nRowSpan
- 1);
1388 if( nEndOfRowSpan
> nSpan
|| nSpan
== USHRT_MAX
)
1389 nSpan
= nEndOfRowSpan
;
1392 else if( nPos
< nDirect
)
1396 if( nSpan
&& nSpan
< USHRT_MAX
)
1401 /** SwTable::NewSplitRow(..) splits all selected boxes horizontally.
1404 BOOL
SwTable::NewSplitRow( SwDoc
* pDoc
, const SwSelBoxes
& rBoxes
, USHORT nCnt
,
1407 CHECK_TABLE( *this )
1409 _FndBox
aFndBox( 0, 0 );
1410 aFndBox
.SetTableLines( rBoxes
, *this );
1412 if( bSameHeight
&& pDoc
->GetRootFrm() )
1414 SwSplitLines aRowLines
;
1415 SwSplitLines aSplitLines
;
1416 USHORT nFirst
= lcl_CalculateSplitLineHeights( aRowLines
, aSplitLines
,
1417 *this, rBoxes
, nCnt
);
1418 aFndBox
.DelFrms( *this );
1420 SwSplitLines::iterator pSplit
= aSplitLines
.begin();
1421 SwSplitLines::iterator pCurr
= aRowLines
.begin();
1422 while( pCurr
!= aRowLines
.end() )
1424 while( pSplit
!= aSplitLines
.end() && *pSplit
< *pCurr
)
1426 InsertSpannedRow( pDoc
, nFirst
, 1 );
1427 SwTableLine
* pRow
= GetTabLines()[ nFirst
];
1428 SwFrmFmt
* pRowFmt
= pRow
->ClaimFrmFmt();
1429 SwFmtFrmSize
aFSz( pRowFmt
->GetFrmSize() );
1430 aFSz
.SetHeightSizeType( ATT_MIN_SIZE
);
1431 aFSz
.SetHeight( *pSplit
- nLast
);
1432 pRowFmt
->SetFmtAttr( aFSz
);
1437 if( pSplit
!= aSplitLines
.end() && *pCurr
== *pSplit
)
1439 SwTableLine
* pRow
= GetTabLines()[ nFirst
];
1440 SwFrmFmt
* pRowFmt
= pRow
->ClaimFrmFmt();
1441 SwFmtFrmSize
aFSz( pRowFmt
->GetFrmSize() );
1442 aFSz
.SetHeightSizeType( ATT_MIN_SIZE
);
1443 aFSz
.SetHeight( *pCurr
- nLast
);
1444 pRowFmt
->SetFmtAttr( aFSz
);
1452 aFndBox
.DelFrms( *this );
1453 bSameHeight
= FALSE
;
1457 SwLineOffsetArray aLineOffs
;
1458 lcl_SophisticatedFillLineIndices( aLineOffs
, *this, rBoxes
, nCnt
);
1459 SwLineOffsetArray::reverse_iterator
pCurr( aLineOffs
.rbegin() );
1460 while( pCurr
!= aLineOffs
.rend() )
1462 InsertSpannedRow( pDoc
, pCurr
->first
, pCurr
->second
);
1467 std::set
< USHORT
> aIndices
;
1468 for( USHORT i
= 0; i
< rBoxes
.Count(); ++i
)
1470 ASSERT( rBoxes
[i
]->getRowSpan() != 1, "Forgot to split?" )
1471 if( rBoxes
[i
]->getRowSpan() > 1 )
1472 aIndices
.insert( i
);
1475 std::set
< USHORT
>::iterator pCurrBox
= aIndices
.begin();
1476 while( pCurrBox
!= aIndices
.end() )
1477 lcl_UnMerge( *this, *rBoxes
[*pCurrBox
++], nCnt
, bSameHeight
);
1479 CHECK_TABLE( *this )
1481 aFndBox
.MakeFrms( *this );
1486 /** SwTable::InsertRow(..) inserts one or more rows before or behind the selected
1490 BOOL
SwTable::InsertRow( SwDoc
* pDoc
, const SwSelBoxes
& rBoxes
,
1491 USHORT nCnt
, BOOL bBehind
)
1496 CHECK_TABLE( *this )
1497 USHORT nRowIdx
= lcl_LineIndex( *this, rBoxes
, bBehind
);
1498 if( nRowIdx
< USHRT_MAX
)
1500 _FndBox
aFndBox( 0, 0 );
1501 aFndBox
.SetTableLines( rBoxes
, *this );
1502 aFndBox
.DelFrms( *this );
1503 // aFndBox.SaveChartData( *this );
1506 SwTableLine
*pLine
= GetTabLines()[ nRowIdx
];
1507 SwSelBoxes aLineBoxes
;
1508 lcl_FillSelBoxes( aLineBoxes
, *pLine
);
1509 _InsertRow( pDoc
, aLineBoxes
, nCnt
, bBehind
);
1510 USHORT nBoxCount
= pLine
->GetTabBoxes().Count();
1511 USHORT nOfs
= bBehind
? 0 : 1;
1512 for( USHORT n
= 0; n
< nCnt
; ++n
)
1514 SwTableLine
*pNewLine
= GetTabLines()[ nRowIdx
+nCnt
-n
-nOfs
];
1515 for( USHORT nCurrBox
= 0; nCurrBox
< nBoxCount
; ++nCurrBox
)
1517 long nRowSpan
= pLine
->GetTabBoxes()[nCurrBox
]->getRowSpan();
1520 if( nRowSpan
== 1 || nRowSpan
== -1 )
1522 else if( nRowSpan
> 1 )
1523 nRowSpan
= - nRowSpan
;
1532 pNewLine
->GetTabBoxes()[ nCurrBox
]->setRowSpan( nRowSpan
- n
);
1538 lcl_ChangeRowSpan( *this, nCnt
, --nRowIdx
, true );
1540 aFndBox
.MakeFrms( *this );
1541 // aFndBox.RestoreChartData( *this );
1543 CHECK_TABLE( *this )
1546 bRet
= _InsertRow( pDoc
, rBoxes
, nCnt
, bBehind
);
1550 /** SwTable::PrepareDelBoxes(..) adjusts the row span attributes for an upcoming
1551 deletion of table cells and invalidates the layout of these cells.
1554 void SwTable::PrepareDelBoxes( const SwSelBoxes
& rBoxes
)
1558 for( USHORT i
= 0; i
< rBoxes
.Count(); ++i
)
1560 SwTableBox
* pBox
= rBoxes
[i
];
1561 long nRowSpan
= pBox
->getRowSpan();
1562 if( nRowSpan
!= 1 && pBox
->GetFrmFmt()->GetFrmSize().GetWidth() )
1564 long nLeft
= lcl_Box2LeftBorder( *pBox
);
1565 SwTableLine
*pLine
= pBox
->GetUpper();
1566 USHORT nLinePos
= GetTabLines().C40_GETPOS(SwTableLine
, pLine
);
1567 ASSERT( nLinePos
< USHRT_MAX
, "Box/table mismatch" )
1570 if( ++nLinePos
< GetTabLines().Count() )
1572 pLine
= GetTabLines()[ nLinePos
];
1573 pBox
= lcl_LeftBorder2Box( nLeft
, pLine
);
1574 ASSERT( pBox
, "RowSpan irritation I" )
1576 pBox
->setRowSpan( --nRowSpan
);
1579 else if( nLinePos
> 0 )
1583 pLine
= GetTabLines()[ --nLinePos
];
1584 pBox
= lcl_LeftBorder2Box( nLeft
, pLine
);
1585 ASSERT( pBox
, "RowSpan irritation II" )
1588 nRowSpan
= pBox
->getRowSpan();
1591 lcl_InvalidateCellFrm( *pBox
);
1596 pBox
->setRowSpan( nRowSpan
);
1601 while( nRowSpan
< 0 && nLinePos
> 0 );
1608 /** lcl_SearchSelBox(..) adds cells of a given table row to the selection structure
1609 if it overlaps with the given x-position range
1612 void lcl_SearchSelBox( const SwTable
&rTable
, SwSelBoxes
& rBoxes
, long nMin
, long nMax
,
1613 SwTableLine
& rLine
, bool bChkProtected
, bool bColumn
)
1617 long nMid
= ( nMax
+ nMin
)/ 2;
1618 USHORT nCount
= rLine
.GetTabBoxes().Count();
1619 for( USHORT nCurrBox
= 0; nCurrBox
< nCount
; ++nCurrBox
)
1621 SwTableBox
* pBox
= rLine
.GetTabBoxes()[nCurrBox
];
1622 ASSERT( pBox
, "Missing table box" );
1623 long nWidth
= pBox
->GetFrmFmt()->GetFrmSize().GetWidth();
1628 if( nRight
<= nMax
)
1629 bAdd
= nLeft
>= nMin
|| nRight
>= nMid
||
1630 nRight
- nMin
> nMin
- nLeft
;
1632 bAdd
= nLeft
<= nMid
|| nRight
- nMax
< nMax
- nLeft
;
1633 long nRowSpan
= pBox
->getRowSpan();
1635 //( bColumn || nRowSpan > 0 ) &&
1637 !pBox
->GetFrmFmt()->GetProtect().IsCntntProtected() ) )
1639 USHORT nOldCnt
= rBoxes
.Count();
1640 rBoxes
.Insert( pBox
);
1641 if( bColumn
&& nRowSpan
!= 1 && nOldCnt
< rBoxes
.Count() )
1643 SwTableBox
*pMasterBox
= pBox
->getRowSpan() > 0 ? pBox
1644 : &pBox
->FindStartOfRowSpan( rTable
, USHRT_MAX
);
1645 lcl_getAllMergedBoxes( rTable
, rBoxes
, *pMasterBox
);
1649 if( nRight
>= nMax
)
1655 /** void SwTable::CreateSelection(..) fills the selection structure with table cells
1656 for a given SwPaM, ie. start and end position inside a table
1659 void SwTable::CreateSelection( const SwPaM
& rPam
, SwSelBoxes
& rBoxes
,
1660 const SearchType eSearch
, bool bChkProtected
) const
1662 ASSERT( bNewModel
, "Don't call me for old tables" );
1663 if( !aLines
.Count() )
1665 const SwNode
* pStartNd
= rPam
.GetPoint()->nNode
.GetNode().FindTableBoxStartNode();
1666 const SwNode
* pEndNd
= rPam
.GetMark()->nNode
.GetNode().FindTableBoxStartNode();
1667 if( !pStartNd
|| !pEndNd
)
1669 CreateSelection( pStartNd
, pEndNd
, rBoxes
, eSearch
, bChkProtected
);
1672 /** void SwTable::CreateSelection(..) fills the selection structure with table cells
1673 for given start and end nodes inside a table
1675 void SwTable::CreateSelection( const SwNode
* pStartNd
, const SwNode
* pEndNd
,
1676 SwSelBoxes
& rBoxes
, const SearchType eSearch
, bool bChkProtected
) const
1678 // SwSelBoxes aKeepBoxes;
1679 if( rBoxes
.Count() )
1681 // aKeepBoxes.Insert( &rBoxes );
1682 rBoxes
.Remove( USHORT(0), rBoxes
.Count() );
1684 // Looking for start and end of the selection given by SwNode-pointer
1685 USHORT nLines
= aLines
.Count();
1686 // nTop becomes the line number of the upper box
1687 // nBottom becomes the line number of the lower box
1688 USHORT nTop
= 0, nBottom
= 0;
1689 // nUpperMin becomes the left border value of the upper box
1690 // nUpperMax becomes the right border of the upper box
1691 // nLowerMin and nLowerMax the borders of the lower box
1692 long nUpperMin
= 0, nUpperMax
= 0;
1693 long nLowerMin
= 0, nLowerMax
= 0;
1694 // nFound will incremented if a box is found
1695 // 0 => no box found; 1 => the upper box has been found; 2 => both found
1697 for( USHORT nRow
= 0; nFound
< 2 && nRow
< nLines
; ++nRow
)
1699 SwTableLine
* pLine
= aLines
[nRow
];
1700 ASSERT( pLine
, "Missing table line" );
1701 USHORT nCols
= pLine
->GetTabBoxes().Count();
1702 for( USHORT nCol
= 0; nCol
< nCols
; ++nCol
)
1704 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCol
];
1705 ASSERT( pBox
, "Missing table box" );
1706 if( pBox
->GetSttNd() == pEndNd
|| pBox
->GetSttNd() == pStartNd
)
1708 if( !bChkProtected
||
1709 !pBox
->GetFrmFmt()->GetProtect().IsCntntProtected() )
1710 rBoxes
.Insert( pBox
);
1714 lcl_CheckMinMax( nLowerMin
, nLowerMax
, *pLine
, nCol
, true );
1721 lcl_CheckMinMax( nUpperMin
, nUpperMax
, *pLine
, nCol
, true );
1723 // If start and end node are identical, we're nearly done..
1724 if( pEndNd
== pStartNd
)
1727 nLowerMin
= nUpperMin
;
1728 nLowerMax
= nUpperMax
;
1736 return; // At least one node was not a part of the given table
1737 if( eSearch
== SEARCH_ROW
)
1739 // Selection of a row is quiet easy:
1740 // every (unprotected) box between start and end line
1741 // with a positive row span will be collected
1742 for( USHORT nRow
= nTop
; nRow
<= nBottom
; ++nRow
)
1744 SwTableLine
* pLine
= aLines
[nRow
];
1745 ASSERT( pLine
, "Missing table line" );
1746 USHORT nCount
= pLine
->GetTabBoxes().Count();
1747 for( USHORT nCurrBox
= 0; nCurrBox
< nCount
; ++nCurrBox
)
1749 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCurrBox
];
1750 ASSERT( pBox
, "Missing table box" );
1751 if( pBox
->getRowSpan() > 0 && ( !bChkProtected
||
1752 !pBox
->GetFrmFmt()->GetProtect().IsCntntProtected() ) )
1753 rBoxes
.Insert( pBox
);
1758 bool bCombine
= nTop
== nBottom
;
1761 long nMinWidth
= nUpperMax
- nUpperMin
;
1762 long nTmp
= nLowerMax
- nLowerMin
;
1763 if( nMinWidth
> nTmp
)
1765 nTmp
= nLowerMax
< nUpperMax
? nLowerMax
: nUpperMax
;
1766 nTmp
-= ( nLowerMin
< nUpperMin
) ? nUpperMin
: nLowerMin
;
1767 // If the overlapping between upper and lower box is less than half
1768 // of the width (of the smaller cell), bCombine is set,
1769 // e.g. if upper and lower cell are in different columns
1770 bCombine
= ( nTmp
+ nTmp
< nMinWidth
);
1774 if( nUpperMin
< nLowerMin
)
1775 nLowerMin
= nUpperMin
;
1777 nUpperMin
= nLowerMin
;
1778 if( nUpperMax
> nLowerMax
)
1779 nLowerMax
= nUpperMax
;
1781 nUpperMax
= nLowerMax
;
1783 const bool bColumn
= eSearch
== SEARCH_COL
;
1786 for( USHORT i
= 0; i
< nTop
; ++i
)
1787 lcl_SearchSelBox( *this, rBoxes
, nUpperMin
, nUpperMax
,
1788 *aLines
[i
], bChkProtected
, bColumn
);
1792 long nMin
= nUpperMin
< nLowerMin
? nUpperMin
: nLowerMin
;
1793 long nMax
= nUpperMax
< nLowerMax
? nLowerMax
: nUpperMax
;
1794 for( USHORT i
= nTop
; i
<= nBottom
; ++i
)
1795 lcl_SearchSelBox( *this, rBoxes
, nMin
, nMax
, *aLines
[i
],
1796 bChkProtected
, bColumn
);
1798 /* if( nTop + 1 < nBottom )
1800 long nInnerMin = nUpperMin < nLowerMin ? nLowerMin : nUpperMin;
1801 long nInnerMax = nUpperMax < nLowerMax ? nUpperMax : nLowerMax;
1802 for( USHORT i = nTop + 1; i < nBottom; ++i )
1803 lcl_SearchSelBox( *this, rBoxes, nInnerMin, nInnerMax, *aLines[i],
1804 bChkProtected, bColumn );
1806 if( bCombine ) // => nUpperMin == nLowerMin, nUpperMax == nLowerMax
1808 if( nBottom > nTop )
1809 lcl_SearchSelBox( *this, rBoxes, nUpperMin, nUpperMax, *aLines[nTop],
1810 bChkProtected, bColumn );
1811 lcl_SearchSelBox( *this, rBoxes, nLowerMin, nLowerMax, *aLines[nBottom],
1812 bChkProtected, bColumn );
1814 else if( aKeepBoxes.Count() )
1816 long nMin = nUpperMin < nLowerMin ? nUpperMin : nLowerMin;
1817 long nMax = nUpperMax < nLowerMax ? nLowerMax : nUpperMax;
1818 SwSelBoxes aCandidates;
1819 for( USHORT i = nTop; i <= nBottom; ++i )
1820 lcl_SearchSelBox( *this, aCandidates, nMin, nMax, *aLines[i],
1821 bChkProtected, bColumn );
1822 USHORT nOld = 0, nNew = 0;
1823 while ( nOld < aKeepBoxes.Count() && nNew < aCandidates.Count() )
1825 const SwTableBox* pPOld = *( aKeepBoxes.GetData() + nOld );
1826 SwTableBox* pPNew = *( aCandidates.GetData() + nNew );
1827 if( pPOld == pPNew )
1828 { // this box will stay
1829 rBoxes.Insert( pPNew );
1833 else if( pPOld->GetSttIdx() < pPNew->GetSttIdx() )
1841 for( USHORT i
= nBottom
+ 1; i
< nLines
; ++i
)
1842 lcl_SearchSelBox( *this, rBoxes
, nLowerMin
, nLowerMax
, *aLines
[i
],
1843 bChkProtected
, true );
1847 /** void SwTable::ExpandColumnSelection(..) adds cell to the give selection to
1848 assure that at least one cell of every row is part of the selection.
1851 void SwTable::ExpandColumnSelection( SwSelBoxes
& rBoxes
, long &rMin
, long &rMax
) const
1853 ASSERT( bNewModel
, "Don't call me for old tables" );
1856 if( !aLines
.Count() || !rBoxes
.Count() )
1859 USHORT nLineCnt
= aLines
.Count();
1860 USHORT nBoxCnt
= rBoxes
.Count();
1862 for( USHORT nRow
= 0; nRow
< nLineCnt
&& nBox
< nBoxCnt
; ++nRow
)
1864 SwTableLine
* pLine
= aLines
[nRow
];
1865 ASSERT( pLine
, "Missing table line" );
1866 USHORT nCols
= pLine
->GetTabBoxes().Count();
1867 for( USHORT nCol
= 0; nCol
< nCols
; ++nCol
)
1869 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCol
];
1870 ASSERT( pBox
, "Missing table box" );
1871 if( pBox
== rBoxes
[nBox
] )
1873 lcl_CheckMinMax( rMin
, rMax
, *pLine
, nCol
, nBox
== 0 );
1874 if( ++nBox
>= nBoxCnt
)
1880 for( USHORT nRow
= 0; nRow
< nLineCnt
; ++nRow
)
1882 SwTableLine
* pLine
= aLines
[nRow
];
1883 USHORT nCols
= pLine
->GetTabBoxes().Count();
1886 for( USHORT nCurrBox
= 0; nCurrBox
< nCols
; ++nCurrBox
)
1889 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCurrBox
];
1890 nRight
+= pBox
->GetFrmFmt()->GetFrmSize().GetWidth();
1891 if( nLeft
>= rMin
&& nRight
<= rMax
)
1892 rBoxes
.Insert( pBox
);
1897 /** SwTable::PrepareDeleteCol(..) adjusts the widths of the neighbour cells of
1898 a cell selection for an upcoming (column) deletion
1900 void SwTable::PrepareDeleteCol( long nMin
, long nMax
)
1902 ASSERT( bNewModel
, "Don't call me for old tables" );
1903 if( !aLines
.Count() || nMax
< nMin
)
1905 long nMid
= nMin
? ( nMin
+ nMax
) / 2 : 0;
1906 const SwTwips nTabSize
= GetFrmFmt()->GetFrmSize().GetWidth();
1907 if( nTabSize
== nMax
)
1909 USHORT nLineCnt
= aLines
.Count();
1910 for( USHORT nRow
= 0; nRow
< nLineCnt
; ++nRow
)
1912 SwTableLine
* pLine
= aLines
[nRow
];
1913 USHORT nCols
= pLine
->GetTabBoxes().Count();
1916 for( USHORT nCurrBox
= 0; nCurrBox
< nCols
; ++nCurrBox
)
1919 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCurrBox
];
1920 nRight
+= pBox
->GetFrmFmt()->GetFrmSize().GetWidth();
1925 long nNewWidth
= -1;
1928 if( nRight
<= nMax
)
1929 nNewWidth
= nMid
- nLeft
;
1931 else if( nRight
> nMax
)
1932 nNewWidth
= nRight
- nMid
;
1935 if( nNewWidth
>= 0 )
1937 SwFrmFmt
* pFrmFmt
= pBox
->ClaimFrmFmt();
1938 SwFmtFrmSize
aFrmSz( pFrmFmt
->GetFrmSize() );
1939 aFrmSz
.SetWidth( nNewWidth
);
1940 pFrmFmt
->SetFmtAttr( aFrmSz
);
1948 /** SwTable::ExpandSelection(..) adds all boxes to the box selections which are
1952 void SwTable::ExpandSelection( SwSelBoxes
& rBoxes
) const
1954 for( USHORT i
= 0; i
< rBoxes
.Count(); ++i
)
1956 SwTableBox
*pBox
= rBoxes
[i
];
1957 long nRowSpan
= pBox
->getRowSpan();
1960 SwTableBox
*pMasterBox
= nRowSpan
> 0 ? pBox
1961 : &pBox
->FindStartOfRowSpan( *this, USHRT_MAX
);
1962 lcl_getAllMergedBoxes( *this, rBoxes
, *pMasterBox
);
1967 /** SwTable::CheckRowSpan(..) looks for the next line without an overlapping to
1971 void SwTable::CheckRowSpan( SwTableLinePtr
&rpLine
, bool bUp
) const
1973 ASSERT( IsNewModel(), "Don't call me for old tables" );
1974 USHORT nLineIdx
= GetTabLines().C40_GETPOS( SwTableLine
, rpLine
);
1975 ASSERT( nLineIdx
< GetTabLines().Count(), "Start line out of range" );
1976 bool bChange
= true;
1982 rpLine
= GetTabLines()[ nLineIdx
];
1983 USHORT nCols
= rpLine
->GetTabBoxes().Count();
1984 for( USHORT nCol
= 0; !bChange
&& nCol
< nCols
; ++nCol
)
1986 SwTableBox
* pBox
= rpLine
->GetTabBoxes()[nCol
];
1987 if( pBox
->getRowSpan() > 1 || pBox
->getRowSpan() < -1 )
2004 USHORT nMaxLine
= GetTabLines().Count();
2008 rpLine
= GetTabLines()[ nLineIdx
];
2009 USHORT nCols
= rpLine
->GetTabBoxes().Count();
2010 for( USHORT nCol
= 0; !bChange
&& nCol
< nCols
; ++nCol
)
2012 SwTableBox
* pBox
= rpLine
->GetTabBoxes()[nCol
];
2013 if( pBox
->getRowSpan() < 0 )
2019 if( nLineIdx
>= nMaxLine
)
2029 // This structure corrects the row span attributes for a top line of a table
2030 // In a top line no negative row span is allowed, so these have to be corrected.
2031 // If there has been at least one correction, all values are stored
2032 // and can be used by undo of table split
2033 SwSaveRowSpan::SwSaveRowSpan( SwTableBoxes
& rBoxes
, USHORT nSplitLn
)
2034 : mnSplitLine( nSplitLn
)
2036 bool bDontSave
= true; // nothing changed, nothing to save
2037 USHORT nColCount
= rBoxes
.Count();
2038 ASSERT( nColCount
, "Empty Table Line" )
2039 mnRowSpans
.resize( nColCount
);
2040 for( USHORT nCurrCol
= 0; nCurrCol
< nColCount
; ++nCurrCol
)
2042 SwTableBox
* pBox
= rBoxes
[nCurrCol
];
2043 ASSERT( pBox
, "Missing Table Box" );
2044 long nRowSp
= pBox
->getRowSpan();
2045 mnRowSpans
[ nCurrCol
] = nRowSp
;
2050 pBox
->setRowSpan( nRowSp
); // correction needed
2057 // This function is called by undo of table split to restore the old row span
2058 // values at the split line
2059 void SwTable::RestoreRowSpan( const SwSaveRowSpan
& rSave
)
2061 if( !IsNewModel() ) // for new model only
2063 USHORT nLineCount
= GetTabLines().Count();
2064 ASSERT( rSave
.mnSplitLine
< nLineCount
, "Restore behind last line?" )
2065 if( rSave
.mnSplitLine
< nLineCount
)
2067 SwTableLine
* pLine
= GetTabLines()[rSave
.mnSplitLine
];
2068 USHORT nColCount
= pLine
->GetTabBoxes().Count();
2069 ASSERT( nColCount
, "Empty Table Line" )
2070 ASSERT( nColCount
== rSave
.mnRowSpans
.size(), "Wrong row span store" )
2071 if( nColCount
== rSave
.mnRowSpans
.size() )
2073 for( USHORT nCurrCol
= 0; nCurrCol
< nColCount
; ++nCurrCol
)
2075 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCurrCol
];
2076 ASSERT( pBox
, "Missing Table Box" );
2077 long nRowSp
= pBox
->getRowSpan();
2078 if( nRowSp
!= rSave
.mnRowSpans
[ nCurrCol
] )
2080 ASSERT( -nRowSp
== rSave
.mnRowSpans
[ nCurrCol
], "Pardon me?!" )
2081 ASSERT( rSave
.mnRowSpans
[ nCurrCol
] < 0, "Pardon me?!" )
2082 pBox
->setRowSpan( -nRowSp
);
2084 USHORT nLine
= rSave
.mnSplitLine
;
2087 long nLeftBorder
= lcl_Box2LeftBorder( *pBox
);
2091 pNext
= lcl_LeftBorder2Box( nLeftBorder
, GetTabLines()[--nLine
] );
2095 long nNewSpan
= pBox
->getRowSpan();
2096 if( pBox
->getRowSpan() < 1 )
2103 pBox
->setRowSpan( nNewSpan
);
2105 } while( nLine
&& pNext
);
2113 SwSaveRowSpan
* SwTable::CleanUpTopRowSpan( USHORT nSplitLine
)
2115 SwSaveRowSpan
* pRet
= 0;
2118 pRet
= new SwSaveRowSpan( GetTabLines()[0]->GetTabBoxes(), nSplitLine
);
2119 if( pRet
->mnRowSpans
.size() == 0 )
2127 void SwTable::CleanUpBottomRowSpan( USHORT nDelLines
)
2131 USHORT nLastLine
= GetTabLines().Count()-1;
2132 SwTableLine
* pLine
= GetTabLines()[nLastLine
];
2133 USHORT nColCount
= pLine
->GetTabBoxes().Count();
2134 ASSERT( nColCount
, "Empty Table Line" )
2135 for( USHORT nCurrCol
= 0; nCurrCol
< nColCount
; ++nCurrCol
)
2137 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCurrCol
];
2138 ASSERT( pBox
, "Missing Table Box" );
2139 long nRowSp
= pBox
->getRowSpan();
2144 lcl_ChangeRowSpan( *this, -static_cast<long>(nDelLines
), nLastLine
, false );
2159 void SwTable::CheckConsistency() const
2163 USHORT nLineCount
= GetTabLines().Count();
2164 const SwTwips nTabSize
= GetFrmFmt()->GetFrmSize().GetWidth();
2165 SwTwips nLineWidth
= 0;
2166 std::list
< RowSpanCheck
> aRowSpanCells
;
2167 std::list
< RowSpanCheck
>::iterator aIter
= aRowSpanCells
.end();
2168 for( USHORT nCurrLine
= 0; nCurrLine
< nLineCount
; ++nCurrLine
)
2171 SwTableLine
* pLine
= GetTabLines()[nCurrLine
];
2172 ASSERT( pLine
, "Missing Table Line" )
2173 USHORT nColCount
= pLine
->GetTabBoxes().Count();
2174 ASSERT( nColCount
, "Empty Table Line" )
2175 for( USHORT nCurrCol
= 0; nCurrCol
< nColCount
; ++nCurrCol
)
2177 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCurrCol
];
2178 ASSERT( pBox
, "Missing Table Box" );
2179 SwTwips nNewWidth
= pBox
->GetFrmFmt()->GetFrmSize().GetWidth() + nWidth
;
2180 long nRowSp
= pBox
->getRowSpan();
2183 ASSERT( aIter
!= aRowSpanCells
.end(), "Missing master box" )
2185 //RowSpanCheck &rCheck = *aIter;
2187 ASSERT( aIter
->nLeft
== nWidth
&& aIter
->nRight
== nNewWidth
,
2188 "Wrong position/size of overlapped table box" );
2189 --(aIter
->nRowSpan
);
2190 ASSERT( aIter
->nRowSpan
== -nRowSp
, "Wrong row span value" );
2193 std::list
< RowSpanCheck
>::iterator aEraseIter
= aIter
;
2195 aRowSpanCells
.erase( aEraseIter
);
2200 else if( nRowSp
!= 1 )
2202 ASSERT( nRowSp
, "Zero row span?!" );
2203 RowSpanCheck aEntry
;
2204 aEntry
.nLeft
= nWidth
;
2205 aEntry
.nRight
= nNewWidth
;
2206 aEntry
.nRowSpan
= nRowSp
;
2207 aRowSpanCells
.insert( aIter
, aEntry
);
2212 nLineWidth
= nWidth
;
2213 ASSERT( nWidth
== nLineWidth
, "Different Line Widths" )
2214 ASSERT( nWidth
== nTabSize
, "Boxen der Line zu klein/gross" )
2215 ASSERT( nWidth
>= 0 && nWidth
<= USHRT_MAX
, "Width out of range" )
2216 ASSERT( aIter
== aRowSpanCells
.end(), "Missing overlapped box" )
2217 aIter
= aRowSpanCells
.begin();
2219 bool bEmpty
= aRowSpanCells
.empty();
2220 ASSERT( bEmpty
, "Open row span detected" )
2226 #ifdef FINDSTARTENDOFROWSPANCACHE
2228 * A small optimization for FindStartEndOfRowSpan START
2230 * NOTE: Results of some measurement revealed that this cache
2231 * does not improve performance!
2234 class SwFindRowSpanCache
2238 struct SwFindRowSpanCacheObj
2240 const SwTableBox
* mpKeyBox
;
2241 const SwTableBox
* mpCacheBox
;
2245 SwFindRowSpanCacheObj( const SwTableBox
& rKeyBox
, const SwTableBox
& rCacheBox
, USHORT nSteps
, bool bStart
) :
2246 mpKeyBox( &rKeyBox
), mpCacheBox( &rCacheBox
), mnSteps( nSteps
), mbStart( bStart
) {}
2249 std::list
< SwFindRowSpanCacheObj
> aCache
;
2251 static SwFindRowSpanCache
* mpFindRowSpanCache
;
2252 SwFindRowSpanCache();
2256 static SwFindRowSpanCache
& getSwFindRowSpanCache();
2257 const SwTableBox
* FindCachedStartEndOfRowSpan( const SwTableBox
& rKeyBox
, USHORT nSteps
, bool bStart
);
2258 void SetCachedStartEndOfRowSpan( const SwTableBox
& rKeyBox
, const SwTableBox
& rCacheBox
, USHORT nSteps
, bool bStart
);
2259 void SetUseCache( bool bNew
);
2262 SwFindRowSpanCache
* SwFindRowSpanCache::mpFindRowSpanCache
= 0;
2263 SwFindRowSpanCache
& SwFindRowSpanCache::getSwFindRowSpanCache()
2265 if ( !mpFindRowSpanCache
) mpFindRowSpanCache
= new SwFindRowSpanCache
;
2266 return *mpFindRowSpanCache
;
2269 SwFindRowSpanCache::SwFindRowSpanCache() : mbUseCache( false )
2273 void SwFindRowSpanCache::SetUseCache( bool bNew
)
2275 mbUseCache
= bNew
; aCache
.clear();
2278 const SwTableBox
* SwFindRowSpanCache::FindCachedStartEndOfRowSpan( const SwTableBox
& rKeyBox
,
2282 static nCallCount
= 0;
2283 static nSuccessCount
= 0;
2286 if ( !mbUseCache
) return 0;
2288 const SwTableBox
* pRet
= 0;
2290 std::list
< SwFindRowSpanCacheObj
>::const_iterator aIter
;
2291 for ( aIter
= aCache
.begin(); aIter
!= aCache
.end(); ++aIter
)
2293 if ( aIter
->mpKeyBox
== &rKeyBox
&&
2294 aIter
->mnSteps
== nSteps
&&
2295 aIter
->mbStart
== bStart
)
2297 pRet
= aIter
->mpCacheBox
;
2306 const int FindBoxCacheSize
= 2;
2308 void SwFindRowSpanCache::SetCachedStartEndOfRowSpan( const SwTableBox
& rKeyBox
,
2309 const SwTableBox
& rCacheBox
,
2313 if ( !mbUseCache
) return;
2315 const SwFindRowSpanCacheObj
aNew( rKeyBox
, rCacheBox
, nSteps
, bStart
);
2316 aCache
.push_front( aNew
);
2317 if ( aCache
.size() > FindBoxCacheSize
)
2322 * A small optimization for FindStartEndOfRowSpan END