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

Generated by: LCOV version 1.11