diff options
author | RĂ¼diger Timm <rt@openoffice.org> | 2008-03-12 09:05:12 +0000 |
---|---|---|
committer | RĂ¼diger Timm <rt@openoffice.org> | 2008-03-12 09:05:12 +0000 |
commit | efcb2e25b751192e00aa6bd33176cb311436bf33 (patch) | |
tree | 481c27749100989eef601db1463d67eb5d7483c0 /svx/source/table/tablemodel.cxx | |
parent | b6ccc85e1da31f15138caf0a16e52e6b2b6a198b (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.cxx | 1184 |
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); +} + +// ----------------------------------------------------------------------------- + +} } |