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