1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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>
37 #include <boost/bind.hpp>
39 #include <vcl/svapp.hxx>
40 #include <vos/mutex.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"
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
)
82 rVector
.resize( nIndex
);
86 Iter
aBegin( rVector
.begin() );
91 rVector
.erase( aBegin
);
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
)
112 if( nIndex
>= static_cast< sal_Int32
>( rVector
.size() ) )
115 nIndex
= static_cast< sal_Int32
>( rVector
.size() ); // cap to end
116 rVector
.resize( nIndex
+ nCount
);
121 sal_Int32 nFind
= nIndex
;
122 Iter
aIter( rVector
.begin() );
127 rVector
.insert( aIter
, nCount
, aEmpty
);
133 // -----------------------------------------------------------------------------
135 TableModel::TableModel( SdrTableObj
* pTableObj
)
136 : TableModelBase( m_aMutex
)
137 , mpTableObj( pTableObj
)
138 , mbModified( sal_False
)
139 , mbNotifyPending( false )
144 TableModel::TableModel( SdrTableObj
* pTableObj
, const TableModelRef
& xSourceTable
)
145 : TableModelBase( m_aMutex
)
146 , mpTableObj( pTableObj
)
147 , mbModified( sal_False
)
148 , mbNotifyPending( false )
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
;
160 (*maRows
[nRows
]) = (*xSourceTable
->maRows
[nRows
]);
162 sal_Int32 nColumns
= nColCount
;
164 (*maColumns
[nColumns
]) = (*xSourceTable
->maColumns
[nColumns
]);
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
)
190 maRows
.reserve( 20 );
193 maColumns
.reserve( 20 );
195 if( nRows
&& nColumns
)
197 maColumns
.resize( nColumns
);
198 maRows
.resize( nRows
);
201 maRows
[nRows
].set( new TableRow( this, nRows
, nColumns
) );
204 maColumns
[nColumns
].set( new TableColumn( this, nColumns
) );
208 // -----------------------------------------------------------------------------
210 // -----------------------------------------------------------------------------
212 sal_Int32
TableModel::getLeft()
217 // -----------------------------------------------------------------------------
219 sal_Int32
TableModel::getTop()
224 // -----------------------------------------------------------------------------
226 sal_Int32
TableModel::getRight()
228 return getColumnCount();
231 // -----------------------------------------------------------------------------
233 sal_Int32
TableModel::getBottom()
235 return getRowCount();
238 // -----------------------------------------------------------------------------
240 Reference
< XTable
> TableModel::getTable()
245 // -----------------------------------------------------------------------------
247 void TableModel::UndoInsertRows( sal_Int32 nIndex
, sal_Int32 nCount
)
249 TableModelNotifyGuard
aGuard( this );
252 remove_range
<RowVector
,RowVector::iterator
>( maRows
, nIndex
, nCount
);
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
];
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();
284 maRows
[nRows
]->removeColumns( nIndex
, nCount
);
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
);
312 setModified(sal_True
);
315 // -----------------------------------------------------------------------------
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 // -----------------------------------------------------------------------------
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 // -----------------------------------------------------------------------------
381 // -----------------------------------------------------------------------------
383 sal_Bool SAL_CALL
TableModel::isModified( ) throw (RuntimeException
)
385 OGuard
aGuard( Application::GetSolarMutex() );
389 // -----------------------------------------------------------------------------
391 void SAL_CALL
TableModel::setModified( sal_Bool bModified
) throw (PropertyVetoException
, RuntimeException
)
394 OGuard
aGuard( Application::GetSolarMutex() );
395 mbModified
= 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 // -----------------------------------------------------------------------------
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 // -----------------------------------------------------------------------------
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
) );
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 // -----------------------------------------------------------------------------
480 // -----------------------------------------------------------------------------
482 Reference
< XPropertySetInfo
> SAL_CALL
TableModel::getPropertySetInfo( ) throw (RuntimeException
)
484 Reference
< XPropertySetInfo
> 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
)
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 // -----------------------------------------------------------------------------
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
)
541 // -----------------------------------------------------------------------------
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();
592 // -----------------------------------------------------------------------------
594 // -----------------------------------------------------------------------------
596 void TableModel::lockBroadcasts() throw (RuntimeException
)
598 OGuard
aGuard( Application::GetSolarMutex() );
601 // -----------------------------------------------------------------------------
603 void TableModel::unlockBroadcasts() throw (RuntimeException
)
605 OGuard
aGuard( Application::GetSolarMutex() );
607 if( mnNotifyLock
<= 0 )
610 if( mbNotifyPending
)
611 notifyModification();
615 // -----------------------------------------------------------------------------
616 #ifdef PLEASE_DEBUG_THE_TABLES
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
)
631 aSource
.Source
= static_cast< ::cppu::OWeakObject
* >(this);
632 pModifyListeners
->notifyEach( &XModifyListener::modified
, aSource
);
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();
668 fprintf( file
, " column-span=\"%ld\"", nColSpan
);
670 fprintf( file
, " row-span=\"%ld\"", nRowSpan
);
673 fprintf( file
, " merged=\"true\"" );
675 fprintf( file
, "/>" );
677 fprintf( file
, "\n\r</row>\n\r" );
680 fprintf( file
, "</table>\n\r" );
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
];
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 )
720 // -----------------------------------------------------------------------------
722 CellRef
TableModel::createCell()
726 mpTableObj
->createCell( 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();
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();
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();
790 merge( nCol
, nRow
, nColSpan
, nRowSpan
);
799 pModel
->SetChanged();
804 DBG_ERROR("sdr::table::TableModel::insertColumns(), exception caught!");
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();
834 pModel
->BegUndo( ImpGetResStr(STR_UNDO_COL_DELETE
) );
835 pModel
->AddUndo( pModel
->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj
) );
837 TableModelRef
xThis( this );
838 ColumnVector
aRemovedCols( nCount
);
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;
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() )
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
);
895 xCell
->merge( nColSpan
- nRemove
, xCell
->getRowSpan() );
900 // now remove the columns
901 remove_range
<ColumnVector
,ColumnVector::iterator
>( maColumns
, nIndex
, nCount
);
903 maRows
[nRows
]->removeColumns( nIndex
, nCount
);
909 pModel
->SetChanged();
913 DBG_ERROR("sdr::table::TableModel::removeColumns(), exception caught!");
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
;
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();
964 merge( nCol
, nRow
, nColSpan
, nRowSpan
);
971 DBG_ERROR("sdr::table::TableModel::insertRows(), exception caught!");
977 pModel
->SetChanged();
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
;
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;
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() )
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
);
1056 xCell
->merge( xCell
->getColumnSpan(), nRowSpan
- nRemove
);
1061 // now remove the rows
1062 remove_range
<RowVector
,RowVector::iterator
>( maRows
, nIndex
, nCount
);
1068 pModel
->SetChanged();
1072 DBG_ERROR("sdr::table::TableModel::removeRows(), exception caught!");
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;
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() )
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
;
1133 xSet2
->setPropertyValue( sWidth
, Any( nWidth1
) );
1135 catch( Exception
& e
)
1138 DBG_ERROR("svx::TableModel::optimize(), exception caught!");
1141 removeColumns( nCol
, 1 );
1142 bWasModified
= true;
1148 sal_Int32 nRow
= getRowCountImpl() - 1;
1152 for( nCol
= 0; (nCol
< getColumnCountImpl()) && bEmpty
; nCol
++ )
1154 Reference
< XMergeableCell
> xCell( getCellByPosition( nCol
, nRow
), UNO_QUERY
);
1155 if( xCell
.is() && !xCell
->isMerged() )
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
)
1175 DBG_ERROR("svx::TableModel::optimize(), exception caught!");
1178 removeRows( nRow
, 1 );
1179 bWasModified
= true;
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!");
1206 CellRef
xOriginCell( dynamic_cast< Cell
* >( getCellByPosition( nCol
, nRow
).get() ) );
1207 if( xOriginCell
.is() )
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() )
1227 xOriginCell
->mergeContent( xCell
);
1235 // -----------------------------------------------------------------------------
1237 void TableModel::updateRows()
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 // -----------------------------------------------------------------------------