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