/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace css::awt; using namespace css::awt::grid; using namespace css::i18n; using namespace css::lang; using namespace css::ucb; using namespace css::uno; namespace { class SortableGridDataModel; class MethodGuard; typedef ::cppu::WeakComponentImplHelper < css::awt::grid::XSortableMutableGridDataModel , css::lang::XServiceInfo , css::lang::XInitialization > SortableGridDataModel_Base; typedef ::cppu::ImplHelper1 < css::awt::grid::XGridDataListener > SortableGridDataModel_PrivateBase; class SortableGridDataModel :public ::cppu::BaseMutex ,public SortableGridDataModel_Base ,public SortableGridDataModel_PrivateBase { public: explicit SortableGridDataModel( const css::uno::Reference< css::uno::XComponentContext > & rxContext ); SortableGridDataModel( SortableGridDataModel const & i_copySource ); bool isInitialized() const { return m_isInitialized; } protected: virtual ~SortableGridDataModel() override; public: // XSortableGridData virtual void SAL_CALL sortByColumn( ::sal_Int32 ColumnIndex, sal_Bool SortAscending ) override; virtual void SAL_CALL removeColumnSort( ) override; virtual css::beans::Pair< ::sal_Int32, sal_Bool > SAL_CALL getCurrentSortOrder( ) override; // XMutableGridDataModel virtual void SAL_CALL addRow( const css::uno::Any& Heading, const css::uno::Sequence< css::uno::Any >& Data ) override; virtual void SAL_CALL addRows( const css::uno::Sequence< css::uno::Any >& Headings, const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& Data ) override; virtual void SAL_CALL insertRow( ::sal_Int32 i_index, const css::uno::Any& i_heading, const css::uno::Sequence< css::uno::Any >& Data ) override; virtual void SAL_CALL insertRows( ::sal_Int32 i_index, const css::uno::Sequence< css::uno::Any>& Headings, const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& Data ) override; virtual void SAL_CALL removeRow( ::sal_Int32 RowIndex ) override; virtual void SAL_CALL removeAllRows( ) override; virtual void SAL_CALL updateCellData( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const css::uno::Any& Value ) override; virtual void SAL_CALL updateRowData( const css::uno::Sequence< ::sal_Int32 >& ColumnIndexes, ::sal_Int32 RowIndex, const css::uno::Sequence< css::uno::Any >& Values ) override; virtual void SAL_CALL updateRowHeading( ::sal_Int32 RowIndex, const css::uno::Any& Heading ) override; virtual void SAL_CALL updateCellToolTip( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const css::uno::Any& Value ) override; virtual void SAL_CALL updateRowToolTip( ::sal_Int32 RowIndex, const css::uno::Any& Value ) override; virtual void SAL_CALL addGridDataListener( const css::uno::Reference< css::awt::grid::XGridDataListener >& Listener ) override; virtual void SAL_CALL removeGridDataListener( const css::uno::Reference< css::awt::grid::XGridDataListener >& Listener ) override; // XGridDataModel virtual ::sal_Int32 SAL_CALL getRowCount() override; virtual ::sal_Int32 SAL_CALL getColumnCount() override; virtual css::uno::Any SAL_CALL getCellData( ::sal_Int32 Column, ::sal_Int32 RowIndex ) override; virtual css::uno::Any SAL_CALL getCellToolTip( ::sal_Int32 Column, ::sal_Int32 RowIndex ) override; virtual css::uno::Any SAL_CALL getRowHeading( ::sal_Int32 RowIndex ) override; virtual css::uno::Sequence< css::uno::Any > SAL_CALL getRowData( ::sal_Int32 RowIndex ) override; // OComponentHelper virtual void SAL_CALL disposing() override; // XCloneable virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override; // XServiceInfo virtual OUString SAL_CALL getImplementationName( ) override; virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; // XInitialization virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; // XGridDataListener virtual void SAL_CALL rowsInserted( const css::awt::grid::GridDataEvent& Event ) override; virtual void SAL_CALL rowsRemoved( const css::awt::grid::GridDataEvent& Event ) override; virtual void SAL_CALL dataChanged( const css::awt::grid::GridDataEvent& Event ) override; virtual void SAL_CALL rowHeadingChanged( const css::awt::grid::GridDataEvent& Event ) override; // XEventListener virtual void SAL_CALL disposing( const css::lang::EventObject& i_event ) override; // XInterface virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; virtual void SAL_CALL acquire( ) noexcept final override; virtual void SAL_CALL release( ) noexcept override; // XTypeProvider virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL getImplementationId( ) override; private: /** translates the given public index into one to be passed to our delegator @throws css::lang::IndexOutOfBoundsException if the given index does not denote a valid row */ ::sal_Int32 impl_getPrivateRowIndex_throw( ::sal_Int32 const i_publicRowIndex ) const; /** translates the given private row index to a public one */ ::sal_Int32 impl_getPublicRowIndex_nothrow( ::sal_Int32 const i_privateRowIndex ) const; bool impl_isSorted_nothrow() const { return m_currentSortColumn >= 0; } /** rebuilds the index translation structure. Neither m_currentSortColumn nor m_sortAscending are touched by this method. Also, the given column index is not checked, this is the responsibility of the caller. */ bool impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, bool const i_sortAscending ); /** translates the given event, obtained from our delegator, to a version which can be broadcasted to our own clients. */ css::awt::grid::GridDataEvent impl_createPublicEvent( css::awt::grid::GridDataEvent const & i_originalEvent ) const; /** broadcasts the given event to our registered XGridDataListeners */ void impl_broadcast( void ( SAL_CALL css::awt::grid::XGridDataListener::*i_listenerMethod )( const css::awt::grid::GridDataEvent & ), css::awt::grid::GridDataEvent const & i_publicEvent, MethodGuard& i_instanceLock ); /** rebuilds our indexes, notifying row removal and row addition events First, a rowsRemoved event is notified to our registered listeners. Then, the index translation tables are rebuilt, and a rowsInserted event is notified. Only to be called when we're sorted. */ void impl_rebuildIndexesAndNotify( MethodGuard& i_instanceLock ); /** removes the current sorting, and notifies a change of all data */ void impl_removeColumnSort( MethodGuard& i_instanceLock ); /** removes the current sorting, without any broadcast */ void impl_removeColumnSort_noBroadcast(); private: css::uno::Reference< css::uno::XComponentContext > m_xContext; bool m_isInitialized; css::uno::Reference< css::awt::grid::XMutableGridDataModel > m_delegator; css::uno::Reference< css::i18n::XCollator > m_collator; ::sal_Int32 m_currentSortColumn; bool m_sortAscending; ::std::vector< ::sal_Int32 > m_publicToPrivateRowIndex; ::std::vector< ::sal_Int32 > m_privateToPublicRowIndex; }; class MethodGuard : public ::comphelper::ComponentGuard { public: MethodGuard( SortableGridDataModel& i_component, ::cppu::OBroadcastHelper & i_broadcastHelper ) :comphelper::ComponentGuard( i_component, i_broadcastHelper ) { if ( !i_component.isInitialized() ) throw css::lang::NotInitializedException( OUString(), i_component ); } }; template< class STLCONTAINER > void lcl_clear( STLCONTAINER& i_container ) { STLCONTAINER().swap(i_container); } SortableGridDataModel::SortableGridDataModel( Reference< XComponentContext > const & rxContext ) :SortableGridDataModel_Base( m_aMutex ) ,SortableGridDataModel_PrivateBase() ,m_xContext( rxContext ) ,m_isInitialized( false ) ,m_delegator() ,m_collator() ,m_currentSortColumn( -1 ) ,m_sortAscending( true ) ,m_publicToPrivateRowIndex() ,m_privateToPublicRowIndex() { } SortableGridDataModel::SortableGridDataModel( SortableGridDataModel const & i_copySource ) :cppu::BaseMutex() ,SortableGridDataModel_Base( m_aMutex ) ,SortableGridDataModel_PrivateBase() ,m_xContext( i_copySource.m_xContext ) ,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 ) { 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(); } } Any SAL_CALL SortableGridDataModel::queryInterface( const Type& aType ) { Any aReturn( SortableGridDataModel_Base::queryInterface( aType ) ); if ( !aReturn.hasValue() ) aReturn = SortableGridDataModel_PrivateBase::queryInterface( aType ); return aReturn; } void SAL_CALL SortableGridDataModel::acquire( ) noexcept { SortableGridDataModel_Base::acquire(); } void SAL_CALL SortableGridDataModel::release( ) noexcept { SortableGridDataModel_Base::release(); } Sequence< Type > SAL_CALL SortableGridDataModel::getTypes( ) { 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( ) { return css::uno::Sequence(); } Reference< XCollator > lcl_loadDefaultCollator_throw( const Reference & rxContext ) { Reference< XCollator > const xCollator = Collator::create( rxContext ); xCollator->loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 ); return xCollator; } void SAL_CALL SortableGridDataModel::initialize( const Sequence< Any >& i_arguments ) { ::comphelper::ComponentGuard aGuard( *this, rBHelper ); if ( m_delegator.is() ) throw AlreadyInitializedException( 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_xContext ); 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( OUString(), *this, 2 ); break; } if ( !xDelegator.is() ) throw IllegalArgumentException( 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( cppu::UnoType::get() ); if ( pListeners == nullptr ) return; i_instanceLock.clear(); pListeners->notifyEach( i_listenerMethod, i_publicEvent ); } void SAL_CALL SortableGridDataModel::rowsInserted( const GridDataEvent& i_event ) { MethodGuard aGuard( *this, rBHelper ); if ( impl_isSorted_nothrow() ) { // no infrastructure is in place currently to sort the new row to its proper location, // so we remove the sorting here. impl_removeColumnSort( aGuard ); aGuard.reset(); } GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); impl_broadcast( &XGridDataListener::rowsInserted, aEvent, aGuard ); } void lcl_decrementValuesGreaterThan( ::std::vector< ::sal_Int32 > & io_indexMap, sal_Int32 const i_threshold ) { for ( auto& rIndex : io_indexMap ) { if ( rIndex >= i_threshold ) --rIndex; } } 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 ); // rebuild the index if ( !impl_reIndex_nothrow( m_currentSortColumn, m_sortAscending ) ) { impl_removeColumnSort( i_instanceLock ); return; } // 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(); // 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 ) { MethodGuard aGuard( *this, rBHelper ); // 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 ( o3tl::make_unsigned( 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 ) { MethodGuard aGuard( *this, rBHelper ); GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); impl_broadcast( &XGridDataListener::dataChanged, aEvent, aGuard ); } void SAL_CALL SortableGridDataModel::rowHeadingChanged( const GridDataEvent& i_event ) { MethodGuard aGuard( *this, rBHelper ); GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); impl_broadcast( &XGridDataListener::rowHeadingChanged, aEvent, aGuard ); } void SAL_CALL SortableGridDataModel::disposing( const EventObject& ) { } class CellDataLessComparison { public: CellDataLessComparison( ::std::vector< Any > const & i_data, ::comphelper::IKeyPredicateLess const & i_predicate, 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 ]; // 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; bool const m_sortAscending; }; bool SortableGridDataModel::impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, 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::unique_ptr< ::comphelper::IKeyPredicateLess > const pPredicate( ::comphelper::getStandardLessPredicate( dataType, m_collator ) ); ENSURE_OR_RETURN_FALSE( pPredicate, "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("toolkit.controls"); return false; } // also build the "private to public" mapping ::std::vector< sal_Int32 > aPrivateToPublic( aPublicToPrivate.size() ); for ( size_t i=0; i= getColumnCount() ) ) throw IndexOutOfBoundsException( OUString(), *this ); if ( !impl_reIndex_nothrow( i_columnIndex, i_sortAscending ) ) return; m_currentSortColumn = i_columnIndex; m_sortAscending = i_sortAscending; impl_broadcast( &XGridDataListener::dataChanged, GridDataEvent( *this, -1, -1, -1, -1 ), aGuard ); } void SortableGridDataModel::impl_removeColumnSort_noBroadcast() { lcl_clear( m_publicToPrivateRowIndex ); lcl_clear( m_privateToPublicRowIndex ); m_currentSortColumn = -1; m_sortAscending = true; } void SortableGridDataModel::impl_removeColumnSort( MethodGuard& i_instanceLock ) { impl_removeColumnSort_noBroadcast(); impl_broadcast( &XGridDataListener::dataChanged, GridDataEvent( *this, -1, -1, -1, -1 ), i_instanceLock ); } void SAL_CALL SortableGridDataModel::removeColumnSort( ) { MethodGuard aGuard( *this, rBHelper ); impl_removeColumnSort( aGuard ); } css::beans::Pair< ::sal_Int32, sal_Bool > SAL_CALL SortableGridDataModel::getCurrentSortOrder( ) { MethodGuard aGuard( *this, rBHelper ); return css::beans::Pair< ::sal_Int32, sal_Bool >( m_currentSortColumn, m_sortAscending ); } void SAL_CALL SortableGridDataModel::addRow( const Any& i_heading, const Sequence< Any >& i_data ) { MethodGuard aGuard( *this, rBHelper ); 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 ) { MethodGuard aGuard( *this, rBHelper ); Reference< XMutableGridDataModel > const delegator( m_delegator ); aGuard.clear(); delegator->addRows( i_headings, i_data ); } void SAL_CALL SortableGridDataModel::insertRow( ::sal_Int32 i_index, const Any& i_heading, const Sequence< Any >& i_data ) { MethodGuard aGuard( *this, rBHelper ); ::sal_Int32 const rowIndex = i_index == getRowCount() ? i_index : impl_getPrivateRowIndex_throw( i_index ); // note that |RowCount| is a valid index in this method, but not for impl_getPrivateRowIndex_throw Reference< XMutableGridDataModel > const delegator( m_delegator ); aGuard.clear(); delegator->insertRow( rowIndex, i_heading, i_data ); } void SAL_CALL SortableGridDataModel::insertRows( ::sal_Int32 i_index, const Sequence< Any>& i_headings, const Sequence< Sequence< Any > >& i_data ) { MethodGuard aGuard( *this, rBHelper ); ::sal_Int32 const rowIndex = i_index == getRowCount() ? i_index : impl_getPrivateRowIndex_throw( i_index ); // note that |RowCount| is a valid index in this method, but not for impl_getPrivateRowIndex_throw Reference< XMutableGridDataModel > const delegator( m_delegator ); aGuard.clear(); delegator->insertRows( rowIndex, i_headings, i_data ); } void SAL_CALL SortableGridDataModel::removeRow( ::sal_Int32 i_rowIndex ) { MethodGuard aGuard( *this, rBHelper ); ::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( ) { MethodGuard aGuard( *this, rBHelper ); 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 ) { MethodGuard aGuard( *this, rBHelper ); ::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 ) { MethodGuard aGuard( *this, rBHelper ); ::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 ) { MethodGuard aGuard( *this, rBHelper ); ::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 ) { MethodGuard aGuard( *this, rBHelper ); ::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 ) { MethodGuard aGuard( *this, rBHelper ); ::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 ) { rBHelper.addListener( cppu::UnoType::get(), i_listener ); } void SAL_CALL SortableGridDataModel::removeGridDataListener( const Reference< XGridDataListener >& i_listener ) { rBHelper.removeListener( cppu::UnoType::get(), i_listener ); } ::sal_Int32 SAL_CALL SortableGridDataModel::getRowCount() { MethodGuard aGuard( *this, rBHelper ); Reference< XMutableGridDataModel > const delegator( m_delegator ); aGuard.clear(); return delegator->getRowCount(); } ::sal_Int32 SAL_CALL SortableGridDataModel::getColumnCount() { MethodGuard aGuard( *this, rBHelper ); Reference< XMutableGridDataModel > const delegator( m_delegator ); aGuard.clear(); return delegator->getColumnCount(); } Any SAL_CALL SortableGridDataModel::getCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) { MethodGuard aGuard( *this, rBHelper ); ::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 ) { MethodGuard aGuard( *this, rBHelper ); ::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 ) { MethodGuard aGuard( *this, rBHelper ); ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); Reference< XMutableGridDataModel > const delegator( m_delegator ); aGuard.clear(); return delegator->getRowHeading( rowIndex ); } Sequence< Any > SAL_CALL SortableGridDataModel::getRowData( ::sal_Int32 i_rowIndex ) { MethodGuard aGuard( *this, rBHelper ); ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); Reference< XMutableGridDataModel > const delegator( m_delegator ); aGuard.clear(); return delegator->getRowData( rowIndex ); } void SAL_CALL SortableGridDataModel::disposing() { m_currentSortColumn = -1; Reference< XComponent > const delegatorComponent( m_delegator ); 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< css::util::XCloneable > SAL_CALL SortableGridDataModel::createClone( ) { MethodGuard aGuard( *this, rBHelper ); return new SortableGridDataModel( *this ); } OUString SAL_CALL SortableGridDataModel::getImplementationName( ) { return "org.openoffice.comp.toolkit.SortableGridDataModel"; } sal_Bool SAL_CALL SortableGridDataModel::supportsService( const OUString& i_serviceName ) { return cppu::supportsService(this, i_serviceName); } Sequence< OUString > SAL_CALL SortableGridDataModel::getSupportedServiceNames( ) { return { "com.sun.star.awt.grid.SortableGridDataModel" }; } ::sal_Int32 SortableGridDataModel::impl_getPrivateRowIndex_throw( ::sal_Int32 const i_publicRowIndex ) const { if ( ( i_publicRowIndex < 0 ) || ( i_publicRowIndex >= m_delegator->getRowCount() ) ) throw IndexOutOfBoundsException( OUString(), *const_cast< SortableGridDataModel* >( this ) ); if ( !impl_isSorted_nothrow() ) // no need to translate anything return i_publicRowIndex; ENSURE_OR_RETURN( o3tl::make_unsigned( 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( o3tl::make_unsigned( i_privateRowIndex ) < m_privateToPublicRowIndex.size(), "SortableGridDataModel::impl_getPublicRowIndex_nothrow: invalid index!", i_privateRowIndex ); return m_privateToPublicRowIndex[ i_privateRowIndex ]; } } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * org_openoffice_comp_toolkit_SortableGridDataModel_get_implementation( css::uno::XComponentContext *context, css::uno::Sequence const &) { return cppu::acquire(new SortableGridDataModel(context)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */