xref: /aoo41x/main/sw/source/core/table/swnewtable.cxx (revision efeef26f)
1*efeef26fSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*efeef26fSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*efeef26fSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*efeef26fSAndrew Rist  * distributed with this work for additional information
6*efeef26fSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*efeef26fSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*efeef26fSAndrew Rist  * "License"); you may not use this file except in compliance
9*efeef26fSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*efeef26fSAndrew Rist  *
11*efeef26fSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*efeef26fSAndrew Rist  *
13*efeef26fSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*efeef26fSAndrew Rist  * software distributed under the License is distributed on an
15*efeef26fSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*efeef26fSAndrew Rist  * KIND, either express or implied.  See the License for the
17*efeef26fSAndrew Rist  * specific language governing permissions and limitations
18*efeef26fSAndrew Rist  * under the License.
19*efeef26fSAndrew Rist  *
20*efeef26fSAndrew Rist  *************************************************************/
21*efeef26fSAndrew Rist 
22*efeef26fSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sw.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <swtable.hxx>
28cdf0e10cSrcweir #include <tblsel.hxx>
29cdf0e10cSrcweir #include <tblrwcl.hxx>
30cdf0e10cSrcweir #include <node.hxx>
31cdf0e10cSrcweir #include <UndoTable.hxx>
32cdf0e10cSrcweir #include <pam.hxx>
33cdf0e10cSrcweir #include <frmfmt.hxx>
34cdf0e10cSrcweir #include <frmatr.hxx>
35cdf0e10cSrcweir #include <cellfrm.hxx>
36cdf0e10cSrcweir #include <fmtfsize.hxx>
37cdf0e10cSrcweir #include <doc.hxx>
38cdf0e10cSrcweir #include <IDocumentUndoRedo.hxx>
39cdf0e10cSrcweir #include <vector>
40cdf0e10cSrcweir #include <set>
41cdf0e10cSrcweir #include <list>
42cdf0e10cSrcweir #include <memory>
43cdf0e10cSrcweir #include <editeng/boxitem.hxx>
44cdf0e10cSrcweir #include <editeng/protitem.hxx>
45cdf0e10cSrcweir #include <swtblfmt.hxx>
46cdf0e10cSrcweir #include <switerator.hxx>
47cdf0e10cSrcweir 
48cdf0e10cSrcweir #ifndef DBG_UTIL
49cdf0e10cSrcweir #define CHECK_TABLE(t)
50cdf0e10cSrcweir #else
51cdf0e10cSrcweir #ifdef DEBUG
52cdf0e10cSrcweir #define CHECK_TABLE(t) (t).CheckConsistency();
53cdf0e10cSrcweir #else
54cdf0e10cSrcweir #define CHECK_TABLE(t)
55cdf0e10cSrcweir #endif
56cdf0e10cSrcweir #endif
57cdf0e10cSrcweir 
58cdf0e10cSrcweir // ---------------------------------------------------------------
59cdf0e10cSrcweir 
60cdf0e10cSrcweir /** SwBoxSelection is a small helperclass (structure) to handle selections
61cdf0e10cSrcweir     of cells (boxes) between table functions
62cdf0e10cSrcweir 
63cdf0e10cSrcweir     It contains an "array" of table boxes, a rectangulare selection of table boxes.
64cdf0e10cSrcweir     To be more specific, it contains a vector of box selections,
65cdf0e10cSrcweir     every box selection (SwSelBoxes) contains the selected boxes inside one row.
66cdf0e10cSrcweir     The member mnMergeWidth contains the width of the selected boxes
67cdf0e10cSrcweir */
68cdf0e10cSrcweir 
69cdf0e10cSrcweir class SwBoxSelection
70cdf0e10cSrcweir {
71cdf0e10cSrcweir public:
72cdf0e10cSrcweir     std::vector<const SwSelBoxes*> aBoxes;
73cdf0e10cSrcweir     long mnMergeWidth;
SwBoxSelection()74cdf0e10cSrcweir     SwBoxSelection() : mnMergeWidth(0) {}
isEmpty() const75cdf0e10cSrcweir     bool isEmpty() const { return aBoxes.size() == 0; }
insertBoxes(const SwSelBoxes * pNew)76cdf0e10cSrcweir     void insertBoxes( const SwSelBoxes* pNew ){ aBoxes.insert( aBoxes.end(), pNew ); }
77cdf0e10cSrcweir };
78cdf0e10cSrcweir 
79cdf0e10cSrcweir /** NewMerge(..) removes the superfluous cells after cell merge
80cdf0e10cSrcweir 
81cdf0e10cSrcweir SwTable::NewMerge(..) does some cleaning up,
82cdf0e10cSrcweir it simply deletes the superfluous cells ("cell span")
83cdf0e10cSrcweir and notifies the Undo about it.
84cdf0e10cSrcweir The main work has been done by SwTable::PrepareMerge(..) already.
85cdf0e10cSrcweir 
86cdf0e10cSrcweir @param rBoxes
87cdf0e10cSrcweir the boxes to remove
88cdf0e10cSrcweir 
89cdf0e10cSrcweir @param pUndo
90cdf0e10cSrcweir the undo object to notify, maybe empty
91cdf0e10cSrcweir 
92cdf0e10cSrcweir @return sal_True for compatibility reasons with OldMerge(..)
93cdf0e10cSrcweir */
94cdf0e10cSrcweir 
NewMerge(SwDoc * pDoc,const SwSelBoxes & rBoxes,const SwSelBoxes & rMerged,SwTableBox *,SwUndoTblMerge * pUndo)95cdf0e10cSrcweir sal_Bool SwTable::NewMerge( SwDoc* pDoc, const SwSelBoxes& rBoxes,
96cdf0e10cSrcweir      const SwSelBoxes& rMerged, SwTableBox*, SwUndoTblMerge* pUndo )
97cdf0e10cSrcweir {
98cdf0e10cSrcweir     if( pUndo )
99cdf0e10cSrcweir 		pUndo->SetSelBoxes( rBoxes );
100cdf0e10cSrcweir 	DeleteSel( pDoc, rBoxes, &rMerged, 0, sal_True, sal_True );
101cdf0e10cSrcweir 
102cdf0e10cSrcweir     CHECK_TABLE( *this )
103cdf0e10cSrcweir     return sal_True;
104cdf0e10cSrcweir }
105cdf0e10cSrcweir 
106cdf0e10cSrcweir /** lcl_CheckMinMax helps evaluating (horizontal) min/max of boxes
107cdf0e10cSrcweir 
108cdf0e10cSrcweir lcl_CheckMinMax(..) compares the left border and the right border
109cdf0e10cSrcweir of a given cell with the given range and sets it accordingly.
110cdf0e10cSrcweir 
111cdf0e10cSrcweir @param rMin
112cdf0e10cSrcweir will be decremented if necessary to the left border of the cell
113cdf0e10cSrcweir 
114cdf0e10cSrcweir @param rMax
115cdf0e10cSrcweir will be incremented if necessary to the right border of the cell
116cdf0e10cSrcweir 
117cdf0e10cSrcweir @param rLine
118cdf0e10cSrcweir the row (table line) of the interesting box
119cdf0e10cSrcweir 
120cdf0e10cSrcweir @param nCheck
121cdf0e10cSrcweir the index of the box in the table box array of the given row
122cdf0e10cSrcweir 
123cdf0e10cSrcweir @param bSet
124cdf0e10cSrcweir if bSet is false, rMin and rMax will be manipulated if necessary
125cdf0e10cSrcweir if bSet is true, rMin and rMax will be set to the left and right border of the box
126cdf0e10cSrcweir 
127cdf0e10cSrcweir */
128cdf0e10cSrcweir 
lcl_CheckMinMax(long & rMin,long & rMax,const SwTableLine & rLine,sal_uInt16 nCheck,bool bSet)129cdf0e10cSrcweir void lcl_CheckMinMax( long& rMin, long& rMax, const SwTableLine& rLine, sal_uInt16 nCheck, bool bSet )
130cdf0e10cSrcweir {
131cdf0e10cSrcweir     ++nCheck;
132cdf0e10cSrcweir     if( rLine.GetTabBoxes().Count() < nCheck )
133cdf0e10cSrcweir     {   // robust
134cdf0e10cSrcweir         ASSERT( false, "Box out of table line" );
135cdf0e10cSrcweir         nCheck = rLine.GetTabBoxes().Count();
136cdf0e10cSrcweir     }
137cdf0e10cSrcweir 
138cdf0e10cSrcweir     long nNew = 0; // will be the right border of the current box
139cdf0e10cSrcweir     long nWidth = 0; // the width of the current box
140cdf0e10cSrcweir     for( sal_uInt16 nCurrBox = 0; nCurrBox < nCheck; ++nCurrBox )
141cdf0e10cSrcweir     {
142cdf0e10cSrcweir         SwTableBox* pBox = rLine.GetTabBoxes()[nCurrBox];
143cdf0e10cSrcweir         ASSERT( pBox, "Missing table box" );
144cdf0e10cSrcweir         nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
145cdf0e10cSrcweir         nNew += nWidth;
146cdf0e10cSrcweir     }
147cdf0e10cSrcweir     // nNew is the right border of the wished box
148cdf0e10cSrcweir     if( bSet || nNew > rMax )
149cdf0e10cSrcweir         rMax = nNew;
150cdf0e10cSrcweir     nNew -= nWidth; // nNew becomes the left border of the wished box
151cdf0e10cSrcweir     if( bSet || nNew < rMin )
152cdf0e10cSrcweir         rMin = nNew;
153cdf0e10cSrcweir }
154cdf0e10cSrcweir 
155cdf0e10cSrcweir /** lcl_Box2LeftBorder(..) delivers the left (logical) border of a table box
156cdf0e10cSrcweir 
157cdf0e10cSrcweir The left logical border of a table box is the sum of the cell width before this
158cdf0e10cSrcweir box.
159cdf0e10cSrcweir 
160cdf0e10cSrcweir @param rBox
161cdf0e10cSrcweir is the requested table box
162cdf0e10cSrcweir 
163cdf0e10cSrcweir @return is the left logical border (long, even it cannot be negative)
164cdf0e10cSrcweir 
165cdf0e10cSrcweir */
166cdf0e10cSrcweir 
lcl_Box2LeftBorder(const SwTableBox & rBox)167cdf0e10cSrcweir long lcl_Box2LeftBorder( const SwTableBox& rBox )
168cdf0e10cSrcweir {
169cdf0e10cSrcweir     if( !rBox.GetUpper() )
170cdf0e10cSrcweir         return 0;
171cdf0e10cSrcweir     long nLeft = 0;
172cdf0e10cSrcweir     const SwTableLine &rLine = *rBox.GetUpper();
173cdf0e10cSrcweir     sal_uInt16 nCount = rLine.GetTabBoxes().Count();
174cdf0e10cSrcweir     for( sal_uInt16 nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
175cdf0e10cSrcweir     {
176cdf0e10cSrcweir         SwTableBox* pBox = rLine.GetTabBoxes()[nCurrBox];
177cdf0e10cSrcweir         ASSERT( pBox, "Missing table box" );
178cdf0e10cSrcweir         if( pBox == &rBox )
179cdf0e10cSrcweir             return nLeft;
180cdf0e10cSrcweir         nLeft += pBox->GetFrmFmt()->GetFrmSize().GetWidth();
181cdf0e10cSrcweir     }
182cdf0e10cSrcweir     ASSERT( false, "Box not found in own upper?" );
183cdf0e10cSrcweir     return nLeft;
184cdf0e10cSrcweir }
185cdf0e10cSrcweir 
186cdf0e10cSrcweir /** lcl_LeftBorder2Box delivers the box to a given left border
187cdf0e10cSrcweir 
188cdf0e10cSrcweir It's used to find the master/follow table boxes in previous/next rows.
189cdf0e10cSrcweir Don't call this function to check if there is such a box,
190cdf0e10cSrcweir call it if you know there has to be such box.
191cdf0e10cSrcweir 
192cdf0e10cSrcweir @param nLeft
193cdf0e10cSrcweir the left border (logical x-value) of the demanded box
194cdf0e10cSrcweir 
195cdf0e10cSrcweir @param rLine
196cdf0e10cSrcweir the row (table line) to be scanned
197cdf0e10cSrcweir 
198cdf0e10cSrcweir @return a pointer to the table box inside the given row with the wished left border
199cdf0e10cSrcweir 
200cdf0e10cSrcweir */
201cdf0e10cSrcweir 
lcl_LeftBorder2Box(long nLeft,const SwTableLine * pLine)202cdf0e10cSrcweir SwTableBox* lcl_LeftBorder2Box( long nLeft, const SwTableLine* pLine )
203cdf0e10cSrcweir {
204cdf0e10cSrcweir     if( !pLine )
205cdf0e10cSrcweir         return 0;
206cdf0e10cSrcweir     long nCurrLeft = 0;
207cdf0e10cSrcweir     sal_uInt16 nCount = pLine->GetTabBoxes().Count();
208cdf0e10cSrcweir     for( sal_uInt16 nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
209cdf0e10cSrcweir     {
210cdf0e10cSrcweir         SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
211cdf0e10cSrcweir         ASSERT( pBox, "Missing table box" );
212cdf0e10cSrcweir         if( nCurrLeft >= nLeft && pBox->GetFrmFmt()->GetFrmSize().GetWidth() )
213cdf0e10cSrcweir         {
214cdf0e10cSrcweir             ASSERT( nCurrLeft == nLeft, "Wrong box found" );
215cdf0e10cSrcweir             return pBox;
216cdf0e10cSrcweir         }
217cdf0e10cSrcweir         nCurrLeft += pBox->GetFrmFmt()->GetFrmSize().GetWidth();
218cdf0e10cSrcweir     }
219cdf0e10cSrcweir     ASSERT( false, "Didn't found wished box" );
220cdf0e10cSrcweir     return 0;
221cdf0e10cSrcweir }
222cdf0e10cSrcweir 
223cdf0e10cSrcweir /** lcl_ChangeRowSpan corrects row span after insertion/deletion of rows
224cdf0e10cSrcweir 
225cdf0e10cSrcweir lcl_ChangeRowSpan(..) has to be called after an insertion or deletion of rows
226cdf0e10cSrcweir to adjust the row spans of previous rows accordingly.
227cdf0e10cSrcweir If rows are deleted, the previous rows with row spans into the deleted area
228cdf0e10cSrcweir have to be decremented by the number of _overlapped_ inserted rows.
229cdf0e10cSrcweir If rows are inserted, the previous rows with row span into the inserted area
230cdf0e10cSrcweir have to be incremented by the number of inserted rows.
231cdf0e10cSrcweir For those row spans which ends exactly above the inserted area it has to be
232cdf0e10cSrcweir decided by the parameter bSingle if they have to be expanded or not.
233cdf0e10cSrcweir 
234cdf0e10cSrcweir @param rTable
235cdf0e10cSrcweir the table to manipulate (has to be a new model table)
236cdf0e10cSrcweir 
237cdf0e10cSrcweir @param nDiff
238cdf0e10cSrcweir the number of rows which has been inserted (nDiff > 0) or deleted (nDiff < 0)
239cdf0e10cSrcweir 
240cdf0e10cSrcweir @param nRowIdx
241cdf0e10cSrcweir the index of the first row which has to be checked
242cdf0e10cSrcweir 
243cdf0e10cSrcweir @param bSingle
244cdf0e10cSrcweir true if the new inserted row should not extend row spans which ends in the row above
245cdf0e10cSrcweir this is for rows inserted by UI "insert row"
246cdf0e10cSrcweir false if all cells of an inserted row has to be overlapped by the previous row
247cdf0e10cSrcweir this is for rows inserted by "split row"
248cdf0e10cSrcweir false is also needed for deleted rows
249cdf0e10cSrcweir 
250cdf0e10cSrcweir */
251cdf0e10cSrcweir 
lcl_ChangeRowSpan(const SwTable & rTable,const long nDiff,sal_uInt16 nRowIdx,const bool bSingle)252cdf0e10cSrcweir void lcl_ChangeRowSpan( const SwTable& rTable, const long nDiff,
253cdf0e10cSrcweir                         sal_uInt16 nRowIdx, const bool bSingle )
254cdf0e10cSrcweir {
255cdf0e10cSrcweir     if( !nDiff || nRowIdx >= rTable.GetTabLines().Count() )
256cdf0e10cSrcweir         return;
257cdf0e10cSrcweir     ASSERT( !bSingle || nDiff > 0, "Don't set bSingle when deleting lines!" );
258cdf0e10cSrcweir     bool bGoOn;
259cdf0e10cSrcweir     // nDistance is the distance between the current row and the critical row,
260cdf0e10cSrcweir     // e.g. the deleted rows or the inserted rows.
261cdf0e10cSrcweir     // If the row span is lower than the distance there is nothing to do
262cdf0e10cSrcweir     // because the row span ends before the critical area.
263cdf0e10cSrcweir     // When the inserted rows should not be overlapped by row spans which ends
264cdf0e10cSrcweir     // exactly in the row above, the trick is to start with a distance of 1.
265cdf0e10cSrcweir     long nDistance = bSingle ? 1 : 0;
266cdf0e10cSrcweir     do
267cdf0e10cSrcweir     {
268cdf0e10cSrcweir         bGoOn = false; // will be set to true if we found a non-master cell
269cdf0e10cSrcweir         // which has to be manipulated => we have to chekc the previous row, too.
270cdf0e10cSrcweir         const SwTableLine* pLine = rTable.GetTabLines()[ nRowIdx ];
271cdf0e10cSrcweir         sal_uInt16 nBoxCount = pLine->GetTabBoxes().Count();
272cdf0e10cSrcweir         for( sal_uInt16 nCurrBox = 0; nCurrBox < nBoxCount; ++nCurrBox )
273cdf0e10cSrcweir         {
274cdf0e10cSrcweir             long nRowSpan = pLine->GetTabBoxes()[nCurrBox]->getRowSpan();
275cdf0e10cSrcweir             long nAbsSpan = nRowSpan > 0 ? nRowSpan : -nRowSpan;
276cdf0e10cSrcweir             // Check if the last overlapped cell is above or below
277cdf0e10cSrcweir             // the critical area
278cdf0e10cSrcweir             if( nAbsSpan > nDistance )
279cdf0e10cSrcweir             {
280cdf0e10cSrcweir                 if( nDiff > 0 )
281cdf0e10cSrcweir                 {
282cdf0e10cSrcweir                     if( nRowSpan > 0 )
283cdf0e10cSrcweir                         nRowSpan += nDiff; // increment row span of master cell
284cdf0e10cSrcweir                     else
285cdf0e10cSrcweir                     {
286cdf0e10cSrcweir                         nRowSpan -= nDiff; // increment row span of non-master cell
287cdf0e10cSrcweir                         bGoOn = true;
288cdf0e10cSrcweir                     }
289cdf0e10cSrcweir                 }
290cdf0e10cSrcweir                 else
291cdf0e10cSrcweir                 {
292cdf0e10cSrcweir                     if( nRowSpan > 0 )
293cdf0e10cSrcweir                     {   // A master cell
294cdf0e10cSrcweir                          // end of row span behind the deleted area ..
295cdf0e10cSrcweir                         if( nRowSpan - nDistance > -nDiff )
296cdf0e10cSrcweir                             nRowSpan += nDiff;
297cdf0e10cSrcweir                         else // .. or inside the deleted area
298cdf0e10cSrcweir                             nRowSpan = nDistance + 1;
299cdf0e10cSrcweir                     }
300cdf0e10cSrcweir                     else
301cdf0e10cSrcweir                     {   // Same for a non-master cell
302cdf0e10cSrcweir                         if( nRowSpan + nDistance < nDiff )
303cdf0e10cSrcweir                             nRowSpan -= nDiff;
304cdf0e10cSrcweir                         else
305cdf0e10cSrcweir                             nRowSpan = -nDistance - 1;
306cdf0e10cSrcweir                         bGoOn = true; // We have to continue
307cdf0e10cSrcweir                     }
308cdf0e10cSrcweir                 }
309cdf0e10cSrcweir                 pLine->GetTabBoxes()[ nCurrBox ]->setRowSpan( nRowSpan );
310cdf0e10cSrcweir             }
311cdf0e10cSrcweir         }
312cdf0e10cSrcweir         ++nDistance;
313cdf0e10cSrcweir         if( nRowIdx )
314cdf0e10cSrcweir             --nRowIdx;
315cdf0e10cSrcweir         else
316cdf0e10cSrcweir             bGoOn = false; //robust
317cdf0e10cSrcweir     } while( bGoOn );
318cdf0e10cSrcweir }
319cdf0e10cSrcweir 
320cdf0e10cSrcweir /** CollectBoxSelection(..) create a rectangulare selection based on the given SwPaM
321cdf0e10cSrcweir     and prepares the selected cells for merging
322cdf0e10cSrcweir */
323cdf0e10cSrcweir 
CollectBoxSelection(const SwPaM & rPam) const324cdf0e10cSrcweir SwBoxSelection* SwTable::CollectBoxSelection( const SwPaM& rPam ) const
325cdf0e10cSrcweir {
326cdf0e10cSrcweir     ASSERT( bNewModel, "Don't call me for old tables" );
327cdf0e10cSrcweir     if( !aLines.Count() )
328cdf0e10cSrcweir         return 0;
329cdf0e10cSrcweir     const SwNode* pStartNd = rPam.Start()->nNode.GetNode().FindTableBoxStartNode();
330cdf0e10cSrcweir     const SwNode* pEndNd = rPam.End()->nNode.GetNode().FindTableBoxStartNode();
331cdf0e10cSrcweir     if( !pStartNd || !pEndNd || pStartNd == pEndNd )
332cdf0e10cSrcweir         return 0;
333cdf0e10cSrcweir 
334cdf0e10cSrcweir     sal_uInt16 nLines = aLines.Count();
335cdf0e10cSrcweir     sal_uInt16 nTop = 0, nBottom = 0;
336cdf0e10cSrcweir     long nMin = 0, nMax = 0;
337cdf0e10cSrcweir     int nFound = 0;
338cdf0e10cSrcweir     for( sal_uInt16 nRow = 0; nFound < 2 && nRow < nLines; ++nRow )
339cdf0e10cSrcweir     {
340cdf0e10cSrcweir         SwTableLine* pLine = aLines[nRow];
341cdf0e10cSrcweir         ASSERT( pLine, "Missing table line" );
342cdf0e10cSrcweir         sal_uInt16 nCols = pLine->GetTabBoxes().Count();
343cdf0e10cSrcweir         for( sal_uInt16 nCol = 0; nCol < nCols; ++nCol )
344cdf0e10cSrcweir         {
345cdf0e10cSrcweir             SwTableBox* pBox = pLine->GetTabBoxes()[nCol];
346cdf0e10cSrcweir             ASSERT( pBox, "Missing table box" );
347cdf0e10cSrcweir             if( nFound )
348cdf0e10cSrcweir             {
349cdf0e10cSrcweir                 if( pBox->GetSttNd() == pEndNd )
350cdf0e10cSrcweir                 {
351cdf0e10cSrcweir                     nBottom = nRow;
352cdf0e10cSrcweir                     lcl_CheckMinMax( nMin, nMax, *pLine, nCol, false );
353cdf0e10cSrcweir                     ++nFound;
354cdf0e10cSrcweir                     break;
355cdf0e10cSrcweir                 }
356cdf0e10cSrcweir             }
357cdf0e10cSrcweir             else if( pBox->GetSttNd() == pStartNd )
358cdf0e10cSrcweir             {
359cdf0e10cSrcweir                 nTop = nRow;
360cdf0e10cSrcweir                 lcl_CheckMinMax( nMin, nMax, *pLine, nCol, true );
361cdf0e10cSrcweir                 ++nFound;
362cdf0e10cSrcweir             }
363cdf0e10cSrcweir         }
364cdf0e10cSrcweir     }
365cdf0e10cSrcweir     if( nFound < 2 )
366cdf0e10cSrcweir         return 0;
367cdf0e10cSrcweir 
368cdf0e10cSrcweir     bool bOkay = true;
369cdf0e10cSrcweir     long nMid = ( nMin + nMax ) / 2;
370cdf0e10cSrcweir 
371cdf0e10cSrcweir     SwBoxSelection* pRet = new SwBoxSelection();
372cdf0e10cSrcweir     std::list< std::pair< SwTableBox*, long > > aNewWidthList;
373cdf0e10cSrcweir     sal_uInt16 nCheckBottom = nBottom;
374cdf0e10cSrcweir     long nLeftSpan = 0;
375cdf0e10cSrcweir     long nRightSpan = 0;
376cdf0e10cSrcweir     long nLeftSpanCnt = 0;
377cdf0e10cSrcweir     long nRightSpanCnt = 0;
378cdf0e10cSrcweir     for( sal_uInt16 nRow = nTop; nRow <= nBottom && bOkay; ++nRow )
379cdf0e10cSrcweir     {
380cdf0e10cSrcweir         SwTableLine* pLine = aLines[nRow];
381cdf0e10cSrcweir         ASSERT( pLine, "Missing table line" );
382cdf0e10cSrcweir         SwSelBoxes *pBoxes = new SwSelBoxes();
383cdf0e10cSrcweir         long nLeft = 0;
384cdf0e10cSrcweir         long nRight = 0;
385cdf0e10cSrcweir         long nRowSpan = 1;
386cdf0e10cSrcweir         sal_uInt16 nCount = pLine->GetTabBoxes().Count();
387cdf0e10cSrcweir         for( sal_uInt16 nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
388cdf0e10cSrcweir         {
389cdf0e10cSrcweir             SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
390cdf0e10cSrcweir             ASSERT( pBox, "Missing table box" );
391cdf0e10cSrcweir             nLeft = nRight;
392cdf0e10cSrcweir             nRight += pBox->GetFrmFmt()->GetFrmSize().GetWidth();
393cdf0e10cSrcweir             nRowSpan = pBox->getRowSpan();
394cdf0e10cSrcweir             if( nRight <= nMin )
395cdf0e10cSrcweir             {
396cdf0e10cSrcweir                 if( nRight == nMin && nLeftSpanCnt )
397cdf0e10cSrcweir                     bOkay = false;
398cdf0e10cSrcweir                 continue;
399cdf0e10cSrcweir             }
400cdf0e10cSrcweir             SwTableBox* pInnerBox = 0;
401cdf0e10cSrcweir             SwTableBox* pLeftBox = 0;
402cdf0e10cSrcweir             SwTableBox* pRightBox = 0;
403cdf0e10cSrcweir             long nDiff = 0;
404cdf0e10cSrcweir             long nDiff2 = 0;
405cdf0e10cSrcweir             if( nLeft < nMin )
406cdf0e10cSrcweir             {
407cdf0e10cSrcweir                 if( nRight >= nMid || nRight + nLeft >= nMin + nMin )
408cdf0e10cSrcweir                 {
409cdf0e10cSrcweir                     if( nCurrBox )
410cdf0e10cSrcweir                     {
411cdf0e10cSrcweir                         pBoxes->Insert( pBox );
412cdf0e10cSrcweir                         pInnerBox = pBox;
413cdf0e10cSrcweir                         pLeftBox = pLine->GetTabBoxes()[nCurrBox-1];
414cdf0e10cSrcweir                         nDiff = nMin - nLeft;
415cdf0e10cSrcweir                         if( nRight > nMax )
416cdf0e10cSrcweir                         {
417cdf0e10cSrcweir                             if( nCurrBox+1 < nCount )
418cdf0e10cSrcweir                             {
419cdf0e10cSrcweir                                 pRightBox = pLine->GetTabBoxes()[nCurrBox+1];
420cdf0e10cSrcweir                                 nDiff2 = nRight - nMax;
421cdf0e10cSrcweir                             }
422cdf0e10cSrcweir                             else
423cdf0e10cSrcweir                                 bOkay = false;
424cdf0e10cSrcweir                         }
425cdf0e10cSrcweir                         else if( nRightSpanCnt && nRight == nMax )
426cdf0e10cSrcweir                             bOkay = false;
427cdf0e10cSrcweir                     }
428cdf0e10cSrcweir                     else
429cdf0e10cSrcweir                         bOkay = false;
430cdf0e10cSrcweir                 }
431cdf0e10cSrcweir                 else if( nCurrBox+1 < nCount )
432cdf0e10cSrcweir                 {
433cdf0e10cSrcweir                     pLeftBox = pBox;
434cdf0e10cSrcweir                     pInnerBox = pLine->GetTabBoxes()[nCurrBox+1];
435cdf0e10cSrcweir                     nDiff = nMin - nRight;
436cdf0e10cSrcweir                 }
437cdf0e10cSrcweir                 else
438cdf0e10cSrcweir                     bOkay = false;
439cdf0e10cSrcweir             }
440cdf0e10cSrcweir             else if( nRight <= nMax )
441cdf0e10cSrcweir             {
442cdf0e10cSrcweir                 pBoxes->Insert( pBox );
443cdf0e10cSrcweir                 if( nRow == nTop && nRowSpan < 0 )
444cdf0e10cSrcweir                 {
445cdf0e10cSrcweir                     bOkay = false;
446cdf0e10cSrcweir                     break;
447cdf0e10cSrcweir                 }
448cdf0e10cSrcweir                 if( nRowSpan > 1 && nRow + nRowSpan - 1 > nBottom )
449cdf0e10cSrcweir                     nBottom = nRow + (sal_uInt16)nRowSpan - 1;
450cdf0e10cSrcweir                 if( nRowSpan < -1 && nRow - nRowSpan - 1 > nBottom )
451cdf0e10cSrcweir                     nBottom = (sal_uInt16)(nRow - nRowSpan - 1);
452cdf0e10cSrcweir                 if( nRightSpanCnt && nRight == nMax )
453cdf0e10cSrcweir                     bOkay = false;
454cdf0e10cSrcweir             }
455cdf0e10cSrcweir             else if( nLeft < nMax )
456cdf0e10cSrcweir             {
457cdf0e10cSrcweir                 if( nLeft <= nMid || nRight + nLeft <= nMax )
458cdf0e10cSrcweir                 {
459cdf0e10cSrcweir                     if( nCurrBox+1 < nCount )
460cdf0e10cSrcweir                     {
461cdf0e10cSrcweir                         pBoxes->Insert( pBox );
462cdf0e10cSrcweir                         pInnerBox = pBox;
463cdf0e10cSrcweir                         pRightBox = pLine->GetTabBoxes()[nCurrBox+1];
464cdf0e10cSrcweir                         nDiff = nRight - nMax;
465cdf0e10cSrcweir                     }
466cdf0e10cSrcweir                     else
467cdf0e10cSrcweir                         bOkay = false;
468cdf0e10cSrcweir                 }
469cdf0e10cSrcweir                 else if( nCurrBox )
470cdf0e10cSrcweir                 {
471cdf0e10cSrcweir                     pRightBox = pBox;
472cdf0e10cSrcweir                     pInnerBox = pLine->GetTabBoxes()[nCurrBox-1];
473cdf0e10cSrcweir                     nDiff = nLeft - nMax;
474cdf0e10cSrcweir                 }
475cdf0e10cSrcweir                 else
476cdf0e10cSrcweir                     bOkay = false;
477cdf0e10cSrcweir             }
478cdf0e10cSrcweir             else
479cdf0e10cSrcweir                 break;
480cdf0e10cSrcweir             if( pInnerBox )
481cdf0e10cSrcweir             {
482cdf0e10cSrcweir                 if( nRow == nBottom )
483cdf0e10cSrcweir                 {
484cdf0e10cSrcweir                     long nTmpSpan = pInnerBox->getRowSpan();
485cdf0e10cSrcweir                     if( nTmpSpan > 1 )
486cdf0e10cSrcweir                         nBottom += (sal_uInt16)nTmpSpan - 1;
487cdf0e10cSrcweir                     else if( nTmpSpan < -1 )
488cdf0e10cSrcweir                         nBottom = (sal_uInt16)( nBottom - nTmpSpan - 1 );
489cdf0e10cSrcweir                 }
490cdf0e10cSrcweir                 SwTableBox* pOuterBox = pLeftBox;
491cdf0e10cSrcweir                 do
492cdf0e10cSrcweir                 {
493cdf0e10cSrcweir                     if( pOuterBox )
494cdf0e10cSrcweir                     {
495cdf0e10cSrcweir                         long nOutSpan = pOuterBox->getRowSpan();
496cdf0e10cSrcweir                         if( nOutSpan != 1 )
497cdf0e10cSrcweir                         {
498cdf0e10cSrcweir                             sal_uInt16 nCheck = nRow;
499cdf0e10cSrcweir                             if( nOutSpan < 0 )
500cdf0e10cSrcweir                             {
501cdf0e10cSrcweir                                 const SwTableBox& rBox =
502cdf0e10cSrcweir                                     pOuterBox->FindStartOfRowSpan( *this, USHRT_MAX );
503cdf0e10cSrcweir                                 nOutSpan = rBox.getRowSpan();
504cdf0e10cSrcweir                                 const SwTableLine* pTmpL = rBox.GetUpper();
505cdf0e10cSrcweir                                 nCheck = GetTabLines().C40_GETPOS( SwTableLine, pTmpL );
506cdf0e10cSrcweir                                 if( nCheck < nTop )
507cdf0e10cSrcweir                                     bOkay = false;
508cdf0e10cSrcweir                                 if( pOuterBox == pLeftBox )
509cdf0e10cSrcweir                                 {
510cdf0e10cSrcweir                                     if( !nLeftSpanCnt || nMin - nDiff != nLeftSpan )
511cdf0e10cSrcweir                                         bOkay = false;
512cdf0e10cSrcweir                                 }
513cdf0e10cSrcweir                                 else
514cdf0e10cSrcweir                                 {
515cdf0e10cSrcweir                                     if( !nRightSpanCnt || nMax + nDiff != nRightSpan )
516cdf0e10cSrcweir                                         bOkay = false;
517cdf0e10cSrcweir                                 }
518cdf0e10cSrcweir                             }
519cdf0e10cSrcweir                             else
520cdf0e10cSrcweir                             {
521cdf0e10cSrcweir                                 if( pOuterBox == pLeftBox )
522cdf0e10cSrcweir                                 {
523cdf0e10cSrcweir                                     if( nLeftSpanCnt )
524cdf0e10cSrcweir                                         bOkay = false;
525cdf0e10cSrcweir                                     nLeftSpan = nMin - nDiff;
526cdf0e10cSrcweir                                     nLeftSpanCnt = nOutSpan;
527cdf0e10cSrcweir                                 }
528cdf0e10cSrcweir                                 else
529cdf0e10cSrcweir                                 {
530cdf0e10cSrcweir                                     if( nRightSpanCnt )
531cdf0e10cSrcweir                                         bOkay = false;
532cdf0e10cSrcweir                                     nRightSpan = nMax + nDiff;
533cdf0e10cSrcweir                                     nRightSpanCnt = nOutSpan;
534cdf0e10cSrcweir                                 }
535cdf0e10cSrcweir                             }
536cdf0e10cSrcweir                             nCheck += (sal_uInt16)nOutSpan - 1;
537cdf0e10cSrcweir                             if( nCheck > nCheckBottom )
538cdf0e10cSrcweir                                 nCheckBottom = nCheck;
539cdf0e10cSrcweir                         }
540cdf0e10cSrcweir                         else if( ( nLeftSpanCnt && pLeftBox == pOuterBox ) ||
541cdf0e10cSrcweir                             ( nRightSpanCnt && pRightBox == pOuterBox ) )
542cdf0e10cSrcweir                             bOkay = false;
543cdf0e10cSrcweir                         std::pair< SwTableBox*, long > aTmp;
544cdf0e10cSrcweir                         aTmp.first = pInnerBox;
545cdf0e10cSrcweir                         aTmp.second = -nDiff;
546cdf0e10cSrcweir                         aNewWidthList.push_back( aTmp );
547cdf0e10cSrcweir                         aTmp.first = pOuterBox;
548cdf0e10cSrcweir                         aTmp.second = nDiff;
549cdf0e10cSrcweir                         aNewWidthList.push_back( aTmp );
550cdf0e10cSrcweir                     }
551cdf0e10cSrcweir 					pOuterBox = pOuterBox == pRightBox ? 0 : pRightBox;
552cdf0e10cSrcweir                     if( nDiff2 )
553cdf0e10cSrcweir                         nDiff = nDiff2;
554cdf0e10cSrcweir                 } while( pOuterBox );
555cdf0e10cSrcweir             }
556cdf0e10cSrcweir         }
557cdf0e10cSrcweir         if( nLeftSpanCnt )
558cdf0e10cSrcweir             --nLeftSpanCnt;
559cdf0e10cSrcweir         if( nRightSpanCnt )
560cdf0e10cSrcweir             --nRightSpanCnt;
561cdf0e10cSrcweir         pRet->insertBoxes( pBoxes );
562cdf0e10cSrcweir     }
563cdf0e10cSrcweir     pRet->mnMergeWidth = nMax - nMin;
564cdf0e10cSrcweir     if( nCheckBottom > nBottom )
565cdf0e10cSrcweir         bOkay = false;
566cdf0e10cSrcweir     if( bOkay )
567cdf0e10cSrcweir     {
568cdf0e10cSrcweir         std::list< std::pair< SwTableBox*, long > >::iterator
569cdf0e10cSrcweir             pCurr = aNewWidthList.begin();
570cdf0e10cSrcweir         while( pCurr != aNewWidthList.end() )
571cdf0e10cSrcweir         {
572cdf0e10cSrcweir             SwFrmFmt* pFmt = pCurr->first->ClaimFrmFmt();
573cdf0e10cSrcweir             long nNewWidth = pFmt->GetFrmSize().GetWidth() + pCurr->second;
574cdf0e10cSrcweir             pFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nNewWidth, 0 ) );
575cdf0e10cSrcweir             ++pCurr;
576cdf0e10cSrcweir         }
577cdf0e10cSrcweir     }
578cdf0e10cSrcweir     else
579cdf0e10cSrcweir     {
580cdf0e10cSrcweir         delete pRet;
581cdf0e10cSrcweir         pRet = 0;
582cdf0e10cSrcweir     }
583cdf0e10cSrcweir     return pRet;
584cdf0e10cSrcweir }
585cdf0e10cSrcweir 
586cdf0e10cSrcweir /** lcl_InvalidateCellFrm(..) invalidates all layout representations of a given cell
587cdf0e10cSrcweir     to initiate a reformatting
588cdf0e10cSrcweir */
589cdf0e10cSrcweir 
lcl_InvalidateCellFrm(const SwTableBox & rBox)590cdf0e10cSrcweir void lcl_InvalidateCellFrm( const SwTableBox& rBox )
591cdf0e10cSrcweir {
592cdf0e10cSrcweir 	SwIterator<SwCellFrm,SwFmt> aIter( *rBox.GetFrmFmt() );
593cdf0e10cSrcweir 	for( SwCellFrm* pCell = aIter.First(); pCell; pCell = aIter.Next() )
594cdf0e10cSrcweir 	{
595cdf0e10cSrcweir 		if( pCell->GetTabBox() == &rBox )
596cdf0e10cSrcweir         {
597cdf0e10cSrcweir 			pCell->InvalidateSize();
598cdf0e10cSrcweir             SwFrm* pLower = pCell->GetLower();
599cdf0e10cSrcweir             if( pLower )
600cdf0e10cSrcweir                 pLower->_InvalidateSize();
601cdf0e10cSrcweir         }
602cdf0e10cSrcweir     }
603cdf0e10cSrcweir }
604cdf0e10cSrcweir 
605cdf0e10cSrcweir /** lcl_InsertPosition(..) evaluates the insert positions in every table line,
606cdf0e10cSrcweir     when a selection of cells is given and returns the average cell widths
607cdf0e10cSrcweir */
608cdf0e10cSrcweir 
lcl_InsertPosition(SwTable & rTable,std::vector<sal_uInt16> & rInsPos,const SwSelBoxes & rBoxes,sal_Bool bBehind)609cdf0e10cSrcweir long lcl_InsertPosition( SwTable &rTable, std::vector<sal_uInt16>& rInsPos,
610cdf0e10cSrcweir     const SwSelBoxes& rBoxes, sal_Bool bBehind )
611cdf0e10cSrcweir {
612cdf0e10cSrcweir     sal_Int32 nAddWidth = 0;
613cdf0e10cSrcweir     long nCount = 0;
614cdf0e10cSrcweir     for( sal_uInt16 j = 0; j < rBoxes.Count(); ++j )
615cdf0e10cSrcweir     {
616cdf0e10cSrcweir         SwTableBox *pBox = rBoxes[j];
617cdf0e10cSrcweir         SwTableLine* pLine = pBox->GetUpper();
618cdf0e10cSrcweir         long nWidth = rBoxes[j]->GetFrmFmt()->GetFrmSize().GetWidth();
619cdf0e10cSrcweir         nAddWidth += nWidth;
620cdf0e10cSrcweir         sal_uInt16 nCurrBox = pLine->GetTabBoxes().C40_GETPOS(SwTableBox, pBox );
621cdf0e10cSrcweir         sal_uInt16 nCurrLine = rTable.GetTabLines().C40_GETPOS(SwTableLine, pLine );
622cdf0e10cSrcweir         ASSERT( nCurrLine != USHRT_MAX, "Time to say Good-Bye.." );
623cdf0e10cSrcweir         if( rInsPos[ nCurrLine ] == USHRT_MAX )
624cdf0e10cSrcweir         {
625cdf0e10cSrcweir             rInsPos[ nCurrLine ] = nCurrBox;
626cdf0e10cSrcweir             ++nCount;
627cdf0e10cSrcweir         }
628cdf0e10cSrcweir         else if( ( rInsPos[ nCurrLine ] > nCurrBox ) == !bBehind )
629cdf0e10cSrcweir             rInsPos[ nCurrLine ] = nCurrBox;
630cdf0e10cSrcweir     }
631cdf0e10cSrcweir     if( nCount )
632cdf0e10cSrcweir         nAddWidth /= nCount;
633cdf0e10cSrcweir     return nAddWidth;
634cdf0e10cSrcweir }
635cdf0e10cSrcweir 
636cdf0e10cSrcweir /** SwTable::NewInsertCol(..) insert new column(s) into a table
637cdf0e10cSrcweir 
638cdf0e10cSrcweir 
639cdf0e10cSrcweir @param pDoc
640cdf0e10cSrcweir the document
641cdf0e10cSrcweir 
642cdf0e10cSrcweir @param rBoxes
643cdf0e10cSrcweir the selected boxes
644cdf0e10cSrcweir 
645cdf0e10cSrcweir @param nCnt
646cdf0e10cSrcweir the number of columns to insert
647cdf0e10cSrcweir 
648cdf0e10cSrcweir @param bBehind
649cdf0e10cSrcweir insertion behind (true) or before (false) the selected boxes
650cdf0e10cSrcweir 
651cdf0e10cSrcweir @return true, if any insertion has been done successfully
652cdf0e10cSrcweir 
653cdf0e10cSrcweir */
654cdf0e10cSrcweir 
NewInsertCol(SwDoc * pDoc,const SwSelBoxes & rBoxes,sal_uInt16 nCnt,sal_Bool bBehind)655cdf0e10cSrcweir sal_Bool SwTable::NewInsertCol( SwDoc* pDoc, const SwSelBoxes& rBoxes,
656cdf0e10cSrcweir     sal_uInt16 nCnt, sal_Bool bBehind )
657cdf0e10cSrcweir {
658cdf0e10cSrcweir     if( !aLines.Count() || !nCnt )
659cdf0e10cSrcweir         return sal_False;
660cdf0e10cSrcweir 
661cdf0e10cSrcweir     CHECK_TABLE( *this )
662cdf0e10cSrcweir     long nNewBoxWidth = 0;
663cdf0e10cSrcweir     std::vector< sal_uInt16 > aInsPos( aLines.Count(), USHRT_MAX );
664cdf0e10cSrcweir     { // Calculation of the insert positions and the width of the new boxes
665cdf0e10cSrcweir         sal_uInt64 nTableWidth = 0;
666cdf0e10cSrcweir         for( sal_uInt16 i = 0; i < aLines[0]->GetTabBoxes().Count(); ++i )
667cdf0e10cSrcweir             nTableWidth += aLines[0]->GetTabBoxes()[i]->GetFrmFmt()->GetFrmSize().GetWidth();
668cdf0e10cSrcweir 
669cdf0e10cSrcweir         // Fill the vector of insert positions and the (average) width to insert
670cdf0e10cSrcweir         sal_uInt64 nAddWidth = lcl_InsertPosition( *this, aInsPos, rBoxes, bBehind );
671cdf0e10cSrcweir 
672cdf0e10cSrcweir         // Given is the (average) width of the selected boxes, if we would
673cdf0e10cSrcweir         // insert nCnt of columns the table would grow
674cdf0e10cSrcweir         // So we will shrink the table first, then insert the new boxes and
675cdf0e10cSrcweir         // get a table with the same width than before.
676cdf0e10cSrcweir         // But we will not shrink the table by the full already calculated value,
677cdf0e10cSrcweir         // we will reduce this value proportional to the old table width
678cdf0e10cSrcweir         nAddWidth *= nCnt; // we have to insert nCnt boxes per line
679cdf0e10cSrcweir         sal_uInt64 nResultingWidth = nAddWidth + nTableWidth;
680cdf0e10cSrcweir         if( !nResultingWidth )
681cdf0e10cSrcweir             return sal_False;
682cdf0e10cSrcweir         nAddWidth = (nAddWidth * nTableWidth) / nResultingWidth;
683cdf0e10cSrcweir         nNewBoxWidth = long( nAddWidth / nCnt ); // Rounding
684cdf0e10cSrcweir         nAddWidth = nNewBoxWidth * nCnt; // Rounding
685cdf0e10cSrcweir         if( !nAddWidth || nAddWidth >= nTableWidth )
686cdf0e10cSrcweir             return sal_False;
687cdf0e10cSrcweir         AdjustWidths( static_cast< long >(nTableWidth), static_cast< long >(nTableWidth - nAddWidth) );
688cdf0e10cSrcweir     }
689cdf0e10cSrcweir 
690cdf0e10cSrcweir 	_FndBox aFndBox( 0, 0 );
691cdf0e10cSrcweir 	aFndBox.SetTableLines( rBoxes, *this );
692cdf0e10cSrcweir 	aFndBox.DelFrms( *this );
693cdf0e10cSrcweir // 	aFndBox.SaveChartData( *this );
694cdf0e10cSrcweir 
695cdf0e10cSrcweir     SwTableNode* pTblNd = GetTableNode();
696cdf0e10cSrcweir     std::vector<SwTableBoxFmt*> aInsFormat( nCnt, 0 );
697cdf0e10cSrcweir     sal_uInt16 nLastLine = USHRT_MAX;
698cdf0e10cSrcweir     long nLastRowSpan = 1;
699cdf0e10cSrcweir 
700cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < aLines.Count(); ++i )
701cdf0e10cSrcweir     {
702cdf0e10cSrcweir         SwTableLine* pLine = aLines[ i ];
703cdf0e10cSrcweir         sal_uInt16 nInsPos = aInsPos[i];
704cdf0e10cSrcweir         ASSERT( nInsPos != USHRT_MAX, "Didn't found insert position" );
705cdf0e10cSrcweir         SwTableBox* pBox = pLine->GetTabBoxes()[ nInsPos ];
706cdf0e10cSrcweir         if( bBehind )
707cdf0e10cSrcweir             ++nInsPos;
708cdf0e10cSrcweir         SwTableBoxFmt* pBoxFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
709cdf0e10cSrcweir         ::_InsTblBox( pDoc, pTblNd, pLine, pBoxFrmFmt, pBox, nInsPos, nCnt );
710cdf0e10cSrcweir         long nRowSpan = pBox->getRowSpan();
711cdf0e10cSrcweir         long nDiff = i - nLastLine;
712cdf0e10cSrcweir         bool bNewSpan = false;
713cdf0e10cSrcweir         if( nLastLine != USHRT_MAX && nDiff <= nLastRowSpan &&
714cdf0e10cSrcweir             nRowSpan != nDiff - nLastRowSpan )
715cdf0e10cSrcweir         {
716cdf0e10cSrcweir             bNewSpan = true;
717cdf0e10cSrcweir             while( nLastLine < i )
718cdf0e10cSrcweir             {
719cdf0e10cSrcweir                 SwTableLine* pTmpLine = aLines[ nLastLine ];
720cdf0e10cSrcweir                 sal_uInt16 nTmpPos = aInsPos[nLastLine];
721cdf0e10cSrcweir                 if( bBehind )
722cdf0e10cSrcweir                     ++nTmpPos;
723cdf0e10cSrcweir                 for( sal_uInt16 j = 0; j < nCnt; ++j )
724cdf0e10cSrcweir                     pTmpLine->GetTabBoxes()[nTmpPos+j]->setRowSpan( nDiff );
725cdf0e10cSrcweir                 if( nDiff > 0 )
726cdf0e10cSrcweir                     nDiff = -nDiff;
727cdf0e10cSrcweir                 ++nDiff;
728cdf0e10cSrcweir                 ++nLastLine;
729cdf0e10cSrcweir             }
730cdf0e10cSrcweir         }
731cdf0e10cSrcweir         if( nRowSpan > 0 )
732cdf0e10cSrcweir             bNewSpan = true;
733cdf0e10cSrcweir         if( bNewSpan )
734cdf0e10cSrcweir         {
735cdf0e10cSrcweir             nLastLine = i;
736cdf0e10cSrcweir             if( nRowSpan < 0 )
737cdf0e10cSrcweir                 nLastRowSpan = -nRowSpan;
738cdf0e10cSrcweir             else
739cdf0e10cSrcweir                 nLastRowSpan = nRowSpan;
740cdf0e10cSrcweir         }
741cdf0e10cSrcweir 		const SvxBoxItem& aSelBoxItem = pBoxFrmFmt->GetBox();
742cdf0e10cSrcweir 		SvxBoxItem* pNoRightBorder = 0;
743cdf0e10cSrcweir         if( aSelBoxItem.GetRight() )
744cdf0e10cSrcweir         {
745cdf0e10cSrcweir             pNoRightBorder = new SvxBoxItem( aSelBoxItem );
746cdf0e10cSrcweir 			pNoRightBorder->SetLine( 0, BOX_LINE_RIGHT );
747cdf0e10cSrcweir         }
748cdf0e10cSrcweir         for( sal_uInt16 j = 0; j < nCnt; ++j )
749cdf0e10cSrcweir         {
750cdf0e10cSrcweir             SwTableBox *pCurrBox = pLine->GetTabBoxes()[nInsPos+j];
751cdf0e10cSrcweir             if( bNewSpan )
752cdf0e10cSrcweir             {
753cdf0e10cSrcweir                 pCurrBox->setRowSpan( nLastRowSpan );
754cdf0e10cSrcweir                 SwFrmFmt* pFrmFmt = pCurrBox->ClaimFrmFmt();
755cdf0e10cSrcweir                 SwFmtFrmSize aFrmSz( pFrmFmt->GetFrmSize() );
756cdf0e10cSrcweir                 aFrmSz.SetWidth( nNewBoxWidth );
757cdf0e10cSrcweir                 pFrmFmt->SetFmtAttr( aFrmSz );
758cdf0e10cSrcweir                 if( pNoRightBorder && ( !bBehind || j+1 < nCnt ) )
759cdf0e10cSrcweir                     pFrmFmt->SetFmtAttr( *pNoRightBorder );
760cdf0e10cSrcweir                 aInsFormat[j] = (SwTableBoxFmt*)pFrmFmt;
761cdf0e10cSrcweir             }
762cdf0e10cSrcweir             else
763cdf0e10cSrcweir                 pCurrBox->ChgFrmFmt( aInsFormat[j] );
764cdf0e10cSrcweir         }
765cdf0e10cSrcweir         if( bBehind && pNoRightBorder )
766cdf0e10cSrcweir         {
767cdf0e10cSrcweir             SwFrmFmt* pFrmFmt = pBox->ClaimFrmFmt();
768cdf0e10cSrcweir             pFrmFmt->SetFmtAttr( *pNoRightBorder );
769cdf0e10cSrcweir         }
770cdf0e10cSrcweir         delete pNoRightBorder;
771cdf0e10cSrcweir     }
772cdf0e10cSrcweir 
773cdf0e10cSrcweir 	aFndBox.MakeFrms( *this );
774cdf0e10cSrcweir // 	aFndBox.RestoreChartData( *this );
775cdf0e10cSrcweir #ifdef DBG_UTIL
776cdf0e10cSrcweir     {
777cdf0e10cSrcweir         const SwTableBoxes &rTabBoxes = aLines[0]->GetTabBoxes();
778cdf0e10cSrcweir         long nNewWidth = 0;
779cdf0e10cSrcweir         for( sal_uInt16 i = 0; i < rTabBoxes.Count(); ++i )
780cdf0e10cSrcweir             nNewWidth += rTabBoxes[i]->GetFrmFmt()->GetFrmSize().GetWidth();
781cdf0e10cSrcweir         ASSERT( nNewWidth > 0, "Very small" );
782cdf0e10cSrcweir     }
783cdf0e10cSrcweir #endif
784cdf0e10cSrcweir     CHECK_TABLE( *this )
785cdf0e10cSrcweir 
786cdf0e10cSrcweir     return sal_True;
787cdf0e10cSrcweir }
788cdf0e10cSrcweir 
789cdf0e10cSrcweir /** SwTable::PrepareMerge(..) some preparation for the coming Merge(..)
790cdf0e10cSrcweir 
791cdf0e10cSrcweir For the old table model, ::GetMergeSel(..) is called only,
792cdf0e10cSrcweir for the new table model, PrepareMerge does the main work.
793cdf0e10cSrcweir It modifices all cells to merge (width, border, rowspan etc.) and collects
794cdf0e10cSrcweir the cells which have to be deleted by Merge(..) afterwards.
795cdf0e10cSrcweir If there are superfluous rows, these cells are put into the deletion list as well.
796cdf0e10cSrcweir 
797cdf0e10cSrcweir @param rPam
798cdf0e10cSrcweir the selection to merge
799cdf0e10cSrcweir 
800cdf0e10cSrcweir @param rBoxes
801cdf0e10cSrcweir should be empty at the beginning, at the end it is filled with boxes to delete.
802cdf0e10cSrcweir 
803cdf0e10cSrcweir @param ppMergeBox
804cdf0e10cSrcweir will be set to the master cell box
805cdf0e10cSrcweir 
806cdf0e10cSrcweir @param pUndo
807cdf0e10cSrcweir the undo object to record all changes
808cdf0e10cSrcweir can be Null, e.g. when called by Redo(..)
809cdf0e10cSrcweir 
810cdf0e10cSrcweir @return
811cdf0e10cSrcweir 
812cdf0e10cSrcweir */
813cdf0e10cSrcweir 
PrepareMerge(const SwPaM & rPam,SwSelBoxes & rBoxes,SwSelBoxes & rMerged,SwTableBox ** ppMergeBox,SwUndoTblMerge * pUndo)814cdf0e10cSrcweir bool SwTable::PrepareMerge( const SwPaM& rPam, SwSelBoxes& rBoxes,
815cdf0e10cSrcweir    SwSelBoxes& rMerged, SwTableBox** ppMergeBox, SwUndoTblMerge* pUndo )
816cdf0e10cSrcweir {
817cdf0e10cSrcweir     if( !bNewModel )
818cdf0e10cSrcweir     {
819cdf0e10cSrcweir         ::GetMergeSel( rPam, rBoxes, ppMergeBox, pUndo );
820cdf0e10cSrcweir         return rBoxes.Count() > 1;
821cdf0e10cSrcweir     }
822cdf0e10cSrcweir     CHECK_TABLE( *this )
823cdf0e10cSrcweir     // We have to assert a "rectangular" box selection before we start to merge
824cdf0e10cSrcweir     std::auto_ptr< SwBoxSelection > pSel( CollectBoxSelection( rPam ) );
825cdf0e10cSrcweir     if( !pSel.get() || pSel->isEmpty() )
826cdf0e10cSrcweir         return false;
827cdf0e10cSrcweir     // Now we should have a rectangle of boxes,
828cdf0e10cSrcweir     // i.e. contiguous cells in contiguous rows
829cdf0e10cSrcweir     bool bMerge = false; // will be set if any content is transferred from
830cdf0e10cSrcweir     // a "not already overlapped" cell into the new master cell.
831cdf0e10cSrcweir     SwTableBox *pMergeBox = (*pSel->aBoxes[0])[0]; // the master cell box
832cdf0e10cSrcweir     if( !pMergeBox )
833cdf0e10cSrcweir         return false;
834cdf0e10cSrcweir     (*ppMergeBox) = pMergeBox;
835cdf0e10cSrcweir     // The new master box will get the left and the top border of the top-left
836cdf0e10cSrcweir     // box of the selection and because the new master cell _is_ the top-left
837cdf0e10cSrcweir     // box, the left and right border does not need to be changed.
838cdf0e10cSrcweir     // The right and bottom border instead has to be derived from the right-
839cdf0e10cSrcweir     // bottom box of the selection. If this is a overlapped cell,
840cdf0e10cSrcweir     // the appropiate master box.
841cdf0e10cSrcweir     SwTableBox* pLastBox = 0; // the right-bottom (master) cell
842cdf0e10cSrcweir     SwDoc* pDoc = GetFrmFmt()->GetDoc();
843cdf0e10cSrcweir     SwPosition aInsPos( *pMergeBox->GetSttNd()->EndOfSectionNode() );
844cdf0e10cSrcweir     SwPaM aChkPam( aInsPos );
845cdf0e10cSrcweir     // The number of lines in the selection rectangle: nLineCount
846cdf0e10cSrcweir     const sal_uInt16 nLineCount = sal_uInt16(pSel->aBoxes.size());
847cdf0e10cSrcweir     // BTW: nLineCount is the rowspan of the new master cell
848cdf0e10cSrcweir     long nRowSpan = nLineCount;
849cdf0e10cSrcweir     // We will need the first and last line of the selection
850cdf0e10cSrcweir     // to check if there any superfluous row after merging
851cdf0e10cSrcweir     SwTableLine* pFirstLn = 0;
852cdf0e10cSrcweir     SwTableLine* pLastLn = 0;
853cdf0e10cSrcweir     // Iteration over the lines of the selection...
854cdf0e10cSrcweir     for( sal_uInt16 nCurrLine = 0; nCurrLine < nLineCount; ++nCurrLine )
855cdf0e10cSrcweir     {
856cdf0e10cSrcweir         // The selected boxes in the current line
857cdf0e10cSrcweir         const SwSelBoxes* pBoxes = pSel->aBoxes[ nCurrLine ];
858cdf0e10cSrcweir         sal_uInt16 nColCount = pBoxes->Count();
859cdf0e10cSrcweir         // Iteration over the selected cell in the current row
860cdf0e10cSrcweir         for( sal_uInt16 nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol )
861cdf0e10cSrcweir         {
862cdf0e10cSrcweir             SwTableBox* pBox = (*pBoxes)[nCurrCol];
863cdf0e10cSrcweir             rMerged.Insert( pBox );
864cdf0e10cSrcweir             // Only the first selected cell in every row will be alive,
865cdf0e10cSrcweir             // the other will be deleted => put into rBoxes
866cdf0e10cSrcweir             if( nCurrCol )
867cdf0e10cSrcweir                 rBoxes.Insert( pBox );
868cdf0e10cSrcweir             else
869cdf0e10cSrcweir             {
870cdf0e10cSrcweir                 if( nCurrLine == 1 )
871cdf0e10cSrcweir                     pFirstLn = pBox->GetUpper(); // we need this line later on
872cdf0e10cSrcweir                 if( nCurrLine + 1 == nLineCount )
873cdf0e10cSrcweir                     pLastLn = pBox->GetUpper(); // and this one, too.
874cdf0e10cSrcweir             }
875cdf0e10cSrcweir             // A box has to be merged if it's not the master box itself,
876cdf0e10cSrcweir             // but an already overlapped cell must not be merged as well.
877cdf0e10cSrcweir             bool bDoMerge = pBox != pMergeBox && pBox->getRowSpan() > 0;
878cdf0e10cSrcweir             // The last box has to be in the last "column" of the selection
879cdf0e10cSrcweir             // and it has to be a master cell
880cdf0e10cSrcweir             if( nCurrCol+1 == nColCount && pBox->getRowSpan() > 0 )
881cdf0e10cSrcweir                 pLastBox = pBox;
882cdf0e10cSrcweir             if( bDoMerge )
883cdf0e10cSrcweir             {
884cdf0e10cSrcweir                 bMerge = true;
885cdf0e10cSrcweir                 // If the cell to merge contains only one empty paragraph,
886cdf0e10cSrcweir                 // we do not transfer this paragraph.
887cdf0e10cSrcweir                 if( !IsEmptyBox( *pBox, aChkPam ) )
888cdf0e10cSrcweir                 {
889cdf0e10cSrcweir                     SwNodeIndex& rInsPosNd = aInsPos.nNode;
890cdf0e10cSrcweir                     SwPaM aPam( aInsPos );
891cdf0e10cSrcweir                     aPam.GetPoint()->nNode.Assign( *pBox->GetSttNd()->EndOfSectionNode(), -1 );
892cdf0e10cSrcweir                     SwCntntNode* pCNd = aPam.GetCntntNode();
893cdf0e10cSrcweir                     sal_uInt16 nL = pCNd ? pCNd->Len() : 0;
894cdf0e10cSrcweir                     aPam.GetPoint()->nContent.Assign( pCNd, nL );
895cdf0e10cSrcweir                     SwNodeIndex aSttNdIdx( *pBox->GetSttNd(), 1 );
896cdf0e10cSrcweir                     bool const bUndo = pDoc->GetIDocumentUndoRedo().DoesUndo();
897cdf0e10cSrcweir                     if( pUndo )
898cdf0e10cSrcweir                     {
899cdf0e10cSrcweir                         pDoc->GetIDocumentUndoRedo().DoUndo(false);
900cdf0e10cSrcweir                     }
901cdf0e10cSrcweir                     pDoc->AppendTxtNode( *aPam.GetPoint() );
902cdf0e10cSrcweir                     if( pUndo )
903cdf0e10cSrcweir                     {
904cdf0e10cSrcweir                         pDoc->GetIDocumentUndoRedo().DoUndo(bUndo);
905cdf0e10cSrcweir                     }
906cdf0e10cSrcweir                     SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode );
907cdf0e10cSrcweir                     if( pUndo )
908cdf0e10cSrcweir                         pUndo->MoveBoxCntnt( pDoc, aRg, rInsPosNd );
909cdf0e10cSrcweir                     else
910cdf0e10cSrcweir                     {
911cdf0e10cSrcweir                         pDoc->MoveNodeRange( aRg, rInsPosNd,
912cdf0e10cSrcweir                             IDocumentContentOperations::DOC_NO_DELFRMS );
913cdf0e10cSrcweir                     }
914cdf0e10cSrcweir                 }
915cdf0e10cSrcweir             }
916cdf0e10cSrcweir             // Only the cell of the first selected column will stay alive
917cdf0e10cSrcweir             // and got a new row span
918cdf0e10cSrcweir             if( !nCurrCol )
919cdf0e10cSrcweir                 pBox->setRowSpan( nRowSpan );
920cdf0e10cSrcweir         }
921cdf0e10cSrcweir         if( nRowSpan > 0 ) // the master cell is done, from now on we set
922cdf0e10cSrcweir             nRowSpan = -nRowSpan; // negative row spans
923cdf0e10cSrcweir         ++nRowSpan; // ... -3, -2, -1
924cdf0e10cSrcweir     }
925cdf0e10cSrcweir     if( bMerge )
926cdf0e10cSrcweir     {
927cdf0e10cSrcweir         // A row containing overlapped cells is superfluous,
928cdf0e10cSrcweir         // these cells can be put into rBoxes for deletion
929cdf0e10cSrcweir         _FindSuperfluousRows( rBoxes, pFirstLn, pLastLn );
930cdf0e10cSrcweir         // pNewFmt will be set to the new master box and the overlapped cells
931cdf0e10cSrcweir         SwFrmFmt* pNewFmt = pMergeBox->ClaimFrmFmt();
932cdf0e10cSrcweir         pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, pSel->mnMergeWidth, 0 ) );
933cdf0e10cSrcweir         for( sal_uInt16 nCurrLine = 0; nCurrLine < nLineCount; ++nCurrLine )
934cdf0e10cSrcweir         {
935cdf0e10cSrcweir             const SwSelBoxes* pBoxes = pSel->aBoxes[ nCurrLine ];
936cdf0e10cSrcweir             sal_uInt16 nColCount = pBoxes->Count();
937cdf0e10cSrcweir             for( sal_uInt16 nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol )
938cdf0e10cSrcweir             {
939cdf0e10cSrcweir                 SwTableBox* pBox = (*pBoxes)[nCurrCol];
940cdf0e10cSrcweir                 if( nCurrCol )
941cdf0e10cSrcweir                 {
942cdf0e10cSrcweir                     // Even this box will be deleted soon,
943cdf0e10cSrcweir                     // we have to correct the width to avoid side effects
944cdf0e10cSrcweir                     SwFrmFmt* pFmt = pBox->ClaimFrmFmt();
945cdf0e10cSrcweir                     pFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, 0, 0 ) );
946cdf0e10cSrcweir                 }
947cdf0e10cSrcweir                 else
948cdf0e10cSrcweir                     pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt );
949cdf0e10cSrcweir             }
950cdf0e10cSrcweir         }
951cdf0e10cSrcweir         if( pLastBox ) // Robust
952cdf0e10cSrcweir         {
953cdf0e10cSrcweir             // The new borders of the master cell...
954cdf0e10cSrcweir             SvxBoxItem aBox( pMergeBox->GetFrmFmt()->GetBox() );
955cdf0e10cSrcweir             bool bOld = aBox.GetRight() || aBox.GetBottom();
956cdf0e10cSrcweir             const SvxBoxItem& rBox = pLastBox->GetFrmFmt()->GetBox();
957cdf0e10cSrcweir             aBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT );
958cdf0e10cSrcweir             aBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM );
959cdf0e10cSrcweir             if( bOld || aBox.GetLeft() || aBox.GetTop() || aBox.GetRight() || aBox.GetBottom() )
960cdf0e10cSrcweir                 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( aBox );
961cdf0e10cSrcweir         }
962cdf0e10cSrcweir 
963cdf0e10cSrcweir         if( pUndo )
964cdf0e10cSrcweir             pUndo->AddNewBox( pMergeBox->GetSttIdx() );
965cdf0e10cSrcweir     }
966cdf0e10cSrcweir     return bMerge;
967cdf0e10cSrcweir }
968cdf0e10cSrcweir 
969cdf0e10cSrcweir /** SwTable::_FindSuperfluousRows(..) is looking for superfluous rows, i.e. rows
970cdf0e10cSrcweir     containing overlapped cells only.
971cdf0e10cSrcweir */
972cdf0e10cSrcweir 
_FindSuperfluousRows(SwSelBoxes & rBoxes,SwTableLine * pFirstLn,SwTableLine * pLastLn)973cdf0e10cSrcweir void SwTable::_FindSuperfluousRows( SwSelBoxes& rBoxes,
974cdf0e10cSrcweir     SwTableLine* pFirstLn, SwTableLine* pLastLn )
975cdf0e10cSrcweir {
976cdf0e10cSrcweir     if( !pFirstLn || !pLastLn )
977cdf0e10cSrcweir     {
978cdf0e10cSrcweir         if( !rBoxes.Count() )
979cdf0e10cSrcweir             return;
980cdf0e10cSrcweir         pFirstLn = rBoxes[0]->GetUpper();
981cdf0e10cSrcweir         pLastLn = rBoxes[ rBoxes.Count() - 1 ]->GetUpper();
982cdf0e10cSrcweir     }
983cdf0e10cSrcweir     sal_uInt16 nFirstLn = GetTabLines().C40_GETPOS(SwTableLine, pFirstLn );
984cdf0e10cSrcweir     sal_uInt16 nLastLn = GetTabLines().C40_GETPOS(SwTableLine, pLastLn );
985cdf0e10cSrcweir     for( sal_uInt16 nRow = nFirstLn; nRow <= nLastLn; ++nRow )
986cdf0e10cSrcweir     {
987cdf0e10cSrcweir         SwTableLine* pLine = aLines[nRow];
988cdf0e10cSrcweir         ASSERT( pLine, "Missing table line" );
989cdf0e10cSrcweir         sal_uInt16 nCols = pLine->GetTabBoxes().Count();
990cdf0e10cSrcweir         bool bSuperfl = true;
991cdf0e10cSrcweir         for( sal_uInt16 nCol = 0; nCol < nCols; ++nCol )
992cdf0e10cSrcweir         {
993cdf0e10cSrcweir             SwTableBox *pBox = pLine->GetTabBoxes()[nCol];
994cdf0e10cSrcweir             if( pBox->getRowSpan() > 0 &&
995cdf0e10cSrcweir                 USHRT_MAX == rBoxes.GetPos( pBox ) )
996cdf0e10cSrcweir             {
997cdf0e10cSrcweir                 bSuperfl = false;
998cdf0e10cSrcweir                 break;
999cdf0e10cSrcweir             }
1000cdf0e10cSrcweir         }
1001cdf0e10cSrcweir         if( bSuperfl )
1002cdf0e10cSrcweir         {
1003cdf0e10cSrcweir             for( sal_uInt16 nCol = 0; nCol < nCols; ++nCol )
1004cdf0e10cSrcweir             {
1005cdf0e10cSrcweir                 SwTableBox* pBox = pLine->GetTabBoxes()[nCol];
1006cdf0e10cSrcweir                 rBoxes.Insert( pBox );
1007cdf0e10cSrcweir             }
1008cdf0e10cSrcweir         }
1009cdf0e10cSrcweir     }
1010cdf0e10cSrcweir }
1011cdf0e10cSrcweir 
1012cdf0e10cSrcweir /** SwTableBox::FindStartOfRowSpan(..) retruns the "master" cell, the cell which
1013cdf0e10cSrcweir     overlaps the given cell, it maybe the cell itself.
1014cdf0e10cSrcweir */
1015cdf0e10cSrcweir 
FindStartOfRowSpan(const SwTable & rTable,sal_uInt16 nMaxStep)1016cdf0e10cSrcweir SwTableBox& SwTableBox::FindStartOfRowSpan( const SwTable& rTable, sal_uInt16 nMaxStep )
1017cdf0e10cSrcweir {
1018cdf0e10cSrcweir     if( getRowSpan() > 0 || !nMaxStep )
1019cdf0e10cSrcweir         return *this;
1020cdf0e10cSrcweir 
1021cdf0e10cSrcweir     long nLeftBorder = lcl_Box2LeftBorder( *this );
1022cdf0e10cSrcweir     SwTableBox* pBox = this;
1023cdf0e10cSrcweir     const SwTableLine* pMyUpper = GetUpper();
1024cdf0e10cSrcweir     sal_uInt16 nLine = rTable.GetTabLines().C40_GETPOS(SwTableLine, pMyUpper );
1025cdf0e10cSrcweir     if( nLine && nLine < rTable.GetTabLines().Count() )
1026cdf0e10cSrcweir     {
1027cdf0e10cSrcweir         SwTableBox* pNext;
1028cdf0e10cSrcweir         do
1029cdf0e10cSrcweir         {
1030cdf0e10cSrcweir             pNext = lcl_LeftBorder2Box( nLeftBorder, rTable.GetTabLines()[--nLine] );
1031cdf0e10cSrcweir             if( pNext )
1032cdf0e10cSrcweir                 pBox = pNext;
1033cdf0e10cSrcweir         } while( nLine && --nMaxStep && pNext && pBox->getRowSpan() < 1 );
1034cdf0e10cSrcweir     }
1035cdf0e10cSrcweir 
1036cdf0e10cSrcweir     return *pBox;
1037cdf0e10cSrcweir }
1038cdf0e10cSrcweir 
1039cdf0e10cSrcweir /** SwTableBox::FindEndOfRowSpan(..) returns the last overlapped cell if there is
1040cdf0e10cSrcweir     any. Otherwise the cell itself will returned.
1041cdf0e10cSrcweir */
1042cdf0e10cSrcweir 
FindEndOfRowSpan(const SwTable & rTable,sal_uInt16 nMaxStep)1043cdf0e10cSrcweir SwTableBox& SwTableBox::FindEndOfRowSpan( const SwTable& rTable, sal_uInt16 nMaxStep )
1044cdf0e10cSrcweir {
1045cdf0e10cSrcweir     long nAbsSpan = getRowSpan();
1046cdf0e10cSrcweir     if( nAbsSpan < 0 )
1047cdf0e10cSrcweir         nAbsSpan = -nAbsSpan;
1048cdf0e10cSrcweir     if( nAbsSpan == 1 || !nMaxStep )
1049cdf0e10cSrcweir         return *this;
1050cdf0e10cSrcweir 
1051cdf0e10cSrcweir     if( nMaxStep > --nAbsSpan )
1052cdf0e10cSrcweir         nMaxStep = (sal_uInt16)nAbsSpan;
1053cdf0e10cSrcweir     const SwTableLine* pMyUpper = GetUpper();
1054cdf0e10cSrcweir     sal_uInt16 nLine = rTable.GetTabLines().C40_GETPOS(SwTableLine, pMyUpper );
1055cdf0e10cSrcweir     nMaxStep = nLine + nMaxStep;
1056cdf0e10cSrcweir     if( nMaxStep >= rTable.GetTabLines().Count() )
1057cdf0e10cSrcweir         nMaxStep = rTable.GetTabLines().Count() - 1;
1058cdf0e10cSrcweir     long nLeftBorder = lcl_Box2LeftBorder( *this );
1059cdf0e10cSrcweir     SwTableBox* pBox =
1060cdf0e10cSrcweir         lcl_LeftBorder2Box( nLeftBorder, rTable.GetTabLines()[ nMaxStep ] );
1061cdf0e10cSrcweir     if ( !pBox )
1062cdf0e10cSrcweir         pBox = this;
1063cdf0e10cSrcweir 
1064cdf0e10cSrcweir     return *pBox;
1065cdf0e10cSrcweir }
1066cdf0e10cSrcweir 
1067cdf0e10cSrcweir /** lcl_getAllMergedBoxes(..) collects all overlapped boxes to a given (master) box
1068cdf0e10cSrcweir */
1069cdf0e10cSrcweir 
lcl_getAllMergedBoxes(const SwTable & rTable,SwSelBoxes & rBoxes,SwTableBox & rBox)1070cdf0e10cSrcweir void lcl_getAllMergedBoxes( const SwTable& rTable, SwSelBoxes& rBoxes, SwTableBox& rBox )
1071cdf0e10cSrcweir {
1072cdf0e10cSrcweir     SwTableBox* pBox = &rBox;
1073cdf0e10cSrcweir     ASSERT( pBox == &rBox.FindStartOfRowSpan( rTable, USHRT_MAX ), "Not a master box" );
1074cdf0e10cSrcweir     rBoxes.Insert( pBox );
1075cdf0e10cSrcweir     if( pBox->getRowSpan() == 1 )
1076cdf0e10cSrcweir         return;
1077cdf0e10cSrcweir     const SwTableLine* pMyUpper = pBox->GetUpper();
1078cdf0e10cSrcweir     sal_uInt16 nLine = rTable.GetTabLines().C40_GETPOS(SwTableLine, pMyUpper );
1079cdf0e10cSrcweir     long nLeftBorder = lcl_Box2LeftBorder( *pBox );
1080cdf0e10cSrcweir     sal_uInt16 nCount = rTable.GetTabLines().Count();
1081cdf0e10cSrcweir     while( ++nLine < nCount && pBox && pBox->getRowSpan() != -1 )
1082cdf0e10cSrcweir     {
1083cdf0e10cSrcweir         pBox = lcl_LeftBorder2Box( nLeftBorder, rTable.GetTabLines()[nLine] );
1084cdf0e10cSrcweir         if( pBox )
1085cdf0e10cSrcweir             rBoxes.Insert( pBox );
1086cdf0e10cSrcweir     };
1087cdf0e10cSrcweir }
1088cdf0e10cSrcweir 
1089cdf0e10cSrcweir /** lcl_UnMerge(..) manipulates the row span attribute of a given master cell
1090cdf0e10cSrcweir     and its overlapped cells to split them into several pieces.
1091cdf0e10cSrcweir */
1092cdf0e10cSrcweir 
lcl_UnMerge(const SwTable & rTable,SwTableBox & rBox,sal_uInt16 nCnt,sal_Bool bSameHeight)1093cdf0e10cSrcweir void lcl_UnMerge( const SwTable& rTable, SwTableBox& rBox, sal_uInt16 nCnt,
1094cdf0e10cSrcweir     sal_Bool bSameHeight )
1095cdf0e10cSrcweir {
1096cdf0e10cSrcweir     SwSelBoxes aBoxes;
1097cdf0e10cSrcweir     lcl_getAllMergedBoxes( rTable, aBoxes, rBox );
1098cdf0e10cSrcweir     sal_uInt16 nCount = aBoxes.Count();
1099cdf0e10cSrcweir     if( nCount < 2 )
1100cdf0e10cSrcweir         return;
1101cdf0e10cSrcweir     if( nCnt > nCount )
1102cdf0e10cSrcweir         nCnt = nCount;
1103cdf0e10cSrcweir     sal_uInt16 *pSplitIdx = new sal_uInt16[ nCnt ];
1104cdf0e10cSrcweir     if( bSameHeight )
1105cdf0e10cSrcweir     {
1106cdf0e10cSrcweir         SwTwips *pHeights = new SwTwips[ nCount ];
1107cdf0e10cSrcweir         SwTwips nHeight = 0;
1108cdf0e10cSrcweir         for( sal_uInt16 i = 0; i < nCount; ++i )
1109cdf0e10cSrcweir         {
1110cdf0e10cSrcweir             SwTableLine* pLine = aBoxes[ i ]->GetUpper();
1111cdf0e10cSrcweir             SwFrmFmt *pRowFmt = pLine->GetFrmFmt();
1112cdf0e10cSrcweir             pHeights[ i ] = pRowFmt->GetFrmSize().GetHeight();
1113cdf0e10cSrcweir             nHeight += pHeights[ i ];
1114cdf0e10cSrcweir         }
1115cdf0e10cSrcweir         SwTwips nSumH = 0;
1116cdf0e10cSrcweir         sal_uInt16 nIdx = 0;
1117cdf0e10cSrcweir         for( sal_uInt16 i = 1; i <= nCnt; ++i )
1118cdf0e10cSrcweir         {
1119cdf0e10cSrcweir             SwTwips nSplit = ( i * nHeight ) / nCnt;
1120cdf0e10cSrcweir             while( nSumH < nSplit && nIdx < nCount )
1121cdf0e10cSrcweir                 nSumH += pHeights[ nIdx++ ];
1122cdf0e10cSrcweir             pSplitIdx[ i - 1 ] = nIdx;
1123cdf0e10cSrcweir         }
1124cdf0e10cSrcweir         delete[] pHeights;
1125cdf0e10cSrcweir     }
1126cdf0e10cSrcweir     else
1127cdf0e10cSrcweir     {
1128cdf0e10cSrcweir         for( long i = 1; i <= nCnt; ++i )
1129cdf0e10cSrcweir             pSplitIdx[ i - 1 ] = (sal_uInt16)( ( i * nCount ) / nCnt );
1130cdf0e10cSrcweir     }
1131cdf0e10cSrcweir     sal_uInt16 nIdx = 0;
1132cdf0e10cSrcweir     for( long i = 0; i < nCnt; ++i )
1133cdf0e10cSrcweir     {
1134cdf0e10cSrcweir         sal_uInt16 nNextIdx = pSplitIdx[ i ];
1135cdf0e10cSrcweir         aBoxes[ nIdx ]->setRowSpan( nNextIdx - nIdx );
1136cdf0e10cSrcweir         lcl_InvalidateCellFrm( *aBoxes[ nIdx ] );
1137cdf0e10cSrcweir         while( ++nIdx < nNextIdx )
1138cdf0e10cSrcweir             aBoxes[ nIdx ]->setRowSpan( nIdx - nNextIdx );
1139cdf0e10cSrcweir     }
1140cdf0e10cSrcweir     delete[] pSplitIdx;
1141cdf0e10cSrcweir }
1142cdf0e10cSrcweir 
1143cdf0e10cSrcweir /** lcl_FillSelBoxes(..) puts all boxes of a given line into the selection structure
1144cdf0e10cSrcweir */
1145cdf0e10cSrcweir 
lcl_FillSelBoxes(SwSelBoxes & rBoxes,SwTableLine & rLine)1146cdf0e10cSrcweir void lcl_FillSelBoxes( SwSelBoxes &rBoxes, SwTableLine &rLine )
1147cdf0e10cSrcweir {
1148cdf0e10cSrcweir     sal_uInt16 nBoxCount = rLine.GetTabBoxes().Count();
1149cdf0e10cSrcweir     sal_uInt16 nCurrBox;
1150cdf0e10cSrcweir     for( nCurrBox = 0; nCurrBox < nBoxCount; ++nCurrBox )
1151cdf0e10cSrcweir         rBoxes.Insert( rLine.GetTabBoxes()[nCurrBox] );
1152cdf0e10cSrcweir }
1153cdf0e10cSrcweir 
1154cdf0e10cSrcweir /** SwTable::InsertSpannedRow(..) inserts "superfluous" rows, i.e. rows containig
1155cdf0e10cSrcweir     overlapped cells only. This is a preparation for an upcoming split.
1156cdf0e10cSrcweir */
1157cdf0e10cSrcweir 
InsertSpannedRow(SwDoc * pDoc,sal_uInt16 nRowIdx,sal_uInt16 nCnt)1158cdf0e10cSrcweir void SwTable::InsertSpannedRow( SwDoc* pDoc, sal_uInt16 nRowIdx, sal_uInt16 nCnt )
1159cdf0e10cSrcweir {
1160cdf0e10cSrcweir     CHECK_TABLE( *this )
1161cdf0e10cSrcweir     ASSERT( nCnt && nRowIdx < GetTabLines().Count(), "Wrong call of InsertSpannedRow" );
1162cdf0e10cSrcweir     SwSelBoxes aBoxes;
1163cdf0e10cSrcweir     SwTableLine& rLine = *GetTabLines()[ nRowIdx ];
1164cdf0e10cSrcweir     lcl_FillSelBoxes( aBoxes, rLine );
1165cdf0e10cSrcweir     SwFmtFrmSize aFSz( rLine.GetFrmFmt()->GetFrmSize() );
1166cdf0e10cSrcweir     if( ATT_VAR_SIZE != aFSz.GetHeightSizeType() )
1167cdf0e10cSrcweir     {
1168cdf0e10cSrcweir         SwFrmFmt* pFrmFmt = rLine.ClaimFrmFmt();
1169cdf0e10cSrcweir         long nNewHeight = aFSz.GetHeight() / ( nCnt + 1 );
1170cdf0e10cSrcweir         if( !nNewHeight )
1171cdf0e10cSrcweir             ++nNewHeight;
1172cdf0e10cSrcweir         aFSz.SetHeight( nNewHeight );
1173cdf0e10cSrcweir         pFrmFmt->SetFmtAttr( aFSz );
1174cdf0e10cSrcweir     }
1175cdf0e10cSrcweir     _InsertRow( pDoc, aBoxes, nCnt, sal_True );
1176cdf0e10cSrcweir     sal_uInt16 nBoxCount = rLine.GetTabBoxes().Count();
1177cdf0e10cSrcweir     for( sal_uInt16 n = 0; n < nCnt; ++n )
1178cdf0e10cSrcweir     {
1179cdf0e10cSrcweir         SwTableLine *pNewLine = GetTabLines()[ nRowIdx + nCnt - n ];
1180cdf0e10cSrcweir         for( sal_uInt16 nCurrBox = 0; nCurrBox < nBoxCount; ++nCurrBox )
1181cdf0e10cSrcweir         {
1182cdf0e10cSrcweir             long nRowSpan = rLine.GetTabBoxes()[nCurrBox]->getRowSpan();
1183cdf0e10cSrcweir             if( nRowSpan > 0 )
1184cdf0e10cSrcweir                 nRowSpan = - nRowSpan;
1185cdf0e10cSrcweir             pNewLine->GetTabBoxes()[ nCurrBox ]->setRowSpan( nRowSpan - n );
1186cdf0e10cSrcweir         }
1187cdf0e10cSrcweir     }
1188cdf0e10cSrcweir     lcl_ChangeRowSpan( *this, nCnt, nRowIdx, false );
1189cdf0e10cSrcweir     CHECK_TABLE( *this )
1190cdf0e10cSrcweir }
1191cdf0e10cSrcweir 
1192cdf0e10cSrcweir typedef std::pair< sal_uInt16, sal_uInt16 > SwLineOffset;
1193cdf0e10cSrcweir typedef std::list< SwLineOffset > SwLineOffsetArray;
1194cdf0e10cSrcweir 
1195cdf0e10cSrcweir /******************************************************************************
1196cdf0e10cSrcweir When a couple of table boxes has to be split,
1197cdf0e10cSrcweir lcl_SophisticatedFillLineIndices delivers the information where and how many
1198cdf0e10cSrcweir rows have to be inserted.
1199cdf0e10cSrcweir Input
1200cdf0e10cSrcweir     rTable: the table to manipulate
1201cdf0e10cSrcweir     rBoxes: an array of boxes to split
1202cdf0e10cSrcweir     nCnt:   how many parts are wanted
1203cdf0e10cSrcweir Output
1204cdf0e10cSrcweir     rArr:   a list of pairs ( line index, number of lines to insert )
1205cdf0e10cSrcweir 
1206cdf0e10cSrcweir ******************************************************************************/
1207cdf0e10cSrcweir 
lcl_SophisticatedFillLineIndices(SwLineOffsetArray & rArr,const SwTable & rTable,const SwSelBoxes & rBoxes,sal_uInt16 nCnt)1208cdf0e10cSrcweir void lcl_SophisticatedFillLineIndices( SwLineOffsetArray &rArr,
1209cdf0e10cSrcweir     const SwTable& rTable, const SwSelBoxes& rBoxes, sal_uInt16 nCnt )
1210cdf0e10cSrcweir {
1211cdf0e10cSrcweir     std::list< SwLineOffset > aBoxes;
1212cdf0e10cSrcweir     SwLineOffset aLnOfs( USHRT_MAX, USHRT_MAX );
1213cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
1214cdf0e10cSrcweir     {   // Collect all end line indices and the row spans
1215cdf0e10cSrcweir         const SwTableBox &rBox = rBoxes[ i ]->FindStartOfRowSpan( rTable );
1216cdf0e10cSrcweir         ASSERT( rBox.getRowSpan() > 0, "Didn't I say 'StartOfRowSpan' ??" )
1217cdf0e10cSrcweir         if( nCnt > rBox.getRowSpan() )
1218cdf0e10cSrcweir         {
1219cdf0e10cSrcweir             const SwTableLine *pLine = rBox.GetUpper();
1220cdf0e10cSrcweir             const sal_uInt16 nEnd = sal_uInt16( rBox.getRowSpan() +
1221cdf0e10cSrcweir                 rTable.GetTabLines().C40_GETPOS( SwTableLine, pLine ) );
1222cdf0e10cSrcweir             // The next if statement is a small optimization
1223cdf0e10cSrcweir             if( aLnOfs.first != nEnd || aLnOfs.second != rBox.getRowSpan() )
1224cdf0e10cSrcweir             {
1225cdf0e10cSrcweir                 aLnOfs.first = nEnd; // ok, this is the line behind the box
1226cdf0e10cSrcweir                 aLnOfs.second = sal_uInt16( rBox.getRowSpan() ); // the row span
1227cdf0e10cSrcweir                 aBoxes.insert( aBoxes.end(), aLnOfs );
1228cdf0e10cSrcweir             }
1229cdf0e10cSrcweir         }
1230cdf0e10cSrcweir     }
1231cdf0e10cSrcweir     // As I said, I noted the line index _behind_ the last line of the boxes
1232cdf0e10cSrcweir     // in the resulting array the index has to be _on_ the line
1233cdf0e10cSrcweir     // nSum is to evaluate the wished value
1234cdf0e10cSrcweir     sal_uInt16 nSum = 1;
1235cdf0e10cSrcweir     while( aBoxes.size() )
1236cdf0e10cSrcweir     {
1237cdf0e10cSrcweir         // I. step:
1238cdf0e10cSrcweir         // Looking for the "smallest" line end with the smallest row span
1239cdf0e10cSrcweir         std::list< SwLineOffset >::iterator pCurr = aBoxes.begin();
1240cdf0e10cSrcweir         aLnOfs = *pCurr; // the line end and row span of the first box
1241cdf0e10cSrcweir         while( ++pCurr != aBoxes.end() )
1242cdf0e10cSrcweir         {
1243cdf0e10cSrcweir             if( aLnOfs.first > pCurr->first )
1244cdf0e10cSrcweir             {   // Found a smaller line end
1245cdf0e10cSrcweir                 aLnOfs.first = pCurr->first;
1246cdf0e10cSrcweir                 aLnOfs.second = pCurr->second; // row span
1247cdf0e10cSrcweir             }
1248cdf0e10cSrcweir             else if( aLnOfs.first == pCurr->first &&
1249cdf0e10cSrcweir                      aLnOfs.second < pCurr->second )
1250cdf0e10cSrcweir                 aLnOfs.second = pCurr->second; // Found a smaller row span
1251cdf0e10cSrcweir         }
1252cdf0e10cSrcweir         ASSERT( aLnOfs.second < nCnt, "Clean-up failed" )
1253cdf0e10cSrcweir         aLnOfs.second = nCnt - aLnOfs.second; // the number of rows to insert
1254cdf0e10cSrcweir         rArr.insert( rArr.end(),
1255cdf0e10cSrcweir             SwLineOffset( aLnOfs.first - nSum, aLnOfs.second ) );
1256cdf0e10cSrcweir         // the correction has to be incremented because in the following
1257cdf0e10cSrcweir         // loops the line ends were manipulated
1258cdf0e10cSrcweir         nSum = nSum + aLnOfs.second;
1259cdf0e10cSrcweir 
1260cdf0e10cSrcweir         pCurr = aBoxes.begin();
1261cdf0e10cSrcweir         while( pCurr != aBoxes.end() )
1262cdf0e10cSrcweir         {
1263cdf0e10cSrcweir             if( pCurr->first == aLnOfs.first )
1264cdf0e10cSrcweir             {   // These boxes can be removed because the last insertion
1265cdf0e10cSrcweir                 // of rows will expand their row span above the needed value
1266cdf0e10cSrcweir                 std::list< SwLineOffset >::iterator pDel = pCurr;
1267cdf0e10cSrcweir                 ++pCurr;
1268cdf0e10cSrcweir                 aBoxes.erase( pDel );
1269cdf0e10cSrcweir             }
1270cdf0e10cSrcweir             else
1271cdf0e10cSrcweir             {
1272cdf0e10cSrcweir                 bool bBefore = ( pCurr->first - pCurr->second < aLnOfs.first );
1273cdf0e10cSrcweir                 // Manipulation of the end line indices as if the rows are
1274cdf0e10cSrcweir                 // already inserted
1275cdf0e10cSrcweir                 pCurr->first = pCurr->first + aLnOfs.second;
1276cdf0e10cSrcweir                 if( bBefore )
1277cdf0e10cSrcweir                 {   // If the insertion is inside the box,
1278cdf0e10cSrcweir                     // its row span has to be incremented
1279cdf0e10cSrcweir                     pCurr->second = pCurr->second + aLnOfs.second;
1280cdf0e10cSrcweir                     if( pCurr->second >= nCnt )
1281cdf0e10cSrcweir                     {   // if the row span is bigger than the split factor
1282cdf0e10cSrcweir                         // this box is done
1283cdf0e10cSrcweir                         std::list< SwLineOffset >::iterator pDel = pCurr;
1284cdf0e10cSrcweir                         ++pCurr;
1285cdf0e10cSrcweir                         aBoxes.erase( pDel );
1286cdf0e10cSrcweir                     }
1287cdf0e10cSrcweir                     else
1288cdf0e10cSrcweir                         ++pCurr;
1289cdf0e10cSrcweir                 }
1290cdf0e10cSrcweir                 else
1291cdf0e10cSrcweir                     ++pCurr;
1292cdf0e10cSrcweir             }
1293cdf0e10cSrcweir         }
1294cdf0e10cSrcweir     }
1295cdf0e10cSrcweir }
1296cdf0e10cSrcweir 
1297cdf0e10cSrcweir typedef std::set< SwTwips > SwSplitLines;
1298cdf0e10cSrcweir 
1299cdf0e10cSrcweir /** lcl_CalculateSplitLineHeights(..) delivers all y-positions where table rows have
1300cdf0e10cSrcweir     to be splitted to fulfill the requested "split same height"
1301cdf0e10cSrcweir */
1302cdf0e10cSrcweir 
lcl_CalculateSplitLineHeights(SwSplitLines & rCurr,SwSplitLines & rNew,const SwTable & rTable,const SwSelBoxes & rBoxes,sal_uInt16 nCnt)1303cdf0e10cSrcweir sal_uInt16 lcl_CalculateSplitLineHeights( SwSplitLines &rCurr, SwSplitLines &rNew,
1304cdf0e10cSrcweir     const SwTable& rTable, const SwSelBoxes& rBoxes, sal_uInt16 nCnt )
1305cdf0e10cSrcweir {
1306cdf0e10cSrcweir     if( nCnt < 2 )
1307cdf0e10cSrcweir         return 0;
1308cdf0e10cSrcweir     std::list< SwLineOffset > aBoxes;
1309cdf0e10cSrcweir     SwLineOffset aLnOfs( USHRT_MAX, USHRT_MAX );
1310cdf0e10cSrcweir     sal_uInt16 nFirst = USHRT_MAX; // becomes the index of the first line
1311cdf0e10cSrcweir     sal_uInt16 nLast = 0; // becomes the index of the last line of the splitting
1312cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
1313cdf0e10cSrcweir     {   // Collect all pairs (start+end) of line indices to split
1314cdf0e10cSrcweir         const SwTableBox &rBox = rBoxes[ i ]->FindStartOfRowSpan( rTable );
1315cdf0e10cSrcweir         ASSERT( rBox.getRowSpan() > 0, "Didn't I say 'StartOfRowSpan' ??" )
1316cdf0e10cSrcweir         const SwTableLine *pLine = rBox.GetUpper();
1317cdf0e10cSrcweir         const sal_uInt16 nStart = rTable.GetTabLines().C40_GETPOS( SwTableLine, pLine );
1318cdf0e10cSrcweir         const sal_uInt16 nEnd = sal_uInt16( rBox.getRowSpan() + nStart - 1 );
1319cdf0e10cSrcweir         // The next if statement is a small optimization
1320cdf0e10cSrcweir         if( aLnOfs.first != nStart || aLnOfs.second != nEnd )
1321cdf0e10cSrcweir         {
1322cdf0e10cSrcweir             aLnOfs.first = nStart;
1323cdf0e10cSrcweir             aLnOfs.second = nEnd;
1324cdf0e10cSrcweir             aBoxes.insert( aBoxes.end(), aLnOfs );
1325cdf0e10cSrcweir             if( nStart < nFirst )
1326cdf0e10cSrcweir                 nFirst = nStart;
1327cdf0e10cSrcweir             if( nEnd > nLast )
1328cdf0e10cSrcweir                 nLast = nEnd;
1329cdf0e10cSrcweir         }
1330cdf0e10cSrcweir     }
1331cdf0e10cSrcweir 
1332cdf0e10cSrcweir     if( aBoxes.empty() )
1333cdf0e10cSrcweir         return 0;
1334cdf0e10cSrcweir     SwTwips nHeight = 0;
1335cdf0e10cSrcweir     SwTwips* pLines = new SwTwips[ nLast + 1 - nFirst ];
1336cdf0e10cSrcweir     for( sal_uInt16 i = nFirst; i <= nLast; ++i )
1337cdf0e10cSrcweir     {
1338cdf0e10cSrcweir         bool bLayoutAvailable = false;
1339cdf0e10cSrcweir         nHeight += rTable.GetTabLines()[ i ]->GetTableLineHeight( bLayoutAvailable );
1340cdf0e10cSrcweir         rCurr.insert( rCurr.end(), nHeight );
1341cdf0e10cSrcweir         pLines[ i - nFirst ] = nHeight;
1342cdf0e10cSrcweir     }
1343cdf0e10cSrcweir     std::list< SwLineOffset >::iterator pSplit = aBoxes.begin();
1344cdf0e10cSrcweir     while( pSplit != aBoxes.end() )
1345cdf0e10cSrcweir     {
1346cdf0e10cSrcweir         SwTwips nBase = pSplit->first <= nFirst ? 0 :
1347cdf0e10cSrcweir                         pLines[ pSplit->first - nFirst - 1 ];
1348cdf0e10cSrcweir         SwTwips nDiff = pLines[ pSplit->second - nFirst ] - nBase;
1349cdf0e10cSrcweir         for( sal_uInt16 i = 1; i < nCnt; ++i )
1350cdf0e10cSrcweir         {
1351cdf0e10cSrcweir             SwTwips nSplit = nBase + ( i * nDiff ) / nCnt;
1352cdf0e10cSrcweir             rNew.insert( nSplit );
1353cdf0e10cSrcweir         }
1354cdf0e10cSrcweir         ++pSplit;
1355cdf0e10cSrcweir     }
1356cdf0e10cSrcweir     delete[] pLines;
1357cdf0e10cSrcweir     return nFirst;
1358cdf0e10cSrcweir }
1359cdf0e10cSrcweir 
1360cdf0e10cSrcweir /** lcl_LineIndex(..) delivers the line index of the line behind or above
1361cdf0e10cSrcweir     the box selection.
1362cdf0e10cSrcweir */
1363cdf0e10cSrcweir 
lcl_LineIndex(const SwTable & rTable,const SwSelBoxes & rBoxes,bool bBehind)1364cdf0e10cSrcweir sal_uInt16 lcl_LineIndex( const SwTable& rTable, const SwSelBoxes& rBoxes,
1365cdf0e10cSrcweir                       bool bBehind )
1366cdf0e10cSrcweir {
1367cdf0e10cSrcweir     sal_uInt16 nDirect = USHRT_MAX;
1368cdf0e10cSrcweir     sal_uInt16 nSpan = USHRT_MAX;
1369cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
1370cdf0e10cSrcweir     {
1371cdf0e10cSrcweir         SwTableBox *pBox = rBoxes[i];
1372cdf0e10cSrcweir         const SwTableLine* pLine = rBoxes[i]->GetUpper();
1373cdf0e10cSrcweir         sal_uInt16 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pLine );
1374cdf0e10cSrcweir         if( USHRT_MAX != nPos )
1375cdf0e10cSrcweir         {
1376cdf0e10cSrcweir             if( bBehind )
1377cdf0e10cSrcweir             {
1378cdf0e10cSrcweir                 if( nPos > nDirect || nDirect == USHRT_MAX )
1379cdf0e10cSrcweir                     nDirect = nPos;
1380cdf0e10cSrcweir                 long nRowSpan = pBox->getRowSpan();
1381cdf0e10cSrcweir                 if( nRowSpan < 2 )
1382cdf0e10cSrcweir                     nSpan = 0;
1383cdf0e10cSrcweir                 else if( nSpan )
1384cdf0e10cSrcweir                 {
1385cdf0e10cSrcweir                     sal_uInt16 nEndOfRowSpan = (sal_uInt16)(nPos + nRowSpan - 1);
1386cdf0e10cSrcweir                     if( nEndOfRowSpan > nSpan || nSpan == USHRT_MAX )
1387cdf0e10cSrcweir                         nSpan = nEndOfRowSpan;
1388cdf0e10cSrcweir                 }
1389cdf0e10cSrcweir             }
1390cdf0e10cSrcweir             else if( nPos < nDirect )
1391cdf0e10cSrcweir                 nDirect = nPos;
1392cdf0e10cSrcweir         }
1393cdf0e10cSrcweir     }
1394cdf0e10cSrcweir     if( nSpan && nSpan < USHRT_MAX )
1395cdf0e10cSrcweir         return nSpan;
1396cdf0e10cSrcweir     return nDirect;
1397cdf0e10cSrcweir }
1398cdf0e10cSrcweir 
1399cdf0e10cSrcweir /** SwTable::NewSplitRow(..) splits all selected boxes horizontally.
1400cdf0e10cSrcweir */
1401cdf0e10cSrcweir 
NewSplitRow(SwDoc * pDoc,const SwSelBoxes & rBoxes,sal_uInt16 nCnt,sal_Bool bSameHeight)1402cdf0e10cSrcweir sal_Bool SwTable::NewSplitRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt,
1403cdf0e10cSrcweir     sal_Bool bSameHeight )
1404cdf0e10cSrcweir {
1405cdf0e10cSrcweir     CHECK_TABLE( *this )
1406cdf0e10cSrcweir     ++nCnt;
1407cdf0e10cSrcweir 	_FndBox aFndBox( 0, 0 );
1408cdf0e10cSrcweir 	aFndBox.SetTableLines( rBoxes, *this );
1409cdf0e10cSrcweir 
1410cdf0e10cSrcweir     if( bSameHeight && pDoc->GetCurrentViewShell() )	//swmod 071108//swmod 071225
1411cdf0e10cSrcweir     {
1412cdf0e10cSrcweir         SwSplitLines aRowLines;
1413cdf0e10cSrcweir         SwSplitLines aSplitLines;
1414cdf0e10cSrcweir         sal_uInt16 nFirst = lcl_CalculateSplitLineHeights( aRowLines, aSplitLines,
1415cdf0e10cSrcweir             *this, rBoxes, nCnt );
1416cdf0e10cSrcweir         aFndBox.DelFrms( *this );
1417cdf0e10cSrcweir         SwTwips nLast = 0;
1418cdf0e10cSrcweir         SwSplitLines::iterator pSplit = aSplitLines.begin();
1419cdf0e10cSrcweir         SwSplitLines::iterator pCurr = aRowLines.begin();
1420cdf0e10cSrcweir         while( pCurr != aRowLines.end() )
1421cdf0e10cSrcweir         {
1422cdf0e10cSrcweir             while( pSplit != aSplitLines.end() && *pSplit < *pCurr )
1423cdf0e10cSrcweir             {
1424cdf0e10cSrcweir                 InsertSpannedRow( pDoc, nFirst, 1 );
1425cdf0e10cSrcweir                 SwTableLine* pRow = GetTabLines()[ nFirst ];
1426cdf0e10cSrcweir                 SwFrmFmt* pRowFmt = pRow->ClaimFrmFmt();
1427cdf0e10cSrcweir                 SwFmtFrmSize aFSz( pRowFmt->GetFrmSize() );
1428cdf0e10cSrcweir                 aFSz.SetHeightSizeType( ATT_MIN_SIZE );
1429cdf0e10cSrcweir                 aFSz.SetHeight( *pSplit - nLast );
1430cdf0e10cSrcweir                 pRowFmt->SetFmtAttr( aFSz );
1431cdf0e10cSrcweir                 nLast = *pSplit;
1432cdf0e10cSrcweir                 ++pSplit;
1433cdf0e10cSrcweir                 ++nFirst;
1434cdf0e10cSrcweir             }
1435cdf0e10cSrcweir             if( pSplit != aSplitLines.end() && *pCurr == *pSplit )
1436cdf0e10cSrcweir                 ++pSplit;
1437cdf0e10cSrcweir             SwTableLine* pRow = GetTabLines()[ nFirst ];
1438cdf0e10cSrcweir             SwFrmFmt* pRowFmt = pRow->ClaimFrmFmt();
1439cdf0e10cSrcweir             SwFmtFrmSize aFSz( pRowFmt->GetFrmSize() );
1440cdf0e10cSrcweir             aFSz.SetHeightSizeType( ATT_MIN_SIZE );
1441cdf0e10cSrcweir             aFSz.SetHeight( *pCurr - nLast );
1442cdf0e10cSrcweir             pRowFmt->SetFmtAttr( aFSz );
1443cdf0e10cSrcweir             nLast = *pCurr;
1444cdf0e10cSrcweir             ++pCurr;
1445cdf0e10cSrcweir             ++nFirst;
1446cdf0e10cSrcweir         }
1447cdf0e10cSrcweir     }
1448cdf0e10cSrcweir     else
1449cdf0e10cSrcweir     {
1450cdf0e10cSrcweir         aFndBox.DelFrms( *this );
1451cdf0e10cSrcweir         bSameHeight = sal_False;
1452cdf0e10cSrcweir     }
1453cdf0e10cSrcweir     if( !bSameHeight )
1454cdf0e10cSrcweir     {
1455cdf0e10cSrcweir         SwLineOffsetArray aLineOffs;
1456cdf0e10cSrcweir         lcl_SophisticatedFillLineIndices( aLineOffs, *this, rBoxes, nCnt );
1457cdf0e10cSrcweir         SwLineOffsetArray::reverse_iterator pCurr( aLineOffs.rbegin() );
1458cdf0e10cSrcweir         while( pCurr != aLineOffs.rend() )
1459cdf0e10cSrcweir         {
1460cdf0e10cSrcweir             InsertSpannedRow( pDoc, pCurr->first, pCurr->second );
1461cdf0e10cSrcweir             ++pCurr;
1462cdf0e10cSrcweir         }
1463cdf0e10cSrcweir     }
1464cdf0e10cSrcweir 
1465cdf0e10cSrcweir     std::set< sal_uInt16> aIndices;
1466cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
1467cdf0e10cSrcweir     {
1468cdf0e10cSrcweir         ASSERT( rBoxes[i]->getRowSpan() != 1, "Forgot to split?" )
1469cdf0e10cSrcweir         if( rBoxes[i]->getRowSpan() > 1 )
1470cdf0e10cSrcweir             aIndices.insert( i );
1471cdf0e10cSrcweir     }
1472cdf0e10cSrcweir 
1473cdf0e10cSrcweir     std::set< sal_uInt16 >::iterator pCurrBox = aIndices.begin();
1474cdf0e10cSrcweir     while( pCurrBox != aIndices.end() )
1475cdf0e10cSrcweir         lcl_UnMerge( *this, *rBoxes[*pCurrBox++], nCnt, bSameHeight );
1476cdf0e10cSrcweir 
1477cdf0e10cSrcweir     CHECK_TABLE( *this )
1478cdf0e10cSrcweir 	//Layout updaten
1479cdf0e10cSrcweir 	aFndBox.MakeFrms( *this );
1480cdf0e10cSrcweir 
1481cdf0e10cSrcweir     return sal_True;
1482cdf0e10cSrcweir }
1483cdf0e10cSrcweir 
1484cdf0e10cSrcweir /** SwTable::InsertRow(..) inserts one or more rows before or behind the selected
1485cdf0e10cSrcweir     boxes.
1486cdf0e10cSrcweir */
1487cdf0e10cSrcweir 
InsertRow(SwDoc * pDoc,const SwSelBoxes & rBoxes,sal_uInt16 nCnt,sal_Bool bBehind)1488cdf0e10cSrcweir sal_Bool SwTable::InsertRow( SwDoc* pDoc, const SwSelBoxes& rBoxes,
1489cdf0e10cSrcweir 						sal_uInt16 nCnt, sal_Bool bBehind )
1490cdf0e10cSrcweir {
1491cdf0e10cSrcweir     bool bRet = false;
1492cdf0e10cSrcweir     if( IsNewModel() )
1493cdf0e10cSrcweir     {
1494cdf0e10cSrcweir         CHECK_TABLE( *this )
1495cdf0e10cSrcweir         sal_uInt16 nRowIdx = lcl_LineIndex( *this, rBoxes, bBehind );
1496cdf0e10cSrcweir         if( nRowIdx < USHRT_MAX )
1497cdf0e10cSrcweir         {
1498cdf0e10cSrcweir             _FndBox aFndBox( 0, 0 );
1499cdf0e10cSrcweir             aFndBox.SetTableLines( rBoxes, *this );
1500cdf0e10cSrcweir             aFndBox.DelFrms( *this );
1501cdf0e10cSrcweir //             aFndBox.SaveChartData( *this );
1502cdf0e10cSrcweir 
1503cdf0e10cSrcweir             bRet = true;
1504cdf0e10cSrcweir             SwTableLine *pLine = GetTabLines()[ nRowIdx ];
1505cdf0e10cSrcweir             SwSelBoxes aLineBoxes;
1506cdf0e10cSrcweir             lcl_FillSelBoxes( aLineBoxes, *pLine );
1507cdf0e10cSrcweir             _InsertRow( pDoc, aLineBoxes, nCnt, bBehind );
1508cdf0e10cSrcweir             sal_uInt16 nBoxCount = pLine->GetTabBoxes().Count();
1509cdf0e10cSrcweir             sal_uInt16 nOfs = bBehind ? 0 : 1;
1510cdf0e10cSrcweir             for( sal_uInt16 n = 0; n < nCnt; ++n )
1511cdf0e10cSrcweir             {
1512cdf0e10cSrcweir                 SwTableLine *pNewLine = GetTabLines()[ nRowIdx+nCnt-n-nOfs];
1513cdf0e10cSrcweir                 for( sal_uInt16 nCurrBox = 0; nCurrBox < nBoxCount; ++nCurrBox )
1514cdf0e10cSrcweir                 {
1515cdf0e10cSrcweir                     long nRowSpan = pLine->GetTabBoxes()[nCurrBox]->getRowSpan();
1516cdf0e10cSrcweir                     if( bBehind )
1517cdf0e10cSrcweir                     {
1518cdf0e10cSrcweir                         if( nRowSpan == 1 || nRowSpan == -1 )
1519cdf0e10cSrcweir                             nRowSpan = n + 1;
1520cdf0e10cSrcweir                         else if( nRowSpan > 1 )
1521cdf0e10cSrcweir                             nRowSpan = - nRowSpan;
1522cdf0e10cSrcweir                     }
1523cdf0e10cSrcweir                     else
1524cdf0e10cSrcweir                     {
1525cdf0e10cSrcweir                         if( nRowSpan > 0 )
1526cdf0e10cSrcweir                             nRowSpan = n + 1;
1527cdf0e10cSrcweir                         else
1528cdf0e10cSrcweir                             --nRowSpan;
1529cdf0e10cSrcweir                     }
1530cdf0e10cSrcweir                     pNewLine->GetTabBoxes()[ nCurrBox ]->setRowSpan( nRowSpan - n );
1531cdf0e10cSrcweir                 }
1532cdf0e10cSrcweir             }
1533cdf0e10cSrcweir             if( bBehind )
1534cdf0e10cSrcweir                 ++nRowIdx;
1535cdf0e10cSrcweir             if( nRowIdx )
1536cdf0e10cSrcweir                 lcl_ChangeRowSpan( *this, nCnt, --nRowIdx, true );
1537cdf0e10cSrcweir             //Layout update
1538cdf0e10cSrcweir             aFndBox.MakeFrms( *this );
1539cdf0e10cSrcweir //             aFndBox.RestoreChartData( *this );
1540cdf0e10cSrcweir         }
1541cdf0e10cSrcweir         CHECK_TABLE( *this )
1542cdf0e10cSrcweir     }
1543cdf0e10cSrcweir     else
1544cdf0e10cSrcweir         bRet = _InsertRow( pDoc, rBoxes, nCnt, bBehind );
1545cdf0e10cSrcweir     return bRet;
1546cdf0e10cSrcweir }
1547cdf0e10cSrcweir 
1548cdf0e10cSrcweir /** SwTable::PrepareDelBoxes(..) adjusts the row span attributes for an upcoming
1549cdf0e10cSrcweir     deletion of table cells and invalidates the layout of these cells.
1550cdf0e10cSrcweir */
1551cdf0e10cSrcweir 
PrepareDelBoxes(const SwSelBoxes & rBoxes)1552cdf0e10cSrcweir void SwTable::PrepareDelBoxes( const SwSelBoxes& rBoxes )
1553cdf0e10cSrcweir {
1554cdf0e10cSrcweir     if( IsNewModel() )
1555cdf0e10cSrcweir     {
1556cdf0e10cSrcweir         for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
1557cdf0e10cSrcweir         {
1558cdf0e10cSrcweir             SwTableBox* pBox = rBoxes[i];
1559cdf0e10cSrcweir             long nRowSpan = pBox->getRowSpan();
1560cdf0e10cSrcweir             if( nRowSpan != 1 && pBox->GetFrmFmt()->GetFrmSize().GetWidth() )
1561cdf0e10cSrcweir             {
1562cdf0e10cSrcweir                 long nLeft = lcl_Box2LeftBorder( *pBox );
1563cdf0e10cSrcweir                 SwTableLine *pLine = pBox->GetUpper();
1564cdf0e10cSrcweir                 sal_uInt16 nLinePos = GetTabLines().C40_GETPOS(SwTableLine, pLine);
1565cdf0e10cSrcweir                 ASSERT( nLinePos < USHRT_MAX, "Box/table mismatch" )
1566cdf0e10cSrcweir                 if( nRowSpan > 1 )
1567cdf0e10cSrcweir                 {
1568cdf0e10cSrcweir                     if( ++nLinePos < GetTabLines().Count() )
1569cdf0e10cSrcweir                     {
1570cdf0e10cSrcweir                         pLine = GetTabLines()[ nLinePos ];
1571cdf0e10cSrcweir                         pBox = lcl_LeftBorder2Box( nLeft, pLine );
1572cdf0e10cSrcweir                         ASSERT( pBox, "RowSpan irritation I" )
1573cdf0e10cSrcweir                         if( pBox )
1574cdf0e10cSrcweir                             pBox->setRowSpan( --nRowSpan );
1575cdf0e10cSrcweir                     }
1576cdf0e10cSrcweir                 }
1577cdf0e10cSrcweir                 else if( nLinePos > 0 )
1578cdf0e10cSrcweir                 {
1579cdf0e10cSrcweir                     do
1580cdf0e10cSrcweir                     {
1581cdf0e10cSrcweir                         pLine = GetTabLines()[ --nLinePos ];
1582cdf0e10cSrcweir                         pBox = lcl_LeftBorder2Box( nLeft, pLine );
1583cdf0e10cSrcweir                         ASSERT( pBox, "RowSpan irritation II" )
1584cdf0e10cSrcweir                         if( pBox )
1585cdf0e10cSrcweir                         {
1586cdf0e10cSrcweir                             nRowSpan = pBox->getRowSpan();
1587cdf0e10cSrcweir                             if( nRowSpan > 1 )
1588cdf0e10cSrcweir                             {
1589cdf0e10cSrcweir                                 lcl_InvalidateCellFrm( *pBox );
1590cdf0e10cSrcweir                                 --nRowSpan;
1591cdf0e10cSrcweir                             }
1592cdf0e10cSrcweir                             else
1593cdf0e10cSrcweir                                 ++nRowSpan;
1594cdf0e10cSrcweir                             pBox->setRowSpan( nRowSpan );
1595cdf0e10cSrcweir                         }
1596cdf0e10cSrcweir                         else
1597cdf0e10cSrcweir                             nRowSpan = 1;
1598cdf0e10cSrcweir                     }
1599cdf0e10cSrcweir                     while( nRowSpan < 0 && nLinePos > 0 );
1600cdf0e10cSrcweir                 }
1601cdf0e10cSrcweir             }
1602cdf0e10cSrcweir         }
1603cdf0e10cSrcweir     }
1604cdf0e10cSrcweir }
1605cdf0e10cSrcweir 
1606cdf0e10cSrcweir /** lcl_SearchSelBox(..) adds cells of a given table row to the selection structure
1607cdf0e10cSrcweir     if it overlaps with the given x-position range
1608cdf0e10cSrcweir */
1609cdf0e10cSrcweir 
lcl_SearchSelBox(const SwTable & rTable,SwSelBoxes & rBoxes,long nMin,long nMax,SwTableLine & rLine,bool bChkProtected,bool bColumn)1610cdf0e10cSrcweir void lcl_SearchSelBox( const SwTable &rTable, SwSelBoxes& rBoxes, long nMin, long nMax,
1611cdf0e10cSrcweir                        SwTableLine& rLine, bool bChkProtected, bool bColumn )
1612cdf0e10cSrcweir {
1613cdf0e10cSrcweir     long nLeft = 0;
1614cdf0e10cSrcweir     long nRight = 0;
1615cdf0e10cSrcweir     long nMid = ( nMax + nMin )/ 2;
1616cdf0e10cSrcweir     sal_uInt16 nCount = rLine.GetTabBoxes().Count();
1617cdf0e10cSrcweir     for( sal_uInt16 nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
1618cdf0e10cSrcweir     {
1619cdf0e10cSrcweir         SwTableBox* pBox = rLine.GetTabBoxes()[nCurrBox];
1620cdf0e10cSrcweir         ASSERT( pBox, "Missing table box" );
1621cdf0e10cSrcweir         long nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1622cdf0e10cSrcweir         nRight += nWidth;
1623cdf0e10cSrcweir         if( nRight > nMin )
1624cdf0e10cSrcweir         {
1625cdf0e10cSrcweir             bool bAdd = false;
1626cdf0e10cSrcweir             if( nRight <= nMax )
1627cdf0e10cSrcweir                 bAdd = nLeft >= nMin || nRight >= nMid ||
1628cdf0e10cSrcweir                        nRight - nMin > nMin - nLeft;
1629cdf0e10cSrcweir             else
1630cdf0e10cSrcweir                 bAdd = nLeft <= nMid || nRight - nMax < nMax - nLeft;
1631cdf0e10cSrcweir             long nRowSpan = pBox->getRowSpan();
1632cdf0e10cSrcweir             if( bAdd &&
1633cdf0e10cSrcweir                 //( bColumn || nRowSpan > 0 ) &&
1634cdf0e10cSrcweir                 ( !bChkProtected ||
1635cdf0e10cSrcweir                 !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) )
1636cdf0e10cSrcweir             {
1637cdf0e10cSrcweir                 sal_uInt16 nOldCnt = rBoxes.Count();
1638cdf0e10cSrcweir                 rBoxes.Insert( pBox );
1639cdf0e10cSrcweir                 if( bColumn && nRowSpan != 1 && nOldCnt < rBoxes.Count() )
1640cdf0e10cSrcweir                 {
1641cdf0e10cSrcweir                     SwTableBox *pMasterBox = pBox->getRowSpan() > 0 ? pBox
1642cdf0e10cSrcweir                         : &pBox->FindStartOfRowSpan( rTable, USHRT_MAX );
1643cdf0e10cSrcweir                     lcl_getAllMergedBoxes( rTable, rBoxes, *pMasterBox );
1644cdf0e10cSrcweir                 }
1645cdf0e10cSrcweir             }
1646cdf0e10cSrcweir         }
1647cdf0e10cSrcweir         if( nRight >= nMax )
1648cdf0e10cSrcweir             break;
1649cdf0e10cSrcweir         nLeft = nRight;
1650cdf0e10cSrcweir     }
1651cdf0e10cSrcweir }
1652cdf0e10cSrcweir 
1653cdf0e10cSrcweir /** void SwTable::CreateSelection(..) fills the selection structure with table cells
1654cdf0e10cSrcweir     for a given SwPaM, ie. start and end position inside a table
1655cdf0e10cSrcweir */
1656cdf0e10cSrcweir 
CreateSelection(const SwPaM & rPam,SwSelBoxes & rBoxes,const SearchType eSearch,bool bChkProtected) const1657cdf0e10cSrcweir void SwTable::CreateSelection(  const SwPaM& rPam, SwSelBoxes& rBoxes,
1658cdf0e10cSrcweir     const SearchType eSearch, bool bChkProtected ) const
1659cdf0e10cSrcweir {
1660cdf0e10cSrcweir     ASSERT( bNewModel, "Don't call me for old tables" );
1661cdf0e10cSrcweir     if( !aLines.Count() )
1662cdf0e10cSrcweir         return;
1663cdf0e10cSrcweir     const SwNode* pStartNd = rPam.GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1664cdf0e10cSrcweir     const SwNode* pEndNd = rPam.GetMark()->nNode.GetNode().FindTableBoxStartNode();
1665cdf0e10cSrcweir     if( !pStartNd || !pEndNd )
1666cdf0e10cSrcweir         return;
1667cdf0e10cSrcweir     CreateSelection( pStartNd, pEndNd, rBoxes, eSearch, bChkProtected );
1668cdf0e10cSrcweir }
1669cdf0e10cSrcweir 
1670cdf0e10cSrcweir /** void SwTable::CreateSelection(..) fills the selection structure with table cells
1671cdf0e10cSrcweir     for given start and end nodes inside a table
1672cdf0e10cSrcweir */
CreateSelection(const SwNode * pStartNd,const SwNode * pEndNd,SwSelBoxes & rBoxes,const SearchType eSearch,bool bChkProtected) const1673cdf0e10cSrcweir void SwTable::CreateSelection( const SwNode* pStartNd, const SwNode* pEndNd,
1674cdf0e10cSrcweir     SwSelBoxes& rBoxes, const SearchType eSearch, bool bChkProtected ) const
1675cdf0e10cSrcweir {
1676cdf0e10cSrcweir     // SwSelBoxes aKeepBoxes;
1677cdf0e10cSrcweir     if( rBoxes.Count() )
1678cdf0e10cSrcweir     {
1679cdf0e10cSrcweir         // aKeepBoxes.Insert( &rBoxes );
1680cdf0e10cSrcweir 		rBoxes.Remove( sal_uInt16(0), rBoxes.Count() );
1681cdf0e10cSrcweir     }
1682cdf0e10cSrcweir     // Looking for start and end of the selection given by SwNode-pointer
1683cdf0e10cSrcweir     sal_uInt16 nLines = aLines.Count();
1684cdf0e10cSrcweir     // nTop becomes the line number of the upper box
1685cdf0e10cSrcweir     // nBottom becomes the line number of the lower box
1686cdf0e10cSrcweir     sal_uInt16 nTop = 0, nBottom = 0;
1687cdf0e10cSrcweir     // nUpperMin becomes the left border value of the upper box
1688cdf0e10cSrcweir     // nUpperMax becomes the right border of the upper box
1689cdf0e10cSrcweir     // nLowerMin and nLowerMax the borders of the lower box
1690cdf0e10cSrcweir     long nUpperMin = 0, nUpperMax = 0;
1691cdf0e10cSrcweir     long nLowerMin = 0, nLowerMax = 0;
1692cdf0e10cSrcweir     // nFound will incremented if a box is found
1693cdf0e10cSrcweir     // 0 => no box found; 1 => the upper box has been found; 2 => both found
1694cdf0e10cSrcweir     int nFound = 0;
1695cdf0e10cSrcweir     for( sal_uInt16 nRow = 0; nFound < 2 && nRow < nLines; ++nRow )
1696cdf0e10cSrcweir     {
1697cdf0e10cSrcweir         SwTableLine* pLine = aLines[nRow];
1698cdf0e10cSrcweir         ASSERT( pLine, "Missing table line" );
1699cdf0e10cSrcweir         sal_uInt16 nCols = pLine->GetTabBoxes().Count();
1700cdf0e10cSrcweir         for( sal_uInt16 nCol = 0; nCol < nCols; ++nCol )
1701cdf0e10cSrcweir         {
1702cdf0e10cSrcweir             SwTableBox* pBox = pLine->GetTabBoxes()[nCol];
1703cdf0e10cSrcweir             ASSERT( pBox, "Missing table box" );
1704cdf0e10cSrcweir             if( pBox->GetSttNd() == pEndNd || pBox->GetSttNd() == pStartNd )
1705cdf0e10cSrcweir             {
1706cdf0e10cSrcweir                 if( !bChkProtected ||
1707cdf0e10cSrcweir                     !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
1708cdf0e10cSrcweir                     rBoxes.Insert( pBox );
1709cdf0e10cSrcweir                 if( nFound )
1710cdf0e10cSrcweir                 {
1711cdf0e10cSrcweir                     nBottom = nRow;
1712cdf0e10cSrcweir                     lcl_CheckMinMax( nLowerMin, nLowerMax, *pLine, nCol, true );
1713cdf0e10cSrcweir                     ++nFound;
1714cdf0e10cSrcweir                     break;
1715cdf0e10cSrcweir                 }
1716cdf0e10cSrcweir                 else
1717cdf0e10cSrcweir                 {
1718cdf0e10cSrcweir                     nTop = nRow;
1719cdf0e10cSrcweir                     lcl_CheckMinMax( nUpperMin, nUpperMax, *pLine, nCol, true );
1720cdf0e10cSrcweir                     ++nFound;
1721cdf0e10cSrcweir                      // If start and end node are identical, we're nearly done..
1722cdf0e10cSrcweir                     if( pEndNd == pStartNd )
1723cdf0e10cSrcweir                     {
1724cdf0e10cSrcweir                         nBottom = nTop;
1725cdf0e10cSrcweir                         nLowerMin = nUpperMin;
1726cdf0e10cSrcweir                         nLowerMax = nUpperMax;
1727cdf0e10cSrcweir                         ++nFound;
1728cdf0e10cSrcweir                     }
1729cdf0e10cSrcweir                 }
1730cdf0e10cSrcweir             }
1731cdf0e10cSrcweir         }
1732cdf0e10cSrcweir     }
1733cdf0e10cSrcweir     if( nFound < 2 )
1734cdf0e10cSrcweir         return; // At least one node was not a part of the given table
1735cdf0e10cSrcweir     if( eSearch == SEARCH_ROW )
1736cdf0e10cSrcweir     {
1737cdf0e10cSrcweir         // Selection of a row is quiet easy:
1738cdf0e10cSrcweir         // every (unprotected) box between start and end line
1739cdf0e10cSrcweir         // with a positive row span will be collected
1740cdf0e10cSrcweir         for( sal_uInt16 nRow = nTop; nRow <= nBottom; ++nRow )
1741cdf0e10cSrcweir         {
1742cdf0e10cSrcweir             SwTableLine* pLine = aLines[nRow];
1743cdf0e10cSrcweir             ASSERT( pLine, "Missing table line" );
1744cdf0e10cSrcweir             sal_uInt16 nCount = pLine->GetTabBoxes().Count();
1745cdf0e10cSrcweir             for( sal_uInt16 nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
1746cdf0e10cSrcweir             {
1747cdf0e10cSrcweir                 SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
1748cdf0e10cSrcweir                 ASSERT( pBox, "Missing table box" );
1749cdf0e10cSrcweir 				if( pBox->getRowSpan() > 0 && ( !bChkProtected ||
1750cdf0e10cSrcweir                     !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) )
1751cdf0e10cSrcweir                     rBoxes.Insert( pBox );
1752cdf0e10cSrcweir             }
1753cdf0e10cSrcweir         }
1754cdf0e10cSrcweir         return;
1755cdf0e10cSrcweir     }
1756cdf0e10cSrcweir     bool bCombine = nTop == nBottom;
1757cdf0e10cSrcweir     if( !bCombine )
1758cdf0e10cSrcweir     {
1759cdf0e10cSrcweir         long nMinWidth = nUpperMax - nUpperMin;
1760cdf0e10cSrcweir         long nTmp = nLowerMax - nLowerMin;
1761cdf0e10cSrcweir         if( nMinWidth > nTmp )
1762cdf0e10cSrcweir             nMinWidth = nTmp;
1763cdf0e10cSrcweir         nTmp = nLowerMax < nUpperMax ? nLowerMax : nUpperMax;
1764cdf0e10cSrcweir         nTmp -= ( nLowerMin < nUpperMin ) ? nUpperMin : nLowerMin;
1765cdf0e10cSrcweir         // If the overlapping between upper and lower box is less than half
1766cdf0e10cSrcweir         // of the width (of the smaller cell), bCombine is set,
1767cdf0e10cSrcweir         // e.g. if upper and lower cell are in different columns
1768cdf0e10cSrcweir         bCombine = ( nTmp + nTmp < nMinWidth );
1769cdf0e10cSrcweir     }
1770cdf0e10cSrcweir     if( bCombine )
1771cdf0e10cSrcweir     {
1772cdf0e10cSrcweir         if( nUpperMin < nLowerMin )
1773cdf0e10cSrcweir             nLowerMin = nUpperMin;
1774cdf0e10cSrcweir         else
1775cdf0e10cSrcweir             nUpperMin = nLowerMin;
1776cdf0e10cSrcweir         if( nUpperMax > nLowerMax )
1777cdf0e10cSrcweir             nLowerMax = nUpperMax;
1778cdf0e10cSrcweir         else
1779cdf0e10cSrcweir             nUpperMax = nLowerMax;
1780cdf0e10cSrcweir     }
1781cdf0e10cSrcweir     const bool bColumn = eSearch == SEARCH_COL;
1782cdf0e10cSrcweir     if( bColumn )
1783cdf0e10cSrcweir     {
1784cdf0e10cSrcweir         for( sal_uInt16 i = 0; i < nTop; ++i )
1785cdf0e10cSrcweir             lcl_SearchSelBox( *this, rBoxes, nUpperMin, nUpperMax,
1786cdf0e10cSrcweir                               *aLines[i], bChkProtected, bColumn );
1787cdf0e10cSrcweir     }
1788cdf0e10cSrcweir 
1789cdf0e10cSrcweir     {
1790cdf0e10cSrcweir         long nMin = nUpperMin < nLowerMin ? nUpperMin : nLowerMin;
1791cdf0e10cSrcweir         long nMax = nUpperMax < nLowerMax ? nLowerMax : nUpperMax;
1792cdf0e10cSrcweir         for( sal_uInt16 i = nTop; i <= nBottom; ++i )
1793cdf0e10cSrcweir             lcl_SearchSelBox( *this, rBoxes, nMin, nMax, *aLines[i],
1794cdf0e10cSrcweir                               bChkProtected, bColumn );
1795cdf0e10cSrcweir     }
1796cdf0e10cSrcweir     /* if( nTop + 1 < nBottom )
1797cdf0e10cSrcweir     {
1798cdf0e10cSrcweir         long nInnerMin = nUpperMin < nLowerMin ? nLowerMin : nUpperMin;
1799cdf0e10cSrcweir         long nInnerMax = nUpperMax < nLowerMax ? nUpperMax : nLowerMax;
1800cdf0e10cSrcweir         for( sal_uInt16 i = nTop + 1; i < nBottom; ++i )
1801cdf0e10cSrcweir             lcl_SearchSelBox( *this, rBoxes, nInnerMin, nInnerMax, *aLines[i],
1802cdf0e10cSrcweir                               bChkProtected, bColumn );
1803cdf0e10cSrcweir     }
1804cdf0e10cSrcweir     if( bCombine ) // => nUpperMin == nLowerMin, nUpperMax == nLowerMax
1805cdf0e10cSrcweir     {
1806cdf0e10cSrcweir         if( nBottom > nTop )
1807cdf0e10cSrcweir             lcl_SearchSelBox( *this, rBoxes, nUpperMin, nUpperMax, *aLines[nTop],
1808cdf0e10cSrcweir                               bChkProtected, bColumn );
1809cdf0e10cSrcweir         lcl_SearchSelBox( *this, rBoxes, nLowerMin, nLowerMax, *aLines[nBottom],
1810cdf0e10cSrcweir                           bChkProtected, bColumn );
1811cdf0e10cSrcweir     }
1812cdf0e10cSrcweir     else if( aKeepBoxes.Count() )
1813cdf0e10cSrcweir     {
1814cdf0e10cSrcweir         long nMin = nUpperMin < nLowerMin ? nUpperMin : nLowerMin;
1815cdf0e10cSrcweir         long nMax = nUpperMax < nLowerMax ? nLowerMax : nUpperMax;
1816cdf0e10cSrcweir         SwSelBoxes aCandidates;
1817cdf0e10cSrcweir         for( sal_uInt16 i = nTop; i <= nBottom; ++i )
1818cdf0e10cSrcweir             lcl_SearchSelBox( *this, aCandidates, nMin, nMax, *aLines[i],
1819cdf0e10cSrcweir                               bChkProtected, bColumn );
1820cdf0e10cSrcweir         sal_uInt16 nOld = 0, nNew = 0;
1821cdf0e10cSrcweir         while ( nOld < aKeepBoxes.Count() && nNew < aCandidates.Count() )
1822cdf0e10cSrcweir         {
1823cdf0e10cSrcweir             const SwTableBox* pPOld = *( aKeepBoxes.GetData() + nOld );
1824cdf0e10cSrcweir             SwTableBox* pPNew = *( aCandidates.GetData() + nNew );
1825cdf0e10cSrcweir             if( pPOld == pPNew )
1826cdf0e10cSrcweir             {   // this box will stay
1827cdf0e10cSrcweir                 rBoxes.Insert( pPNew );
1828cdf0e10cSrcweir                 ++nOld;
1829cdf0e10cSrcweir                 ++nNew;
1830cdf0e10cSrcweir             }
1831cdf0e10cSrcweir             else if( pPOld->GetSttIdx() < pPNew->GetSttIdx() )
1832cdf0e10cSrcweir                 ++nOld;
1833cdf0e10cSrcweir             else
1834cdf0e10cSrcweir                 ++nNew;
1835cdf0e10cSrcweir         }
1836cdf0e10cSrcweir     } */
1837cdf0e10cSrcweir     if( bColumn )
1838cdf0e10cSrcweir     {
1839cdf0e10cSrcweir         for( sal_uInt16 i = nBottom + 1; i < nLines; ++i )
1840cdf0e10cSrcweir             lcl_SearchSelBox( *this, rBoxes, nLowerMin, nLowerMax, *aLines[i],
1841cdf0e10cSrcweir                               bChkProtected, true );
1842cdf0e10cSrcweir     }
1843cdf0e10cSrcweir }
1844cdf0e10cSrcweir 
1845cdf0e10cSrcweir /** void SwTable::ExpandColumnSelection(..) adds cell to the give selection to
1846cdf0e10cSrcweir     assure that at least one cell of every row is part of the selection.
1847cdf0e10cSrcweir */
1848cdf0e10cSrcweir 
ExpandColumnSelection(SwSelBoxes & rBoxes,long & rMin,long & rMax) const1849cdf0e10cSrcweir void SwTable::ExpandColumnSelection( SwSelBoxes& rBoxes, long &rMin, long &rMax ) const
1850cdf0e10cSrcweir {
1851cdf0e10cSrcweir     ASSERT( bNewModel, "Don't call me for old tables" );
1852cdf0e10cSrcweir     rMin = 0;
1853cdf0e10cSrcweir     rMax = 0;
1854cdf0e10cSrcweir     if( !aLines.Count() || !rBoxes.Count() )
1855cdf0e10cSrcweir         return;
1856cdf0e10cSrcweir 
1857cdf0e10cSrcweir     sal_uInt16 nLineCnt = aLines.Count();
1858cdf0e10cSrcweir     sal_uInt16 nBoxCnt = rBoxes.Count();
1859cdf0e10cSrcweir     sal_uInt16 nBox = 0;
1860cdf0e10cSrcweir     for( sal_uInt16 nRow = 0; nRow < nLineCnt && nBox < nBoxCnt; ++nRow )
1861cdf0e10cSrcweir     {
1862cdf0e10cSrcweir         SwTableLine* pLine = aLines[nRow];
1863cdf0e10cSrcweir         ASSERT( pLine, "Missing table line" );
1864cdf0e10cSrcweir         sal_uInt16 nCols = pLine->GetTabBoxes().Count();
1865cdf0e10cSrcweir         for( sal_uInt16 nCol = 0; nCol < nCols; ++nCol )
1866cdf0e10cSrcweir         {
1867cdf0e10cSrcweir             SwTableBox* pBox = pLine->GetTabBoxes()[nCol];
1868cdf0e10cSrcweir             ASSERT( pBox, "Missing table box" );
1869cdf0e10cSrcweir             if( pBox == rBoxes[nBox] )
1870cdf0e10cSrcweir             {
1871cdf0e10cSrcweir                 lcl_CheckMinMax( rMin, rMax, *pLine, nCol, nBox == 0 );
1872cdf0e10cSrcweir                 if( ++nBox >= nBoxCnt )
1873cdf0e10cSrcweir                     break;
1874cdf0e10cSrcweir             }
1875cdf0e10cSrcweir         }
1876cdf0e10cSrcweir     }
1877cdf0e10cSrcweir     nBox = 0;
1878cdf0e10cSrcweir     for( sal_uInt16 nRow = 0; nRow < nLineCnt; ++nRow )
1879cdf0e10cSrcweir     {
1880cdf0e10cSrcweir         SwTableLine* pLine = aLines[nRow];
1881cdf0e10cSrcweir         sal_uInt16 nCols = pLine->GetTabBoxes().Count();
1882cdf0e10cSrcweir         long nLeft = 0;
1883cdf0e10cSrcweir         long nRight = 0;
1884cdf0e10cSrcweir         for( sal_uInt16 nCurrBox = 0; nCurrBox < nCols; ++nCurrBox )
1885cdf0e10cSrcweir         {
1886cdf0e10cSrcweir             nLeft = nRight;
1887cdf0e10cSrcweir             SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
1888cdf0e10cSrcweir             nRight += pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1889cdf0e10cSrcweir             if( nLeft >= rMin && nRight <= rMax )
1890cdf0e10cSrcweir                 rBoxes.Insert( pBox );
1891cdf0e10cSrcweir         }
1892cdf0e10cSrcweir     }
1893cdf0e10cSrcweir }
1894cdf0e10cSrcweir 
1895cdf0e10cSrcweir /** SwTable::PrepareDeleteCol(..) adjusts the widths of the neighbour cells of
1896cdf0e10cSrcweir     a cell selection for an upcoming (column) deletion
1897cdf0e10cSrcweir */
PrepareDeleteCol(long nMin,long nMax)1898cdf0e10cSrcweir void SwTable::PrepareDeleteCol( long nMin, long nMax )
1899cdf0e10cSrcweir {
1900cdf0e10cSrcweir     ASSERT( bNewModel, "Don't call me for old tables" );
1901cdf0e10cSrcweir     if( !aLines.Count() || nMax < nMin )
1902cdf0e10cSrcweir         return;
1903cdf0e10cSrcweir     long nMid = nMin ? ( nMin + nMax ) / 2 : 0;
1904cdf0e10cSrcweir 	const SwTwips nTabSize = GetFrmFmt()->GetFrmSize().GetWidth();
1905cdf0e10cSrcweir     if( nTabSize == nMax )
1906cdf0e10cSrcweir         nMid = nMax;
1907cdf0e10cSrcweir     sal_uInt16 nLineCnt = aLines.Count();
1908cdf0e10cSrcweir     for( sal_uInt16 nRow = 0; nRow < nLineCnt; ++nRow )
1909cdf0e10cSrcweir     {
1910cdf0e10cSrcweir         SwTableLine* pLine = aLines[nRow];
1911cdf0e10cSrcweir         sal_uInt16 nCols = pLine->GetTabBoxes().Count();
1912cdf0e10cSrcweir         long nLeft = 0;
1913cdf0e10cSrcweir         long nRight = 0;
1914cdf0e10cSrcweir         for( sal_uInt16 nCurrBox = 0; nCurrBox < nCols; ++nCurrBox )
1915cdf0e10cSrcweir         {
1916cdf0e10cSrcweir             nLeft = nRight;
1917cdf0e10cSrcweir             SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
1918cdf0e10cSrcweir             nRight += pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1919cdf0e10cSrcweir             if( nRight < nMin )
1920cdf0e10cSrcweir                 continue;
1921cdf0e10cSrcweir             if( nLeft > nMax )
1922cdf0e10cSrcweir                 break;
1923cdf0e10cSrcweir             long nNewWidth = -1;
1924cdf0e10cSrcweir             if( nLeft < nMin )
1925cdf0e10cSrcweir             {
1926cdf0e10cSrcweir                 if( nRight <= nMax )
1927cdf0e10cSrcweir                     nNewWidth = nMid - nLeft;
1928cdf0e10cSrcweir             }
1929cdf0e10cSrcweir             else if( nRight > nMax )
1930cdf0e10cSrcweir                 nNewWidth = nRight - nMid;
1931cdf0e10cSrcweir             else
1932cdf0e10cSrcweir                 nNewWidth = 0;
1933cdf0e10cSrcweir             if( nNewWidth >= 0 )
1934cdf0e10cSrcweir             {
1935cdf0e10cSrcweir                 SwFrmFmt* pFrmFmt = pBox->ClaimFrmFmt();
1936cdf0e10cSrcweir                 SwFmtFrmSize aFrmSz( pFrmFmt->GetFrmSize() );
1937cdf0e10cSrcweir                 aFrmSz.SetWidth( nNewWidth );
1938cdf0e10cSrcweir                 pFrmFmt->SetFmtAttr( aFrmSz );
1939cdf0e10cSrcweir             }
1940cdf0e10cSrcweir         }
1941cdf0e10cSrcweir     }
1942cdf0e10cSrcweir }
1943cdf0e10cSrcweir 
1944cdf0e10cSrcweir 
1945cdf0e10cSrcweir 
1946cdf0e10cSrcweir /** SwTable::ExpandSelection(..) adds all boxes to the box selections which are
1947cdf0e10cSrcweir     overlapped by it.
1948cdf0e10cSrcweir */
1949cdf0e10cSrcweir 
ExpandSelection(SwSelBoxes & rBoxes) const1950cdf0e10cSrcweir void SwTable::ExpandSelection( SwSelBoxes& rBoxes ) const
1951cdf0e10cSrcweir {
1952cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
1953cdf0e10cSrcweir     {
1954cdf0e10cSrcweir         SwTableBox *pBox = rBoxes[i];
1955cdf0e10cSrcweir         long nRowSpan = pBox->getRowSpan();
1956cdf0e10cSrcweir         if( nRowSpan != 1 )
1957cdf0e10cSrcweir         {
1958cdf0e10cSrcweir             SwTableBox *pMasterBox = nRowSpan > 0 ? pBox
1959cdf0e10cSrcweir                     : &pBox->FindStartOfRowSpan( *this, USHRT_MAX );
1960cdf0e10cSrcweir             lcl_getAllMergedBoxes( *this, rBoxes, *pMasterBox );
1961cdf0e10cSrcweir         }
1962cdf0e10cSrcweir     }
1963cdf0e10cSrcweir }
1964cdf0e10cSrcweir 
1965cdf0e10cSrcweir /** SwTable::CheckRowSpan(..) looks for the next line without an overlapping to
1966cdf0e10cSrcweir     the previous line.
1967cdf0e10cSrcweir */
1968cdf0e10cSrcweir 
CheckRowSpan(SwTableLinePtr & rpLine,bool bUp) const1969cdf0e10cSrcweir void SwTable::CheckRowSpan( SwTableLinePtr &rpLine, bool bUp ) const
1970cdf0e10cSrcweir {
1971cdf0e10cSrcweir     ASSERT( IsNewModel(), "Don't call me for old tables" );
1972cdf0e10cSrcweir     sal_uInt16 nLineIdx = GetTabLines().C40_GETPOS( SwTableLine, rpLine );
1973cdf0e10cSrcweir     ASSERT( nLineIdx < GetTabLines().Count(), "Start line out of range" );
1974cdf0e10cSrcweir     bool bChange = true;
1975cdf0e10cSrcweir     if( bUp )
1976cdf0e10cSrcweir     {
1977cdf0e10cSrcweir         while( bChange )
1978cdf0e10cSrcweir         {
1979cdf0e10cSrcweir             bChange = false;
1980cdf0e10cSrcweir             rpLine = GetTabLines()[ nLineIdx ];
1981cdf0e10cSrcweir             sal_uInt16 nCols = rpLine->GetTabBoxes().Count();
1982cdf0e10cSrcweir             for( sal_uInt16 nCol = 0; !bChange && nCol < nCols; ++nCol )
1983cdf0e10cSrcweir             {
1984cdf0e10cSrcweir                 SwTableBox* pBox = rpLine->GetTabBoxes()[nCol];
1985cdf0e10cSrcweir                 if( pBox->getRowSpan() > 1 || pBox->getRowSpan() < -1 )
1986cdf0e10cSrcweir                     bChange = true;
1987cdf0e10cSrcweir             }
1988cdf0e10cSrcweir             if( bChange )
1989cdf0e10cSrcweir             {
1990cdf0e10cSrcweir                 if( nLineIdx )
1991cdf0e10cSrcweir                     --nLineIdx;
1992cdf0e10cSrcweir                 else
1993cdf0e10cSrcweir                 {
1994cdf0e10cSrcweir                     bChange = false;
1995cdf0e10cSrcweir                     rpLine = 0;
1996cdf0e10cSrcweir                 }
1997cdf0e10cSrcweir             }
1998cdf0e10cSrcweir         }
1999cdf0e10cSrcweir     }
2000cdf0e10cSrcweir     else
2001cdf0e10cSrcweir     {
2002cdf0e10cSrcweir         sal_uInt16 nMaxLine = GetTabLines().Count();
2003cdf0e10cSrcweir         while( bChange )
2004cdf0e10cSrcweir         {
2005cdf0e10cSrcweir             bChange = false;
2006cdf0e10cSrcweir             rpLine = GetTabLines()[ nLineIdx ];
2007cdf0e10cSrcweir             sal_uInt16 nCols = rpLine->GetTabBoxes().Count();
2008cdf0e10cSrcweir             for( sal_uInt16 nCol = 0; !bChange && nCol < nCols; ++nCol )
2009cdf0e10cSrcweir             {
2010cdf0e10cSrcweir                 SwTableBox* pBox = rpLine->GetTabBoxes()[nCol];
2011cdf0e10cSrcweir                 if( pBox->getRowSpan() < 0 )
2012cdf0e10cSrcweir                     bChange = true;
2013cdf0e10cSrcweir             }
2014cdf0e10cSrcweir             if( bChange )
2015cdf0e10cSrcweir             {
2016cdf0e10cSrcweir                 ++nLineIdx;
2017cdf0e10cSrcweir                 if( nLineIdx >= nMaxLine )
2018cdf0e10cSrcweir                 {
2019cdf0e10cSrcweir                     bChange = false;
2020cdf0e10cSrcweir                     rpLine = 0;
2021cdf0e10cSrcweir                 }
2022cdf0e10cSrcweir             }
2023cdf0e10cSrcweir         }
2024cdf0e10cSrcweir     }
2025cdf0e10cSrcweir }
2026cdf0e10cSrcweir 
2027cdf0e10cSrcweir // This structure corrects the row span attributes for a top line of a table
2028cdf0e10cSrcweir // In a top line no negative row span is allowed, so these have to be corrected.
2029cdf0e10cSrcweir // If there has been at least one correction, all values are stored
2030cdf0e10cSrcweir // and can be used by undo of table split
SwSaveRowSpan(SwTableBoxes & rBoxes,sal_uInt16 nSplitLn)2031cdf0e10cSrcweir SwSaveRowSpan::SwSaveRowSpan( SwTableBoxes& rBoxes, sal_uInt16 nSplitLn )
2032cdf0e10cSrcweir     : mnSplitLine( nSplitLn )
2033cdf0e10cSrcweir {
2034cdf0e10cSrcweir     bool bDontSave = true; // nothing changed, nothing to save
2035cdf0e10cSrcweir     sal_uInt16 nColCount = rBoxes.Count();
2036cdf0e10cSrcweir     ASSERT( nColCount, "Empty Table Line" )
2037cdf0e10cSrcweir     mnRowSpans.resize( nColCount );
2038cdf0e10cSrcweir     for( sal_uInt16 nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol )
2039cdf0e10cSrcweir     {
2040cdf0e10cSrcweir         SwTableBox* pBox = rBoxes[nCurrCol];
2041cdf0e10cSrcweir         ASSERT( pBox, "Missing Table Box" );
2042cdf0e10cSrcweir         long nRowSp = pBox->getRowSpan();
2043cdf0e10cSrcweir         mnRowSpans[ nCurrCol ] = nRowSp;
2044cdf0e10cSrcweir         if( nRowSp < 0 )
2045cdf0e10cSrcweir         {
2046cdf0e10cSrcweir             bDontSave = false;
2047cdf0e10cSrcweir             nRowSp = -nRowSp;
2048cdf0e10cSrcweir             pBox->setRowSpan( nRowSp ); // correction needed
2049cdf0e10cSrcweir         }
2050cdf0e10cSrcweir     }
2051cdf0e10cSrcweir     if( bDontSave )
2052cdf0e10cSrcweir         mnRowSpans.clear();
2053cdf0e10cSrcweir }
2054cdf0e10cSrcweir 
2055cdf0e10cSrcweir // This function is called by undo of table split to restore the old row span
2056cdf0e10cSrcweir // values at the split line
RestoreRowSpan(const SwSaveRowSpan & rSave)2057cdf0e10cSrcweir void SwTable::RestoreRowSpan( const SwSaveRowSpan& rSave )
2058cdf0e10cSrcweir {
2059cdf0e10cSrcweir     if( !IsNewModel() ) // for new model only
2060cdf0e10cSrcweir         return;
2061cdf0e10cSrcweir     sal_uInt16 nLineCount = GetTabLines().Count();
2062cdf0e10cSrcweir     ASSERT( rSave.mnSplitLine < nLineCount, "Restore behind last line?" )
2063cdf0e10cSrcweir     if( rSave.mnSplitLine < nLineCount )
2064cdf0e10cSrcweir     {
2065cdf0e10cSrcweir         SwTableLine* pLine = GetTabLines()[rSave.mnSplitLine];
2066cdf0e10cSrcweir         sal_uInt16 nColCount = pLine->GetTabBoxes().Count();
2067cdf0e10cSrcweir         ASSERT( nColCount, "Empty Table Line" )
2068cdf0e10cSrcweir         ASSERT( nColCount == rSave.mnRowSpans.size(), "Wrong row span store" )
2069cdf0e10cSrcweir         if( nColCount == rSave.mnRowSpans.size() )
2070cdf0e10cSrcweir         {
2071cdf0e10cSrcweir             for( sal_uInt16 nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol )
2072cdf0e10cSrcweir             {
2073cdf0e10cSrcweir                 SwTableBox* pBox = pLine->GetTabBoxes()[nCurrCol];
2074cdf0e10cSrcweir                 ASSERT( pBox, "Missing Table Box" );
2075cdf0e10cSrcweir                 long nRowSp = pBox->getRowSpan();
2076cdf0e10cSrcweir                 if( nRowSp != rSave.mnRowSpans[ nCurrCol ] )
2077cdf0e10cSrcweir                 {
2078cdf0e10cSrcweir                     ASSERT( -nRowSp == rSave.mnRowSpans[ nCurrCol ], "Pardon me?!" )
2079cdf0e10cSrcweir                     ASSERT( rSave.mnRowSpans[ nCurrCol ] < 0, "Pardon me?!" )
2080cdf0e10cSrcweir                     pBox->setRowSpan( -nRowSp );
2081cdf0e10cSrcweir 
2082cdf0e10cSrcweir                     sal_uInt16 nLine = rSave.mnSplitLine;
2083cdf0e10cSrcweir                     if( nLine )
2084cdf0e10cSrcweir                     {
2085cdf0e10cSrcweir                         long nLeftBorder = lcl_Box2LeftBorder( *pBox );
2086cdf0e10cSrcweir                         SwTableBox* pNext;
2087cdf0e10cSrcweir                         do
2088cdf0e10cSrcweir                         {
2089cdf0e10cSrcweir                             pNext = lcl_LeftBorder2Box( nLeftBorder, GetTabLines()[--nLine] );
2090cdf0e10cSrcweir                             if( pNext )
2091cdf0e10cSrcweir                             {
2092cdf0e10cSrcweir                                 pBox = pNext;
2093cdf0e10cSrcweir                                 long nNewSpan = pBox->getRowSpan();
2094cdf0e10cSrcweir                                 if( pBox->getRowSpan() < 1 )
2095cdf0e10cSrcweir                                     nNewSpan -= nRowSp;
2096cdf0e10cSrcweir                                 else
2097cdf0e10cSrcweir                                 {
2098cdf0e10cSrcweir                                     nNewSpan += nRowSp;
2099cdf0e10cSrcweir                                     pNext = 0;
2100cdf0e10cSrcweir                                 }
2101cdf0e10cSrcweir                                 pBox->setRowSpan( nNewSpan );
2102cdf0e10cSrcweir                             }
2103cdf0e10cSrcweir                         } while( nLine && pNext );
2104cdf0e10cSrcweir                     }
2105cdf0e10cSrcweir                 }
2106cdf0e10cSrcweir             }
2107cdf0e10cSrcweir         }
2108cdf0e10cSrcweir     }
2109cdf0e10cSrcweir }
2110cdf0e10cSrcweir 
CleanUpTopRowSpan(sal_uInt16 nSplitLine)2111cdf0e10cSrcweir SwSaveRowSpan* SwTable::CleanUpTopRowSpan( sal_uInt16 nSplitLine )
2112cdf0e10cSrcweir {
2113cdf0e10cSrcweir     SwSaveRowSpan* pRet = 0;
2114cdf0e10cSrcweir     if( !IsNewModel() )
2115cdf0e10cSrcweir         return pRet;
2116cdf0e10cSrcweir     pRet = new SwSaveRowSpan( GetTabLines()[0]->GetTabBoxes(), nSplitLine );
2117cdf0e10cSrcweir     if( pRet->mnRowSpans.size() == 0 )
2118cdf0e10cSrcweir     {
2119cdf0e10cSrcweir         delete pRet;
2120cdf0e10cSrcweir         pRet = 0;
2121cdf0e10cSrcweir     }
2122cdf0e10cSrcweir     return pRet;
2123cdf0e10cSrcweir }
2124cdf0e10cSrcweir 
CleanUpBottomRowSpan(sal_uInt16 nDelLines)2125cdf0e10cSrcweir void SwTable::CleanUpBottomRowSpan( sal_uInt16 nDelLines )
2126cdf0e10cSrcweir {
2127cdf0e10cSrcweir     if( !IsNewModel() )
2128cdf0e10cSrcweir         return;
2129cdf0e10cSrcweir     sal_uInt16 nLastLine = GetTabLines().Count()-1;
2130cdf0e10cSrcweir     SwTableLine* pLine = GetTabLines()[nLastLine];
2131cdf0e10cSrcweir     sal_uInt16 nColCount = pLine->GetTabBoxes().Count();
2132cdf0e10cSrcweir     ASSERT( nColCount, "Empty Table Line" )
2133cdf0e10cSrcweir     for( sal_uInt16 nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol )
2134cdf0e10cSrcweir     {
2135cdf0e10cSrcweir         SwTableBox* pBox = pLine->GetTabBoxes()[nCurrCol];
2136cdf0e10cSrcweir         ASSERT( pBox, "Missing Table Box" );
2137cdf0e10cSrcweir         long nRowSp = pBox->getRowSpan();
2138cdf0e10cSrcweir         if( nRowSp < 0 )
2139cdf0e10cSrcweir             nRowSp = -nRowSp;
2140cdf0e10cSrcweir         if( nRowSp > 1 )
2141cdf0e10cSrcweir         {
2142cdf0e10cSrcweir             lcl_ChangeRowSpan( *this, -static_cast<long>(nDelLines), nLastLine, false );
2143cdf0e10cSrcweir             break;
2144cdf0e10cSrcweir         }
2145cdf0e10cSrcweir     }
2146cdf0e10cSrcweir }
2147cdf0e10cSrcweir 
2148cdf0e10cSrcweir #ifdef DBG_UTIL
2149cdf0e10cSrcweir 
2150cdf0e10cSrcweir struct RowSpanCheck
2151cdf0e10cSrcweir {
2152cdf0e10cSrcweir     long nRowSpan;
2153cdf0e10cSrcweir     SwTwips nLeft;
2154cdf0e10cSrcweir     SwTwips nRight;
2155cdf0e10cSrcweir };
2156cdf0e10cSrcweir 
CheckConsistency() const2157cdf0e10cSrcweir void SwTable::CheckConsistency() const
2158cdf0e10cSrcweir {
2159cdf0e10cSrcweir     if( !IsNewModel() )
2160cdf0e10cSrcweir         return;
2161cdf0e10cSrcweir     sal_uInt16 nLineCount = GetTabLines().Count();
2162cdf0e10cSrcweir 	const SwTwips nTabSize = GetFrmFmt()->GetFrmSize().GetWidth();
2163cdf0e10cSrcweir     SwTwips nLineWidth = 0;
2164cdf0e10cSrcweir     std::list< RowSpanCheck > aRowSpanCells;
2165cdf0e10cSrcweir     std::list< RowSpanCheck >::iterator aIter = aRowSpanCells.end();
2166cdf0e10cSrcweir     for( sal_uInt16 nCurrLine = 0; nCurrLine < nLineCount; ++nCurrLine )
2167cdf0e10cSrcweir     {
2168cdf0e10cSrcweir         SwTwips nWidth = 0;
2169cdf0e10cSrcweir         SwTableLine* pLine = GetTabLines()[nCurrLine];
2170cdf0e10cSrcweir         ASSERT( pLine, "Missing Table Line" )
2171cdf0e10cSrcweir         sal_uInt16 nColCount = pLine->GetTabBoxes().Count();
2172cdf0e10cSrcweir         ASSERT( nColCount, "Empty Table Line" )
2173cdf0e10cSrcweir         for( sal_uInt16 nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol )
2174cdf0e10cSrcweir         {
2175cdf0e10cSrcweir             SwTableBox* pBox = pLine->GetTabBoxes()[nCurrCol];
2176cdf0e10cSrcweir             ASSERT( pBox, "Missing Table Box" );
2177cdf0e10cSrcweir             SwTwips nNewWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth() + nWidth;
2178cdf0e10cSrcweir             long nRowSp = pBox->getRowSpan();
2179cdf0e10cSrcweir             if( nRowSp < 0 )
2180cdf0e10cSrcweir             {
2181cdf0e10cSrcweir                 ASSERT( aIter != aRowSpanCells.end(), "Missing master box" )
2182cdf0e10cSrcweir #ifdef DBG_UTIL
2183cdf0e10cSrcweir                 //RowSpanCheck &rCheck = *aIter;
2184cdf0e10cSrcweir #endif
2185cdf0e10cSrcweir                 ASSERT( aIter->nLeft == nWidth && aIter->nRight == nNewWidth,
2186cdf0e10cSrcweir                     "Wrong position/size of overlapped table box" );
2187cdf0e10cSrcweir                 --(aIter->nRowSpan);
2188cdf0e10cSrcweir                 ASSERT( aIter->nRowSpan == -nRowSp, "Wrong row span value" );
2189cdf0e10cSrcweir                 if( nRowSp == -1 )
2190cdf0e10cSrcweir                 {
2191cdf0e10cSrcweir                     std::list< RowSpanCheck >::iterator aEraseIter = aIter;
2192cdf0e10cSrcweir                     ++aIter;
2193cdf0e10cSrcweir                     aRowSpanCells.erase( aEraseIter );
2194cdf0e10cSrcweir                 }
2195cdf0e10cSrcweir                 else
2196cdf0e10cSrcweir                     ++aIter;
2197cdf0e10cSrcweir             }
2198cdf0e10cSrcweir             else if( nRowSp != 1 )
2199cdf0e10cSrcweir             {
2200cdf0e10cSrcweir                 ASSERT( nRowSp, "Zero row span?!" );
2201cdf0e10cSrcweir                 RowSpanCheck aEntry;
2202cdf0e10cSrcweir                 aEntry.nLeft = nWidth;
2203cdf0e10cSrcweir                 aEntry.nRight = nNewWidth;
2204cdf0e10cSrcweir                 aEntry.nRowSpan = nRowSp;
2205cdf0e10cSrcweir                 aRowSpanCells.insert( aIter, aEntry );
2206cdf0e10cSrcweir             }
2207cdf0e10cSrcweir             nWidth = nNewWidth;
2208cdf0e10cSrcweir         }
2209cdf0e10cSrcweir         if( !nCurrLine )
2210cdf0e10cSrcweir             nLineWidth = nWidth;
2211cdf0e10cSrcweir         ASSERT( nWidth == nLineWidth, "Different Line Widths" )
2212cdf0e10cSrcweir         ASSERT( nWidth == nTabSize, "Boxen der Line zu klein/gross" )
2213cdf0e10cSrcweir         ASSERT( nWidth >= 0 && nWidth <= USHRT_MAX, "Width out of range" )
2214cdf0e10cSrcweir         ASSERT( aIter == aRowSpanCells.end(), "Missing overlapped box" )
2215cdf0e10cSrcweir         aIter = aRowSpanCells.begin();
2216cdf0e10cSrcweir     }
2217cdf0e10cSrcweir     bool bEmpty = aRowSpanCells.empty();
2218cdf0e10cSrcweir     ASSERT( bEmpty, "Open row span detected" )
2219cdf0e10cSrcweir }
2220cdf0e10cSrcweir 
2221cdf0e10cSrcweir #endif
2222cdf0e10cSrcweir 
2223cdf0e10cSrcweir 
2224cdf0e10cSrcweir #ifdef FINDSTARTENDOFROWSPANCACHE
2225cdf0e10cSrcweir /*
2226cdf0e10cSrcweir  * A small optimization for FindStartEndOfRowSpan START
2227cdf0e10cSrcweir  *
2228cdf0e10cSrcweir  * NOTE: Results of some measurement revealed that this cache
2229cdf0e10cSrcweir  * does not improve performance!
2230cdf0e10cSrcweir  */
2231cdf0e10cSrcweir 
2232cdf0e10cSrcweir class SwFindRowSpanCache
2233cdf0e10cSrcweir {
2234cdf0e10cSrcweir private:
2235cdf0e10cSrcweir 
2236cdf0e10cSrcweir     struct SwFindRowSpanCacheObj
2237cdf0e10cSrcweir     {
2238cdf0e10cSrcweir         const SwTableBox* mpKeyBox;
2239cdf0e10cSrcweir         const SwTableBox* mpCacheBox;
2240cdf0e10cSrcweir         sal_uInt16 mnSteps;
2241cdf0e10cSrcweir         bool mbStart;
2242cdf0e10cSrcweir 
SwFindRowSpanCacheObjSwFindRowSpanCache::SwFindRowSpanCacheObj2243cdf0e10cSrcweir         SwFindRowSpanCacheObj( const SwTableBox& rKeyBox, const SwTableBox& rCacheBox, sal_uInt16 nSteps, bool bStart ) :
2244cdf0e10cSrcweir             mpKeyBox( &rKeyBox ), mpCacheBox( &rCacheBox ), mnSteps( nSteps ), mbStart( bStart ) {}
2245cdf0e10cSrcweir     };
2246cdf0e10cSrcweir 
2247cdf0e10cSrcweir     std::list< SwFindRowSpanCacheObj > aCache;
2248cdf0e10cSrcweir     bool mbUseCache;
2249cdf0e10cSrcweir     static SwFindRowSpanCache* mpFindRowSpanCache;
2250cdf0e10cSrcweir     SwFindRowSpanCache();
2251cdf0e10cSrcweir 
2252cdf0e10cSrcweir public:
2253cdf0e10cSrcweir 
2254cdf0e10cSrcweir     static SwFindRowSpanCache& getSwFindRowSpanCache();
2255cdf0e10cSrcweir     const SwTableBox* FindCachedStartEndOfRowSpan( const SwTableBox& rKeyBox, sal_uInt16 nSteps, bool bStart );
2256cdf0e10cSrcweir     void SetCachedStartEndOfRowSpan( const SwTableBox& rKeyBox, const SwTableBox& rCacheBox, sal_uInt16 nSteps, bool bStart );
2257cdf0e10cSrcweir     void SetUseCache( bool bNew );
2258cdf0e10cSrcweir };
2259cdf0e10cSrcweir 
2260cdf0e10cSrcweir SwFindRowSpanCache* SwFindRowSpanCache::mpFindRowSpanCache = 0;
getSwFindRowSpanCache()2261cdf0e10cSrcweir SwFindRowSpanCache& SwFindRowSpanCache::getSwFindRowSpanCache()
2262cdf0e10cSrcweir {
2263cdf0e10cSrcweir     if ( !mpFindRowSpanCache ) mpFindRowSpanCache = new SwFindRowSpanCache;
2264cdf0e10cSrcweir     return *mpFindRowSpanCache;
2265cdf0e10cSrcweir }
2266cdf0e10cSrcweir 
SwFindRowSpanCache()2267cdf0e10cSrcweir SwFindRowSpanCache::SwFindRowSpanCache() : mbUseCache( false )
2268cdf0e10cSrcweir {
2269cdf0e10cSrcweir }
2270cdf0e10cSrcweir 
SetUseCache(bool bNew)2271cdf0e10cSrcweir void SwFindRowSpanCache::SetUseCache( bool bNew )
2272cdf0e10cSrcweir {
2273cdf0e10cSrcweir     mbUseCache = bNew; aCache.clear();
2274cdf0e10cSrcweir }
2275cdf0e10cSrcweir 
FindCachedStartEndOfRowSpan(const SwTableBox & rKeyBox,sal_uInt16 nSteps,bool bStart)2276cdf0e10cSrcweir const SwTableBox* SwFindRowSpanCache::FindCachedStartEndOfRowSpan( const SwTableBox& rKeyBox,
2277cdf0e10cSrcweir                                                                    sal_uInt16 nSteps,
2278cdf0e10cSrcweir                                                                    bool bStart )
2279cdf0e10cSrcweir {
2280cdf0e10cSrcweir     static nCallCount = 0;
2281cdf0e10cSrcweir     static nSuccessCount = 0;
2282cdf0e10cSrcweir     ++nCallCount;
2283cdf0e10cSrcweir 
2284cdf0e10cSrcweir     if ( !mbUseCache ) return 0;
2285cdf0e10cSrcweir 
2286cdf0e10cSrcweir     const SwTableBox* pRet = 0;
2287cdf0e10cSrcweir 
2288cdf0e10cSrcweir     std::list< SwFindRowSpanCacheObj >::const_iterator aIter;
2289cdf0e10cSrcweir     for ( aIter = aCache.begin(); aIter != aCache.end(); ++aIter )
2290cdf0e10cSrcweir     {
2291cdf0e10cSrcweir         if ( aIter->mpKeyBox == &rKeyBox &&
2292cdf0e10cSrcweir              aIter->mnSteps == nSteps &&
2293cdf0e10cSrcweir              aIter->mbStart == bStart )
2294cdf0e10cSrcweir         {
2295cdf0e10cSrcweir             pRet = aIter->mpCacheBox;
2296cdf0e10cSrcweir             ++nSuccessCount;
2297cdf0e10cSrcweir             break;
2298cdf0e10cSrcweir         }
2299cdf0e10cSrcweir     }
2300cdf0e10cSrcweir 
2301cdf0e10cSrcweir     return pRet;
2302cdf0e10cSrcweir }
2303cdf0e10cSrcweir 
2304cdf0e10cSrcweir const int FindBoxCacheSize = 2;
2305cdf0e10cSrcweir 
SetCachedStartEndOfRowSpan(const SwTableBox & rKeyBox,const SwTableBox & rCacheBox,sal_uInt16 nSteps,bool bStart)2306cdf0e10cSrcweir void SwFindRowSpanCache::SetCachedStartEndOfRowSpan( const SwTableBox& rKeyBox,
2307cdf0e10cSrcweir                                                      const SwTableBox& rCacheBox,
2308cdf0e10cSrcweir                                                      sal_uInt16 nSteps,
2309cdf0e10cSrcweir                                                      bool bStart )
2310cdf0e10cSrcweir {
2311cdf0e10cSrcweir     if ( !mbUseCache ) return;
2312cdf0e10cSrcweir 
2313cdf0e10cSrcweir     const SwFindRowSpanCacheObj aNew( rKeyBox, rCacheBox, nSteps, bStart );
2314cdf0e10cSrcweir     aCache.push_front( aNew );
2315cdf0e10cSrcweir     if ( aCache.size() > FindBoxCacheSize )
2316cdf0e10cSrcweir         aCache.pop_back();
2317cdf0e10cSrcweir }
2318cdf0e10cSrcweir 
2319cdf0e10cSrcweir /*
2320cdf0e10cSrcweir  * A small optimization for FindStartEndOfRowSpan END
2321cdf0e10cSrcweir  */
2322cdf0e10cSrcweir 
2323cdf0e10cSrcweir #endif
2324cdf0e10cSrcweir 
2325