1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_toolkit.hxx" 30 31 #include "defaultgriddatamodel.hxx" 32 33 #include <comphelper/stlunosequence.hxx> 34 #include <comphelper/componentguard.hxx> 35 #include <toolkit/helper/servicenames.hxx> 36 #include <tools/diagnose_ex.h> 37 #include <rtl/ref.hxx> 38 39 #include <algorithm> 40 #include <functional> 41 42 //...................................................................................................................... 43 namespace toolkit 44 //...................................................................................................................... 45 { 46 /** === begin UNO using === **/ 47 using ::com::sun::star::uno::Reference; 48 using ::com::sun::star::uno::RuntimeException; 49 using ::com::sun::star::uno::Sequence; 50 using ::com::sun::star::uno::UNO_QUERY_THROW; 51 using ::com::sun::star::uno::UNO_QUERY; 52 using ::com::sun::star::uno::XInterface; 53 using ::com::sun::star::lang::XComponent; 54 using ::com::sun::star::lang::EventObject; 55 using ::com::sun::star::uno::Exception; 56 using ::com::sun::star::util::XCloneable; 57 /** === end UNO using === **/ 58 59 using ::comphelper::stl_begin; 60 using ::comphelper::stl_end; 61 62 //================================================================================================================== 63 //= DefaultGridDataModel 64 //================================================================================================================== 65 //------------------------------------------------------------------------------------------------------------------ 66 DefaultGridDataModel::DefaultGridDataModel() 67 :DefaultGridDataModel_Base( m_aMutex ) 68 ,m_aRowHeaders() 69 ,m_nColumnCount(0) 70 { 71 } 72 73 //------------------------------------------------------------------------------------------------------------------ 74 DefaultGridDataModel::DefaultGridDataModel( DefaultGridDataModel const & i_copySource ) 75 :cppu::BaseMutex() 76 ,DefaultGridDataModel_Base( m_aMutex ) 77 ,m_aData( i_copySource.m_aData ) 78 ,m_aRowHeaders( i_copySource.m_aRowHeaders ) 79 ,m_nColumnCount( i_copySource.m_nColumnCount ) 80 { 81 } 82 83 //------------------------------------------------------------------------------------------------------------------ 84 DefaultGridDataModel::~DefaultGridDataModel() 85 { 86 } 87 88 //------------------------------------------------------------------------------------------------------------------ 89 void DefaultGridDataModel::broadcast( GridDataEvent const & i_event, 90 void ( SAL_CALL XGridDataListener::*i_listenerMethod )( GridDataEvent const & ), ::comphelper::ComponentGuard & i_instanceLock ) 91 { 92 ::cppu::OInterfaceContainerHelper* pListeners = rBHelper.getContainer( XGridDataListener::static_type() ); 93 if ( !pListeners ) 94 return; 95 96 i_instanceLock.clear(); 97 pListeners->notifyEach( i_listenerMethod, i_event ); 98 } 99 100 //------------------------------------------------------------------------------------------------------------------ 101 ::sal_Int32 SAL_CALL DefaultGridDataModel::getRowCount() throw (::com::sun::star::uno::RuntimeException) 102 { 103 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 104 return impl_getRowCount_nolck(); 105 } 106 107 //------------------------------------------------------------------------------------------------------------------ 108 ::sal_Int32 SAL_CALL DefaultGridDataModel::getColumnCount() throw (::com::sun::star::uno::RuntimeException) 109 { 110 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 111 return m_nColumnCount; 112 } 113 114 //------------------------------------------------------------------------------------------------------------------ 115 DefaultGridDataModel::CellData const & DefaultGridDataModel::impl_getCellData_throw( sal_Int32 const i_column, sal_Int32 const i_row ) const 116 { 117 if ( ( i_row < 0 ) || ( size_t( i_row ) > m_aData.size() ) 118 || ( i_column < 0 ) || ( i_column > m_nColumnCount ) 119 ) 120 throw IndexOutOfBoundsException( ::rtl::OUString(), *const_cast< DefaultGridDataModel* >( this ) ); 121 122 RowData const & rRow( m_aData[ i_row ] ); 123 if ( size_t( i_column ) < rRow.size() ) 124 return rRow[ i_column ]; 125 126 static CellData s_aEmpty; 127 return s_aEmpty; 128 } 129 130 //------------------------------------------------------------------------------------------------------------------ 131 DefaultGridDataModel::RowData& DefaultGridDataModel::impl_getRowDataAccess_throw( sal_Int32 const i_rowIndex, size_t const i_requiredColumnCount ) 132 { 133 OSL_ENSURE( i_requiredColumnCount <= size_t( m_nColumnCount ), "DefaultGridDataModel::impl_getRowDataAccess_throw: invalid column count!" ); 134 if ( ( i_rowIndex < 0 ) || ( size_t( i_rowIndex ) >= m_aData.size() ) ) 135 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 136 137 RowData& rRowData( m_aData[ i_rowIndex ] ); 138 if ( rRowData.size() < i_requiredColumnCount ) 139 rRowData.resize( i_requiredColumnCount ); 140 return rRowData; 141 } 142 143 //------------------------------------------------------------------------------------------------------------------ 144 DefaultGridDataModel::CellData& DefaultGridDataModel::impl_getCellDataAccess_throw( sal_Int32 const i_columnIndex, sal_Int32 const i_rowIndex ) 145 { 146 if ( ( i_columnIndex < 0 ) || ( i_columnIndex >= m_nColumnCount ) ) 147 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 148 149 RowData& rRowData( impl_getRowDataAccess_throw( i_rowIndex, size_t( i_columnIndex + 1 ) ) ); 150 return rRowData[ i_columnIndex ]; 151 } 152 153 //------------------------------------------------------------------------------------------------------------------ 154 Any SAL_CALL DefaultGridDataModel::getCellData( ::sal_Int32 i_column, ::sal_Int32 i_row ) throw (RuntimeException, IndexOutOfBoundsException) 155 { 156 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 157 return impl_getCellData_throw( i_column, i_row ).first; 158 } 159 160 //------------------------------------------------------------------------------------------------------------------ 161 Any SAL_CALL DefaultGridDataModel::getCellToolTip( ::sal_Int32 i_column, ::sal_Int32 i_row ) throw (RuntimeException, IndexOutOfBoundsException) 162 { 163 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 164 return impl_getCellData_throw( i_column, i_row ).second; 165 } 166 167 //------------------------------------------------------------------------------------------------------------------ 168 Any SAL_CALL DefaultGridDataModel::getRowHeading( ::sal_Int32 i_row ) throw (RuntimeException, IndexOutOfBoundsException) 169 { 170 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 171 172 if ( ( i_row < 0 ) || ( size_t( i_row ) >= m_aRowHeaders.size() ) ) 173 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 174 175 return m_aRowHeaders[ i_row ]; 176 } 177 178 //------------------------------------------------------------------------------------------------------------------ 179 Sequence< Any > SAL_CALL DefaultGridDataModel::getRowData( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException) 180 { 181 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 182 183 Sequence< Any > resultData( m_nColumnCount ); 184 RowData& rRowData = impl_getRowDataAccess_throw( i_rowIndex, m_nColumnCount ); 185 186 ::std::transform( rRowData.begin(), rRowData.end(), resultData.getArray(), ::std::select1st< CellData >() ); 187 return resultData; 188 } 189 190 //------------------------------------------------------------------------------------------------------------------ 191 void DefaultGridDataModel::impl_insertRow( sal_Int32 const i_position, Any const & i_heading, Sequence< Any > const & i_rowData, sal_Int32 const i_assumedColCount ) 192 { 193 OSL_PRECOND( ( i_assumedColCount <= 0 ) || ( i_assumedColCount >= i_rowData.getLength() ), 194 "DefaultGridDataModel::impl_insertRow: invalid column count!" ); 195 196 // insert heading 197 m_aRowHeaders.insert( m_aRowHeaders.begin() + i_position, i_heading ); 198 199 // create new data row 200 RowData newRow( i_assumedColCount > 0 ? i_assumedColCount : i_rowData.getLength() ); 201 RowData::iterator cellData = newRow.begin(); 202 for ( const Any* pData = stl_begin( i_rowData ); pData != stl_end( i_rowData ); ++pData, ++cellData ) 203 cellData->first = *pData; 204 205 // insert data row 206 m_aData.insert( m_aData.begin() + i_position, newRow ); 207 } 208 209 //------------------------------------------------------------------------------------------------------------------ 210 void SAL_CALL DefaultGridDataModel::addRow( const Any& i_heading, const Sequence< Any >& i_data ) throw (RuntimeException) 211 { 212 insertRow( getRowCount(), i_heading, i_data ); 213 } 214 215 //------------------------------------------------------------------------------------------------------------------ 216 void SAL_CALL DefaultGridDataModel::addRows( const Sequence< Any >& i_headings, const Sequence< Sequence< Any > >& i_data ) throw (IllegalArgumentException, RuntimeException) 217 { 218 insertRows( getRowCount(), i_headings, i_data ); 219 } 220 221 //------------------------------------------------------------------------------------------------------------------ 222 void SAL_CALL DefaultGridDataModel::insertRow( ::sal_Int32 i_index, const Any& i_heading, const Sequence< Any >& i_data ) throw (RuntimeException, IndexOutOfBoundsException) 223 { 224 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 225 226 if ( ( i_index < 0 ) || ( i_index > impl_getRowCount_nolck() ) ) 227 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 228 229 // actually insert the row 230 impl_insertRow( i_index, i_heading, i_data ); 231 232 // update column count 233 sal_Int32 const columnCount = i_data.getLength(); 234 if ( columnCount > m_nColumnCount ) 235 m_nColumnCount = columnCount; 236 237 broadcast( 238 GridDataEvent( *this, -1, -1, i_index, i_index ), 239 &XGridDataListener::rowsInserted, 240 aGuard 241 ); 242 } 243 244 //------------------------------------------------------------------------------------------------------------------ 245 void SAL_CALL DefaultGridDataModel::insertRows( ::sal_Int32 i_index, const Sequence< Any>& i_headings, const Sequence< Sequence< Any > >& i_data ) throw (IllegalArgumentException, IndexOutOfBoundsException, RuntimeException) 246 { 247 if ( i_headings.getLength() != i_data.getLength() ) 248 throw IllegalArgumentException( ::rtl::OUString(), *this, -1 ); 249 250 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 251 252 if ( ( i_index < 0 ) || ( i_index > impl_getRowCount_nolck() ) ) 253 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 254 255 sal_Int32 const rowCount = i_headings.getLength(); 256 if ( rowCount == 0 ) 257 return; 258 259 // determine max col count in the new data 260 sal_Int32 maxColCount = 0; 261 for ( sal_Int32 row=0; row<rowCount; ++row ) 262 if ( i_data[row].getLength() > maxColCount ) 263 maxColCount = i_data[row].getLength(); 264 265 if ( maxColCount < m_nColumnCount ) 266 maxColCount = m_nColumnCount; 267 268 for ( sal_Int32 row=0; row<rowCount; ++row ) 269 { 270 impl_insertRow( i_index + row, i_headings[row], i_data[row], maxColCount ); 271 } 272 273 if ( maxColCount > m_nColumnCount ) 274 m_nColumnCount = maxColCount; 275 276 broadcast( 277 GridDataEvent( *this, -1, -1, i_index, i_index + rowCount - 1 ), 278 &XGridDataListener::rowsInserted, 279 aGuard 280 ); 281 } 282 283 //------------------------------------------------------------------------------------------------------------------ 284 void SAL_CALL DefaultGridDataModel::removeRow( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException) 285 { 286 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 287 288 if ( ( i_rowIndex < 0 ) || ( size_t( i_rowIndex ) >= m_aData.size() ) ) 289 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 290 291 m_aRowHeaders.erase( m_aRowHeaders.begin() + i_rowIndex ); 292 m_aData.erase( m_aData.begin() + i_rowIndex ); 293 294 broadcast( 295 GridDataEvent( *this, -1, -1, i_rowIndex, i_rowIndex ), 296 &XGridDataListener::rowsRemoved, 297 aGuard 298 ); 299 } 300 301 //------------------------------------------------------------------------------------------------------------------ 302 void SAL_CALL DefaultGridDataModel::removeAllRows( ) throw (RuntimeException) 303 { 304 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 305 306 m_aRowHeaders.clear(); 307 m_aData.clear(); 308 309 broadcast( 310 GridDataEvent( *this, -1, -1, -1, -1 ), 311 &XGridDataListener::rowsRemoved, 312 aGuard 313 ); 314 } 315 316 //------------------------------------------------------------------------------------------------------------------ 317 void SAL_CALL DefaultGridDataModel::updateCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) throw (IndexOutOfBoundsException, RuntimeException) 318 { 319 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 320 321 impl_getCellDataAccess_throw( i_columnIndex, i_rowIndex ).first = i_value; 322 323 broadcast( 324 GridDataEvent( *this, i_columnIndex, i_columnIndex, i_rowIndex, i_rowIndex ), 325 &XGridDataListener::dataChanged, 326 aGuard 327 ); 328 } 329 330 //------------------------------------------------------------------------------------------------------------------ 331 void SAL_CALL DefaultGridDataModel::updateRowData( const Sequence< ::sal_Int32 >& i_columnIndexes, ::sal_Int32 i_rowIndex, const Sequence< Any >& i_values ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) 332 { 333 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 334 335 if ( ( i_rowIndex < 0 ) || ( size_t( i_rowIndex ) >= m_aData.size() ) ) 336 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 337 338 if ( i_columnIndexes.getLength() != i_values.getLength() ) 339 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); 340 341 sal_Int32 const columnCount = i_columnIndexes.getLength(); 342 if ( columnCount == 0 ) 343 return; 344 345 for ( sal_Int32 col = 0; col < columnCount; ++col ) 346 { 347 if ( ( i_columnIndexes[col] < 0 ) || ( i_columnIndexes[col] > m_nColumnCount ) ) 348 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 349 } 350 351 RowData& rDataRow = m_aData[ i_rowIndex ]; 352 for ( sal_Int32 col = 0; col < columnCount; ++col ) 353 { 354 sal_Int32 const columnIndex = i_columnIndexes[ col ]; 355 if ( size_t( columnIndex ) >= rDataRow.size() ) 356 rDataRow.resize( columnIndex + 1 ); 357 358 rDataRow[ columnIndex ].first = i_values[ col ]; 359 } 360 361 sal_Int32 const firstAffectedColumn = *::std::min_element( stl_begin( i_columnIndexes ), stl_end( i_columnIndexes ) ); 362 sal_Int32 const lastAffectedColumn = *::std::max_element( stl_begin( i_columnIndexes ), stl_end( i_columnIndexes ) ); 363 broadcast( 364 GridDataEvent( *this, firstAffectedColumn, lastAffectedColumn, i_rowIndex, i_rowIndex ), 365 &XGridDataListener::dataChanged, 366 aGuard 367 ); 368 } 369 370 //------------------------------------------------------------------------------------------------------------------ 371 void SAL_CALL DefaultGridDataModel::updateRowHeading( ::sal_Int32 i_rowIndex, const Any& i_heading ) throw (IndexOutOfBoundsException, RuntimeException) 372 { 373 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 374 375 if ( ( i_rowIndex < 0 ) || ( size_t( i_rowIndex ) >= m_aRowHeaders.size() ) ) 376 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 377 378 m_aRowHeaders[ i_rowIndex ] = i_heading; 379 380 broadcast( 381 GridDataEvent( *this, -1, -1, i_rowIndex, i_rowIndex ), 382 &XGridDataListener::rowHeadingChanged, 383 aGuard 384 ); 385 } 386 387 //------------------------------------------------------------------------------------------------------------------ 388 void SAL_CALL DefaultGridDataModel::updateCellToolTip( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) throw (IndexOutOfBoundsException, RuntimeException) 389 { 390 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 391 impl_getCellDataAccess_throw( i_columnIndex, i_rowIndex ).second = i_value; 392 } 393 394 //------------------------------------------------------------------------------------------------------------------ 395 void SAL_CALL DefaultGridDataModel::updateRowToolTip( ::sal_Int32 i_rowIndex, const Any& i_value ) throw (IndexOutOfBoundsException, RuntimeException) 396 { 397 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 398 399 RowData& rRowData = impl_getRowDataAccess_throw( i_rowIndex, m_nColumnCount ); 400 for ( RowData::iterator cell = rRowData.begin(); cell != rRowData.end(); ++cell ) 401 cell->second = i_value; 402 } 403 404 //------------------------------------------------------------------------------------------------------------------ 405 void SAL_CALL DefaultGridDataModel::addGridDataListener( const Reference< grid::XGridDataListener >& i_listener ) throw (RuntimeException) 406 { 407 rBHelper.addListener( XGridDataListener::static_type(), i_listener ); 408 } 409 410 //------------------------------------------------------------------------------------------------------------------ 411 void SAL_CALL DefaultGridDataModel::removeGridDataListener( const Reference< grid::XGridDataListener >& i_listener ) throw (RuntimeException) 412 { 413 rBHelper.removeListener( XGridDataListener::static_type(), i_listener ); 414 } 415 416 //------------------------------------------------------------------------------------------------------------------ 417 void SAL_CALL DefaultGridDataModel::disposing() 418 { 419 ::com::sun::star::lang::EventObject aEvent; 420 aEvent.Source.set( *this ); 421 rBHelper.aLC.disposeAndClear( aEvent ); 422 423 ::osl::MutexGuard aGuard( m_aMutex ); 424 GridData aEmptyData; 425 m_aData.swap( aEmptyData ); 426 427 ::std::vector< Any > aEmptyRowHeaders; 428 m_aRowHeaders.swap( aEmptyRowHeaders ); 429 430 m_nColumnCount = 0; 431 } 432 433 //------------------------------------------------------------------------------------------------------------------ 434 ::rtl::OUString SAL_CALL DefaultGridDataModel::getImplementationName( ) throw (RuntimeException) 435 { 436 static const ::rtl::OUString aImplName( RTL_CONSTASCII_USTRINGPARAM( "toolkit.DefaultGridDataModel" ) ); 437 return aImplName; 438 } 439 440 //------------------------------------------------------------------------------------------------------------------ 441 sal_Bool SAL_CALL DefaultGridDataModel::supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException) 442 { 443 return ServiceName.equalsAscii( szServiceName_DefaultGridDataModel ); 444 } 445 446 //------------------------------------------------------------------------------------------------------------------ 447 Sequence< ::rtl::OUString > SAL_CALL DefaultGridDataModel::getSupportedServiceNames( ) throw (RuntimeException) 448 { 449 static const ::rtl::OUString aServiceName( ::rtl::OUString::createFromAscii( szServiceName_DefaultGridDataModel ) ); 450 static const Sequence< ::rtl::OUString > aSeq( &aServiceName, 1 ); 451 return aSeq; 452 } 453 454 //------------------------------------------------------------------------------------------------------------------ 455 Reference< XCloneable > SAL_CALL DefaultGridDataModel::createClone( ) throw (RuntimeException) 456 { 457 return new DefaultGridDataModel( *this ); 458 } 459 460 //...................................................................................................................... 461 } // namespace toolkit 462 //...................................................................................................................... 463 464 Reference< XInterface > SAL_CALL DefaultGridDataModel_CreateInstance( const Reference< XMultiServiceFactory >& ) 465 { 466 return Reference < XInterface >( ( ::cppu::OWeakObject* ) new ::toolkit::DefaultGridDataModel() ); 467 } 468