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