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