1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_svx.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir #include "svx/svdotable.hxx" 32*cdf0e10cSrcweir #include "cellcursor.hxx" 33*cdf0e10cSrcweir #include "tablelayouter.hxx" 34*cdf0e10cSrcweir #include "cell.hxx" 35*cdf0e10cSrcweir #include "svx/svdmodel.hxx" 36*cdf0e10cSrcweir #include "svx/svdstr.hrc" 37*cdf0e10cSrcweir #include "svx/svdglob.hxx" 38*cdf0e10cSrcweir 39*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 40*cdf0e10cSrcweir 41*cdf0e10cSrcweir using ::rtl::OUString; 42*cdf0e10cSrcweir using namespace ::com::sun::star::uno; 43*cdf0e10cSrcweir using namespace ::com::sun::star::lang; 44*cdf0e10cSrcweir using namespace ::com::sun::star::container; 45*cdf0e10cSrcweir using namespace ::com::sun::star::beans; 46*cdf0e10cSrcweir using namespace ::com::sun::star::table; 47*cdf0e10cSrcweir 48*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 49*cdf0e10cSrcweir 50*cdf0e10cSrcweir namespace sdr { namespace table { 51*cdf0e10cSrcweir 52*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 53*cdf0e10cSrcweir // CellCursor 54*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 55*cdf0e10cSrcweir 56*cdf0e10cSrcweir CellCursor::CellCursor( const TableModelRef & xTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) 57*cdf0e10cSrcweir : CellCursorBase( xTable, nLeft, nTop, nRight, nBottom ) 58*cdf0e10cSrcweir { 59*cdf0e10cSrcweir } 60*cdf0e10cSrcweir 61*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 62*cdf0e10cSrcweir 63*cdf0e10cSrcweir CellCursor::~CellCursor() 64*cdf0e10cSrcweir { 65*cdf0e10cSrcweir } 66*cdf0e10cSrcweir 67*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 68*cdf0e10cSrcweir // XCellCursor 69*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 70*cdf0e10cSrcweir 71*cdf0e10cSrcweir Reference< XCell > SAL_CALL CellCursor::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (IndexOutOfBoundsException, RuntimeException) 72*cdf0e10cSrcweir { 73*cdf0e10cSrcweir return CellRange::getCellByPosition( nColumn, nRow ); 74*cdf0e10cSrcweir } 75*cdf0e10cSrcweir 76*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 77*cdf0e10cSrcweir 78*cdf0e10cSrcweir Reference< XCellRange > SAL_CALL CellCursor::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException) 79*cdf0e10cSrcweir { 80*cdf0e10cSrcweir return CellRange::getCellRangeByPosition( nLeft, nTop, nRight, nBottom ); 81*cdf0e10cSrcweir } 82*cdf0e10cSrcweir 83*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 84*cdf0e10cSrcweir 85*cdf0e10cSrcweir Reference< XCellRange > SAL_CALL CellCursor::getCellRangeByName( const OUString& aRange ) throw (RuntimeException) 86*cdf0e10cSrcweir { 87*cdf0e10cSrcweir return CellRange::getCellRangeByName( aRange ); 88*cdf0e10cSrcweir } 89*cdf0e10cSrcweir 90*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 91*cdf0e10cSrcweir // XCellCursor 92*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 93*cdf0e10cSrcweir 94*cdf0e10cSrcweir void SAL_CALL CellCursor::gotoStart( ) throw (RuntimeException) 95*cdf0e10cSrcweir { 96*cdf0e10cSrcweir mnRight = mnLeft; 97*cdf0e10cSrcweir mnBottom = mnTop; 98*cdf0e10cSrcweir } 99*cdf0e10cSrcweir 100*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 101*cdf0e10cSrcweir 102*cdf0e10cSrcweir void SAL_CALL CellCursor::gotoEnd( ) throw (RuntimeException) 103*cdf0e10cSrcweir { 104*cdf0e10cSrcweir mnLeft = mnRight; 105*cdf0e10cSrcweir mnTop = mnBottom; 106*cdf0e10cSrcweir } 107*cdf0e10cSrcweir 108*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 109*cdf0e10cSrcweir 110*cdf0e10cSrcweir void SAL_CALL CellCursor::gotoNext( ) throw (RuntimeException) 111*cdf0e10cSrcweir { 112*cdf0e10cSrcweir if( mxTable.is() ) 113*cdf0e10cSrcweir { 114*cdf0e10cSrcweir mnRight++; 115*cdf0e10cSrcweir if( mnRight >= mxTable->getColumnCount() ) 116*cdf0e10cSrcweir { 117*cdf0e10cSrcweir // if we past the last column, try skip to the row line 118*cdf0e10cSrcweir mnTop++; 119*cdf0e10cSrcweir if( mnTop >= mxTable->getRowCount() ) 120*cdf0e10cSrcweir { 121*cdf0e10cSrcweir // if we past the last row, do not move cursor at all 122*cdf0e10cSrcweir mnTop--; 123*cdf0e10cSrcweir mnRight--; 124*cdf0e10cSrcweir } 125*cdf0e10cSrcweir else 126*cdf0e10cSrcweir { 127*cdf0e10cSrcweir // restart at the first column on the next row 128*cdf0e10cSrcweir mnRight = 0; 129*cdf0e10cSrcweir } 130*cdf0e10cSrcweir } 131*cdf0e10cSrcweir } 132*cdf0e10cSrcweir 133*cdf0e10cSrcweir mnLeft = mnRight; 134*cdf0e10cSrcweir mnTop = mnBottom; 135*cdf0e10cSrcweir } 136*cdf0e10cSrcweir 137*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 138*cdf0e10cSrcweir 139*cdf0e10cSrcweir void SAL_CALL CellCursor::gotoPrevious( ) throw (RuntimeException) 140*cdf0e10cSrcweir { 141*cdf0e10cSrcweir if( mxTable.is() ) 142*cdf0e10cSrcweir { 143*cdf0e10cSrcweir if( mnLeft > 0 ) 144*cdf0e10cSrcweir { 145*cdf0e10cSrcweir --mnLeft; 146*cdf0e10cSrcweir } 147*cdf0e10cSrcweir else if( mnTop > 0 ) 148*cdf0e10cSrcweir { 149*cdf0e10cSrcweir --mnTop; 150*cdf0e10cSrcweir mnLeft = mxTable->getColumnCount() - 1; 151*cdf0e10cSrcweir } 152*cdf0e10cSrcweir } 153*cdf0e10cSrcweir 154*cdf0e10cSrcweir mnRight = mnLeft; 155*cdf0e10cSrcweir mnBottom = mnTop; 156*cdf0e10cSrcweir } 157*cdf0e10cSrcweir 158*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 159*cdf0e10cSrcweir 160*cdf0e10cSrcweir void SAL_CALL CellCursor::gotoOffset( ::sal_Int32 nColumnOffset, ::sal_Int32 nRowOffset ) throw (RuntimeException) 161*cdf0e10cSrcweir { 162*cdf0e10cSrcweir if( mxTable.is() ) 163*cdf0e10cSrcweir { 164*cdf0e10cSrcweir const sal_Int32 nLeft = mnLeft + nColumnOffset; 165*cdf0e10cSrcweir if( (nLeft >= 0) && (nLeft < mxTable->getColumnCount() ) ) 166*cdf0e10cSrcweir mnRight = mnLeft = nLeft; 167*cdf0e10cSrcweir 168*cdf0e10cSrcweir const sal_Int32 nTop = mnTop + nRowOffset; 169*cdf0e10cSrcweir if( (nTop >= 0) && (nTop < mxTable->getRowCount()) ) 170*cdf0e10cSrcweir mnTop = mnBottom = nTop; 171*cdf0e10cSrcweir } 172*cdf0e10cSrcweir } 173*cdf0e10cSrcweir 174*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 175*cdf0e10cSrcweir // XMergeableCellCursor 176*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 177*cdf0e10cSrcweir 178*cdf0e10cSrcweir /** returns true and the merged cell positions if a merge is valid or false if a merge is 179*cdf0e10cSrcweir not valid for that range */ 180*cdf0e10cSrcweir bool CellCursor::GetMergedSelection( CellPos& rStart, CellPos& rEnd ) 181*cdf0e10cSrcweir { 182*cdf0e10cSrcweir rStart.mnCol = mnLeft; rStart.mnRow = mnTop; 183*cdf0e10cSrcweir rEnd.mnCol = mnRight; rEnd.mnRow = mnBottom; 184*cdf0e10cSrcweir 185*cdf0e10cSrcweir // single cell merge is never valid 186*cdf0e10cSrcweir if( mxTable.is() && ((mnLeft != mnRight) || (mnTop != mnBottom)) ) try 187*cdf0e10cSrcweir { 188*cdf0e10cSrcweir CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( mnLeft, mnTop ).get() ) ); 189*cdf0e10cSrcweir 190*cdf0e10cSrcweir // check if first cell is merged 191*cdf0e10cSrcweir if( xCell.is() && xCell->isMerged() ) 192*cdf0e10cSrcweir findMergeOrigin( mxTable, mnLeft, mnTop, rStart.mnCol, rStart.mnRow ); 193*cdf0e10cSrcweir 194*cdf0e10cSrcweir // check if last cell is merged 195*cdf0e10cSrcweir xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( mnRight, mnBottom ).get() ) ); 196*cdf0e10cSrcweir if( xCell.is() ) 197*cdf0e10cSrcweir { 198*cdf0e10cSrcweir if( xCell->isMerged() ) 199*cdf0e10cSrcweir { 200*cdf0e10cSrcweir findMergeOrigin( mxTable, mnRight, mnBottom, rEnd.mnCol, rEnd.mnRow ); 201*cdf0e10cSrcweir // merge not possible if selection is only one cell and all its merges 202*cdf0e10cSrcweir if( rEnd == rStart ) 203*cdf0e10cSrcweir return false; 204*cdf0e10cSrcweir xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rEnd.mnCol, rEnd.mnRow ).get() ) ); 205*cdf0e10cSrcweir } 206*cdf0e10cSrcweir } 207*cdf0e10cSrcweir if( xCell.is() ) 208*cdf0e10cSrcweir { 209*cdf0e10cSrcweir rEnd.mnCol += xCell->getColumnSpan()-1; 210*cdf0e10cSrcweir rEnd.mnRow += xCell->getRowSpan()-1; 211*cdf0e10cSrcweir } 212*cdf0e10cSrcweir 213*cdf0e10cSrcweir // now check if everything is inside the given bounds 214*cdf0e10cSrcweir sal_Int32 nRow, nCol; 215*cdf0e10cSrcweir for( nRow = rStart.mnRow; nRow <= rEnd.mnRow; nRow++ ) 216*cdf0e10cSrcweir { 217*cdf0e10cSrcweir for( nCol = rStart.mnCol; nCol <= rEnd.mnCol; nCol++ ) 218*cdf0e10cSrcweir { 219*cdf0e10cSrcweir xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); 220*cdf0e10cSrcweir if( !xCell.is() ) 221*cdf0e10cSrcweir continue; 222*cdf0e10cSrcweir 223*cdf0e10cSrcweir if( xCell->isMerged() ) 224*cdf0e10cSrcweir { 225*cdf0e10cSrcweir sal_Int32 nOriginCol, nOriginRow; 226*cdf0e10cSrcweir if( findMergeOrigin( mxTable, nCol, nRow, nOriginCol, nOriginRow ) ) 227*cdf0e10cSrcweir { 228*cdf0e10cSrcweir if( (nOriginCol < rStart.mnCol) || (nOriginRow < rStart.mnRow) ) 229*cdf0e10cSrcweir return false; 230*cdf0e10cSrcweir 231*cdf0e10cSrcweir xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( nOriginCol, nOriginRow ).get() ) ); 232*cdf0e10cSrcweir if( xCell.is() ) 233*cdf0e10cSrcweir { 234*cdf0e10cSrcweir nOriginCol += xCell->getColumnSpan()-1; 235*cdf0e10cSrcweir nOriginRow += xCell->getRowSpan()-1; 236*cdf0e10cSrcweir 237*cdf0e10cSrcweir if( (nOriginCol > rEnd.mnCol) || (nOriginRow > rEnd.mnRow) ) 238*cdf0e10cSrcweir return false; 239*cdf0e10cSrcweir } 240*cdf0e10cSrcweir } 241*cdf0e10cSrcweir } 242*cdf0e10cSrcweir else if( ((nCol + xCell->getColumnSpan() - 1) > rEnd.mnCol) || ((nRow + xCell->getRowSpan() - 1 ) > rEnd.mnRow) ) 243*cdf0e10cSrcweir { 244*cdf0e10cSrcweir return false; 245*cdf0e10cSrcweir } 246*cdf0e10cSrcweir } 247*cdf0e10cSrcweir } 248*cdf0e10cSrcweir return true; 249*cdf0e10cSrcweir } 250*cdf0e10cSrcweir catch( Exception& ) 251*cdf0e10cSrcweir { 252*cdf0e10cSrcweir DBG_ERROR("sdr::table::SvmxTableController::GetMergedSelection(), exception caught!"); 253*cdf0e10cSrcweir } 254*cdf0e10cSrcweir return false; 255*cdf0e10cSrcweir } 256*cdf0e10cSrcweir 257*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 258*cdf0e10cSrcweir 259*cdf0e10cSrcweir void SAL_CALL CellCursor::merge( ) throw (NoSupportException, RuntimeException) 260*cdf0e10cSrcweir { 261*cdf0e10cSrcweir CellPos aStart, aEnd; 262*cdf0e10cSrcweir if( !GetMergedSelection( aStart, aEnd ) ) 263*cdf0e10cSrcweir throw NoSupportException(); 264*cdf0e10cSrcweir 265*cdf0e10cSrcweir if( !mxTable.is() || (mxTable->getSdrTableObj() == 0) ) 266*cdf0e10cSrcweir throw DisposedException(); 267*cdf0e10cSrcweir 268*cdf0e10cSrcweir SdrModel* pModel = mxTable->getSdrTableObj()->GetModel(); 269*cdf0e10cSrcweir const bool bUndo = pModel && mxTable->getSdrTableObj()->IsInserted() && pModel->IsUndoEnabled(); 270*cdf0e10cSrcweir 271*cdf0e10cSrcweir if( bUndo ) 272*cdf0e10cSrcweir pModel->BegUndo( ImpGetResStr(STR_TABLE_MERGE) ); 273*cdf0e10cSrcweir 274*cdf0e10cSrcweir try 275*cdf0e10cSrcweir { 276*cdf0e10cSrcweir mxTable->merge( aStart.mnCol, aStart.mnRow, aEnd.mnCol - aStart.mnCol + 1, aEnd.mnRow - aStart.mnRow + 1 ); 277*cdf0e10cSrcweir mxTable->optimize(); 278*cdf0e10cSrcweir mxTable->setModified(sal_True); 279*cdf0e10cSrcweir } 280*cdf0e10cSrcweir catch( Exception& ) 281*cdf0e10cSrcweir { 282*cdf0e10cSrcweir DBG_ERROR("sdr::table::CellCursor::merge(), exception caught!"); 283*cdf0e10cSrcweir } 284*cdf0e10cSrcweir 285*cdf0e10cSrcweir if( bUndo ) 286*cdf0e10cSrcweir pModel->EndUndo(); 287*cdf0e10cSrcweir 288*cdf0e10cSrcweir if( pModel ) 289*cdf0e10cSrcweir pModel->SetChanged(); 290*cdf0e10cSrcweir } 291*cdf0e10cSrcweir 292*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 293*cdf0e10cSrcweir 294*cdf0e10cSrcweir void CellCursor::split_column( sal_Int32 nCol, sal_Int32 nColumns, std::vector< sal_Int32 >& rLeftOvers ) 295*cdf0e10cSrcweir { 296*cdf0e10cSrcweir const sal_Int32 nRowCount = mxTable->getRowCount(); 297*cdf0e10cSrcweir 298*cdf0e10cSrcweir sal_Int32 nNewCols = 0, nRow; 299*cdf0e10cSrcweir 300*cdf0e10cSrcweir // first check how many columns we need to add 301*cdf0e10cSrcweir for( nRow = mnTop; nRow <= mnBottom; ++nRow ) 302*cdf0e10cSrcweir { 303*cdf0e10cSrcweir CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); 304*cdf0e10cSrcweir if( xCell.is() && !xCell->isMerged() ) 305*cdf0e10cSrcweir nNewCols = std::max( nNewCols, nColumns - xCell->getColumnSpan() + 1 - rLeftOvers[nRow] ); 306*cdf0e10cSrcweir } 307*cdf0e10cSrcweir 308*cdf0e10cSrcweir if( nNewCols > 0 ) 309*cdf0e10cSrcweir { 310*cdf0e10cSrcweir const OUString sWidth( RTL_CONSTASCII_USTRINGPARAM("Width") ); 311*cdf0e10cSrcweir Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_QUERY_THROW ); 312*cdf0e10cSrcweir Reference< XPropertySet > xRefColumn( xCols->getByIndex( nCol ), UNO_QUERY_THROW ); 313*cdf0e10cSrcweir sal_Int32 nWidth = 0; 314*cdf0e10cSrcweir xRefColumn->getPropertyValue( sWidth ) >>= nWidth; 315*cdf0e10cSrcweir const sal_Int32 nNewWidth = nWidth / (nNewCols + 1); 316*cdf0e10cSrcweir 317*cdf0e10cSrcweir // reference column gets new width + rounding errors 318*cdf0e10cSrcweir xRefColumn->setPropertyValue( sWidth, Any( nWidth - (nNewWidth * nNewCols) ) ); 319*cdf0e10cSrcweir 320*cdf0e10cSrcweir xCols->insertByIndex( nCol + 1, nNewCols ); 321*cdf0e10cSrcweir mnRight += nNewCols; 322*cdf0e10cSrcweir 323*cdf0e10cSrcweir // distribute new width 324*cdf0e10cSrcweir for( sal_Int32 nNewCol = nCol + nNewCols; nNewCol > nCol; --nNewCol ) 325*cdf0e10cSrcweir { 326*cdf0e10cSrcweir Reference< XPropertySet > xNewCol( xCols->getByIndex( nNewCol ), UNO_QUERY_THROW ); 327*cdf0e10cSrcweir xNewCol->setPropertyValue( sWidth, Any( nNewWidth ) ); 328*cdf0e10cSrcweir } 329*cdf0e10cSrcweir } 330*cdf0e10cSrcweir 331*cdf0e10cSrcweir for( nRow = 0; nRow < nRowCount; ++nRow ) 332*cdf0e10cSrcweir { 333*cdf0e10cSrcweir CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); 334*cdf0e10cSrcweir if( !xCell.is() || xCell->isMerged() ) 335*cdf0e10cSrcweir { 336*cdf0e10cSrcweir if( nNewCols > 0 ) 337*cdf0e10cSrcweir { 338*cdf0e10cSrcweir // merged cells are ignored, but newly added columns will be added to leftovers 339*cdf0e10cSrcweir xCell.set( dynamic_cast< Cell* >(mxTable->getCellByPosition( nCol+1, nRow ).get() ) ); 340*cdf0e10cSrcweir if( !xCell.is() || !xCell->isMerged() ) 341*cdf0e10cSrcweir rLeftOvers[nRow] += nNewCols; 342*cdf0e10cSrcweir } 343*cdf0e10cSrcweir } 344*cdf0e10cSrcweir else 345*cdf0e10cSrcweir { 346*cdf0e10cSrcweir sal_Int32 nRowSpan = xCell->getRowSpan() - 1; 347*cdf0e10cSrcweir sal_Int32 nColSpan = xCell->getColumnSpan() - 1; 348*cdf0e10cSrcweir 349*cdf0e10cSrcweir if( (nRow >= mnTop) && (nRow <= mnBottom) ) 350*cdf0e10cSrcweir { 351*cdf0e10cSrcweir sal_Int32 nCellsAvailable = 1 + nColSpan + rLeftOvers[nRow]; 352*cdf0e10cSrcweir if( nColSpan == 0 ) 353*cdf0e10cSrcweir nCellsAvailable += nNewCols; 354*cdf0e10cSrcweir 355*cdf0e10cSrcweir DBG_ASSERT( nCellsAvailable > nColumns, "sdr::table::CellCursor::split_column(), somethings wrong" ); 356*cdf0e10cSrcweir 357*cdf0e10cSrcweir sal_Int32 nSplitSpan = (nCellsAvailable / (nColumns + 1)) - 1; 358*cdf0e10cSrcweir 359*cdf0e10cSrcweir sal_Int32 nSplitCol = nCol; 360*cdf0e10cSrcweir sal_Int32 nSplits = nColumns + 1; 361*cdf0e10cSrcweir while( nSplits-- ) 362*cdf0e10cSrcweir { 363*cdf0e10cSrcweir // last split eats rounding cells 364*cdf0e10cSrcweir if( nSplits == 0 ) 365*cdf0e10cSrcweir nSplitSpan = nCellsAvailable - ((nSplitSpan+1) * nColumns) - 1; 366*cdf0e10cSrcweir 367*cdf0e10cSrcweir mxTable->merge( nSplitCol, nRow, nSplitSpan + 1, nRowSpan + 1); 368*cdf0e10cSrcweir if( nSplits > 0 ) 369*cdf0e10cSrcweir nSplitCol += nSplitSpan + 1; 370*cdf0e10cSrcweir } 371*cdf0e10cSrcweir 372*cdf0e10cSrcweir do 373*cdf0e10cSrcweir { 374*cdf0e10cSrcweir rLeftOvers[nRow++] = 0; 375*cdf0e10cSrcweir } 376*cdf0e10cSrcweir while( nRowSpan-- ); 377*cdf0e10cSrcweir --nRow; 378*cdf0e10cSrcweir } 379*cdf0e10cSrcweir else 380*cdf0e10cSrcweir { 381*cdf0e10cSrcweir // cope with outside cells, merge if needed 382*cdf0e10cSrcweir if( nColSpan < (rLeftOvers[nRow] + nNewCols) ) 383*cdf0e10cSrcweir mxTable->merge( nCol, nRow, (rLeftOvers[nRow] + nNewCols) + 1, nRowSpan + 1 ); 384*cdf0e10cSrcweir 385*cdf0e10cSrcweir do 386*cdf0e10cSrcweir { 387*cdf0e10cSrcweir rLeftOvers[nRow++] = 0; // consumed 388*cdf0e10cSrcweir } 389*cdf0e10cSrcweir while( nRowSpan-- ); 390*cdf0e10cSrcweir --nRow; 391*cdf0e10cSrcweir } 392*cdf0e10cSrcweir } 393*cdf0e10cSrcweir } 394*cdf0e10cSrcweir } 395*cdf0e10cSrcweir 396*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 397*cdf0e10cSrcweir 398*cdf0e10cSrcweir void CellCursor::split_horizontal( sal_Int32 nColumns ) 399*cdf0e10cSrcweir { 400*cdf0e10cSrcweir const sal_Int32 nRowCount = mxTable->getRowCount(); 401*cdf0e10cSrcweir 402*cdf0e10cSrcweir std::vector< sal_Int32 > aLeftOvers( nRowCount ); 403*cdf0e10cSrcweir 404*cdf0e10cSrcweir for( sal_Int32 nCol = mnRight; nCol >= mnLeft; --nCol ) 405*cdf0e10cSrcweir split_column( nCol, nColumns, aLeftOvers ); 406*cdf0e10cSrcweir } 407*cdf0e10cSrcweir 408*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 409*cdf0e10cSrcweir 410*cdf0e10cSrcweir void CellCursor::split_row( sal_Int32 nRow, sal_Int32 nRows, std::vector< sal_Int32 >& rLeftOvers ) 411*cdf0e10cSrcweir { 412*cdf0e10cSrcweir const sal_Int32 nColCount = mxTable->getColumnCount(); 413*cdf0e10cSrcweir 414*cdf0e10cSrcweir sal_Int32 nNewRows = 0, nCol; 415*cdf0e10cSrcweir 416*cdf0e10cSrcweir // first check how many columns we need to add 417*cdf0e10cSrcweir for( nCol = mnLeft; nCol <= mnRight; ++nCol ) 418*cdf0e10cSrcweir { 419*cdf0e10cSrcweir CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); 420*cdf0e10cSrcweir if( xCell.is() && !xCell->isMerged() ) 421*cdf0e10cSrcweir nNewRows = std::max( nNewRows, nRows - xCell->getRowSpan() + 1 - rLeftOvers[nCol] ); 422*cdf0e10cSrcweir } 423*cdf0e10cSrcweir 424*cdf0e10cSrcweir if( nNewRows > 0 ) 425*cdf0e10cSrcweir { 426*cdf0e10cSrcweir const OUString sHeight( RTL_CONSTASCII_USTRINGPARAM("Height") ); 427*cdf0e10cSrcweir Reference< XTableRows > xRows( mxTable->getRows(), UNO_QUERY_THROW ); 428*cdf0e10cSrcweir Reference< XPropertySet > xRefRow( xRows->getByIndex( nRow ), UNO_QUERY_THROW ); 429*cdf0e10cSrcweir sal_Int32 nHeight = 0; 430*cdf0e10cSrcweir xRefRow->getPropertyValue( sHeight ) >>= nHeight; 431*cdf0e10cSrcweir const sal_Int32 nNewHeight = nHeight / (nNewRows + 1); 432*cdf0e10cSrcweir 433*cdf0e10cSrcweir // reference row gets new height + rounding errors 434*cdf0e10cSrcweir xRefRow->setPropertyValue( sHeight, Any( nHeight - (nNewHeight * nNewRows) ) ); 435*cdf0e10cSrcweir 436*cdf0e10cSrcweir xRows->insertByIndex( nRow + 1, nNewRows ); 437*cdf0e10cSrcweir mnBottom += nNewRows; 438*cdf0e10cSrcweir 439*cdf0e10cSrcweir // distribute new width 440*cdf0e10cSrcweir for( sal_Int32 nNewRow = nRow + nNewRows; nNewRow > nRow; --nNewRow ) 441*cdf0e10cSrcweir { 442*cdf0e10cSrcweir Reference< XPropertySet > xNewRow( xRows->getByIndex( nNewRow ), UNO_QUERY_THROW ); 443*cdf0e10cSrcweir xNewRow->setPropertyValue( sHeight, Any( nNewHeight ) ); 444*cdf0e10cSrcweir } 445*cdf0e10cSrcweir } 446*cdf0e10cSrcweir 447*cdf0e10cSrcweir for( nCol = 0; nCol < nColCount; ++nCol ) 448*cdf0e10cSrcweir { 449*cdf0e10cSrcweir CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); 450*cdf0e10cSrcweir if( !xCell.is() || xCell->isMerged() ) 451*cdf0e10cSrcweir { 452*cdf0e10cSrcweir if( nNewRows ) 453*cdf0e10cSrcweir { 454*cdf0e10cSrcweir // merged cells are ignored, but newly added columns will be added to leftovers 455*cdf0e10cSrcweir xCell.set( dynamic_cast< Cell* >(mxTable->getCellByPosition( nCol, nRow+1 ).get() ) ); 456*cdf0e10cSrcweir if( !xCell.is() || !xCell->isMerged() ) 457*cdf0e10cSrcweir rLeftOvers[nCol] += nNewRows; 458*cdf0e10cSrcweir } 459*cdf0e10cSrcweir } 460*cdf0e10cSrcweir else 461*cdf0e10cSrcweir { 462*cdf0e10cSrcweir sal_Int32 nRowSpan = xCell->getRowSpan() - 1; 463*cdf0e10cSrcweir sal_Int32 nColSpan = xCell->getColumnSpan() - 1; 464*cdf0e10cSrcweir 465*cdf0e10cSrcweir if( (nCol >= mnLeft) && (nCol <= mnRight) ) 466*cdf0e10cSrcweir { 467*cdf0e10cSrcweir sal_Int32 nCellsAvailable = 1 + nRowSpan + rLeftOvers[nCol]; 468*cdf0e10cSrcweir if( nRowSpan == 0 ) 469*cdf0e10cSrcweir nCellsAvailable += nNewRows; 470*cdf0e10cSrcweir 471*cdf0e10cSrcweir DBG_ASSERT( nCellsAvailable > nRows, "sdr::table::CellCursor::split_row(), somethings wrong" ); 472*cdf0e10cSrcweir 473*cdf0e10cSrcweir sal_Int32 nSplitSpan = (nCellsAvailable / (nRows + 1)) - 1; 474*cdf0e10cSrcweir 475*cdf0e10cSrcweir sal_Int32 nSplitRow = nRow; 476*cdf0e10cSrcweir sal_Int32 nSplits = nRows + 1; 477*cdf0e10cSrcweir while( nSplits-- ) 478*cdf0e10cSrcweir { 479*cdf0e10cSrcweir // last split eats rounding cells 480*cdf0e10cSrcweir if( nSplits == 0 ) 481*cdf0e10cSrcweir nSplitSpan = nCellsAvailable - ((nSplitSpan+1) * nRows) - 1; 482*cdf0e10cSrcweir 483*cdf0e10cSrcweir mxTable->merge( nCol, nSplitRow, nColSpan + 1, nSplitSpan + 1 ); 484*cdf0e10cSrcweir if( nSplits > 0 ) 485*cdf0e10cSrcweir nSplitRow += nSplitSpan + 1; 486*cdf0e10cSrcweir } 487*cdf0e10cSrcweir 488*cdf0e10cSrcweir do 489*cdf0e10cSrcweir { 490*cdf0e10cSrcweir rLeftOvers[nCol++] = 0; 491*cdf0e10cSrcweir } 492*cdf0e10cSrcweir while( nColSpan-- ); 493*cdf0e10cSrcweir --nCol; 494*cdf0e10cSrcweir } 495*cdf0e10cSrcweir else 496*cdf0e10cSrcweir { 497*cdf0e10cSrcweir // cope with outside cells, merge if needed 498*cdf0e10cSrcweir if( nRowSpan < (rLeftOvers[nCol] + nNewRows) ) 499*cdf0e10cSrcweir mxTable->merge( nCol, nRow, nColSpan + 1, (rLeftOvers[nCol] + nNewRows) + 1 ); 500*cdf0e10cSrcweir 501*cdf0e10cSrcweir do 502*cdf0e10cSrcweir { 503*cdf0e10cSrcweir rLeftOvers[nCol++] = 0; // consumed 504*cdf0e10cSrcweir } 505*cdf0e10cSrcweir while( nColSpan-- ); 506*cdf0e10cSrcweir --nCol; 507*cdf0e10cSrcweir } 508*cdf0e10cSrcweir } 509*cdf0e10cSrcweir } 510*cdf0e10cSrcweir } 511*cdf0e10cSrcweir 512*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 513*cdf0e10cSrcweir 514*cdf0e10cSrcweir void CellCursor::split_vertical( sal_Int32 nRows ) 515*cdf0e10cSrcweir { 516*cdf0e10cSrcweir const sal_Int32 nColCount = mxTable->getColumnCount(); 517*cdf0e10cSrcweir 518*cdf0e10cSrcweir std::vector< sal_Int32 > aLeftOvers( nColCount ); 519*cdf0e10cSrcweir 520*cdf0e10cSrcweir for( sal_Int32 nRow = mnBottom; nRow >= mnTop; --nRow ) 521*cdf0e10cSrcweir split_row( nRow, nRows, aLeftOvers ); 522*cdf0e10cSrcweir } 523*cdf0e10cSrcweir 524*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 525*cdf0e10cSrcweir 526*cdf0e10cSrcweir void SAL_CALL CellCursor::split( sal_Int32 nColumns, sal_Int32 nRows ) throw (NoSupportException, IllegalArgumentException, RuntimeException) 527*cdf0e10cSrcweir { 528*cdf0e10cSrcweir if( (nColumns < 0) || (nRows < 0) ) 529*cdf0e10cSrcweir throw IllegalArgumentException(); 530*cdf0e10cSrcweir 531*cdf0e10cSrcweir if( !mxTable.is() || (mxTable->getSdrTableObj() == 0) ) 532*cdf0e10cSrcweir throw DisposedException(); 533*cdf0e10cSrcweir 534*cdf0e10cSrcweir SdrModel* pModel = mxTable->getSdrTableObj()->GetModel(); 535*cdf0e10cSrcweir const bool bUndo = pModel && mxTable->getSdrTableObj()->IsInserted() && pModel->IsUndoEnabled(); 536*cdf0e10cSrcweir if( bUndo ) 537*cdf0e10cSrcweir pModel->BegUndo( ImpGetResStr(STR_TABLE_SPLIT) ); 538*cdf0e10cSrcweir 539*cdf0e10cSrcweir try 540*cdf0e10cSrcweir { 541*cdf0e10cSrcweir if( nColumns > 0 ) 542*cdf0e10cSrcweir split_horizontal( nColumns ); 543*cdf0e10cSrcweir 544*cdf0e10cSrcweir if( nRows > 0 ) 545*cdf0e10cSrcweir split_vertical( nRows ); 546*cdf0e10cSrcweir 547*cdf0e10cSrcweir if( nColumns > 0 ||nRows > 0 ) 548*cdf0e10cSrcweir mxTable->setModified(sal_True); 549*cdf0e10cSrcweir } 550*cdf0e10cSrcweir catch( Exception& ) 551*cdf0e10cSrcweir { 552*cdf0e10cSrcweir DBG_ERROR("sdr::table::CellCursor::split(), exception caught!"); 553*cdf0e10cSrcweir throw NoSupportException(); 554*cdf0e10cSrcweir } 555*cdf0e10cSrcweir 556*cdf0e10cSrcweir if( bUndo ) 557*cdf0e10cSrcweir pModel->EndUndo(); 558*cdf0e10cSrcweir 559*cdf0e10cSrcweir if( pModel ) 560*cdf0e10cSrcweir pModel->SetChanged(); 561*cdf0e10cSrcweir } 562*cdf0e10cSrcweir 563*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 564*cdf0e10cSrcweir 565*cdf0e10cSrcweir sal_Bool SAL_CALL CellCursor::isMergeable( ) throw (RuntimeException) 566*cdf0e10cSrcweir { 567*cdf0e10cSrcweir CellPos aStart, aEnd; 568*cdf0e10cSrcweir return GetMergedSelection( aStart, aEnd ) ? sal_True : sal_False; 569*cdf0e10cSrcweir } 570*cdf0e10cSrcweir 571*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 572*cdf0e10cSrcweir 573*cdf0e10cSrcweir sal_Bool SAL_CALL CellCursor::isUnmergeable( ) throw (RuntimeException) 574*cdf0e10cSrcweir { 575*cdf0e10cSrcweir // this is true if there is at least one merged cell in the current range 576*cdf0e10cSrcweir for( sal_Int32 nRow = mnTop; nRow <= mnBottom; nRow++ ) 577*cdf0e10cSrcweir { 578*cdf0e10cSrcweir for( sal_Int32 nCol = mnLeft; nCol <= mnRight; nCol++ ) 579*cdf0e10cSrcweir { 580*cdf0e10cSrcweir CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); 581*cdf0e10cSrcweir if( xCell.is() && ( (xCell->getRowSpan() > 1) || (xCell->getColumnSpan() > 1) ) ) 582*cdf0e10cSrcweir return sal_True; 583*cdf0e10cSrcweir } 584*cdf0e10cSrcweir } 585*cdf0e10cSrcweir return sal_False; 586*cdf0e10cSrcweir } 587*cdf0e10cSrcweir 588*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 589*cdf0e10cSrcweir 590*cdf0e10cSrcweir } } 591