summaryrefslogtreecommitdiff
path: root/svx/source/table/tablemodel.cxx
diff options
context:
space:
mode:
authorRĂ¼diger Timm <rt@openoffice.org>2008-03-12 09:05:12 +0000
committerRĂ¼diger Timm <rt@openoffice.org>2008-03-12 09:05:12 +0000
commitefcb2e25b751192e00aa6bd33176cb311436bf33 (patch)
tree481c27749100989eef601db1463d67eb5d7483c0 /svx/source/table/tablemodel.cxx
parentb6ccc85e1da31f15138caf0a16e52e6b2b6a198b (diff)
INTEGRATION: CWS impresstables2 (1.1.2); FILE ADDED
2008/02/27 11:57:22 cl 1.1.2.13: #i68103# fixed clipboard 2008/02/15 14:22:23 cl 1.1.2.12: #i68103# 2008/02/14 09:41:08 cl 1.1.2.11: fixed a unix compile warning 2008/02/06 18:18:49 cl 1.1.2.10: #i68103# fixing some split/merge issues 2008/01/31 10:13:07 cl 1.1.2.9: fixed namespace problems after resync 2008/01/24 17:07:52 cl 1.1.2.8: #i68103# reworked table layouter 2008/01/01 18:37:42 cl 1.1.2.7: #i68103# working on tables 2007/11/29 19:03:16 cl 1.1.2.6: #i68103# working on table templates 2007/10/11 15:18:51 cl 1.1.2.5: #i68103# added undo for tables 2007/08/07 12:00:12 cl 1.1.2.4: fixed merge conflicts 2007/08/06 19:38:03 cl 1.1.2.3: #i68103# worked on cell merging for tables in impress&draw 2007/03/20 12:54:51 cl 1.1.2.2: fixed unix compile errors 2007/03/15 17:15:54 cl 1.1.2.1: #i68103# adding a shape for tables
Diffstat (limited to 'svx/source/table/tablemodel.cxx')
-rw-r--r--svx/source/table/tablemodel.cxx1184
1 files changed, 1184 insertions, 0 deletions
diff --git a/svx/source/table/tablemodel.cxx b/svx/source/table/tablemodel.cxx
new file mode 100644
index 000000000000..47851420bcab
--- /dev/null
+++ b/svx/source/table/tablemodel.cxx
@@ -0,0 +1,1184 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: tablemodel.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-03-12 10:05:12 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svx.hxx"
+
+#include <com/sun/star/table/XMergeableCell.hpp>
+
+#include <algorithm>
+#include <boost/bind.hpp>
+
+#include <vcl/svapp.hxx>
+#include <vos/mutex.hxx>
+
+#include "cell.hxx"
+#include "cellcursor.hxx"
+#include "tablemodel.hxx"
+#include "tablerow.hxx"
+#include "tablerows.hxx"
+#include "tablecolumn.hxx"
+#include "tablecolumns.hxx"
+#include "tableundo.hxx"
+#include "svx/svdotable.hxx"
+#include "svx/svdmodel.hxx"
+#include "svdstr.hrc"
+#include "svdglob.hxx"
+
+using ::rtl::OUString;
+using namespace ::osl;
+using namespace ::vos;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+
+// -----------------------------------------------------------------------------
+
+namespace sdr { namespace table {
+
+// -----------------------------------------------------------------------------
+
+// removes the given range from a vector
+template< class Vec, class Iter > void remove_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
+{
+ const sal_Int32 nSize = static_cast<sal_Int32>(rVector.size());
+ if( nCount && (nIndex >= 0) && (nIndex < nSize) )
+ {
+ if( (nIndex + nCount) >= nSize )
+ {
+ // remove at end
+ rVector.resize( nIndex );
+ }
+ else
+ {
+ Iter aBegin( rVector.begin() );
+ while( nIndex-- )
+ aBegin++;
+ if( nCount == 1 )
+ {
+ rVector.erase( aBegin );
+ }
+ else
+ {
+ Iter aEnd( aBegin );
+
+ while( nCount-- )
+ aEnd++;
+ rVector.erase( aBegin, aEnd );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+/** inserts a range into a vector */
+template< class Vec, class Iter > sal_Int32 insert_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
+{
+ if( nCount )
+ {
+ if( nIndex >= static_cast< sal_Int32 >( rVector.size() ) )
+ {
+ // append at end
+ nIndex = static_cast< sal_Int32 >( rVector.size() ); // cap to end
+ rVector.resize( nIndex + nCount );
+ }
+ else
+ {
+ // insert
+ sal_Int32 nFind = nIndex;
+ Iter aIter( rVector.begin() );
+ while( nFind-- )
+ aIter++;
+ rVector.insert( aIter, nCount, 0 );
+ }
+ }
+ return nIndex;
+}
+
+// -----------------------------------------------------------------------------
+
+TableModel::TableModel( SdrTableObj* pTableObj )
+: TableModelBase( m_aMutex )
+, mpTableObj( pTableObj )
+, mbModified( sal_False )
+, mbNotifyPending( false )
+, mnNotifyLock( 0 )
+{
+}
+
+TableModel::TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable )
+: TableModelBase( m_aMutex )
+, mpTableObj( pTableObj )
+, mbModified( sal_False )
+, mbNotifyPending( false )
+, mnNotifyLock( 0 )
+{
+ if( xSourceTable.is() )
+ {
+ const sal_Int32 nColCount = xSourceTable->getColumnCountImpl();
+ const sal_Int32 nRowCount = xSourceTable->getRowCountImpl();
+
+ init( nColCount, nRowCount );
+
+ sal_Int32 nRows = nRowCount;
+ while( nRows-- )
+ (*maRows[nRows]) = (*xSourceTable->maRows[nRows]);
+
+ sal_Int32 nColumns = nColCount;
+ while( nColumns-- )
+ (*maColumns[nColumns]) = (*xSourceTable->maColumns[nColumns]);
+
+ // copy cells
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ CellRef xTargetCell( getCell( nCol, nRow ) );
+ if( xTargetCell.is() )
+ xTargetCell->cloneFrom( xSourceTable->getCell( nCol, nRow ) );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+TableModel::~TableModel()
+{
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::init( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ if( nRows < 20 )
+ maRows.reserve( 20 );
+
+ if( nColumns < 20 )
+ maColumns.reserve( 20 );
+
+ if( nRows && nColumns )
+ {
+ maColumns.resize( nColumns );
+ maRows.resize( nRows );
+
+ while( nRows-- )
+ maRows[nRows].set( new TableRow( this, nRows, nColumns ) );
+
+ while( nColumns-- )
+ maColumns[nColumns].set( new TableColumn( this, nColumns ) );
+ }
+}
+
+// -----------------------------------------------------------------------------
+// ICellRange
+// -----------------------------------------------------------------------------
+
+sal_Int32 TableModel::getLeft()
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Int32 TableModel::getTop()
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Int32 TableModel::getRight()
+{
+ return getColumnCount();
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Int32 TableModel::getBottom()
+{
+ return getRowCount();
+}
+
+// -----------------------------------------------------------------------------
+
+Reference< XTable > TableModel::getTable()
+{
+ return this;
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ TableModelNotifyGuard aGuard( this );
+
+ // remove the rows
+ remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
+ setModified(sal_True);
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::UndoRemoveRows( sal_Int32 nIndex, RowVector& aRows )
+{
+ TableModelNotifyGuard aGuard( this );
+
+ const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aRows.size() );
+
+ nIndex = insert_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
+
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ maRows[nIndex+nOffset] = aRows[nOffset];
+
+ setModified(sal_True);
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ TableModelNotifyGuard aGuard( this );
+
+ // now remove the columns
+ remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
+ sal_Int32 nRows = getRowCountImpl();
+ while( nRows-- )
+ maRows[nRows]->removeColumns( nIndex, nCount );
+ setModified(sal_True);
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aCols, CellVector& aCells )
+{
+ TableModelNotifyGuard aGuard( this );
+
+ const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aCols.size() );
+
+ // assert if there are not enough cells saved
+ DBG_ASSERT( (aCols.size() * maRows.size()) == aCells.size(), "sdr::table::TableModel::UndoRemoveColumns(), invalid undo data!" );
+
+ nIndex = insert_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ maColumns[nIndex+nOffset] = aCols[nOffset];
+
+ CellVector::iterator aIter( aCells.begin() );
+
+ sal_Int32 nRows = getRowCountImpl();
+ for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
+ maRows[nRow]->insertColumns( nIndex, nCount, &aIter );
+ setModified(sal_True);
+}
+
+// -----------------------------------------------------------------------------
+// XTable
+// -----------------------------------------------------------------------------
+
+Reference< XCellCursor > SAL_CALL TableModel::createCursor() throw (RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+ return createCursorByRange( Reference< XCellRange >( this ) );
+}
+
+// -----------------------------------------------------------------------------
+
+Reference< XCellCursor > SAL_CALL TableModel::createCursorByRange( const Reference< XCellRange >& Range ) throw (IllegalArgumentException, RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+
+ ICellRange* pRange = dynamic_cast< ICellRange* >( Range.get() );
+ if( (pRange == 0) || (pRange->getTable().get() != this) )
+ throw IllegalArgumentException();
+
+ TableModelRef xModel( this );
+ return new CellCursor( xModel, pRange->getLeft(), pRange->getTop(), pRange->getRight(), pRange->getBottom() );
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Int32 SAL_CALL TableModel::getRowCount() throw (RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+ return getRowCountImpl();
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Int32 SAL_CALL TableModel::getColumnCount() throw (RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+ return getColumnCountImpl();
+}
+
+// -----------------------------------------------------------------------------
+// XComponent
+// -----------------------------------------------------------------------------
+
+void TableModel::dispose() throw (RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+ TableModelBase::dispose();
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::addEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
+{
+ TableModelBase::addEventListener( xListener );
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::removeEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
+{
+ TableModelBase::removeEventListener( xListener );
+}
+
+// -----------------------------------------------------------------------------
+// XModifiable
+// -----------------------------------------------------------------------------
+
+sal_Bool SAL_CALL TableModel::isModified( ) throw (RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+ return mbModified;
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::setModified( sal_Bool bModified ) throw (PropertyVetoException, RuntimeException)
+{
+ {
+ OGuard aGuard( Application::GetSolarMutex() );
+ mbModified = bModified;
+ }
+ if( bModified )
+ notifyModification();
+}
+
+// -----------------------------------------------------------------------------
+// XModifyBroadcaster
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::addModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException)
+{
+ rBHelper.addListener( XModifyListener::static_type() , xListener );
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::removeModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException)
+{
+ rBHelper.removeListener( XModifyListener::static_type() , xListener );
+}
+
+// -----------------------------------------------------------------------------
+// XColumnRowRange
+// -----------------------------------------------------------------------------
+
+Reference< XTableColumns > SAL_CALL TableModel::getColumns() throw (RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+
+ if( !mxTableColumns.is() )
+ mxTableColumns.set( new TableColumns( this ) );
+ return mxTableColumns.get();
+}
+
+// -----------------------------------------------------------------------------
+
+Reference< XTableRows > SAL_CALL TableModel::getRows() throw (RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+
+ if( !mxTableRows.is() )
+ mxTableRows.set( new TableRows( this ) );
+ return mxTableRows.get();
+}
+
+// -----------------------------------------------------------------------------
+// XCellRange
+// -----------------------------------------------------------------------------
+
+Reference< XCell > SAL_CALL TableModel::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw ( IndexOutOfBoundsException, RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+
+ CellRef xCell( getCell( nColumn, nRow ) );
+ if( xCell.is() )
+ return xCell.get();
+
+ throw IndexOutOfBoundsException();
+}
+
+// -----------------------------------------------------------------------------
+
+Reference< XCellRange > SAL_CALL TableModel::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+
+ if( (nLeft >= 0) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) && (nRight < getColumnCountImpl()) && (nBottom < getRowCountImpl() ) )
+ {
+ TableModelRef xModel( this );
+ return new CellRange( xModel, nLeft, nTop, nRight, nBottom );
+ }
+
+ throw IndexOutOfBoundsException();
+}
+
+// -----------------------------------------------------------------------------
+
+Reference< XCellRange > SAL_CALL TableModel::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException)
+{
+ return Reference< XCellRange >();
+}
+
+// -----------------------------------------------------------------------------
+// XPropertySet
+// -----------------------------------------------------------------------------
+
+Reference< XPropertySetInfo > SAL_CALL TableModel::getPropertySetInfo( ) throw (RuntimeException)
+{
+ Reference< XPropertySetInfo > xInfo;
+ return xInfo;
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::setPropertyValue( const ::rtl::OUString& /*aPropertyName*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+Any SAL_CALL TableModel::getPropertyValue( const OUString& /*PropertyName*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+ return Any();
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::addVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::removeVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+}
+
+// -----------------------------------------------------------------------------
+// XFastPropertySet
+// -----------------------------------------------------------------------------
+
+void SAL_CALL TableModel::setFastPropertyValue( ::sal_Int32 /*nHandle*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+Any SAL_CALL TableModel::getFastPropertyValue( ::sal_Int32 /*nHandle*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+ Any aAny;
+ return aAny;
+}
+
+// -----------------------------------------------------------------------------
+// internals
+// -----------------------------------------------------------------------------
+
+sal_Int32 TableModel::getRowCountImpl() const
+{
+ return static_cast< sal_Int32 >( maRows.size() );
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Int32 TableModel::getColumnCountImpl() const
+{
+ return static_cast< sal_Int32 >( maColumns.size() );
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::disposing()
+{
+ if( !maRows.empty() )
+ {
+ RowVector::iterator aIter( maRows.begin() );
+ while( aIter != maRows.end() )
+ (*aIter++)->dispose();
+ RowVector().swap(maRows);
+ }
+
+ if( !maColumns.empty() )
+ {
+ ColumnVector::iterator aIter( maColumns.begin() );
+ while( aIter != maColumns.end() )
+ (*aIter++)->dispose();
+ ColumnVector().swap(maColumns);
+ }
+
+ if( mxTableColumns.is() )
+ {
+ mxTableColumns->dispose();
+ mxTableColumns.clear();
+ }
+
+ if( mxTableRows.is() )
+ {
+ mxTableRows->dispose();
+ mxTableRows.clear();
+ }
+
+ mpTableObj = 0;
+}
+
+// -----------------------------------------------------------------------------
+// XBroadcaster
+// -----------------------------------------------------------------------------
+
+void TableModel::lockBroadcasts() throw (RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+ ++mnNotifyLock;
+}
+// -----------------------------------------------------------------------------
+
+void TableModel::unlockBroadcasts() throw (RuntimeException)
+{
+ OGuard aGuard( Application::GetSolarMutex() );
+ --mnNotifyLock;
+ if( mnNotifyLock <= 0 )
+ {
+ mnNotifyLock = 0;
+ if( mbNotifyPending )
+ notifyModification();
+ }
+}
+
+// -----------------------------------------------------------------------------
+#ifdef PLEASE_DEBUG_THE_TABLES
+#include <stdio.h>
+#endif
+
+void TableModel::notifyModification()
+{
+ ::osl::MutexGuard guard( m_aMutex );
+ if( (mnNotifyLock == 0) && mpTableObj && mpTableObj->GetModel() )
+ {
+
+#ifdef PLEASE_DEBUG_THE_TABLES
+ FILE* file = fopen( "e:\\table.log","a+" );
+
+ const sal_Int32 nColCount = getColumnCountImpl();
+ const sal_Int32 nRowCount = getRowCountImpl();
+
+ fprintf( file, "<table columns=\"%ld\" rows=\"%ld\">\n\r", nColCount, nRowCount );
+
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ fprintf( file, "<column this=\"%lx\"/>\n\r", maColumns[nCol].get() );
+ }
+
+ // first check merged cells before and inside the removed rows
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ fprintf( file, "<row this=\"%lx\">\n\r", maRows[nRow].get() );
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ CellRef xCell( getCell( nCol, nRow ) );
+ fprintf( file, "<cell this=\"%lx\"", xCell.get() );
+
+ sal_Int32 nRowSpan = xCell->getRowSpan();
+ sal_Int32 nColSpan = xCell->getColumnSpan();
+ sal_Bool bMerged = xCell->isMerged();
+
+ if( nColSpan > 1 )
+ fprintf( file, " column-span=\"%ld\"", nColSpan );
+ if( nRowSpan > 1 )
+ fprintf( file, " row-span=\"%ld\"", nRowSpan );
+
+ if( bMerged )
+ fprintf( file, " merged=\"true\"" );
+
+ fprintf( file, "/>" );
+ }
+ fprintf( file, "\n\r</row>\n\r" );
+ }
+
+ fprintf( file, "</table>\n\r" );
+ fclose( file );
+#endif
+ mbNotifyPending = false;
+
+ ::cppu::OInterfaceContainerHelper * pModifyListeners = rBHelper.getContainer( XModifyListener::static_type() );
+ if( pModifyListeners )
+ {
+ EventObject aSource;
+ aSource.Source = static_cast< ::cppu::OWeakObject* >(this);
+ pModifyListeners->notifyEach( &XModifyListener::modified, aSource);
+ }
+ }
+ else
+ {
+ mbNotifyPending = true;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+CellRef TableModel::getCell( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ if( ((nRow >= 0) && (nRow < getRowCountImpl())) && (nCol >= 0) && (nCol < getColumnCountImpl()) )
+ {
+ return maRows[nRow]->maCells[nCol];
+ }
+ else
+ {
+ CellRef xRet;
+ return xRet;
+ }
+}
+
+// -----------------------------------------------------------------------------
+/*
+bool TableModel::getCellPos( const CellRef& xCell, ::sal_Int32& rnCol, ::sal_Int32& rnRow ) const
+{
+ const sal_Int32 nRowCount = getRowCount();
+ const sal_Int32 nColCount = getColumnCount();
+ for( rnRow = 0; rnRow < nRowCount; rnRow++ )
+ {
+ for( rnCol = 0; rnCol < nColCount; rnCol++ )
+ {
+ if( maRows[rnRow]->maCells[rnCol] == xCell )
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+*/
+
+// -----------------------------------------------------------------------------
+
+CellRef TableModel::createCell()
+{
+ CellRef xCell;
+ if( mpTableObj )
+ mpTableObj->createCell( xCell );
+ return xCell;
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::insertColumns( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ if( nCount && mpTableObj )
+ {
+ try
+ {
+ SdrModel* pModel = mpTableObj->GetModel();
+
+ TableModelNotifyGuard aGuard( this );
+ nIndex = insert_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
+
+ sal_Int32 nRows = getRowCountImpl();
+ while( nRows-- )
+ maRows[nRows]->insertColumns( nIndex, nCount );
+
+ ColumnVector aNewColumns(nCount);
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ {
+ TableColumnRef xNewCol( new TableColumn( this, nIndex+nOffset ) );
+ maColumns[nIndex+nOffset] = xNewCol;
+ aNewColumns[nOffset] = xNewCol;
+ }
+
+ if( pModel && mpTableObj->IsInserted() )
+ {
+ pModel->BegUndo( ImpGetResStr(STR_TABLE_INSCOL) );
+ pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
+
+ TableModelRef xThis( this );
+
+ nRows = getRowCountImpl();
+ CellVector aNewCells( nCount * nRows );
+ CellVector::iterator aCellIter( aNewCells.begin() );
+
+ nRows = getRowCountImpl();
+ for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
+ {
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ (*aCellIter++) = getCell( nIndex + nOffset, nRow );
+ }
+
+ pModel->AddUndo( new InsertColUndo( xThis, nIndex, aNewColumns, aNewCells ) );
+ }
+
+ const sal_Int32 nRowCount = getRowCountImpl();
+ // check if cells merge over new columns
+ for( sal_Int32 nCol = 0; nCol < nIndex; ++nCol )
+ {
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ CellRef xCell( getCell( nCol, nRow ) );
+ sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
+ if( (nColSpan != 1) && ((nColSpan + nCol ) > nIndex) )
+ {
+ // cell merges over newly created columns, so add the new columns to the merged cell
+ const sal_Int32 nRowSpan = xCell->getRowSpan();
+ nColSpan += nCount;
+ if( pModel && mpTableObj->IsInserted() )
+ xCell->AddUndo();
+ xCell->merge( nColSpan, nRowSpan );
+ // set newly inserted cells to merged state
+ for( sal_Int32 nColOffset = 0; nColOffset < nCount; ++nColOffset )
+ {
+ for( sal_Int32 nRowOffset = 0; nRowOffset < nRowSpan; ++nRowOffset )
+ {
+ CellRef xMergedCell( getCell( nIndex + nColOffset, nRow + nRowOffset ) );
+ if( xMergedCell.is() )
+ xMergedCell->setMerged();
+ }
+ }
+ }
+ }
+ }
+
+ if( pModel && mpTableObj->IsInserted() )
+ pModel->EndUndo();
+
+ }
+ catch( Exception& )
+ {
+ DBG_ERROR("sdr::table::TableModel::insertColumns(), exception caught!");
+ }
+ setModified(sal_True);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::removeColumns( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ sal_Int32 nColCount = getColumnCountImpl();
+
+ if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nColCount) )
+ {
+ try
+ {
+ TableModelNotifyGuard aGuard( this );
+
+ // clip removed columns to columns actually avalaible
+ if( (nIndex + nCount) > nColCount )
+ nCount = nColCount - nIndex;
+
+ sal_Int32 nRows = getRowCountImpl();
+
+ SdrModel* pModel = mpTableObj->GetModel();
+ if( pModel && mpTableObj->IsInserted() )
+ {
+ pModel->BegUndo( ImpGetResStr(STR_UNDO_COL_DELETE) );
+ pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
+
+ TableModelRef xThis( this );
+ ColumnVector aRemovedCols( nCount );
+ sal_Int32 nOffset;
+ for( nOffset = 0; nOffset < nCount; ++nOffset )
+ {
+ aRemovedCols[nOffset] = maColumns[nIndex+nOffset];
+ }
+
+ CellVector aRemovedCells( nCount * nRows );
+ CellVector::iterator aCellIter( aRemovedCells.begin() );
+ for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
+ {
+ for( nOffset = 0; nOffset < nCount; ++nOffset )
+ (*aCellIter++) = getCell( nIndex + nOffset, nRow );
+ }
+
+ pModel->AddUndo( new RemoveColUndo( xThis, nIndex, aRemovedCols, aRemovedCells ) );
+ }
+
+ // only rows before and inside the removed rows are considered
+ nColCount = nIndex + nCount + 1;
+
+ const sal_Int32 nRowCount = getRowCountImpl();
+
+ // first check merged cells before and inside the removed rows
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ CellRef xCell( getCell( nCol, nRow ) );
+ sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
+ if( nColSpan <= 1 )
+ continue;
+
+ if( nCol >= nIndex )
+ {
+ // current cell is inside the removed columns
+ if( (nCol + nColSpan) > ( nIndex + nCount ) )
+ {
+ // current cells merges with columns after the removed columns
+ const sal_Int32 nRemove = nCount - nCol + nIndex;
+
+ CellRef xTargetCell( getCell( nIndex + nCount, nRow ) );
+ if( xTargetCell.is() )
+ {
+ xTargetCell->AddUndo();
+ xTargetCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
+ xTargetCell->replaceContentAndFormating( xCell );
+ }
+ }
+ }
+ else if( nColSpan > (nIndex - nCol) )
+ {
+ // current cells spans inside the removed columns, so adjust
+ const sal_Int32 nRemove = ::std::min( nCount, nCol + nColSpan - nIndex );
+ if( mpTableObj->IsInserted() )
+ xCell->AddUndo();
+ xCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
+ }
+ }
+ }
+
+ // now remove the columns
+ remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
+ while( nRows-- )
+ maRows[nRows]->removeColumns( nIndex, nCount );
+
+ if( pModel && mpTableObj->IsInserted() )
+ pModel->EndUndo();
+ }
+ catch( Exception& )
+ {
+ DBG_ERROR("sdr::table::TableModel::removeColumns(), exception caught!");
+ }
+
+ setModified(sal_True);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::insertRows( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ if( nCount && mpTableObj )
+ {
+ try
+ {
+ TableModelNotifyGuard aGuard( this );
+
+ nIndex = insert_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
+
+ RowVector aNewRows(nCount);
+ const sal_Int32 nColCount = getColumnCountImpl();
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ {
+ TableRowRef xNewRow( new TableRow( this, nIndex+nOffset, nColCount ) );
+ maRows[nIndex+nOffset] = xNewRow;
+ aNewRows[nOffset] = xNewRow;
+ }
+
+ SdrModel* pModel = mpTableObj->GetModel();
+ if( pModel && mpTableObj->IsInserted() )
+ {
+ pModel->BegUndo( ImpGetResStr(STR_TABLE_INSROW) );
+ pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
+ TableModelRef xThis( this );
+ pModel->AddUndo( new InsertRowUndo( xThis, nIndex, aNewRows ) );
+ }
+
+ // check if cells merge over new columns
+ for( sal_Int32 nRow = 0; nRow < nIndex; ++nRow )
+ {
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ CellRef xCell( getCell( nCol, nRow ) );
+ sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
+ if( (nRowSpan > 1) && ((nRowSpan + nRow) > nIndex) )
+ {
+ // cell merges over newly created columns, so add the new columns to the merged cell
+ const sal_Int32 nColSpan = xCell->getColumnSpan();
+ nRowSpan += nCount;
+ xCell->AddUndo();
+ xCell->merge( nColSpan, nRowSpan );
+
+ // set newly inserted cells to merged state
+ for( sal_Int32 nColOffset = 1; nColOffset < nColSpan; ++nColOffset )
+ {
+ for( sal_Int32 nRowOffset = 0; nRowOffset <= nCount; ++nRowOffset )
+ {
+ CellRef xMergedCell( getCell( nCol + nColOffset - 1, nIndex + nRowOffset ) );
+ if( xMergedCell.is() )
+ xMergedCell->setMerged();
+ }
+ }
+ }
+ }
+ }
+
+ if( pModel )
+ pModel->EndUndo();
+ }
+ catch( Exception& )
+ {
+ DBG_ERROR("sdr::table::TableModel::insertRows(), exception caught!");
+ }
+ setModified(sal_True);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void TableModel::removeRows( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ sal_Int32 nRowCount = getRowCountImpl();
+
+ if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nRowCount) )
+ {
+ try
+ {
+ TableModelNotifyGuard aGuard( this );
+
+ // clip removed rows to rows actually avalaible
+ if( (nIndex + nCount) > nRowCount )
+ nCount = nRowCount - nIndex;
+
+ SdrModel* pModel = mpTableObj->GetModel();
+ if( pModel && mpTableObj->IsInserted() )
+ {
+ pModel->BegUndo( ImpGetResStr(STR_UNDO_ROW_DELETE) );
+ pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
+
+ TableModelRef xThis( this );
+
+ RowVector aRemovedRows( nCount );
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ aRemovedRows[nOffset] = maRows[nIndex+nOffset];
+
+ pModel->AddUndo( new RemoveRowUndo( xThis, nIndex, aRemovedRows ) );
+ }
+
+ // only rows before and inside the removed rows are considered
+ nRowCount = nIndex + nCount + 1;
+
+ const sal_Int32 nColCount = getColumnCountImpl();
+
+ // first check merged cells before and inside the removed rows
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ CellRef xCell( getCell( nCol, nRow ) );
+ sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
+ if( nRowSpan <= 1 )
+ continue;
+
+ if( nRow >= nIndex )
+ {
+ // current cell is inside the removed rows
+ if( (nRow + nRowSpan) > (nIndex + nCount) )
+ {
+ // current cells merges with rows after the removed rows
+ const sal_Int32 nRemove = nCount - nRow + nIndex;
+
+ CellRef xTargetCell( getCell( nCol, nIndex + nCount ) );
+ if( xTargetCell.is() )
+ {
+ xTargetCell->AddUndo();
+ xTargetCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
+ xTargetCell->replaceContentAndFormating( xCell );
+ }
+ }
+ }
+ else if( nRowSpan > (nIndex - nRow) )
+ {
+ // current cells spans inside the removed rows, so adjust
+ const sal_Int32 nRemove = ::std::min( nCount, nRow + nRowSpan - nIndex );
+ xCell->AddUndo();
+ xCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
+ }
+ }
+ }
+
+ // now remove the rows
+ remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
+
+ if( pModel )
+ pModel->EndUndo();
+ }
+ catch( Exception& )
+ {
+ DBG_ERROR("sdr::table::TableModel::removeRows(), exception caught!");
+ }
+
+ setModified(sal_True);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+TableRowRef TableModel::getRow( sal_Int32 nRow ) const throw (IndexOutOfBoundsException)
+{
+ if( (nRow >= 0) && (nRow < getRowCountImpl()) )
+ return maRows[nRow];
+
+ throw IndexOutOfBoundsException();
+}
+
+// -----------------------------------------------------------------------------
+
+TableColumnRef TableModel::getColumn( sal_Int32 nColumn ) const throw (IndexOutOfBoundsException)
+{
+ if( (nColumn >= 0) && (nColumn < getColumnCountImpl()) )
+ return maColumns[nColumn];
+
+ throw IndexOutOfBoundsException();
+}
+
+// -----------------------------------------------------------------------------
+
+/** deletes rows and columns that are completly merged. Must be called between BegUndo/EndUndo! */
+void TableModel::optimize()
+{
+ TableModelNotifyGuard aGuard( this );
+
+ bool bWasModified = false;
+
+ if( !maRows.empty() && !maColumns.empty() )
+ {
+ sal_Int32 nCol = getColumnCountImpl() - 1;
+ while( nCol > 0 )
+ {
+ bool bEmpty = true;
+ for( sal_Int32 nRow = 0; (nRow < getRowCountImpl()) && bEmpty; nRow++ )
+ {
+ Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
+ if( xCell.is() && !xCell->isMerged() )
+ bEmpty = false;
+ }
+
+ if( bEmpty )
+ {
+ if( nCol > 0 ) try
+ {
+ const OUString sWidth( RTL_CONSTASCII_USTRINGPARAM("Width") );
+ sal_Int32 nWidth1 = 0, nWidth2 = 0;
+ Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maColumns[nCol].get() ), UNO_QUERY_THROW );
+ Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maColumns[nCol-1].get() ), UNO_QUERY_THROW );
+ xSet1->getPropertyValue( sWidth ) >>= nWidth1;
+ xSet2->getPropertyValue( sWidth ) >>= nWidth2;
+ nWidth1 += nWidth2;
+ xSet2->setPropertyValue( sWidth, Any( nWidth1 ) );
+ }
+ catch( Exception& e )
+ {
+ (void)e;
+ DBG_ERROR("svx::TableModel::optimize(), exception caught!");
+ }
+
+ removeColumns( nCol, 1 );
+ bWasModified = true;
+ }
+
+ nCol--;
+ }
+
+ sal_Int32 nRow = getRowCountImpl() - 1;
+ while( nRow > 0 )
+ {
+ bool bEmpty = true;
+ for( nCol = 0; (nCol < getColumnCountImpl()) && bEmpty; nCol++ )
+ {
+ Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
+ if( xCell.is() && !xCell->isMerged() )
+ bEmpty = false;
+ }
+
+ if( bEmpty )
+ {
+ if( nRow > 0 ) try
+ {
+ const OUString sHeight( RTL_CONSTASCII_USTRINGPARAM("Height") );
+ sal_Int32 nHeight1 = 0, nHeight2 = 0;
+ Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maRows[nRow].get() ), UNO_QUERY_THROW );
+ Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maRows[nRow-1].get() ), UNO_QUERY_THROW );
+ xSet1->getPropertyValue( sHeight ) >>= nHeight1;
+ xSet2->getPropertyValue( sHeight ) >>= nHeight2;
+ nHeight1 += nHeight2;
+ xSet2->setPropertyValue( sHeight, Any( nHeight1 ) );
+ }
+ catch( Exception& e )
+ {
+ (void)e;
+ DBG_ERROR("svx::TableModel::optimize(), exception caught!");
+ }
+
+ removeRows( nRow, 1 );
+ bWasModified = true;
+ }
+
+ nRow--;
+ }
+ }
+ if( bWasModified )
+ setModified(sal_True);
+}
+
+// -----------------------------------------------------------------------------
+
+} }