xref: /AOO41X/main/svx/source/table/cellcursor.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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