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

Generated by: LCOV version 1.10