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