1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
25 #include <vcl/svapp.hxx>
26 #include <osl/mutex.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
)
64 rVector
.resize( nIndex
);
68 Iter
aBegin( rVector
.begin() );
73 rVector
.erase( aBegin
);
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
)
94 if( nIndex
>= static_cast< sal_Int32
>( rVector
.size() ) )
97 nIndex
= static_cast< sal_Int32
>( rVector
.size() ); // cap to end
98 rVector
.resize( nIndex
+ nCount
);
103 sal_Int32 nFind
= nIndex
;
104 Iter
aIter( rVector
.begin() );
109 rVector
.insert( aIter
, nCount
, aEmpty
);
117 TableModel::TableModel( SdrTableObj
* pTableObj
)
118 : TableModelBase( m_aMutex
)
119 , mpTableObj( pTableObj
)
120 , mbModified( false )
121 , mbNotifyPending( false )
126 TableModel::TableModel( SdrTableObj
* pTableObj
, const TableModelRef
& xSourceTable
)
127 : TableModelBase( m_aMutex
)
128 , mpTableObj( pTableObj
)
129 , mbModified( false )
130 , mbNotifyPending( false )
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
;
142 (*maRows
[nRows
]) = (*xSourceTable
->maRows
[nRows
]);
144 sal_Int32 nColumns
= nColCount
;
146 (*maColumns
[nColumns
]) = (*xSourceTable
->maColumns
[nColumns
]);
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
)
172 maRows
.reserve( 20 );
175 maColumns
.reserve( 20 );
177 if( nRows
&& nColumns
)
179 maColumns
.resize( nColumns
);
180 maRows
.resize( nRows
);
183 maRows
[nRows
].set( new TableRow( this, nRows
, nColumns
) );
186 maColumns
[nColumns
].set( new TableColumn( this, nColumns
) );
194 sal_Int32
TableModel::getLeft()
201 sal_Int32
TableModel::getTop()
208 sal_Int32
TableModel::getRight()
210 return getColumnCount();
215 sal_Int32
TableModel::getBottom()
217 return getRowCount();
222 Reference
< XTable
> TableModel::getTable()
229 void TableModel::UndoInsertRows( sal_Int32 nIndex
, sal_Int32 nCount
)
231 TableModelNotifyGuard
aGuard( this );
234 remove_range
<RowVector
,RowVector::iterator
>( maRows
, nIndex
, nCount
);
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
];
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();
266 maRows
[nRows
]->removeColumns( nIndex
, nCount
);
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
);
298 setModified(sal_True
);
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();
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
);
369 sal_Bool SAL_CALL
TableModel::isModified( ) throw (RuntimeException
, std::exception
)
371 ::SolarMutexGuard aGuard
;
377 void SAL_CALL
TableModel::setModified( sal_Bool bModified
) throw (PropertyVetoException
, RuntimeException
, std::exception
)
380 ::SolarMutexGuard aGuard
;
381 mbModified
= 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
);
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();
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
) );
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
>();
468 Reference
< XPropertySetInfo
> SAL_CALL
TableModel::getPropertySetInfo( ) throw (RuntimeException
, std::exception
)
470 Reference
< XPropertySetInfo
> 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
)
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
)
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
)
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();
582 void TableModel::lockBroadcasts() throw (RuntimeException
, std::exception
)
584 ::SolarMutexGuard aGuard
;
589 void TableModel::unlockBroadcasts() throw (RuntimeException
, std::exception
)
591 ::SolarMutexGuard aGuard
;
593 if( 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
)
613 aSource
.Source
= static_cast< ::cppu::OWeakObject
* >(this);
614 pModifyListeners
->notifyEach( &XModifyListener::modified
, aSource
);
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
];
640 CellRef
TableModel::createCell()
644 mpTableObj
->createCell( 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();
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();
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();
708 merge( nCol
, nRow
, nColSpan
, nRowSpan
);
717 pModel
->SetChanged();
722 OSL_FAIL("sdr::table::TableModel::insertColumns(), exception caught!");
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();
752 pModel
->BegUndo( ImpGetResStr(STR_UNDO_COL_DELETE
) );
753 pModel
->AddUndo( pModel
->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj
) );
755 TableModelRef
xThis( this );
756 ColumnVector
aRemovedCols( nCount
);
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;
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() )
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
);
813 xCell
->merge( nColSpan
- nRemove
, xCell
->getRowSpan() );
818 // now remove the columns
819 remove_range
<ColumnVector
,ColumnVector::iterator
>( maColumns
, nIndex
, nCount
);
821 maRows
[nRows
]->removeColumns( nIndex
, nCount
);
827 pModel
->SetChanged();
831 OSL_FAIL("sdr::table::TableModel::removeColumns(), exception caught!");
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
;
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();
882 merge( nCol
, nRow
, nColSpan
, nRowSpan
);
889 OSL_FAIL("sdr::table::TableModel::insertRows(), exception caught!");
895 pModel
->SetChanged();
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
;
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;
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() )
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
);
974 xCell
->merge( xCell
->getColumnSpan(), nRowSpan
- nRemove
);
979 // now remove the rows
980 remove_range
<RowVector
,RowVector::iterator
>( maRows
, nIndex
, nCount
);
986 pModel
->SetChanged();
990 OSL_FAIL("sdr::table::TableModel::removeRows(), exception caught!");
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();
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() )
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
;
1052 xSet2
->setPropertyValue( sWidth
, Any( nWidth1
) );
1054 catch( Exception
& e
)
1057 OSL_FAIL("svx::TableModel::optimize(), exception caught!");
1060 removeColumns( nCol
, 1 );
1061 bWasModified
= true;
1067 sal_Int32 nRow
= getRowCountImpl() - 1;
1068 sal_Int32 nCols
= getColumnCountImpl();
1072 for( nCol
= 0; (nCol
< nCols
) && bEmpty
; nCol
++ )
1074 Reference
< XMergeableCell
> xCell( getCellByPosition( nCol
, nRow
), UNO_QUERY
);
1075 if( xCell
.is() && !xCell
->isMerged() )
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
)
1095 OSL_FAIL("svx::TableModel::optimize(), exception caught!");
1098 removeRows( nRow
, 1 );
1099 bWasModified
= true;
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!");
1126 CellRef
xOriginCell( dynamic_cast< Cell
* >( getCellByPosition( nCol
, nRow
).get() ) );
1127 if( xOriginCell
.is() )
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() )
1147 xOriginCell
->mergeContent( xCell
);
1157 void TableModel::updateRows()
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: */