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