Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / svx / source / table / tablemodel.cxx
blobd40c3ba99f6d7ae889e1ded52959c880f94a4c9b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/table/XMergeableCell.hpp>
23 #include <algorithm>
25 #include <vcl/svapp.hxx>
26 #include <osl/mutex.hxx>
28 #include "cell.hxx"
29 #include "cellcursor.hxx"
30 #include "tablemodel.hxx"
31 #include "tablerow.hxx"
32 #include "tablerows.hxx"
33 #include "tablecolumn.hxx"
34 #include "tablecolumns.hxx"
35 #include "tableundo.hxx"
36 #include "svx/svdotable.hxx"
37 #include "svx/svdmodel.hxx"
38 #include "svx/svdstr.hrc"
39 #include "svdglob.hxx"
41 using namespace ::osl;
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::table;
44 using namespace ::com::sun::star::lang;
45 using namespace ::com::sun::star::container;
46 using namespace ::com::sun::star::beans;
47 using namespace ::com::sun::star::util;
51 namespace sdr { namespace table {
55 // removes the given range from a vector
56 template< class Vec, class Iter > void remove_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
58 const sal_Int32 nSize = static_cast<sal_Int32>(rVector.size());
59 if( nCount && (nIndex >= 0) && (nIndex < nSize) )
61 if( (nIndex + nCount) >= nSize )
63 // remove at end
64 rVector.resize( nIndex );
66 else
68 Iter aBegin( rVector.begin() );
69 while( nIndex-- )
70 aBegin++;
71 if( nCount == 1 )
73 rVector.erase( aBegin );
75 else
77 Iter aEnd( aBegin );
79 while( nCount-- )
80 aEnd++;
81 rVector.erase( aBegin, aEnd );
89 /** inserts a range into a vector */
90 template< class Vec, class Iter, class Entry > sal_Int32 insert_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
92 if( nCount )
94 if( nIndex >= static_cast< sal_Int32 >( rVector.size() ) )
96 // append at end
97 nIndex = static_cast< sal_Int32 >( rVector.size() ); // cap to end
98 rVector.resize( nIndex + nCount );
100 else
102 // insert
103 sal_Int32 nFind = nIndex;
104 Iter aIter( rVector.begin() );
105 while( nFind-- )
106 ++aIter;
108 Entry aEmpty;
109 rVector.insert( aIter, nCount, aEmpty );
112 return nIndex;
117 TableModel::TableModel( SdrTableObj* pTableObj )
118 : TableModelBase( m_aMutex )
119 , mpTableObj( pTableObj )
120 , mbModified( false )
121 , mbNotifyPending( false )
122 , mnNotifyLock( 0 )
126 TableModel::TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable )
127 : TableModelBase( m_aMutex )
128 , mpTableObj( pTableObj )
129 , mbModified( false )
130 , mbNotifyPending( false )
131 , mnNotifyLock( 0 )
133 if( xSourceTable.is() )
135 const sal_Int32 nColCount = xSourceTable->getColumnCountImpl();
136 const sal_Int32 nRowCount = xSourceTable->getRowCountImpl();
138 init( nColCount, nRowCount );
140 sal_Int32 nRows = nRowCount;
141 while( nRows-- )
142 (*maRows[nRows]) = (*xSourceTable->maRows[nRows]);
144 sal_Int32 nColumns = nColCount;
145 while( nColumns-- )
146 (*maColumns[nColumns]) = (*xSourceTable->maColumns[nColumns]);
148 // copy cells
149 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
151 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
153 CellRef xTargetCell( getCell( nCol, nRow ) );
154 if( xTargetCell.is() )
155 xTargetCell->cloneFrom( xSourceTable->getCell( nCol, nRow ) );
163 TableModel::~TableModel()
169 void TableModel::init( sal_Int32 nColumns, sal_Int32 nRows )
171 if( nRows < 20 )
172 maRows.reserve( 20 );
174 if( nColumns < 20 )
175 maColumns.reserve( 20 );
177 if( nRows && nColumns )
179 maColumns.resize( nColumns );
180 maRows.resize( nRows );
182 while( nRows-- )
183 maRows[nRows].set( new TableRow( this, nRows, nColumns ) );
185 while( nColumns-- )
186 maColumns[nColumns].set( new TableColumn( this, nColumns ) );
191 // ICellRange
194 sal_Int32 TableModel::getLeft()
196 return 0;
201 sal_Int32 TableModel::getTop()
203 return 0;
208 sal_Int32 TableModel::getRight()
210 return getColumnCount();
215 sal_Int32 TableModel::getBottom()
217 return getRowCount();
222 Reference< XTable > TableModel::getTable()
224 return this;
229 void TableModel::UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount )
231 TableModelNotifyGuard aGuard( this );
233 // remove the rows
234 remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
235 updateRows();
236 setModified(sal_True);
241 void TableModel::UndoRemoveRows( sal_Int32 nIndex, RowVector& aRows )
243 TableModelNotifyGuard aGuard( this );
245 const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aRows.size() );
247 nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
249 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
250 maRows[nIndex+nOffset] = aRows[nOffset];
252 updateRows();
253 setModified(sal_True);
258 void TableModel::UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount )
260 TableModelNotifyGuard aGuard( this );
262 // now remove the columns
263 remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
264 sal_Int32 nRows = getRowCountImpl();
265 while( nRows-- )
266 maRows[nRows]->removeColumns( nIndex, nCount );
268 updateColumns();
269 setModified(sal_True);
274 void TableModel::UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aCols, CellVector& aCells )
276 TableModelNotifyGuard aGuard( this );
278 const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aCols.size() );
280 // assert if there are not enough cells saved
281 DBG_ASSERT( (aCols.size() * maRows.size()) == aCells.size(), "sdr::table::TableModel::UndoRemoveColumns(), invalid undo data!" );
283 nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
284 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
285 maColumns[nIndex+nOffset] = aCols[nOffset];
287 CellVector::iterator aIter( aCells.begin() );
289 sal_Int32 nRows = getRowCountImpl();
290 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
292 CellVector::iterator aIter2 = aIter + nRow * nCount;
293 OSL_ENSURE(aIter2 < aCells.end(), "invalid iterator!");
294 maRows[nRow]->insertColumns( nIndex, nCount, &aIter2 );
297 updateColumns();
298 setModified(sal_True);
302 // XTable
305 Reference< XCellCursor > SAL_CALL TableModel::createCursor() throw (RuntimeException, std::exception)
307 ::SolarMutexGuard aGuard;
308 return createCursorByRange( Reference< XCellRange >( this ) );
313 Reference< XCellCursor > SAL_CALL TableModel::createCursorByRange( const Reference< XCellRange >& rRange ) throw (IllegalArgumentException, RuntimeException, std::exception)
315 ::SolarMutexGuard aGuard;
317 ICellRange* pRange = dynamic_cast< ICellRange* >( rRange.get() );
318 if( (pRange == 0) || (pRange->getTable().get() != this) )
319 throw IllegalArgumentException();
321 TableModelRef xModel( this );
322 return new CellCursor( xModel, pRange->getLeft(), pRange->getTop(), pRange->getRight(), pRange->getBottom() );
327 sal_Int32 SAL_CALL TableModel::getRowCount() throw (RuntimeException, std::exception)
329 ::SolarMutexGuard aGuard;
330 return getRowCountImpl();
335 sal_Int32 SAL_CALL TableModel::getColumnCount() throw (RuntimeException, std::exception)
337 ::SolarMutexGuard aGuard;
338 return getColumnCountImpl();
342 // XComponent
345 void TableModel::dispose() throw (RuntimeException, std::exception)
347 ::SolarMutexGuard aGuard;
348 TableModelBase::dispose();
353 void SAL_CALL TableModel::addEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException, std::exception)
355 TableModelBase::addEventListener( xListener );
360 void SAL_CALL TableModel::removeEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException, std::exception)
362 TableModelBase::removeEventListener( xListener );
366 // XModifiable
369 sal_Bool SAL_CALL TableModel::isModified( ) throw (RuntimeException, std::exception)
371 ::SolarMutexGuard aGuard;
372 return mbModified;
377 void SAL_CALL TableModel::setModified( sal_Bool bModified ) throw (PropertyVetoException, RuntimeException, std::exception)
380 ::SolarMutexGuard aGuard;
381 mbModified = bModified;
383 if( bModified )
384 notifyModification();
388 // XModifyBroadcaster
391 void SAL_CALL TableModel::addModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException, std::exception)
393 rBHelper.addListener( cppu::UnoType<XModifyListener>::get() , xListener );
398 void SAL_CALL TableModel::removeModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException, std::exception)
400 rBHelper.removeListener( cppu::UnoType<XModifyListener>::get() , xListener );
404 // XColumnRowRange
407 Reference< XTableColumns > SAL_CALL TableModel::getColumns() throw (RuntimeException, std::exception)
409 ::SolarMutexGuard aGuard;
411 if( !mxTableColumns.is() )
412 mxTableColumns.set( new TableColumns( this ) );
413 return mxTableColumns.get();
418 Reference< XTableRows > SAL_CALL TableModel::getRows() throw (RuntimeException, std::exception)
420 ::SolarMutexGuard aGuard;
422 if( !mxTableRows.is() )
423 mxTableRows.set( new TableRows( this ) );
424 return mxTableRows.get();
428 // XCellRange
431 Reference< XCell > SAL_CALL TableModel::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw ( IndexOutOfBoundsException, RuntimeException, std::exception)
433 ::SolarMutexGuard aGuard;
435 CellRef xCell( getCell( nColumn, nRow ) );
436 if( xCell.is() )
437 return xCell.get();
439 throw IndexOutOfBoundsException();
444 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
446 ::SolarMutexGuard aGuard;
448 if( (nLeft >= 0) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) && (nRight < getColumnCountImpl()) && (nBottom < getRowCountImpl() ) )
450 TableModelRef xModel( this );
451 return new CellRange( xModel, nLeft, nTop, nRight, nBottom );
454 throw IndexOutOfBoundsException();
459 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException, std::exception)
461 return Reference< XCellRange >();
465 // XPropertySet
468 Reference< XPropertySetInfo > SAL_CALL TableModel::getPropertySetInfo( ) throw (RuntimeException, std::exception)
470 Reference< XPropertySetInfo > xInfo;
471 return xInfo;
476 void SAL_CALL TableModel::setPropertyValue( const OUString& /*aPropertyName*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception)
482 Any SAL_CALL TableModel::getPropertyValue( const OUString& /*PropertyName*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
484 return Any();
489 void SAL_CALL TableModel::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
495 void SAL_CALL TableModel::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
501 void SAL_CALL TableModel::addVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
507 void SAL_CALL TableModel::removeVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
512 // XFastPropertySet
515 void SAL_CALL TableModel::setFastPropertyValue( ::sal_Int32 /*nHandle*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception)
521 Any SAL_CALL TableModel::getFastPropertyValue( ::sal_Int32 /*nHandle*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
523 Any aAny;
524 return aAny;
528 // internals
531 sal_Int32 TableModel::getRowCountImpl() const
533 return static_cast< sal_Int32 >( maRows.size() );
538 sal_Int32 TableModel::getColumnCountImpl() const
540 return static_cast< sal_Int32 >( maColumns.size() );
545 void TableModel::disposing()
547 if( !maRows.empty() )
549 RowVector::iterator aIter( maRows.begin() );
550 while( aIter != maRows.end() )
551 (*aIter++)->dispose();
552 RowVector().swap(maRows);
555 if( !maColumns.empty() )
557 ColumnVector::iterator aIter( maColumns.begin() );
558 while( aIter != maColumns.end() )
559 (*aIter++)->dispose();
560 ColumnVector().swap(maColumns);
563 if( mxTableColumns.is() )
565 mxTableColumns->dispose();
566 mxTableColumns.clear();
569 if( mxTableRows.is() )
571 mxTableRows->dispose();
572 mxTableRows.clear();
575 mpTableObj = 0;
579 // XBroadcaster
582 void TableModel::lockBroadcasts() throw (RuntimeException, std::exception)
584 ::SolarMutexGuard aGuard;
585 ++mnNotifyLock;
589 void TableModel::unlockBroadcasts() throw (RuntimeException, std::exception)
591 ::SolarMutexGuard aGuard;
592 --mnNotifyLock;
593 if( mnNotifyLock <= 0 )
595 mnNotifyLock = 0;
596 if( mbNotifyPending )
597 notifyModification();
602 void TableModel::notifyModification()
604 ::osl::MutexGuard guard( m_aMutex );
605 if( (mnNotifyLock == 0) && mpTableObj && mpTableObj->GetModel() )
607 mbNotifyPending = false;
609 ::cppu::OInterfaceContainerHelper * pModifyListeners = rBHelper.getContainer( cppu::UnoType<XModifyListener>::get() );
610 if( pModifyListeners )
612 EventObject aSource;
613 aSource.Source = static_cast< ::cppu::OWeakObject* >(this);
614 pModifyListeners->notifyEach( &XModifyListener::modified, aSource);
617 else
619 mbNotifyPending = true;
625 CellRef TableModel::getCell( sal_Int32 nCol, sal_Int32 nRow ) const
627 if( ((nRow >= 0) && (nRow < getRowCountImpl())) && (nCol >= 0) && (nCol < getColumnCountImpl()) )
629 return maRows[nRow]->maCells[nCol];
631 else
633 CellRef xRet;
634 return xRet;
640 CellRef TableModel::createCell()
642 CellRef xCell;
643 if( mpTableObj )
644 mpTableObj->createCell( xCell );
645 return xCell;
650 void TableModel::insertColumns( sal_Int32 nIndex, sal_Int32 nCount )
652 if( nCount && mpTableObj )
656 SdrModel* pModel = mpTableObj->GetModel();
658 TableModelNotifyGuard aGuard( this );
659 nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
661 sal_Int32 nRows = getRowCountImpl();
662 while( nRows-- )
663 maRows[nRows]->insertColumns( nIndex, nCount );
665 ColumnVector aNewColumns(nCount);
666 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
668 TableColumnRef xNewCol( new TableColumn( this, nIndex+nOffset ) );
669 maColumns[nIndex+nOffset] = xNewCol;
670 aNewColumns[nOffset] = xNewCol;
673 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
674 if( bUndo )
676 pModel->BegUndo( ImpGetResStr(STR_TABLE_INSCOL) );
677 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
679 TableModelRef xThis( this );
681 nRows = getRowCountImpl();
682 CellVector aNewCells( nCount * nRows );
683 CellVector::iterator aCellIter( aNewCells.begin() );
685 nRows = getRowCountImpl();
686 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
688 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
689 (*aCellIter++) = getCell( nIndex + nOffset, nRow );
692 pModel->AddUndo( new InsertColUndo( xThis, nIndex, aNewColumns, aNewCells ) );
695 const sal_Int32 nRowCount = getRowCountImpl();
696 // check if cells merge over new columns
697 for( sal_Int32 nCol = 0; nCol < nIndex; ++nCol )
699 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
701 CellRef xCell( getCell( nCol, nRow ) );
702 sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
703 if( (nColSpan != 1) && ((nColSpan + nCol ) > nIndex) )
705 // cell merges over newly created columns, so add the new columns to the merged cell
706 const sal_Int32 nRowSpan = xCell->getRowSpan();
707 nColSpan += nCount;
708 merge( nCol, nRow, nColSpan, nRowSpan );
713 if( bUndo )
714 pModel->EndUndo();
716 if( pModel )
717 pModel->SetChanged();
720 catch( Exception& )
722 OSL_FAIL("sdr::table::TableModel::insertColumns(), exception caught!");
724 updateColumns();
725 setModified(sal_True);
731 void TableModel::removeColumns( sal_Int32 nIndex, sal_Int32 nCount )
733 sal_Int32 nColCount = getColumnCountImpl();
735 if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nColCount) )
739 TableModelNotifyGuard aGuard( this );
741 // clip removed columns to columns actually avalaible
742 if( (nIndex + nCount) > nColCount )
743 nCount = nColCount - nIndex;
745 sal_Int32 nRows = getRowCountImpl();
747 SdrModel* pModel = mpTableObj->GetModel();
749 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
750 if( bUndo )
752 pModel->BegUndo( ImpGetResStr(STR_UNDO_COL_DELETE) );
753 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
755 TableModelRef xThis( this );
756 ColumnVector aRemovedCols( nCount );
757 sal_Int32 nOffset;
758 for( nOffset = 0; nOffset < nCount; ++nOffset )
760 aRemovedCols[nOffset] = maColumns[nIndex+nOffset];
763 CellVector aRemovedCells( nCount * nRows );
764 CellVector::iterator aCellIter( aRemovedCells.begin() );
765 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
767 for( nOffset = 0; nOffset < nCount; ++nOffset )
768 (*aCellIter++) = getCell( nIndex + nOffset, nRow );
771 pModel->AddUndo( new RemoveColUndo( xThis, nIndex, aRemovedCols, aRemovedCells ) );
774 // only rows before and inside the removed rows are considered
775 nColCount = nIndex + nCount + 1;
777 const sal_Int32 nRowCount = getRowCountImpl();
779 // first check merged cells before and inside the removed rows
780 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
782 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
784 CellRef xCell( getCell( nCol, nRow ) );
785 sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
786 if( nColSpan <= 1 )
787 continue;
789 if( nCol >= nIndex )
791 // current cell is inside the removed columns
792 if( (nCol + nColSpan) > ( nIndex + nCount ) )
794 // current cells merges with columns after the removed columns
795 const sal_Int32 nRemove = nCount - nCol + nIndex;
797 CellRef xTargetCell( getCell( nIndex + nCount, nRow ) );
798 if( xTargetCell.is() )
800 if( bUndo )
801 xTargetCell->AddUndo();
802 xTargetCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
803 xTargetCell->replaceContentAndFormating( xCell );
807 else if( nColSpan > (nIndex - nCol) )
809 // current cells spans inside the removed columns, so adjust
810 const sal_Int32 nRemove = ::std::min( nCount, nCol + nColSpan - nIndex );
811 if( bUndo )
812 xCell->AddUndo();
813 xCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
818 // now remove the columns
819 remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
820 while( nRows-- )
821 maRows[nRows]->removeColumns( nIndex, nCount );
823 if( bUndo )
824 pModel->EndUndo();
826 if( pModel )
827 pModel->SetChanged();
829 catch( Exception& )
831 OSL_FAIL("sdr::table::TableModel::removeColumns(), exception caught!");
834 updateColumns();
835 setModified(sal_True);
841 void TableModel::insertRows( sal_Int32 nIndex, sal_Int32 nCount )
843 if( nCount && mpTableObj )
845 SdrModel* pModel = mpTableObj->GetModel();
846 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
849 TableModelNotifyGuard aGuard( this );
851 nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
853 RowVector aNewRows(nCount);
854 const sal_Int32 nColCount = getColumnCountImpl();
855 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
857 TableRowRef xNewRow( new TableRow( this, nIndex+nOffset, nColCount ) );
858 maRows[nIndex+nOffset] = xNewRow;
859 aNewRows[nOffset] = xNewRow;
862 if( bUndo )
864 pModel->BegUndo( ImpGetResStr(STR_TABLE_INSROW) );
865 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
866 TableModelRef xThis( this );
867 pModel->AddUndo( new InsertRowUndo( xThis, nIndex, aNewRows ) );
870 // check if cells merge over new columns
871 for( sal_Int32 nRow = 0; nRow < nIndex; ++nRow )
873 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
875 CellRef xCell( getCell( nCol, nRow ) );
876 sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
877 if( (nRowSpan > 1) && ((nRowSpan + nRow) > nIndex) )
879 // cell merges over newly created columns, so add the new columns to the merged cell
880 const sal_Int32 nColSpan = xCell->getColumnSpan();
881 nRowSpan += nCount;
882 merge( nCol, nRow, nColSpan, nRowSpan );
887 catch( Exception& )
889 OSL_FAIL("sdr::table::TableModel::insertRows(), exception caught!");
891 if( bUndo )
892 pModel->EndUndo();
894 if( pModel )
895 pModel->SetChanged();
897 updateRows();
898 setModified(sal_True);
904 void TableModel::removeRows( sal_Int32 nIndex, sal_Int32 nCount )
906 sal_Int32 nRowCount = getRowCountImpl();
908 if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nRowCount) )
910 SdrModel* pModel = mpTableObj->GetModel();
911 const bool bUndo = pModel && mpTableObj->IsInserted()&& pModel->IsUndoEnabled();
915 TableModelNotifyGuard aGuard( this );
917 // clip removed rows to rows actually avalaible
918 if( (nIndex + nCount) > nRowCount )
919 nCount = nRowCount - nIndex;
921 if( bUndo )
923 pModel->BegUndo( ImpGetResStr(STR_UNDO_ROW_DELETE) );
924 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
926 TableModelRef xThis( this );
928 RowVector aRemovedRows( nCount );
929 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
930 aRemovedRows[nOffset] = maRows[nIndex+nOffset];
932 pModel->AddUndo( new RemoveRowUndo( xThis, nIndex, aRemovedRows ) );
935 // only rows before and inside the removed rows are considered
936 nRowCount = nIndex + nCount + 1;
938 const sal_Int32 nColCount = getColumnCountImpl();
940 // first check merged cells before and inside the removed rows
941 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
943 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
945 CellRef xCell( getCell( nCol, nRow ) );
946 sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
947 if( nRowSpan <= 1 )
948 continue;
950 if( nRow >= nIndex )
952 // current cell is inside the removed rows
953 if( (nRow + nRowSpan) > (nIndex + nCount) )
955 // current cells merges with rows after the removed rows
956 const sal_Int32 nRemove = nCount - nRow + nIndex;
958 CellRef xTargetCell( getCell( nCol, nIndex + nCount ) );
959 if( xTargetCell.is() )
961 if( bUndo )
962 xTargetCell->AddUndo();
963 xTargetCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
964 xTargetCell->replaceContentAndFormating( xCell );
968 else if( nRowSpan > (nIndex - nRow) )
970 // current cells spans inside the removed rows, so adjust
971 const sal_Int32 nRemove = ::std::min( nCount, nRow + nRowSpan - nIndex );
972 if( bUndo )
973 xCell->AddUndo();
974 xCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
979 // now remove the rows
980 remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
982 if( bUndo )
983 pModel->EndUndo();
985 if( pModel )
986 pModel->SetChanged();
988 catch( Exception& )
990 OSL_FAIL("sdr::table::TableModel::removeRows(), exception caught!");
993 updateRows();
994 setModified(sal_True);
1000 TableRowRef TableModel::getRow( sal_Int32 nRow ) const throw (IndexOutOfBoundsException)
1002 if( (nRow >= 0) && (nRow < getRowCountImpl()) )
1003 return maRows[nRow];
1005 throw IndexOutOfBoundsException();
1010 TableColumnRef TableModel::getColumn( sal_Int32 nColumn ) const throw (IndexOutOfBoundsException)
1012 if( (nColumn >= 0) && (nColumn < getColumnCountImpl()) )
1013 return maColumns[nColumn];
1015 throw IndexOutOfBoundsException();
1020 /** deletes rows and columns that are completely merged. Must be called between BegUndo/EndUndo! */
1021 void TableModel::optimize()
1023 TableModelNotifyGuard aGuard( this );
1025 bool bWasModified = false;
1027 if( !maRows.empty() && !maColumns.empty() )
1029 sal_Int32 nCol = getColumnCountImpl() - 1;
1030 sal_Int32 nRows = getRowCountImpl();
1031 while( nCol > 0 )
1033 bool bEmpty = true;
1034 for( sal_Int32 nRow = 0; (nRow < nRows) && bEmpty; nRow++ )
1036 Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
1037 if( xCell.is() && !xCell->isMerged() )
1038 bEmpty = false;
1041 if( bEmpty )
1043 if( nCol > 0 ) try
1045 const OUString sWidth("Width");
1046 sal_Int32 nWidth1 = 0, nWidth2 = 0;
1047 Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maColumns[nCol].get() ), UNO_QUERY_THROW );
1048 Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maColumns[nCol-1].get() ), UNO_QUERY_THROW );
1049 xSet1->getPropertyValue( sWidth ) >>= nWidth1;
1050 xSet2->getPropertyValue( sWidth ) >>= nWidth2;
1051 nWidth1 += nWidth2;
1052 xSet2->setPropertyValue( sWidth, Any( nWidth1 ) );
1054 catch( Exception& e )
1056 (void)e;
1057 OSL_FAIL("svx::TableModel::optimize(), exception caught!");
1060 removeColumns( nCol, 1 );
1061 bWasModified = true;
1064 nCol--;
1067 sal_Int32 nRow = getRowCountImpl() - 1;
1068 sal_Int32 nCols = getColumnCountImpl();
1069 while( nRow > 0 )
1071 bool bEmpty = true;
1072 for( nCol = 0; (nCol < nCols) && bEmpty; nCol++ )
1074 Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
1075 if( xCell.is() && !xCell->isMerged() )
1076 bEmpty = false;
1079 if( bEmpty )
1081 if( nRow > 0 ) try
1083 const OUString sHeight("Height");
1084 sal_Int32 nHeight1 = 0, nHeight2 = 0;
1085 Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maRows[nRow].get() ), UNO_QUERY_THROW );
1086 Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maRows[nRow-1].get() ), UNO_QUERY_THROW );
1087 xSet1->getPropertyValue( sHeight ) >>= nHeight1;
1088 xSet2->getPropertyValue( sHeight ) >>= nHeight2;
1089 nHeight1 += nHeight2;
1090 xSet2->setPropertyValue( sHeight, Any( nHeight1 ) );
1092 catch( Exception& e )
1094 (void)e;
1095 OSL_FAIL("svx::TableModel::optimize(), exception caught!");
1098 removeRows( nRow, 1 );
1099 bWasModified = true;
1102 nRow--;
1105 if( bWasModified )
1106 setModified(sal_True);
1111 void TableModel::merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan )
1113 SdrModel* pModel = mpTableObj->GetModel();
1115 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
1117 const sal_Int32 nLastRow = nRow + nRowSpan;
1118 const sal_Int32 nLastCol = nCol + nColSpan;
1120 if( (nLastRow > getRowCount()) || (nLastCol > getColumnCount() ) )
1122 OSL_FAIL("TableModel::merge(), merge beyound the table!");
1125 // merge first cell
1126 CellRef xOriginCell( dynamic_cast< Cell* >( getCellByPosition( nCol, nRow ).get() ) );
1127 if( xOriginCell.is() )
1129 if( bUndo )
1130 xOriginCell->AddUndo();
1131 xOriginCell->merge( nColSpan, nRowSpan );
1134 sal_Int32 nTempCol = nCol + 1;
1136 // merge remaining cells
1137 for( ; nRow < nLastRow; nRow++ )
1139 for( ; nTempCol < nLastCol; nTempCol++ )
1141 CellRef xCell( dynamic_cast< Cell* >( getCellByPosition( nTempCol, nRow ).get() ) );
1142 if( xCell.is() && !xCell->isMerged() )
1144 if( bUndo )
1145 xCell->AddUndo();
1146 xCell->setMerged();
1147 xOriginCell->mergeContent( xCell );
1150 nTempCol = nCol;
1157 void TableModel::updateRows()
1159 sal_Int32 nRow = 0;
1160 RowVector::iterator iter = maRows.begin();
1161 while( iter != maRows.end() )
1163 (*iter++)->mnRow = nRow++;
1169 void TableModel::updateColumns()
1171 sal_Int32 nColumn = 0;
1172 ColumnVector::iterator iter = maColumns.begin();
1173 while( iter != maColumns.end() )
1175 (*iter++)->mnColumn = nColumn++;
1183 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */