diff options
Diffstat (limited to 'toolkit/source/controls/grid/sortablegriddatamodel.cxx')
-rwxr-xr-x | toolkit/source/controls/grid/sortablegriddatamodel.cxx | 877 |
1 files changed, 877 insertions, 0 deletions
diff --git a/toolkit/source/controls/grid/sortablegriddatamodel.cxx b/toolkit/source/controls/grid/sortablegriddatamodel.cxx new file mode 100755 index 000000000000..77a2ffa1637b --- /dev/null +++ b/toolkit/source/controls/grid/sortablegriddatamodel.cxx @@ -0,0 +1,877 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_toolkit.hxx" + +#include "sortablegriddatamodel.hxx" +#include "toolkit/helper/servicenames.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/i18n/XCollator.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/ucb/AlreadyInitializedException.hpp> +/** === end UNO includes === **/ + +#include <comphelper/anycompare.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <tools/diagnose_ex.h> +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> + +#include <set> + +//...................................................................................................................... +namespace toolkit +{ +//...................................................................................................................... + + /** === begin UNO using === **/ + using ::com::sun::star::uno::TypeClass; + using ::com::sun::star::uno::TypeClass_VOID; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::lang::IndexOutOfBoundsException; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::awt::grid::XGridDataListener; + using ::com::sun::star::beans::Pair; + using ::com::sun::star::util::XCloneable; + using ::com::sun::star::i18n::XCollator; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::awt::grid::GridDataEvent; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::ucb::AlreadyInitializedException; + /** === end UNO using === **/ + +#ifdef DBG_UTIL + const char* SortableGridDataModel_checkInvariants( const void* _pInstance ) + { + return static_cast< const SortableGridDataModel* >( _pInstance )->checkInvariants(); + } + + //------------------------------------------------------------------------------------------------------------------ + const char* SortableGridDataModel::checkInvariants() const + { + if ( m_publicToPrivateRowIndex.size() != m_privateToPublicRowIndex.size() ) + return "inconsistent index maps"; + + if ( m_delegator.is() ) + { + if ( m_publicToPrivateRowIndex.size() != size_t( m_delegator->getRowCount() ) ) + return "wrong cached row count"; + } + else + { + if ( !m_publicToPrivateRowIndex.empty() ) + return "disposed or not initialized, but having a non-empty map"; + } + + for ( size_t publicIndex=0; publicIndex<m_publicToPrivateRowIndex.size(); ++publicIndex ) + { + ::sal_Int32 const privateIndex = m_publicToPrivateRowIndex[ publicIndex ]; + if ( ( privateIndex < 0 ) || ( size_t( privateIndex ) >= m_privateToPublicRowIndex.size() ) ) + return "invalid cached private index"; + + if ( m_privateToPublicRowIndex[ privateIndex ] != sal_Int32( publicIndex ) ) + return "index map traversal not commutavive"; + } + + if ( impl_isSorted_nothrow() && m_publicToPrivateRowIndex.empty() ) + return "sorted, but no row index translation tables"; + + if ( !impl_isSorted_nothrow() && !m_publicToPrivateRowIndex.empty() ) + return "unsorted, but have index translation tables"; + + return NULL; + } +#endif + +#define DBG_CHECK_ME() \ + DBG_CHKTHIS( SortableGridDataModel, SortableGridDataModel_checkInvariants ) + + //------------------------------------------------------------------------------------------------------------------ + namespace + { + template< class STLCONTAINER > + static void lcl_clear( STLCONTAINER& i_container ) + { + STLCONTAINER empty; + empty.swap( i_container ); + } + } + + //================================================================================================================== + //= SortableGridDataModel + //================================================================================================================== + DBG_NAME( SortableGridDataModel ) + //------------------------------------------------------------------------------------------------------------------ + SortableGridDataModel::SortableGridDataModel( Reference< XMultiServiceFactory > const & i_factory ) + :SortableGridDataModel_Base( m_aMutex ) + ,SortableGridDataModel_PrivateBase() + ,m_context( i_factory ) + ,m_isInitialized( false ) + ,m_delegator() + ,m_collator() + ,m_currentSortColumn( -1 ) + ,m_sortAscending( true ) + ,m_publicToPrivateRowIndex() + ,m_privateToPublicRowIndex() + { + DBG_CTOR( SortableGridDataModel, SortableGridDataModel_checkInvariants ); + } + + //------------------------------------------------------------------------------------------------------------------ + SortableGridDataModel::SortableGridDataModel( SortableGridDataModel const & i_copySource ) + :cppu::BaseMutex() + ,SortableGridDataModel_Base( m_aMutex ) + ,SortableGridDataModel_PrivateBase() + ,m_context( i_copySource.m_context ) + ,m_isInitialized( true ) + ,m_delegator() + ,m_collator( i_copySource.m_collator ) + ,m_currentSortColumn( i_copySource.m_currentSortColumn ) + ,m_sortAscending( i_copySource.m_sortAscending ) + ,m_publicToPrivateRowIndex( i_copySource.m_publicToPrivateRowIndex ) + ,m_privateToPublicRowIndex( i_copySource.m_privateToPublicRowIndex ) + { + DBG_CTOR( SortableGridDataModel, SortableGridDataModel_checkInvariants ); + + ENSURE_OR_THROW( i_copySource.m_delegator.is(), + "not expected to be called for a disposed copy source!" ); + m_delegator.set( i_copySource.m_delegator->createClone(), UNO_QUERY_THROW ); + } + + //------------------------------------------------------------------------------------------------------------------ + SortableGridDataModel::~SortableGridDataModel() + { + if ( !rBHelper.bDisposed ) + { + acquire(); + dispose(); + } + + DBG_DTOR( SortableGridDataModel, SortableGridDataModel_checkInvariants ); + } + + //------------------------------------------------------------------------------------------------------------------ + Any SAL_CALL SortableGridDataModel::queryInterface( const Type& aType ) throw (RuntimeException) + { + Any aReturn( SortableGridDataModel_Base::queryInterface( aType ) ); + if ( !aReturn.hasValue() ) + aReturn = SortableGridDataModel_PrivateBase::queryInterface( aType ); + return aReturn; + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::acquire( ) throw () + { + SortableGridDataModel_Base::acquire(); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::release( ) throw () + { + SortableGridDataModel_Base::release(); + } + + //------------------------------------------------------------------------------------------------------------------ + Sequence< Type > SAL_CALL SortableGridDataModel::getTypes( ) throw (RuntimeException) + { + return SortableGridDataModel_Base::getTypes(); + // don't expose the types got via SortableGridDataModel_PrivateBase - they're private, after all + } + + //------------------------------------------------------------------------------------------------------------------ + Sequence< ::sal_Int8 > SAL_CALL SortableGridDataModel::getImplementationId( ) throw (RuntimeException) + { + static ::cppu::OImplementationId aId; + return aId.getImplementationId(); + } + + //------------------------------------------------------------------------------------------------------------------ + namespace + { + Reference< XCollator > lcl_loadDefaultCollator_throw( ::comphelper::ComponentContext const & i_context ) + { + Reference< XCollator > const xCollator( i_context.createComponent( "com.sun.star.i18n.Collator" ), UNO_QUERY_THROW ); + xCollator->loadDefaultCollator( Application::GetSettings().GetLocale(), 0 ); + return xCollator; + } + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::initialize( const Sequence< Any >& i_arguments ) throw (Exception, RuntimeException) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + if ( m_delegator.is() ) + throw AlreadyInitializedException( ::rtl::OUString(), *this ); + + Reference< XMutableGridDataModel > xDelegator; + Reference< XCollator > xCollator; + switch ( i_arguments.getLength() ) + { + case 1: // SortableGridDataModel.create( XMutableGridDataModel ) + xDelegator.set( i_arguments[0], UNO_QUERY ); + xCollator = lcl_loadDefaultCollator_throw( m_context ); + break; + + case 2: // SortableGridDataModel.createWithCollator( XMutableGridDataModel, XCollator ) + xDelegator.set( i_arguments[0], UNO_QUERY ); + xCollator.set( i_arguments[1], UNO_QUERY ); + if ( !xCollator.is() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 2 ); + break; + } + if ( !xDelegator.is() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + + m_delegator = xDelegator; + m_collator = xCollator; + + m_delegator->addGridDataListener( this ); + + m_isInitialized = true; + } + + //------------------------------------------------------------------------------------------------------------------ + GridDataEvent SortableGridDataModel::impl_createPublicEvent( GridDataEvent const & i_originalEvent ) const + { + GridDataEvent aEvent( i_originalEvent ); + aEvent.Source = *const_cast< SortableGridDataModel* >( this ); + aEvent.FirstRow = impl_getPublicRowIndex_nothrow( aEvent.FirstRow ); + aEvent.LastRow = impl_getPublicRowIndex_nothrow( aEvent.LastRow ); + return aEvent; + } + + //------------------------------------------------------------------------------------------------------------------ + void SortableGridDataModel::impl_broadcast( void ( SAL_CALL XGridDataListener::*i_listenerMethod )( const GridDataEvent & ), + GridDataEvent const & i_publicEvent, MethodGuard& i_instanceLock ) + { + ::cppu::OInterfaceContainerHelper* pListeners = rBHelper.getContainer( XGridDataListener::static_type() ); + if ( pListeners == NULL ) + return; + + i_instanceLock.clear(); + pListeners->notifyEach( i_listenerMethod, i_publicEvent ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::rowsInserted( const GridDataEvent& i_event ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + // if the data is not sorted, broadcast the event unchanged + if ( !impl_isSorted_nothrow() ) + { + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + impl_broadcast( &XGridDataListener::rowsInserted, aEvent, aGuard ); + return; + } + + bool needReIndex = false; + if ( i_event.FirstRow > i_event.LastRow ) + { + OSL_ENSURE( false, "SortableGridDataModel::rowsInserted: invalid event - invalid row indexes!" ); + needReIndex = true; + } + else if ( size_t( i_event.FirstRow ) > m_privateToPublicRowIndex.size() ) + { + OSL_ENSURE( false, "SortableGridDataModel::rowsInserted: invalid event - too large row index!" ); + needReIndex = true; + } + + if ( needReIndex ) + { + impl_rebuildIndexesAndNotify( aGuard ); + return; + } + + // we do not insert the new rows into the sort order - if somebody adds rows while we're sorted, s/he has + // to resort. Instead, we simply append the rows, no matter where they were inserted in the delegator data + // model. + sal_Int32 const nPublicFirstRow = sal_Int32( m_privateToPublicRowIndex.size() ); + sal_Int32 nPublicLastRow = nPublicFirstRow; + for ( sal_Int32 newRow = i_event.FirstRow; newRow <= i_event.LastRow; ++newRow, ++nPublicLastRow ) + { + m_privateToPublicRowIndex.push_back( nPublicLastRow ); + m_publicToPrivateRowIndex.push_back( nPublicLastRow ); + } + + // broadcast the event + GridDataEvent const aEvent( *this, -1, -1, nPublicFirstRow, nPublicLastRow ); + impl_broadcast( &XGridDataListener::rowsInserted, aEvent, aGuard ); + } + + //------------------------------------------------------------------------------------------------------------------ + namespace + { + void lcl_decrementValuesGreaterThan( ::std::vector< ::sal_Int32 > & io_indexMap, sal_Int32 const i_threshold ) + { + for ( ::std::vector< ::sal_Int32 >::iterator loop = io_indexMap.begin(); + loop != io_indexMap.end(); + ++loop + ) + { + if ( *loop >= i_threshold ) + --*loop; + } + } + } + + //------------------------------------------------------------------------------------------------------------------ + void SortableGridDataModel::impl_rebuildIndexesAndNotify( MethodGuard& i_instanceLock ) + { + OSL_PRECOND( impl_isSorted_nothrow(), "SortableGridDataModel::impl_rebuildIndexesAndNotify: illegal call!" ); + + // clear the indexes + lcl_clear( m_publicToPrivateRowIndex ); + lcl_clear( m_privateToPublicRowIndex ); + + // broadcast an artificial event, saying that all rows have been removed + GridDataEvent const aRemovalEvent( *this, -1, -1, -1, -1 ); + impl_broadcast( &XGridDataListener::rowsRemoved, aRemovalEvent, i_instanceLock ); + i_instanceLock.reset(); + + // rebuild the index + impl_reIndex_nothrow( m_currentSortColumn, m_sortAscending ); + + // broadcast an artificial event, saying that n rows have been added + GridDataEvent const aAdditionEvent( *this, -1, -1, 0, m_delegator->getRowCount() - 1 ); + impl_broadcast( &XGridDataListener::rowsInserted, aAdditionEvent, i_instanceLock ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::rowsRemoved( const GridDataEvent& i_event ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + // if the data is not sorted, broadcast the event unchanged + if ( !impl_isSorted_nothrow() ) + { + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + impl_broadcast( &XGridDataListener::rowsRemoved, aEvent, aGuard ); + return; + } + + // if all rows have been removed, also simply multiplex to own listeners + if ( i_event.FirstRow < 0 ) + { + lcl_clear( m_publicToPrivateRowIndex ); + lcl_clear( m_privateToPublicRowIndex ); + GridDataEvent aEvent( i_event ); + aEvent.Source = *this; + impl_broadcast( &XGridDataListener::rowsRemoved, aEvent, aGuard ); + return; + } + + bool needReIndex = false; + if ( i_event.FirstRow != i_event.LastRow ) + { + OSL_ENSURE( false, "SortableGridDataModel::rowsRemoved: missing implementation - removal of multiple rows!" ); + needReIndex = true; + } + else if ( size_t( i_event.FirstRow ) >= m_privateToPublicRowIndex.size() ) + { + OSL_ENSURE( false, "SortableGridDataModel::rowsRemoved: inconsistent/wrong data!" ); + needReIndex = true; + } + + if ( needReIndex ) + { + impl_rebuildIndexesAndNotify( aGuard ); + return; + } + + // build public event version + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + + // remove the entries from the index maps + sal_Int32 const privateIndex = i_event.FirstRow; + sal_Int32 const publicIndex = aEvent.FirstRow; + + m_publicToPrivateRowIndex.erase( m_publicToPrivateRowIndex.begin() + publicIndex ); + m_privateToPublicRowIndex.erase( m_privateToPublicRowIndex.begin() + privateIndex ); + + // adjust remaining entries in the index maps + lcl_decrementValuesGreaterThan( m_publicToPrivateRowIndex, privateIndex ); + lcl_decrementValuesGreaterThan( m_privateToPublicRowIndex, publicIndex ); + + // broadcast the event + impl_broadcast( &XGridDataListener::rowsRemoved, aEvent, aGuard ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::dataChanged( const GridDataEvent& i_event ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + impl_broadcast( &XGridDataListener::dataChanged, aEvent, aGuard ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::rowHeadingChanged( const GridDataEvent& i_event ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + impl_broadcast( &XGridDataListener::rowHeadingChanged, aEvent, aGuard ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::disposing( const EventObject& i_event ) throw (RuntimeException) + { + // not interested in + OSL_UNUSED( i_event ); + } + + //------------------------------------------------------------------------------------------------------------------ + namespace + { + class CellDataLessComparison : public ::std::binary_function< sal_Int32, sal_Int32, bool > + { + public: + CellDataLessComparison( + ::std::vector< Any > const & i_data, + ::comphelper::IKeyPredicateLess& i_predicate, + sal_Bool const i_sortAscending + ) + :m_data( i_data ) + ,m_predicate( i_predicate ) + ,m_sortAscending( i_sortAscending ) + { + } + + bool operator()( sal_Int32 const i_lhs, sal_Int32 const i_rhs ) const + { + Any const & lhs = m_data[ i_lhs ]; + Any const & rhs = m_data[ i_rhs ]; + // <VOID/> is less than everything else + if ( !lhs.hasValue() ) + return m_sortAscending; + if ( !rhs.hasValue() ) + return !m_sortAscending; + + // actually compare + if ( m_sortAscending ) + return m_predicate.isLess( lhs, rhs ); + else + return m_predicate.isLess( rhs, lhs ); + } + + private: + ::std::vector< Any > const & m_data; + ::comphelper::IKeyPredicateLess const & m_predicate; + sal_Bool const m_sortAscending; + }; + } + + //------------------------------------------------------------------------------------------------------------------ + void SortableGridDataModel::impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, sal_Bool const i_sortAscending ) + { + ::sal_Int32 const rowCount( getRowCount() ); + ::std::vector< ::sal_Int32 > aPublicToPrivate( rowCount ); + + try + { + // build an unsorted translation table, and retrieve the unsorted data + ::std::vector< Any > aColumnData( rowCount ); + Type dataType; + for ( ::sal_Int32 rowIndex = 0; rowIndex < rowCount; ++rowIndex ) + { + aColumnData[ rowIndex ] = m_delegator->getCellData( i_columnIndex, rowIndex ); + aPublicToPrivate[ rowIndex ] = rowIndex; + + // determine the data types we assume for the complete column + if ( ( dataType.getTypeClass() == TypeClass_VOID ) && aColumnData[ rowIndex ].hasValue() ) + dataType = aColumnData[ rowIndex ].getValueType(); + } + + // get predicate object + ::std::auto_ptr< ::comphelper::IKeyPredicateLess > const pPredicate( ::comphelper::getStandardLessPredicate( dataType, m_collator ) ); + ENSURE_OR_RETURN_VOID( pPredicate.get(), "SortableGridDataModel::impl_reIndex_nothrow: no sortable data found!" ); + + // then sort + CellDataLessComparison const aComparator( aColumnData, *pPredicate, i_sortAscending ); + ::std::sort( aPublicToPrivate.begin(), aPublicToPrivate.end(), aComparator ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + return; + } + + // also build the "private to public" mapping + ::std::vector< sal_Int32 > aPrivateToPublic( aPublicToPrivate.size() ); + for ( size_t i=0; i<aPublicToPrivate.size(); ++i ) + aPrivateToPublic[ aPublicToPrivate[i] ] = i; + + m_publicToPrivateRowIndex.swap( aPublicToPrivate ); + m_privateToPublicRowIndex.swap( aPrivateToPublic ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::sortByColumn( ::sal_Int32 i_columnIndex, ::sal_Bool i_sortAscending ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + if ( ( i_columnIndex < 0 ) || ( i_columnIndex >= getColumnCount() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); + + impl_reIndex_nothrow( i_columnIndex, i_sortAscending ); + + m_currentSortColumn = i_columnIndex; + m_sortAscending = i_sortAscending; + + impl_broadcast( + &XGridDataListener::dataChanged, + GridDataEvent( *this, -1, -1, -1, -1 ), + aGuard + ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::removeColumnSort( ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + lcl_clear( m_publicToPrivateRowIndex ); + lcl_clear( m_privateToPublicRowIndex ); + + m_currentSortColumn = -1; + m_sortAscending = sal_True; + + impl_broadcast( + &XGridDataListener::dataChanged, + GridDataEvent( *this, -1, -1, -1, -1 ), + aGuard + ); + } + + //------------------------------------------------------------------------------------------------------------------ + Pair< ::sal_Int32, ::sal_Bool > SAL_CALL SortableGridDataModel::getCurrentSortOrder( ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + return Pair< ::sal_Int32, ::sal_Bool >( m_currentSortColumn, m_sortAscending ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::addRow( const Any& i_heading, const Sequence< Any >& i_data ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->addRow( i_heading, i_data ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::addRows( const Sequence< Any >& i_headings, const Sequence< Sequence< Any > >& i_data ) throw (IllegalArgumentException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->addRows( i_headings, i_data ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::removeRow( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->removeRow( rowIndex ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::removeAllRows( ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->removeAllRows(); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::updateCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateCellData( i_columnIndex, rowIndex, i_value ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::updateRowData( const Sequence< ::sal_Int32 >& i_columnIndexes, ::sal_Int32 i_rowIndex, const Sequence< Any >& i_values ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateRowData( i_columnIndexes, rowIndex, i_values ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::updateRowHeading( ::sal_Int32 i_rowIndex, const Any& i_heading ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateRowHeading( rowIndex, i_heading ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::updateCellToolTip( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateCellToolTip( i_columnIndex, rowIndex, i_value ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::updateRowToolTip( ::sal_Int32 i_rowIndex, const Any& i_value ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateRowToolTip( rowIndex, i_value ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::addGridDataListener( const Reference< XGridDataListener >& i_listener ) throw (RuntimeException) + { + rBHelper.addListener( XGridDataListener::static_type(), i_listener ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::removeGridDataListener( const Reference< XGridDataListener >& i_listener ) throw (RuntimeException) + { + rBHelper.removeListener( XGridDataListener::static_type(), i_listener ); + } + + //------------------------------------------------------------------------------------------------------------------ + ::sal_Int32 SAL_CALL SortableGridDataModel::getRowCount() throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getRowCount(); + } + + //------------------------------------------------------------------------------------------------------------------ + ::sal_Int32 SAL_CALL SortableGridDataModel::getColumnCount() throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getColumnCount(); + } + + //------------------------------------------------------------------------------------------------------------------ + Any SAL_CALL SortableGridDataModel::getCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getCellData( i_columnIndex, rowIndex ); + } + + //------------------------------------------------------------------------------------------------------------------ + Any SAL_CALL SortableGridDataModel::getCellToolTip( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getCellToolTip( i_columnIndex, rowIndex ); + } + + //------------------------------------------------------------------------------------------------------------------ + Any SAL_CALL SortableGridDataModel::getRowHeading( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getRowHeading( rowIndex ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::disposing() + { + m_currentSortColumn = -1; + + Reference< XComponent > const delegatorComponent( m_delegator.get() ); + m_delegator->removeGridDataListener( this ); + m_delegator.clear(); + delegatorComponent->dispose(); + + Reference< XComponent > const collatorComponent( m_collator, UNO_QUERY ); + m_collator.clear(); + if ( collatorComponent.is() ) + collatorComponent->dispose(); + + lcl_clear( m_publicToPrivateRowIndex ); + lcl_clear( m_privateToPublicRowIndex ); + } + + //------------------------------------------------------------------------------------------------------------------ + Reference< XCloneable > SAL_CALL SortableGridDataModel::createClone( ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + return new SortableGridDataModel( *this ); + } + + //------------------------------------------------------------------------------------------------------------------ + ::rtl::OUString SAL_CALL SortableGridDataModel::getImplementationName( ) throw (RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.toolkit.SortableGridDataModel" ) ); + } + + //------------------------------------------------------------------------------------------------------------------ + ::sal_Bool SAL_CALL SortableGridDataModel::supportsService( const ::rtl::OUString& i_serviceName ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > const aServiceNames( getSupportedServiceNames() ); + for ( sal_Int32 i=0; i<aServiceNames.getLength(); ++i ) + if ( aServiceNames[i] == i_serviceName ) + return sal_True; + return sal_False; + } + + //------------------------------------------------------------------------------------------------------------------ + Sequence< ::rtl::OUString > SAL_CALL SortableGridDataModel::getSupportedServiceNames( ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > aServiceNames(1); + aServiceNames[0] = ::rtl::OUString::createFromAscii( szServiceName_SortableGridDataModel ); + return aServiceNames; + } + + //------------------------------------------------------------------------------------------------------------------ + ::sal_Int32 SortableGridDataModel::impl_getPrivateRowIndex_throw( ::sal_Int32 const i_publicRowIndex ) const + { + if ( ( i_publicRowIndex < 0 ) || ( i_publicRowIndex >= m_delegator->getRowCount() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *const_cast< SortableGridDataModel* >( this ) ); + + if ( !impl_isSorted_nothrow() ) + // no need to translate anything + return i_publicRowIndex; + + ENSURE_OR_RETURN( size_t( i_publicRowIndex ) < m_publicToPrivateRowIndex.size(), + "SortableGridDataModel::impl_getPrivateRowIndex_throw: inconsistency!", i_publicRowIndex ); + // obviously the translation table contains too few elements - it should have exactly |getRowCount()| + // elements + + return m_publicToPrivateRowIndex[ i_publicRowIndex ]; + } + + //------------------------------------------------------------------------------------------------------------------ + ::sal_Int32 SortableGridDataModel::impl_getPublicRowIndex_nothrow( ::sal_Int32 const i_privateRowIndex ) const + { + if ( !impl_isSorted_nothrow() ) + // no need to translate anything + return i_privateRowIndex; + + if ( i_privateRowIndex < 0 ) + return i_privateRowIndex; + + ENSURE_OR_RETURN( size_t( i_privateRowIndex ) < m_privateToPublicRowIndex.size(), + "SortableGridDataModel::impl_getPublicRowIndex_nothrow: invalid index!", i_privateRowIndex ); + + return m_privateToPublicRowIndex[ i_privateRowIndex ]; + } + +//...................................................................................................................... +} // namespace toolkit +//...................................................................................................................... + +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL SortableGridDataModel_CreateInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& i_factory ) +{ + return *( new ::toolkit::SortableGridDataModel( i_factory ) ); +} |