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