1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25  ************************************************************************/
26 
27 #include "precompiled_toolkit.hxx"
28 
29 #include "sortablegriddatamodel.hxx"
30 #include "toolkit/helper/servicenames.hxx"
31 
32 /** === begin UNO includes === **/
33 #include <com/sun/star/i18n/XCollator.hpp>
34 #include <com/sun/star/lang/IllegalArgumentException.hpp>
35 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
36 /** === end UNO includes === **/
37 
38 #include <comphelper/anycompare.hxx>
39 #include <cppuhelper/typeprovider.hxx>
40 #include <tools/diagnose_ex.h>
41 #include <tools/debug.hxx>
42 #include <vcl/svapp.hxx>
43 
44 #include <set>
45 
46 //......................................................................................................................
47 namespace toolkit
48 {
49 //......................................................................................................................
50 
51 	/** === begin UNO using === **/
52     using ::com::sun::star::uno::TypeClass;
53     using ::com::sun::star::uno::TypeClass_VOID;
54 	using ::com::sun::star::uno::Reference;
55 	using ::com::sun::star::uno::XInterface;
56 	using ::com::sun::star::uno::UNO_QUERY;
57 	using ::com::sun::star::uno::UNO_QUERY_THROW;
58 	using ::com::sun::star::uno::UNO_SET_THROW;
59 	using ::com::sun::star::uno::Exception;
60 	using ::com::sun::star::uno::RuntimeException;
61 	using ::com::sun::star::uno::Any;
62 	using ::com::sun::star::uno::makeAny;
63 	using ::com::sun::star::uno::Sequence;
64 	using ::com::sun::star::uno::Type;
65     using ::com::sun::star::lang::IndexOutOfBoundsException;
66     using ::com::sun::star::lang::IllegalArgumentException;
67     using ::com::sun::star::awt::grid::XGridDataListener;
68     using ::com::sun::star::beans::Pair;
69     using ::com::sun::star::util::XCloneable;
70     using ::com::sun::star::i18n::XCollator;
71     using ::com::sun::star::lang::IllegalArgumentException;
72     using ::com::sun::star::lang::XMultiServiceFactory;
73     using ::com::sun::star::awt::grid::GridDataEvent;
74     using ::com::sun::star::lang::EventObject;
75     using ::com::sun::star::ucb::AlreadyInitializedException;
76 	/** === end UNO using === **/
77 
78 #ifdef DBG_UTIL
79     const char* SortableGridDataModel_checkInvariants( const void* _pInstance )
80     {
81         return static_cast< const SortableGridDataModel* >( _pInstance )->checkInvariants();
82     }
83 
84 	//------------------------------------------------------------------------------------------------------------------
85     const char* SortableGridDataModel::checkInvariants() const
86     {
87         if ( m_publicToPrivateRowIndex.size() != m_privateToPublicRowIndex.size() )
88             return "inconsistent index maps";
89 
90         if ( m_delegator.is() )
91         {
92             if ( m_publicToPrivateRowIndex.size() != size_t( m_delegator->getRowCount() ) )
93                 return "wrong cached row count";
94         }
95         else
96         {
97             if ( !m_publicToPrivateRowIndex.empty() )
98                 return "disposed or not initialized, but having a non-empty map";
99         }
100 
101         for ( size_t publicIndex=0; publicIndex<m_publicToPrivateRowIndex.size(); ++publicIndex )
102         {
103             ::sal_Int32 const privateIndex = m_publicToPrivateRowIndex[ publicIndex ];
104             if ( ( privateIndex < 0 ) || ( size_t( privateIndex ) >= m_privateToPublicRowIndex.size() ) )
105                 return "invalid cached private index";
106 
107             if ( m_privateToPublicRowIndex[ privateIndex ] != sal_Int32( publicIndex ) )
108                 return "index map traversal not commutavive";
109         }
110 
111         if ( impl_isSorted_nothrow() && m_publicToPrivateRowIndex.empty() )
112             return "sorted, but no row index translation tables";
113 
114         if ( !impl_isSorted_nothrow() && !m_publicToPrivateRowIndex.empty() )
115             return "unsorted, but have index translation tables";
116 
117         return NULL;
118     }
119 #endif
120 
121 #define DBG_CHECK_ME() \
122     DBG_CHKTHIS( SortableGridDataModel, SortableGridDataModel_checkInvariants )
123 
124 	//------------------------------------------------------------------------------------------------------------------
125     namespace
126     {
127         template< class STLCONTAINER >
128         static void lcl_clear( STLCONTAINER& i_container )
129         {
130             STLCONTAINER empty;
131             empty.swap( i_container );
132         }
133     }
134 
135 	//==================================================================================================================
136 	//= SortableGridDataModel
137 	//==================================================================================================================
138     DBG_NAME( SortableGridDataModel )
139 	//------------------------------------------------------------------------------------------------------------------
140     SortableGridDataModel::SortableGridDataModel( Reference< XMultiServiceFactory > const & i_factory )
141         :SortableGridDataModel_Base( m_aMutex )
142         ,SortableGridDataModel_PrivateBase()
143         ,m_context( i_factory )
144         ,m_isInitialized( false )
145         ,m_delegator()
146         ,m_collator()
147         ,m_currentSortColumn( -1 )
148         ,m_sortAscending( true )
149         ,m_publicToPrivateRowIndex()
150         ,m_privateToPublicRowIndex()
151     {
152         DBG_CTOR( SortableGridDataModel, SortableGridDataModel_checkInvariants );
153     }
154 
155 	//------------------------------------------------------------------------------------------------------------------
156     SortableGridDataModel::SortableGridDataModel( SortableGridDataModel const & i_copySource )
157         :cppu::BaseMutex()
158         ,SortableGridDataModel_Base( m_aMutex )
159         ,SortableGridDataModel_PrivateBase()
160         ,m_context( i_copySource.m_context )
161         ,m_isInitialized( true )
162         ,m_delegator()
163         ,m_collator( i_copySource.m_collator )
164         ,m_currentSortColumn( i_copySource.m_currentSortColumn )
165         ,m_sortAscending( i_copySource.m_sortAscending )
166         ,m_publicToPrivateRowIndex( i_copySource.m_publicToPrivateRowIndex )
167         ,m_privateToPublicRowIndex( i_copySource.m_privateToPublicRowIndex )
168     {
169         DBG_CTOR( SortableGridDataModel, SortableGridDataModel_checkInvariants );
170 
171         ENSURE_OR_THROW( i_copySource.m_delegator.is(),
172             "not expected to be called for a disposed copy source!" );
173         m_delegator.set( i_copySource.m_delegator->createClone(), UNO_QUERY_THROW );
174     }
175 
176 	//------------------------------------------------------------------------------------------------------------------
177     SortableGridDataModel::~SortableGridDataModel()
178     {
179         if ( !rBHelper.bDisposed )
180         {
181             acquire();
182             dispose();
183         }
184 
185         DBG_DTOR( SortableGridDataModel, SortableGridDataModel_checkInvariants );
186     }
187 
188     //------------------------------------------------------------------------------------------------------------------
189     Any SAL_CALL SortableGridDataModel::queryInterface( const Type& aType ) throw (RuntimeException)
190     {
191         Any aReturn( SortableGridDataModel_Base::queryInterface( aType ) );
192         if ( !aReturn.hasValue() )
193             aReturn = SortableGridDataModel_PrivateBase::queryInterface( aType );
194         return aReturn;
195     }
196 
197     //------------------------------------------------------------------------------------------------------------------
198     void SAL_CALL SortableGridDataModel::acquire(  ) throw ()
199     {
200         SortableGridDataModel_Base::acquire();
201     }
202 
203     //------------------------------------------------------------------------------------------------------------------
204     void SAL_CALL SortableGridDataModel::release(  ) throw ()
205     {
206         SortableGridDataModel_Base::release();
207     }
208 
209     //------------------------------------------------------------------------------------------------------------------
210     Sequence< Type > SAL_CALL SortableGridDataModel::getTypes(  ) throw (RuntimeException)
211     {
212         return SortableGridDataModel_Base::getTypes();
213         // don't expose the types got via SortableGridDataModel_PrivateBase - they're private, after all
214     }
215 
216     //------------------------------------------------------------------------------------------------------------------
217     Sequence< ::sal_Int8 > SAL_CALL SortableGridDataModel::getImplementationId(  ) throw (RuntimeException)
218     {
219         static ::cppu::OImplementationId aId;
220         return aId.getImplementationId();
221     }
222 
223     //------------------------------------------------------------------------------------------------------------------
224     namespace
225     {
226         Reference< XCollator > lcl_loadDefaultCollator_throw( ::comphelper::ComponentContext const & i_context )
227         {
228             Reference< XCollator > const xCollator( i_context.createComponent( "com.sun.star.i18n.Collator" ), UNO_QUERY_THROW );
229 		    xCollator->loadDefaultCollator( Application::GetSettings().GetLocale(), 0 );
230             return xCollator;
231         }
232     }
233 
234     //------------------------------------------------------------------------------------------------------------------
235     void SAL_CALL SortableGridDataModel::initialize( const Sequence< Any >& i_arguments ) throw (Exception, RuntimeException)
236     {
237         ::comphelper::ComponentGuard aGuard( *this, rBHelper );
238         DBG_CHECK_ME();
239 
240         if ( m_delegator.is() )
241             throw AlreadyInitializedException( ::rtl::OUString(), *this );
242 
243         Reference< XMutableGridDataModel > xDelegator;
244         Reference< XCollator > xCollator;
245         switch ( i_arguments.getLength() )
246         {
247         case 1: // SortableGridDataModel.create( XMutableGridDataModel )
248             xDelegator.set( i_arguments[0], UNO_QUERY );
249             xCollator = lcl_loadDefaultCollator_throw( m_context );
250             break;
251 
252         case 2: // SortableGridDataModel.createWithCollator( XMutableGridDataModel, XCollator )
253             xDelegator.set( i_arguments[0], UNO_QUERY );
254             xCollator.set( i_arguments[1], UNO_QUERY );
255             if ( !xCollator.is() )
256                 throw IllegalArgumentException( ::rtl::OUString(), *this, 2 );
257             break;
258         }
259         if ( !xDelegator.is() )
260             throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
261 
262         m_delegator = xDelegator;
263         m_collator = xCollator;
264 
265         m_delegator->addGridDataListener( this );
266 
267         m_isInitialized = true;
268     }
269 
270     //------------------------------------------------------------------------------------------------------------------
271     GridDataEvent SortableGridDataModel::impl_createPublicEvent( GridDataEvent const & i_originalEvent ) const
272     {
273         GridDataEvent aEvent( i_originalEvent );
274         aEvent.Source = *const_cast< SortableGridDataModel* >( this );
275         aEvent.FirstRow = impl_getPublicRowIndex_nothrow( aEvent.FirstRow );
276         aEvent.LastRow = impl_getPublicRowIndex_nothrow( aEvent.LastRow );
277         return aEvent;
278     }
279 
280     //------------------------------------------------------------------------------------------------------------------
281     void SortableGridDataModel::impl_broadcast( void ( SAL_CALL XGridDataListener::*i_listenerMethod )( const GridDataEvent & ),
282             GridDataEvent const & i_publicEvent, MethodGuard& i_instanceLock )
283     {
284         ::cppu::OInterfaceContainerHelper* pListeners = rBHelper.getContainer( XGridDataListener::static_type() );
285         if ( pListeners == NULL )
286             return;
287 
288         i_instanceLock.clear();
289         pListeners->notifyEach( i_listenerMethod, i_publicEvent );
290     }
291 
292     //------------------------------------------------------------------------------------------------------------------
293     void SAL_CALL SortableGridDataModel::rowsInserted( const GridDataEvent& i_event ) throw (RuntimeException)
294     {
295         MethodGuard aGuard( *this, rBHelper );
296         DBG_CHECK_ME();
297 
298         if ( impl_isSorted_nothrow() )
299         {
300             // no infrastructure is in place currently to sort the new row to its proper location,
301             // so we remove the sorting here.
302             impl_removeColumnSort( aGuard );
303             aGuard.reset();
304         }
305 
306         GridDataEvent const aEvent( impl_createPublicEvent( i_event ) );
307         impl_broadcast( &XGridDataListener::rowsInserted, aEvent, aGuard );
308     }
309 
310     //------------------------------------------------------------------------------------------------------------------
311     namespace
312     {
313         void lcl_decrementValuesGreaterThan( ::std::vector< ::sal_Int32 > & io_indexMap, sal_Int32 const i_threshold )
314         {
315             for (   ::std::vector< ::sal_Int32 >::iterator loop = io_indexMap.begin();
316                     loop != io_indexMap.end();
317                     ++loop
318                 )
319             {
320                 if ( *loop >= i_threshold )
321                     --*loop;
322             }
323         }
324     }
325 
326     //------------------------------------------------------------------------------------------------------------------
327     void SortableGridDataModel::impl_rebuildIndexesAndNotify( MethodGuard& i_instanceLock )
328     {
329         OSL_PRECOND( impl_isSorted_nothrow(), "SortableGridDataModel::impl_rebuildIndexesAndNotify: illegal call!" );
330 
331         // clear the indexes
332         lcl_clear( m_publicToPrivateRowIndex );
333         lcl_clear( m_privateToPublicRowIndex );
334 
335         // rebuild the index
336         if ( !impl_reIndex_nothrow( m_currentSortColumn, m_sortAscending ) )
337         {
338             impl_removeColumnSort( i_instanceLock );
339             return;
340         }
341 
342         // broadcast an artificial event, saying that all rows have been removed
343         GridDataEvent const aRemovalEvent( *this, -1, -1, -1, -1 );
344         impl_broadcast( &XGridDataListener::rowsRemoved, aRemovalEvent, i_instanceLock );
345         i_instanceLock.reset();
346 
347         // broadcast an artificial event, saying that n rows have been added
348         GridDataEvent const aAdditionEvent( *this, -1, -1, 0, m_delegator->getRowCount() - 1 );
349         impl_broadcast( &XGridDataListener::rowsInserted, aAdditionEvent, i_instanceLock );
350     }
351 
352     //------------------------------------------------------------------------------------------------------------------
353     void SAL_CALL SortableGridDataModel::rowsRemoved( const GridDataEvent& i_event ) throw (RuntimeException)
354     {
355         MethodGuard aGuard( *this, rBHelper );
356         DBG_CHECK_ME();
357 
358         // if the data is not sorted, broadcast the event unchanged
359         if ( !impl_isSorted_nothrow() )
360         {
361             GridDataEvent const aEvent( impl_createPublicEvent( i_event ) );
362             impl_broadcast( &XGridDataListener::rowsRemoved, aEvent, aGuard );
363             return;
364         }
365 
366         // if all rows have been removed, also simply multiplex to own listeners
367         if ( i_event.FirstRow < 0 )
368         {
369             lcl_clear( m_publicToPrivateRowIndex );
370             lcl_clear( m_privateToPublicRowIndex );
371             GridDataEvent aEvent( i_event );
372             aEvent.Source = *this;
373             impl_broadcast( &XGridDataListener::rowsRemoved, aEvent, aGuard );
374             return;
375         }
376 
377         bool needReIndex = false;
378         if ( i_event.FirstRow != i_event.LastRow )
379         {
380             OSL_ENSURE( false, "SortableGridDataModel::rowsRemoved: missing implementation - removal of multiple rows!" );
381             needReIndex = true;
382         }
383         else if ( size_t( i_event.FirstRow ) >= m_privateToPublicRowIndex.size() )
384         {
385             OSL_ENSURE( false, "SortableGridDataModel::rowsRemoved: inconsistent/wrong data!" );
386             needReIndex = true;
387         }
388 
389         if ( needReIndex )
390         {
391             impl_rebuildIndexesAndNotify( aGuard );
392             return;
393         }
394 
395         // build public event version
396         GridDataEvent const aEvent( impl_createPublicEvent( i_event ) );
397 
398         // remove the entries from the index maps
399         sal_Int32 const privateIndex = i_event.FirstRow;
400         sal_Int32 const publicIndex = aEvent.FirstRow;
401 
402         m_publicToPrivateRowIndex.erase( m_publicToPrivateRowIndex.begin() + publicIndex );
403         m_privateToPublicRowIndex.erase( m_privateToPublicRowIndex.begin() + privateIndex );
404 
405         // adjust remaining entries in the index maps
406         lcl_decrementValuesGreaterThan( m_publicToPrivateRowIndex, privateIndex );
407         lcl_decrementValuesGreaterThan( m_privateToPublicRowIndex, publicIndex );
408 
409         // broadcast the event
410         impl_broadcast( &XGridDataListener::rowsRemoved, aEvent, aGuard );
411     }
412 
413     //------------------------------------------------------------------------------------------------------------------
414     void SAL_CALL SortableGridDataModel::dataChanged( const GridDataEvent& i_event ) throw (RuntimeException)
415     {
416         MethodGuard aGuard( *this, rBHelper );
417         DBG_CHECK_ME();
418 
419         GridDataEvent const aEvent( impl_createPublicEvent( i_event ) );
420         impl_broadcast( &XGridDataListener::dataChanged, aEvent, aGuard );
421     }
422 
423     //------------------------------------------------------------------------------------------------------------------
424     void SAL_CALL SortableGridDataModel::rowHeadingChanged( const GridDataEvent& i_event ) throw (RuntimeException)
425     {
426         MethodGuard aGuard( *this, rBHelper );
427         DBG_CHECK_ME();
428 
429         GridDataEvent const aEvent( impl_createPublicEvent( i_event ) );
430         impl_broadcast( &XGridDataListener::rowHeadingChanged, aEvent, aGuard );
431     }
432 
433     //------------------------------------------------------------------------------------------------------------------
434     void SAL_CALL SortableGridDataModel::disposing( const EventObject& i_event ) throw (RuntimeException)
435     {
436         // not interested in
437         OSL_UNUSED( i_event );
438     }
439 
440     //------------------------------------------------------------------------------------------------------------------
441     namespace
442     {
443         class CellDataLessComparison : public ::std::binary_function< sal_Int32, sal_Int32, bool >
444         {
445         public:
446             CellDataLessComparison(
447                 ::std::vector< Any > const & i_data,
448                 ::comphelper::IKeyPredicateLess& i_predicate,
449                 sal_Bool const i_sortAscending
450             )
451                 :m_data( i_data )
452                 ,m_predicate( i_predicate )
453                 ,m_sortAscending( i_sortAscending )
454             {
455             }
456 
457             bool operator()( sal_Int32 const i_lhs, sal_Int32 const i_rhs ) const
458             {
459                 Any const & lhs = m_data[ i_lhs ];
460                 Any const & rhs = m_data[ i_rhs ];
461                 // <VOID/> is less than everything else
462                 if ( !lhs.hasValue() )
463                     return m_sortAscending;
464                 if ( !rhs.hasValue() )
465                     return !m_sortAscending;
466 
467                 // actually compare
468                 if ( m_sortAscending )
469                     return m_predicate.isLess( lhs, rhs );
470                 else
471                     return m_predicate.isLess( rhs, lhs );
472             }
473 
474         private:
475             ::std::vector< Any > const &            m_data;
476             ::comphelper::IKeyPredicateLess const & m_predicate;
477             sal_Bool const                          m_sortAscending;
478         };
479     }
480 
481     //------------------------------------------------------------------------------------------------------------------
482     bool SortableGridDataModel::impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, sal_Bool const i_sortAscending )
483     {
484         ::sal_Int32 const rowCount( getRowCount() );
485         ::std::vector< ::sal_Int32 > aPublicToPrivate( rowCount );
486 
487         try
488         {
489             // build an unsorted translation table, and retrieve the unsorted data
490             ::std::vector< Any > aColumnData( rowCount );
491             Type dataType;
492             for ( ::sal_Int32 rowIndex = 0; rowIndex < rowCount; ++rowIndex )
493             {
494                 aColumnData[ rowIndex ] = m_delegator->getCellData( i_columnIndex, rowIndex );
495                 aPublicToPrivate[ rowIndex ] = rowIndex;
496 
497                 // determine the data types we assume for the complete column
498                 if ( ( dataType.getTypeClass() == TypeClass_VOID ) && aColumnData[ rowIndex ].hasValue() )
499                     dataType = aColumnData[ rowIndex ].getValueType();
500             }
501 
502             // get predicate object
503             ::std::auto_ptr< ::comphelper::IKeyPredicateLess > const pPredicate( ::comphelper::getStandardLessPredicate( dataType, m_collator ) );
504             ENSURE_OR_RETURN_FALSE( pPredicate.get(), "SortableGridDataModel::impl_reIndex_nothrow: no sortable data found!" );
505 
506             // then sort
507             CellDataLessComparison const aComparator( aColumnData, *pPredicate, i_sortAscending );
508             ::std::sort( aPublicToPrivate.begin(), aPublicToPrivate.end(), aComparator );
509         }
510         catch( const Exception& )
511         {
512         	DBG_UNHANDLED_EXCEPTION();
513             return false;
514         }
515 
516         // also build the "private to public" mapping
517         ::std::vector< sal_Int32 > aPrivateToPublic( aPublicToPrivate.size() );
518         for ( size_t i=0; i<aPublicToPrivate.size(); ++i )
519             aPrivateToPublic[ aPublicToPrivate[i] ] = i;
520 
521         m_publicToPrivateRowIndex.swap( aPublicToPrivate );
522         m_privateToPublicRowIndex.swap( aPrivateToPublic );
523 
524         return true;
525     }
526 
527     //------------------------------------------------------------------------------------------------------------------
528     void SAL_CALL SortableGridDataModel::sortByColumn( ::sal_Int32 i_columnIndex, ::sal_Bool i_sortAscending ) throw (IndexOutOfBoundsException, RuntimeException)
529     {
530         MethodGuard aGuard( *this, rBHelper );
531         DBG_CHECK_ME();
532 
533         if ( ( i_columnIndex < 0 ) || ( i_columnIndex >= getColumnCount() ) )
534             throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
535 
536         if ( !impl_reIndex_nothrow( i_columnIndex, i_sortAscending ) )
537             return;
538 
539         m_currentSortColumn = i_columnIndex;
540         m_sortAscending = i_sortAscending;
541 
542         impl_broadcast(
543             &XGridDataListener::dataChanged,
544             GridDataEvent( *this, -1, -1, -1, -1 ),
545             aGuard
546         );
547     }
548 
549     //------------------------------------------------------------------------------------------------------------------
550     void SortableGridDataModel::impl_removeColumnSort_noBroadcast()
551     {
552         lcl_clear( m_publicToPrivateRowIndex );
553         lcl_clear( m_privateToPublicRowIndex );
554 
555         m_currentSortColumn = -1;
556         m_sortAscending = sal_True;
557     }
558 
559     //------------------------------------------------------------------------------------------------------------------
560     void SortableGridDataModel::impl_removeColumnSort( MethodGuard& i_instanceLock )
561     {
562         impl_removeColumnSort_noBroadcast();
563         impl_broadcast(
564             &XGridDataListener::dataChanged,
565             GridDataEvent( *this, -1, -1, -1, -1 ),
566             i_instanceLock
567         );
568     }
569 
570     //------------------------------------------------------------------------------------------------------------------
571     void SAL_CALL SortableGridDataModel::removeColumnSort(  ) throw (RuntimeException)
572     {
573         MethodGuard aGuard( *this, rBHelper );
574         DBG_CHECK_ME();
575         impl_removeColumnSort( aGuard );
576     }
577 
578     //------------------------------------------------------------------------------------------------------------------
579     Pair< ::sal_Int32, ::sal_Bool > SAL_CALL SortableGridDataModel::getCurrentSortOrder(  ) throw (RuntimeException)
580     {
581         MethodGuard aGuard( *this, rBHelper );
582         DBG_CHECK_ME();
583 
584         return Pair< ::sal_Int32, ::sal_Bool >( m_currentSortColumn, m_sortAscending );
585     }
586 
587     //------------------------------------------------------------------------------------------------------------------
588     void SAL_CALL SortableGridDataModel::addRow( const Any& i_heading, const Sequence< Any >& i_data ) throw (RuntimeException)
589     {
590         MethodGuard aGuard( *this, rBHelper );
591         DBG_CHECK_ME();
592 
593         Reference< XMutableGridDataModel > const delegator( m_delegator );
594         aGuard.clear();
595         delegator->addRow( i_heading, i_data );
596     }
597 
598     //------------------------------------------------------------------------------------------------------------------
599     void SAL_CALL SortableGridDataModel::addRows( const Sequence< Any >& i_headings, const Sequence< Sequence< Any > >& i_data ) throw (IllegalArgumentException, RuntimeException)
600     {
601         MethodGuard aGuard( *this, rBHelper );
602         DBG_CHECK_ME();
603 
604         Reference< XMutableGridDataModel > const delegator( m_delegator );
605         aGuard.clear();
606         delegator->addRows( i_headings, i_data );
607     }
608 
609     //------------------------------------------------------------------------------------------------------------------
610     void SAL_CALL SortableGridDataModel::insertRow( ::sal_Int32 i_index, const Any& i_heading, const Sequence< Any >& i_data ) throw (RuntimeException, IndexOutOfBoundsException)
611     {
612         MethodGuard aGuard( *this, rBHelper );
613         DBG_CHECK_ME();
614 
615         ::sal_Int32 const rowIndex = i_index == getRowCount() ? i_index : impl_getPrivateRowIndex_throw( i_index );
616             // note that |RowCount| is a valid index in this method, but not for impl_getPrivateRowIndex_throw
617 
618         Reference< XMutableGridDataModel > const delegator( m_delegator );
619         aGuard.clear();
620         delegator->insertRow( rowIndex, i_heading, i_data );
621     }
622 
623     //------------------------------------------------------------------------------------------------------------------
624     void SAL_CALL SortableGridDataModel::insertRows( ::sal_Int32 i_index, const Sequence< Any>& i_headings, const Sequence< Sequence< Any > >& i_data ) throw (IllegalArgumentException, IndexOutOfBoundsException, RuntimeException)
625     {
626         MethodGuard aGuard( *this, rBHelper );
627         DBG_CHECK_ME();
628 
629         ::sal_Int32 const rowIndex = i_index == getRowCount() ? i_index : impl_getPrivateRowIndex_throw( i_index );
630             // note that |RowCount| is a valid index in this method, but not for impl_getPrivateRowIndex_throw
631 
632         Reference< XMutableGridDataModel > const delegator( m_delegator );
633         aGuard.clear();
634         delegator->insertRows( rowIndex, i_headings, i_data );
635     }
636 
637     //------------------------------------------------------------------------------------------------------------------
638     void SAL_CALL SortableGridDataModel::removeRow( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException)
639     {
640         MethodGuard aGuard( *this, rBHelper );
641         DBG_CHECK_ME();
642 
643         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
644 
645         Reference< XMutableGridDataModel > const delegator( m_delegator );
646         aGuard.clear();
647         delegator->removeRow( rowIndex );
648     }
649 
650     //------------------------------------------------------------------------------------------------------------------
651     void SAL_CALL SortableGridDataModel::removeAllRows(  ) throw (RuntimeException)
652     {
653         MethodGuard aGuard( *this, rBHelper );
654         DBG_CHECK_ME();
655 
656         Reference< XMutableGridDataModel > const delegator( m_delegator );
657         aGuard.clear();
658         delegator->removeAllRows();
659     }
660 
661     //------------------------------------------------------------------------------------------------------------------
662     void SAL_CALL SortableGridDataModel::updateCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) throw (IndexOutOfBoundsException, RuntimeException)
663     {
664         MethodGuard aGuard( *this, rBHelper );
665         DBG_CHECK_ME();
666 
667         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
668 
669         Reference< XMutableGridDataModel > const delegator( m_delegator );
670         aGuard.clear();
671         delegator->updateCellData( i_columnIndex, rowIndex, i_value );
672     }
673 
674     //------------------------------------------------------------------------------------------------------------------
675     void SAL_CALL SortableGridDataModel::updateRowData( const Sequence< ::sal_Int32 >& i_columnIndexes, ::sal_Int32 i_rowIndex, const Sequence< Any >& i_values ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException)
676     {
677         MethodGuard aGuard( *this, rBHelper );
678         DBG_CHECK_ME();
679 
680         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
681 
682         Reference< XMutableGridDataModel > const delegator( m_delegator );
683         aGuard.clear();
684         delegator->updateRowData( i_columnIndexes, rowIndex, i_values );
685     }
686 
687     //------------------------------------------------------------------------------------------------------------------
688     void SAL_CALL SortableGridDataModel::updateRowHeading( ::sal_Int32 i_rowIndex, const Any& i_heading ) throw (IndexOutOfBoundsException, RuntimeException)
689     {
690         MethodGuard aGuard( *this, rBHelper );
691         DBG_CHECK_ME();
692 
693         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
694 
695         Reference< XMutableGridDataModel > const delegator( m_delegator );
696         aGuard.clear();
697         delegator->updateRowHeading( rowIndex, i_heading );
698     }
699 
700     //------------------------------------------------------------------------------------------------------------------
701     void SAL_CALL SortableGridDataModel::updateCellToolTip( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) throw (IndexOutOfBoundsException, RuntimeException)
702     {
703         MethodGuard aGuard( *this, rBHelper );
704         DBG_CHECK_ME();
705 
706         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
707 
708         Reference< XMutableGridDataModel > const delegator( m_delegator );
709         aGuard.clear();
710         delegator->updateCellToolTip( i_columnIndex, rowIndex, i_value );
711     }
712 
713     //------------------------------------------------------------------------------------------------------------------
714     void SAL_CALL SortableGridDataModel::updateRowToolTip( ::sal_Int32 i_rowIndex, const Any& i_value ) throw (IndexOutOfBoundsException, RuntimeException)
715     {
716         MethodGuard aGuard( *this, rBHelper );
717         DBG_CHECK_ME();
718 
719         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
720 
721         Reference< XMutableGridDataModel > const delegator( m_delegator );
722         aGuard.clear();
723         delegator->updateRowToolTip( rowIndex, i_value );
724     }
725 
726     //------------------------------------------------------------------------------------------------------------------
727     void SAL_CALL SortableGridDataModel::addGridDataListener( const Reference< XGridDataListener >& i_listener ) throw (RuntimeException)
728     {
729 	    rBHelper.addListener( XGridDataListener::static_type(), i_listener );
730     }
731 
732     //------------------------------------------------------------------------------------------------------------------
733     void SAL_CALL SortableGridDataModel::removeGridDataListener( const Reference< XGridDataListener >& i_listener ) throw (RuntimeException)
734     {
735 	    rBHelper.removeListener( XGridDataListener::static_type(), i_listener );
736     }
737 
738     //------------------------------------------------------------------------------------------------------------------
739     ::sal_Int32 SAL_CALL SortableGridDataModel::getRowCount() throw (RuntimeException)
740     {
741         MethodGuard aGuard( *this, rBHelper );
742         DBG_CHECK_ME();
743 
744         Reference< XMutableGridDataModel > const delegator( m_delegator );
745         aGuard.clear();
746         return delegator->getRowCount();
747     }
748 
749     //------------------------------------------------------------------------------------------------------------------
750     ::sal_Int32 SAL_CALL SortableGridDataModel::getColumnCount() throw (RuntimeException)
751     {
752         MethodGuard aGuard( *this, rBHelper );
753         DBG_CHECK_ME();
754 
755         Reference< XMutableGridDataModel > const delegator( m_delegator );
756         aGuard.clear();
757         return delegator->getColumnCount();
758     }
759 
760     //------------------------------------------------------------------------------------------------------------------
761     Any SAL_CALL SortableGridDataModel::getCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException)
762     {
763         MethodGuard aGuard( *this, rBHelper );
764         DBG_CHECK_ME();
765 
766         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
767 
768         Reference< XMutableGridDataModel > const delegator( m_delegator );
769         aGuard.clear();
770         return delegator->getCellData( i_columnIndex, rowIndex );
771     }
772 
773     //------------------------------------------------------------------------------------------------------------------
774     Any SAL_CALL SortableGridDataModel::getCellToolTip( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException)
775     {
776         MethodGuard aGuard( *this, rBHelper );
777         DBG_CHECK_ME();
778 
779         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
780 
781         Reference< XMutableGridDataModel > const delegator( m_delegator );
782         aGuard.clear();
783         return delegator->getCellToolTip( i_columnIndex, rowIndex );
784     }
785 
786     //------------------------------------------------------------------------------------------------------------------
787     Any SAL_CALL SortableGridDataModel::getRowHeading( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException)
788     {
789         MethodGuard aGuard( *this, rBHelper );
790         DBG_CHECK_ME();
791 
792         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
793 
794         Reference< XMutableGridDataModel > const delegator( m_delegator );
795         aGuard.clear();
796         return delegator->getRowHeading( rowIndex );
797     }
798 
799     //------------------------------------------------------------------------------------------------------------------
800     Sequence< Any > SAL_CALL SortableGridDataModel::getRowData( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException)
801     {
802         MethodGuard aGuard( *this, rBHelper );
803         DBG_CHECK_ME();
804 
805         ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex );
806 
807         Reference< XMutableGridDataModel > const delegator( m_delegator );
808         aGuard.clear();
809         return delegator->getRowData( rowIndex );
810     }
811 
812     //------------------------------------------------------------------------------------------------------------------
813     void SAL_CALL SortableGridDataModel::disposing()
814     {
815         m_currentSortColumn = -1;
816 
817         Reference< XComponent > const delegatorComponent( m_delegator.get() );
818         m_delegator->removeGridDataListener( this );
819         m_delegator.clear();
820         delegatorComponent->dispose();
821 
822         Reference< XComponent > const collatorComponent( m_collator, UNO_QUERY );
823         m_collator.clear();
824         if ( collatorComponent.is() )
825             collatorComponent->dispose();
826 
827         lcl_clear( m_publicToPrivateRowIndex );
828         lcl_clear( m_privateToPublicRowIndex );
829     }
830 
831     //------------------------------------------------------------------------------------------------------------------
832     Reference< XCloneable > SAL_CALL SortableGridDataModel::createClone(  ) throw (RuntimeException)
833     {
834         MethodGuard aGuard( *this, rBHelper );
835         DBG_CHECK_ME();
836 
837         return new SortableGridDataModel( *this );
838     }
839 
840     //------------------------------------------------------------------------------------------------------------------
841     ::rtl::OUString SAL_CALL SortableGridDataModel::getImplementationName(  ) throw (RuntimeException)
842     {
843         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.toolkit.SortableGridDataModel" ) );
844     }
845 
846     //------------------------------------------------------------------------------------------------------------------
847     ::sal_Bool SAL_CALL SortableGridDataModel::supportsService( const ::rtl::OUString& i_serviceName ) throw (RuntimeException)
848     {
849         Sequence< ::rtl::OUString > const aServiceNames( getSupportedServiceNames() );
850         for ( sal_Int32 i=0; i<aServiceNames.getLength(); ++i )
851             if ( aServiceNames[i] == i_serviceName )
852                 return sal_True;
853         return sal_False;
854     }
855 
856     //------------------------------------------------------------------------------------------------------------------
857     Sequence< ::rtl::OUString > SAL_CALL SortableGridDataModel::getSupportedServiceNames(  ) throw (RuntimeException)
858     {
859         Sequence< ::rtl::OUString > aServiceNames(1);
860         aServiceNames[0] = ::rtl::OUString::createFromAscii( szServiceName_SortableGridDataModel );
861         return aServiceNames;
862     }
863 
864     //------------------------------------------------------------------------------------------------------------------
865     ::sal_Int32 SortableGridDataModel::impl_getPrivateRowIndex_throw( ::sal_Int32 const i_publicRowIndex ) const
866     {
867         if ( ( i_publicRowIndex < 0 ) || ( i_publicRowIndex >= m_delegator->getRowCount() ) )
868             throw IndexOutOfBoundsException( ::rtl::OUString(), *const_cast< SortableGridDataModel* >( this ) );
869 
870         if ( !impl_isSorted_nothrow() )
871             // no need to translate anything
872             return i_publicRowIndex;
873 
874         ENSURE_OR_RETURN( size_t( i_publicRowIndex ) < m_publicToPrivateRowIndex.size(),
875             "SortableGridDataModel::impl_getPrivateRowIndex_throw: inconsistency!", i_publicRowIndex );
876                 // obviously the translation table contains too few elements - it should have exactly |getRowCount()|
877                 // elements
878 
879         return m_publicToPrivateRowIndex[ i_publicRowIndex ];
880     }
881 
882     //------------------------------------------------------------------------------------------------------------------
883     ::sal_Int32 SortableGridDataModel::impl_getPublicRowIndex_nothrow( ::sal_Int32 const i_privateRowIndex ) const
884     {
885         if ( !impl_isSorted_nothrow() )
886             // no need to translate anything
887             return i_privateRowIndex;
888 
889         if ( i_privateRowIndex < 0 )
890             return i_privateRowIndex;
891 
892         ENSURE_OR_RETURN( size_t( i_privateRowIndex ) < m_privateToPublicRowIndex.size(),
893             "SortableGridDataModel::impl_getPublicRowIndex_nothrow: invalid index!", i_privateRowIndex );
894 
895         return m_privateToPublicRowIndex[ i_privateRowIndex ];
896     }
897 
898 //......................................................................................................................
899 } // namespace toolkit
900 //......................................................................................................................
901 
902 ::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 )
903 {
904     return *( new ::toolkit::SortableGridDataModel( i_factory ) );
905 }
906