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