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