update dev300-m58
[ooovba.git] / svx / source / table / tablemodel.cxx
blob901f7775e1a3a0783c7f671246d0a25fd10d8204
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tablemodel.cxx,v $
10 * $Revision: 1.4.264.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #include <com/sun/star/table/XMergeableCell.hpp>
36 #include <algorithm>
37 #include <boost/bind.hpp>
39 #include <vcl/svapp.hxx>
40 #include <vos/mutex.hxx>
42 #include "cell.hxx"
43 #include "cellcursor.hxx"
44 #include "tablemodel.hxx"
45 #include "tablerow.hxx"
46 #include "tablerows.hxx"
47 #include "tablecolumn.hxx"
48 #include "tablecolumns.hxx"
49 #include "tableundo.hxx"
50 #include "svx/svdotable.hxx"
51 #include "svx/svdmodel.hxx"
52 #include "svdstr.hrc"
53 #include "svdglob.hxx"
55 //#define PLEASE_DEBUG_THE_TABLES 1
57 using ::rtl::OUString;
58 using namespace ::osl;
59 using namespace ::vos;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::table;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::container;
64 using namespace ::com::sun::star::beans;
65 using namespace ::com::sun::star::util;
67 // -----------------------------------------------------------------------------
69 namespace sdr { namespace table {
71 // -----------------------------------------------------------------------------
73 // removes the given range from a vector
74 template< class Vec, class Iter > void remove_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
76 const sal_Int32 nSize = static_cast<sal_Int32>(rVector.size());
77 if( nCount && (nIndex >= 0) && (nIndex < nSize) )
79 if( (nIndex + nCount) >= nSize )
81 // remove at end
82 rVector.resize( nIndex );
84 else
86 Iter aBegin( rVector.begin() );
87 while( nIndex-- )
88 aBegin++;
89 if( nCount == 1 )
91 rVector.erase( aBegin );
93 else
95 Iter aEnd( aBegin );
97 while( nCount-- )
98 aEnd++;
99 rVector.erase( aBegin, aEnd );
105 // -----------------------------------------------------------------------------
107 /** inserts a range into a vector */
108 template< class Vec, class Iter, class Entry > sal_Int32 insert_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
110 if( nCount )
112 if( nIndex >= static_cast< sal_Int32 >( rVector.size() ) )
114 // append at end
115 nIndex = static_cast< sal_Int32 >( rVector.size() ); // cap to end
116 rVector.resize( nIndex + nCount );
118 else
120 // insert
121 sal_Int32 nFind = nIndex;
122 Iter aIter( rVector.begin() );
123 while( nFind-- )
124 aIter++;
126 Entry aEmpty;
127 rVector.insert( aIter, nCount, aEmpty );
130 return nIndex;
133 // -----------------------------------------------------------------------------
135 TableModel::TableModel( SdrTableObj* pTableObj )
136 : TableModelBase( m_aMutex )
137 , mpTableObj( pTableObj )
138 , mbModified( sal_False )
139 , mbNotifyPending( false )
140 , mnNotifyLock( 0 )
144 TableModel::TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable )
145 : TableModelBase( m_aMutex )
146 , mpTableObj( pTableObj )
147 , mbModified( sal_False )
148 , mbNotifyPending( false )
149 , mnNotifyLock( 0 )
151 if( xSourceTable.is() )
153 const sal_Int32 nColCount = xSourceTable->getColumnCountImpl();
154 const sal_Int32 nRowCount = xSourceTable->getRowCountImpl();
156 init( nColCount, nRowCount );
158 sal_Int32 nRows = nRowCount;
159 while( nRows-- )
160 (*maRows[nRows]) = (*xSourceTable->maRows[nRows]);
162 sal_Int32 nColumns = nColCount;
163 while( nColumns-- )
164 (*maColumns[nColumns]) = (*xSourceTable->maColumns[nColumns]);
166 // copy cells
167 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
169 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
171 CellRef xTargetCell( getCell( nCol, nRow ) );
172 if( xTargetCell.is() )
173 xTargetCell->cloneFrom( xSourceTable->getCell( nCol, nRow ) );
179 // -----------------------------------------------------------------------------
181 TableModel::~TableModel()
185 // -----------------------------------------------------------------------------
187 void TableModel::init( sal_Int32 nColumns, sal_Int32 nRows )
189 if( nRows < 20 )
190 maRows.reserve( 20 );
192 if( nColumns < 20 )
193 maColumns.reserve( 20 );
195 if( nRows && nColumns )
197 maColumns.resize( nColumns );
198 maRows.resize( nRows );
200 while( nRows-- )
201 maRows[nRows].set( new TableRow( this, nRows, nColumns ) );
203 while( nColumns-- )
204 maColumns[nColumns].set( new TableColumn( this, nColumns ) );
208 // -----------------------------------------------------------------------------
209 // ICellRange
210 // -----------------------------------------------------------------------------
212 sal_Int32 TableModel::getLeft()
214 return 0;
217 // -----------------------------------------------------------------------------
219 sal_Int32 TableModel::getTop()
221 return 0;
224 // -----------------------------------------------------------------------------
226 sal_Int32 TableModel::getRight()
228 return getColumnCount();
231 // -----------------------------------------------------------------------------
233 sal_Int32 TableModel::getBottom()
235 return getRowCount();
238 // -----------------------------------------------------------------------------
240 Reference< XTable > TableModel::getTable()
242 return this;
245 // -----------------------------------------------------------------------------
247 void TableModel::UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount )
249 TableModelNotifyGuard aGuard( this );
251 // remove the rows
252 remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
253 updateRows();
254 setModified(sal_True);
257 // -----------------------------------------------------------------------------
259 void TableModel::UndoRemoveRows( sal_Int32 nIndex, RowVector& aRows )
261 TableModelNotifyGuard aGuard( this );
263 const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aRows.size() );
265 nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
267 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
268 maRows[nIndex+nOffset] = aRows[nOffset];
270 updateRows();
271 setModified(sal_True);
274 // -----------------------------------------------------------------------------
276 void TableModel::UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount )
278 TableModelNotifyGuard aGuard( this );
280 // now remove the columns
281 remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
282 sal_Int32 nRows = getRowCountImpl();
283 while( nRows-- )
284 maRows[nRows]->removeColumns( nIndex, nCount );
286 updateColumns();
287 setModified(sal_True);
290 // -----------------------------------------------------------------------------
292 void TableModel::UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aCols, CellVector& aCells )
294 TableModelNotifyGuard aGuard( this );
296 const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aCols.size() );
298 // assert if there are not enough cells saved
299 DBG_ASSERT( (aCols.size() * maRows.size()) == aCells.size(), "sdr::table::TableModel::UndoRemoveColumns(), invalid undo data!" );
301 nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
302 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
303 maColumns[nIndex+nOffset] = aCols[nOffset];
305 CellVector::iterator aIter( aCells.begin() );
307 sal_Int32 nRows = getRowCountImpl();
308 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
309 maRows[nRow]->insertColumns( nIndex, nCount, &aIter );
311 updateColumns();
312 setModified(sal_True);
315 // -----------------------------------------------------------------------------
316 // XTable
317 // -----------------------------------------------------------------------------
319 Reference< XCellCursor > SAL_CALL TableModel::createCursor() throw (RuntimeException)
321 OGuard aGuard( Application::GetSolarMutex() );
322 return createCursorByRange( Reference< XCellRange >( this ) );
325 // -----------------------------------------------------------------------------
327 Reference< XCellCursor > SAL_CALL TableModel::createCursorByRange( const Reference< XCellRange >& Range ) throw (IllegalArgumentException, RuntimeException)
329 OGuard aGuard( Application::GetSolarMutex() );
331 ICellRange* pRange = dynamic_cast< ICellRange* >( Range.get() );
332 if( (pRange == 0) || (pRange->getTable().get() != this) )
333 throw IllegalArgumentException();
335 TableModelRef xModel( this );
336 return new CellCursor( xModel, pRange->getLeft(), pRange->getTop(), pRange->getRight(), pRange->getBottom() );
339 // -----------------------------------------------------------------------------
341 sal_Int32 SAL_CALL TableModel::getRowCount() throw (RuntimeException)
343 OGuard aGuard( Application::GetSolarMutex() );
344 return getRowCountImpl();
347 // -----------------------------------------------------------------------------
349 sal_Int32 SAL_CALL TableModel::getColumnCount() throw (RuntimeException)
351 OGuard aGuard( Application::GetSolarMutex() );
352 return getColumnCountImpl();
355 // -----------------------------------------------------------------------------
356 // XComponent
357 // -----------------------------------------------------------------------------
359 void TableModel::dispose() throw (RuntimeException)
361 OGuard aGuard( Application::GetSolarMutex() );
362 TableModelBase::dispose();
365 // -----------------------------------------------------------------------------
367 void SAL_CALL TableModel::addEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
369 TableModelBase::addEventListener( xListener );
372 // -----------------------------------------------------------------------------
374 void SAL_CALL TableModel::removeEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
376 TableModelBase::removeEventListener( xListener );
379 // -----------------------------------------------------------------------------
380 // XModifiable
381 // -----------------------------------------------------------------------------
383 sal_Bool SAL_CALL TableModel::isModified( ) throw (RuntimeException)
385 OGuard aGuard( Application::GetSolarMutex() );
386 return mbModified;
389 // -----------------------------------------------------------------------------
391 void SAL_CALL TableModel::setModified( sal_Bool bModified ) throw (PropertyVetoException, RuntimeException)
394 OGuard aGuard( Application::GetSolarMutex() );
395 mbModified = bModified;
397 if( bModified )
398 notifyModification();
401 // -----------------------------------------------------------------------------
402 // XModifyBroadcaster
403 // -----------------------------------------------------------------------------
405 void SAL_CALL TableModel::addModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException)
407 rBHelper.addListener( XModifyListener::static_type() , xListener );
410 // -----------------------------------------------------------------------------
412 void SAL_CALL TableModel::removeModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException)
414 rBHelper.removeListener( XModifyListener::static_type() , xListener );
417 // -----------------------------------------------------------------------------
418 // XColumnRowRange
419 // -----------------------------------------------------------------------------
421 Reference< XTableColumns > SAL_CALL TableModel::getColumns() throw (RuntimeException)
423 OGuard aGuard( Application::GetSolarMutex() );
425 if( !mxTableColumns.is() )
426 mxTableColumns.set( new TableColumns( this ) );
427 return mxTableColumns.get();
430 // -----------------------------------------------------------------------------
432 Reference< XTableRows > SAL_CALL TableModel::getRows() throw (RuntimeException)
434 OGuard aGuard( Application::GetSolarMutex() );
436 if( !mxTableRows.is() )
437 mxTableRows.set( new TableRows( this ) );
438 return mxTableRows.get();
441 // -----------------------------------------------------------------------------
442 // XCellRange
443 // -----------------------------------------------------------------------------
445 Reference< XCell > SAL_CALL TableModel::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw ( IndexOutOfBoundsException, RuntimeException)
447 OGuard aGuard( Application::GetSolarMutex() );
449 CellRef xCell( getCell( nColumn, nRow ) );
450 if( xCell.is() )
451 return xCell.get();
453 throw IndexOutOfBoundsException();
456 // -----------------------------------------------------------------------------
458 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException)
460 OGuard aGuard( Application::GetSolarMutex() );
462 if( (nLeft >= 0) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) && (nRight < getColumnCountImpl()) && (nBottom < getRowCountImpl() ) )
464 TableModelRef xModel( this );
465 return new CellRange( xModel, nLeft, nTop, nRight, nBottom );
468 throw IndexOutOfBoundsException();
471 // -----------------------------------------------------------------------------
473 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException)
475 return Reference< XCellRange >();
478 // -----------------------------------------------------------------------------
479 // XPropertySet
480 // -----------------------------------------------------------------------------
482 Reference< XPropertySetInfo > SAL_CALL TableModel::getPropertySetInfo( ) throw (RuntimeException)
484 Reference< XPropertySetInfo > xInfo;
485 return xInfo;
488 // -----------------------------------------------------------------------------
490 void SAL_CALL TableModel::setPropertyValue( const ::rtl::OUString& /*aPropertyName*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
494 // -----------------------------------------------------------------------------
496 Any SAL_CALL TableModel::getPropertyValue( const OUString& /*PropertyName*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
498 return Any();
501 // -----------------------------------------------------------------------------
503 void SAL_CALL TableModel::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
507 // -----------------------------------------------------------------------------
509 void SAL_CALL TableModel::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
513 // -----------------------------------------------------------------------------
515 void SAL_CALL TableModel::addVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
519 // -----------------------------------------------------------------------------
521 void SAL_CALL TableModel::removeVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
525 // -----------------------------------------------------------------------------
526 // XFastPropertySet
527 // -----------------------------------------------------------------------------
529 void SAL_CALL TableModel::setFastPropertyValue( ::sal_Int32 /*nHandle*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
533 // -----------------------------------------------------------------------------
535 Any SAL_CALL TableModel::getFastPropertyValue( ::sal_Int32 /*nHandle*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
537 Any aAny;
538 return aAny;
541 // -----------------------------------------------------------------------------
542 // internals
543 // -----------------------------------------------------------------------------
545 sal_Int32 TableModel::getRowCountImpl() const
547 return static_cast< sal_Int32 >( maRows.size() );
550 // -----------------------------------------------------------------------------
552 sal_Int32 TableModel::getColumnCountImpl() const
554 return static_cast< sal_Int32 >( maColumns.size() );
557 // -----------------------------------------------------------------------------
559 void TableModel::disposing()
561 if( !maRows.empty() )
563 RowVector::iterator aIter( maRows.begin() );
564 while( aIter != maRows.end() )
565 (*aIter++)->dispose();
566 RowVector().swap(maRows);
569 if( !maColumns.empty() )
571 ColumnVector::iterator aIter( maColumns.begin() );
572 while( aIter != maColumns.end() )
573 (*aIter++)->dispose();
574 ColumnVector().swap(maColumns);
577 if( mxTableColumns.is() )
579 mxTableColumns->dispose();
580 mxTableColumns.clear();
583 if( mxTableRows.is() )
585 mxTableRows->dispose();
586 mxTableRows.clear();
589 mpTableObj = 0;
592 // -----------------------------------------------------------------------------
593 // XBroadcaster
594 // -----------------------------------------------------------------------------
596 void TableModel::lockBroadcasts() throw (RuntimeException)
598 OGuard aGuard( Application::GetSolarMutex() );
599 ++mnNotifyLock;
601 // -----------------------------------------------------------------------------
603 void TableModel::unlockBroadcasts() throw (RuntimeException)
605 OGuard aGuard( Application::GetSolarMutex() );
606 --mnNotifyLock;
607 if( mnNotifyLock <= 0 )
609 mnNotifyLock = 0;
610 if( mbNotifyPending )
611 notifyModification();
615 // -----------------------------------------------------------------------------
616 #ifdef PLEASE_DEBUG_THE_TABLES
617 #include <stdio.h>
618 #endif
620 void TableModel::notifyModification()
622 ::osl::MutexGuard guard( m_aMutex );
623 if( (mnNotifyLock == 0) && mpTableObj && mpTableObj->GetModel() )
625 mbNotifyPending = false;
627 ::cppu::OInterfaceContainerHelper * pModifyListeners = rBHelper.getContainer( XModifyListener::static_type() );
628 if( pModifyListeners )
630 EventObject aSource;
631 aSource.Source = static_cast< ::cppu::OWeakObject* >(this);
632 pModifyListeners->notifyEach( &XModifyListener::modified, aSource);
635 else
637 mbNotifyPending = true;
640 #ifdef PLEASE_DEBUG_THE_TABLES
641 FILE* file = fopen( "c:\\table.xml","w" );
643 const sal_Int32 nColCount = getColumnCountImpl();
644 const sal_Int32 nRowCount = getRowCountImpl();
646 fprintf( file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\r" );
647 fprintf( file, "<table columns=\"%ld\" rows=\"%ld\" updated=\"%s\">\n\r", nColCount, nRowCount, mbNotifyPending ? "false" : "true");
649 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
651 fprintf( file, "<column this=\"%lx\"/>\n\r", maColumns[nCol].get() );
654 // first check merged cells before and inside the removed rows
655 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
657 fprintf( file, "<row this=\"%lx\">\n\r", maRows[nRow].get() );
658 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
660 CellRef xCell( getCell( nCol, nRow ) );
661 fprintf( file, "<cell this=\"%lx\"", xCell.get() );
663 sal_Int32 nRowSpan = xCell->getRowSpan();
664 sal_Int32 nColSpan = xCell->getColumnSpan();
665 sal_Bool bMerged = xCell->isMerged();
667 if( nColSpan != 1 )
668 fprintf( file, " column-span=\"%ld\"", nColSpan );
669 if( nRowSpan != 1 )
670 fprintf( file, " row-span=\"%ld\"", nRowSpan );
672 if( bMerged )
673 fprintf( file, " merged=\"true\"" );
675 fprintf( file, "/>" );
677 fprintf( file, "\n\r</row>\n\r" );
680 fprintf( file, "</table>\n\r" );
681 fclose( file );
682 #endif
685 // -----------------------------------------------------------------------------
687 CellRef TableModel::getCell( sal_Int32 nCol, sal_Int32 nRow ) const
689 if( ((nRow >= 0) && (nRow < getRowCountImpl())) && (nCol >= 0) && (nCol < getColumnCountImpl()) )
691 return maRows[nRow]->maCells[nCol];
693 else
695 CellRef xRet;
696 return xRet;
700 // -----------------------------------------------------------------------------
702 bool TableModel::getCellPos( const CellRef& xCell, ::sal_Int32& rnCol, ::sal_Int32& rnRow ) const
704 const sal_Int32 nRowCount = getRowCount();
705 const sal_Int32 nColCount = getColumnCount();
706 for( rnRow = 0; rnRow < nRowCount; rnRow++ )
708 for( rnCol = 0; rnCol < nColCount; rnCol++ )
710 if( maRows[rnRow]->maCells[rnCol] == xCell )
712 return true;
716 return false;
720 // -----------------------------------------------------------------------------
722 CellRef TableModel::createCell()
724 CellRef xCell;
725 if( mpTableObj )
726 mpTableObj->createCell( xCell );
727 return xCell;
730 // -----------------------------------------------------------------------------
732 void TableModel::insertColumns( sal_Int32 nIndex, sal_Int32 nCount )
734 if( nCount && mpTableObj )
738 SdrModel* pModel = mpTableObj->GetModel();
740 TableModelNotifyGuard aGuard( this );
741 nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
743 sal_Int32 nRows = getRowCountImpl();
744 while( nRows-- )
745 maRows[nRows]->insertColumns( nIndex, nCount );
747 ColumnVector aNewColumns(nCount);
748 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
750 TableColumnRef xNewCol( new TableColumn( this, nIndex+nOffset ) );
751 maColumns[nIndex+nOffset] = xNewCol;
752 aNewColumns[nOffset] = xNewCol;
755 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
756 if( bUndo )
758 pModel->BegUndo( ImpGetResStr(STR_TABLE_INSCOL) );
759 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
761 TableModelRef xThis( this );
763 nRows = getRowCountImpl();
764 CellVector aNewCells( nCount * nRows );
765 CellVector::iterator aCellIter( aNewCells.begin() );
767 nRows = getRowCountImpl();
768 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
770 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
771 (*aCellIter++) = getCell( nIndex + nOffset, nRow );
774 pModel->AddUndo( new InsertColUndo( xThis, nIndex, aNewColumns, aNewCells ) );
777 const sal_Int32 nRowCount = getRowCountImpl();
778 // check if cells merge over new columns
779 for( sal_Int32 nCol = 0; nCol < nIndex; ++nCol )
781 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
783 CellRef xCell( getCell( nCol, nRow ) );
784 sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
785 if( (nColSpan != 1) && ((nColSpan + nCol ) > nIndex) )
787 // cell merges over newly created columns, so add the new columns to the merged cell
788 const sal_Int32 nRowSpan = xCell->getRowSpan();
789 nColSpan += nCount;
790 merge( nCol, nRow, nColSpan, nRowSpan );
795 if( bUndo )
796 pModel->EndUndo();
798 if( pModel )
799 pModel->SetChanged();
802 catch( Exception& )
804 DBG_ERROR("sdr::table::TableModel::insertColumns(), exception caught!");
806 updateColumns();
807 setModified(sal_True);
811 // -----------------------------------------------------------------------------
813 void TableModel::removeColumns( sal_Int32 nIndex, sal_Int32 nCount )
815 sal_Int32 nColCount = getColumnCountImpl();
817 if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nColCount) )
821 TableModelNotifyGuard aGuard( this );
823 // clip removed columns to columns actually avalaible
824 if( (nIndex + nCount) > nColCount )
825 nCount = nColCount - nIndex;
827 sal_Int32 nRows = getRowCountImpl();
829 SdrModel* pModel = mpTableObj->GetModel();
831 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
832 if( bUndo )
834 pModel->BegUndo( ImpGetResStr(STR_UNDO_COL_DELETE) );
835 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
837 TableModelRef xThis( this );
838 ColumnVector aRemovedCols( nCount );
839 sal_Int32 nOffset;
840 for( nOffset = 0; nOffset < nCount; ++nOffset )
842 aRemovedCols[nOffset] = maColumns[nIndex+nOffset];
845 CellVector aRemovedCells( nCount * nRows );
846 CellVector::iterator aCellIter( aRemovedCells.begin() );
847 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
849 for( nOffset = 0; nOffset < nCount; ++nOffset )
850 (*aCellIter++) = getCell( nIndex + nOffset, nRow );
853 pModel->AddUndo( new RemoveColUndo( xThis, nIndex, aRemovedCols, aRemovedCells ) );
856 // only rows before and inside the removed rows are considered
857 nColCount = nIndex + nCount + 1;
859 const sal_Int32 nRowCount = getRowCountImpl();
861 // first check merged cells before and inside the removed rows
862 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
864 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
866 CellRef xCell( getCell( nCol, nRow ) );
867 sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
868 if( nColSpan <= 1 )
869 continue;
871 if( nCol >= nIndex )
873 // current cell is inside the removed columns
874 if( (nCol + nColSpan) > ( nIndex + nCount ) )
876 // current cells merges with columns after the removed columns
877 const sal_Int32 nRemove = nCount - nCol + nIndex;
879 CellRef xTargetCell( getCell( nIndex + nCount, nRow ) );
880 if( xTargetCell.is() )
882 if( bUndo )
883 xTargetCell->AddUndo();
884 xTargetCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
885 xTargetCell->replaceContentAndFormating( xCell );
889 else if( nColSpan > (nIndex - nCol) )
891 // current cells spans inside the removed columns, so adjust
892 const sal_Int32 nRemove = ::std::min( nCount, nCol + nColSpan - nIndex );
893 if( bUndo )
894 xCell->AddUndo();
895 xCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
900 // now remove the columns
901 remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
902 while( nRows-- )
903 maRows[nRows]->removeColumns( nIndex, nCount );
905 if( bUndo )
906 pModel->EndUndo();
908 if( pModel )
909 pModel->SetChanged();
911 catch( Exception& )
913 DBG_ERROR("sdr::table::TableModel::removeColumns(), exception caught!");
916 updateColumns();
917 setModified(sal_True);
921 // -----------------------------------------------------------------------------
923 void TableModel::insertRows( sal_Int32 nIndex, sal_Int32 nCount )
925 if( nCount && mpTableObj )
927 SdrModel* pModel = mpTableObj->GetModel();
928 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
931 TableModelNotifyGuard aGuard( this );
933 nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
935 RowVector aNewRows(nCount);
936 const sal_Int32 nColCount = getColumnCountImpl();
937 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
939 TableRowRef xNewRow( new TableRow( this, nIndex+nOffset, nColCount ) );
940 maRows[nIndex+nOffset] = xNewRow;
941 aNewRows[nOffset] = xNewRow;
944 if( bUndo )
946 pModel->BegUndo( ImpGetResStr(STR_TABLE_INSROW) );
947 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
948 TableModelRef xThis( this );
949 pModel->AddUndo( new InsertRowUndo( xThis, nIndex, aNewRows ) );
952 // check if cells merge over new columns
953 for( sal_Int32 nRow = 0; nRow < nIndex; ++nRow )
955 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
957 CellRef xCell( getCell( nCol, nRow ) );
958 sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
959 if( (nRowSpan > 1) && ((nRowSpan + nRow) > nIndex) )
961 // cell merges over newly created columns, so add the new columns to the merged cell
962 const sal_Int32 nColSpan = xCell->getColumnSpan();
963 nRowSpan += nCount;
964 merge( nCol, nRow, nColSpan, nRowSpan );
969 catch( Exception& )
971 DBG_ERROR("sdr::table::TableModel::insertRows(), exception caught!");
973 if( bUndo )
974 pModel->EndUndo();
976 if( pModel )
977 pModel->SetChanged();
979 updateRows();
980 setModified(sal_True);
984 // -----------------------------------------------------------------------------
986 void TableModel::removeRows( sal_Int32 nIndex, sal_Int32 nCount )
988 sal_Int32 nRowCount = getRowCountImpl();
990 if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nRowCount) )
992 SdrModel* pModel = mpTableObj->GetModel();
993 const bool bUndo = pModel && mpTableObj->IsInserted()&& pModel->IsUndoEnabled();
997 TableModelNotifyGuard aGuard( this );
999 // clip removed rows to rows actually avalaible
1000 if( (nIndex + nCount) > nRowCount )
1001 nCount = nRowCount - nIndex;
1003 if( bUndo )
1005 pModel->BegUndo( ImpGetResStr(STR_UNDO_ROW_DELETE) );
1006 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
1008 TableModelRef xThis( this );
1010 RowVector aRemovedRows( nCount );
1011 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
1012 aRemovedRows[nOffset] = maRows[nIndex+nOffset];
1014 pModel->AddUndo( new RemoveRowUndo( xThis, nIndex, aRemovedRows ) );
1017 // only rows before and inside the removed rows are considered
1018 nRowCount = nIndex + nCount + 1;
1020 const sal_Int32 nColCount = getColumnCountImpl();
1022 // first check merged cells before and inside the removed rows
1023 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
1025 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
1027 CellRef xCell( getCell( nCol, nRow ) );
1028 sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
1029 if( nRowSpan <= 1 )
1030 continue;
1032 if( nRow >= nIndex )
1034 // current cell is inside the removed rows
1035 if( (nRow + nRowSpan) > (nIndex + nCount) )
1037 // current cells merges with rows after the removed rows
1038 const sal_Int32 nRemove = nCount - nRow + nIndex;
1040 CellRef xTargetCell( getCell( nCol, nIndex + nCount ) );
1041 if( xTargetCell.is() )
1043 if( bUndo )
1044 xTargetCell->AddUndo();
1045 xTargetCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
1046 xTargetCell->replaceContentAndFormating( xCell );
1050 else if( nRowSpan > (nIndex - nRow) )
1052 // current cells spans inside the removed rows, so adjust
1053 const sal_Int32 nRemove = ::std::min( nCount, nRow + nRowSpan - nIndex );
1054 if( bUndo )
1055 xCell->AddUndo();
1056 xCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
1061 // now remove the rows
1062 remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
1064 if( bUndo )
1065 pModel->EndUndo();
1067 if( pModel )
1068 pModel->SetChanged();
1070 catch( Exception& )
1072 DBG_ERROR("sdr::table::TableModel::removeRows(), exception caught!");
1075 updateRows();
1076 setModified(sal_True);
1080 // -----------------------------------------------------------------------------
1082 TableRowRef TableModel::getRow( sal_Int32 nRow ) const throw (IndexOutOfBoundsException)
1084 if( (nRow >= 0) && (nRow < getRowCountImpl()) )
1085 return maRows[nRow];
1087 throw IndexOutOfBoundsException();
1090 // -----------------------------------------------------------------------------
1092 TableColumnRef TableModel::getColumn( sal_Int32 nColumn ) const throw (IndexOutOfBoundsException)
1094 if( (nColumn >= 0) && (nColumn < getColumnCountImpl()) )
1095 return maColumns[nColumn];
1097 throw IndexOutOfBoundsException();
1100 // -----------------------------------------------------------------------------
1102 /** deletes rows and columns that are completly merged. Must be called between BegUndo/EndUndo! */
1103 void TableModel::optimize()
1105 TableModelNotifyGuard aGuard( this );
1107 bool bWasModified = false;
1109 if( !maRows.empty() && !maColumns.empty() )
1111 sal_Int32 nCol = getColumnCountImpl() - 1;
1112 while( nCol > 0 )
1114 bool bEmpty = true;
1115 for( sal_Int32 nRow = 0; (nRow < getRowCountImpl()) && bEmpty; nRow++ )
1117 Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
1118 if( xCell.is() && !xCell->isMerged() )
1119 bEmpty = false;
1122 if( bEmpty )
1124 if( nCol > 0 ) try
1126 const OUString sWidth( RTL_CONSTASCII_USTRINGPARAM("Width") );
1127 sal_Int32 nWidth1 = 0, nWidth2 = 0;
1128 Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maColumns[nCol].get() ), UNO_QUERY_THROW );
1129 Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maColumns[nCol-1].get() ), UNO_QUERY_THROW );
1130 xSet1->getPropertyValue( sWidth ) >>= nWidth1;
1131 xSet2->getPropertyValue( sWidth ) >>= nWidth2;
1132 nWidth1 += nWidth2;
1133 xSet2->setPropertyValue( sWidth, Any( nWidth1 ) );
1135 catch( Exception& e )
1137 (void)e;
1138 DBG_ERROR("svx::TableModel::optimize(), exception caught!");
1141 removeColumns( nCol, 1 );
1142 bWasModified = true;
1145 nCol--;
1148 sal_Int32 nRow = getRowCountImpl() - 1;
1149 while( nRow > 0 )
1151 bool bEmpty = true;
1152 for( nCol = 0; (nCol < getColumnCountImpl()) && bEmpty; nCol++ )
1154 Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
1155 if( xCell.is() && !xCell->isMerged() )
1156 bEmpty = false;
1159 if( bEmpty )
1161 if( nRow > 0 ) try
1163 const OUString sHeight( RTL_CONSTASCII_USTRINGPARAM("Height") );
1164 sal_Int32 nHeight1 = 0, nHeight2 = 0;
1165 Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maRows[nRow].get() ), UNO_QUERY_THROW );
1166 Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maRows[nRow-1].get() ), UNO_QUERY_THROW );
1167 xSet1->getPropertyValue( sHeight ) >>= nHeight1;
1168 xSet2->getPropertyValue( sHeight ) >>= nHeight2;
1169 nHeight1 += nHeight2;
1170 xSet2->setPropertyValue( sHeight, Any( nHeight1 ) );
1172 catch( Exception& e )
1174 (void)e;
1175 DBG_ERROR("svx::TableModel::optimize(), exception caught!");
1178 removeRows( nRow, 1 );
1179 bWasModified = true;
1182 nRow--;
1185 if( bWasModified )
1186 setModified(sal_True);
1189 // -----------------------------------------------------------------------------
1191 void TableModel::merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan )
1193 SdrModel* pModel = mpTableObj->GetModel();
1195 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
1197 const sal_Int32 nLastRow = nRow + nRowSpan;
1198 const sal_Int32 nLastCol = nCol + nColSpan;
1200 if( (nLastRow > getRowCount()) || (nLastCol > getRowCount() ) )
1202 DBG_ERROR("TableModel::merge(), merge beyound the table!");
1205 // merge first cell
1206 CellRef xOriginCell( dynamic_cast< Cell* >( getCellByPosition( nCol, nRow ).get() ) );
1207 if( xOriginCell.is() )
1209 if( bUndo )
1210 xOriginCell->AddUndo();
1211 xOriginCell->merge( nColSpan, nRowSpan );
1214 sal_Int32 nTempCol = nCol + 1;
1216 // merge remaining cells
1217 for( ; nRow < nLastRow; nRow++ )
1219 for( ; nTempCol < nLastCol; nTempCol++ )
1221 CellRef xCell( dynamic_cast< Cell* >( getCellByPosition( nTempCol, nRow ).get() ) );
1222 if( xCell.is() && !xCell->isMerged() )
1224 if( bUndo )
1225 xCell->AddUndo();
1226 xCell->setMerged();
1227 xOriginCell->mergeContent( xCell );
1230 nTempCol = nCol;
1235 // -----------------------------------------------------------------------------
1237 void TableModel::updateRows()
1239 sal_Int32 nRow = 0;
1240 RowVector::iterator iter = maRows.begin();
1241 while( iter != maRows.end() )
1243 (*iter++)->mnRow = nRow++;
1247 // -----------------------------------------------------------------------------
1249 void TableModel::updateColumns()
1251 sal_Int32 nColumn = 0;
1252 ColumnVector::iterator iter = maColumns.begin();
1253 while( iter != maColumns.end() )
1255 (*iter++)->mnColumn = nColumn++;
1259 // -----------------------------------------------------------------------------