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