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