LCOV - code coverage report
Current view: top level - sw/source/core/table - swnewtable.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 547 1081 50.6 %
Date: 2014-04-11 Functions: 29 38 76.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10