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