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 //------------------------------------------------------------------------------------------------------------------
DefaultGridDataModel()62 DefaultGridDataModel::DefaultGridDataModel()
63 :DefaultGridDataModel_Base( m_aMutex )
64 ,m_aRowHeaders()
65 ,m_nColumnCount(0)
66 {
67 }
68
69 //------------------------------------------------------------------------------------------------------------------
DefaultGridDataModel(DefaultGridDataModel const & i_copySource)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 //------------------------------------------------------------------------------------------------------------------
~DefaultGridDataModel()80 DefaultGridDataModel::~DefaultGridDataModel()
81 {
82 }
83
84 //------------------------------------------------------------------------------------------------------------------
broadcast(GridDataEvent const & i_event,void (SAL_CALL XGridDataListener::* i_listenerMethod)(GridDataEvent const &),::comphelper::ComponentGuard & i_instanceLock)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 //------------------------------------------------------------------------------------------------------------------
getRowCount()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 //------------------------------------------------------------------------------------------------------------------
getColumnCount()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 //------------------------------------------------------------------------------------------------------------------
impl_getCellData_throw(sal_Int32 const i_column,sal_Int32 const i_row) const111 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 //------------------------------------------------------------------------------------------------------------------
impl_getRowDataAccess_throw(sal_Int32 const i_rowIndex,size_t const i_requiredColumnCount)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 //------------------------------------------------------------------------------------------------------------------
impl_getCellDataAccess_throw(sal_Int32 const i_columnIndex,sal_Int32 const i_rowIndex)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 //------------------------------------------------------------------------------------------------------------------
getCellData(::sal_Int32 i_column,::sal_Int32 i_row)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 //------------------------------------------------------------------------------------------------------------------
getCellToolTip(::sal_Int32 i_column,::sal_Int32 i_row)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 //------------------------------------------------------------------------------------------------------------------
getRowHeading(::sal_Int32 i_row)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 //------------------------------------------------------------------------------------------------------------------
getRowData(::sal_Int32 i_rowIndex)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 //------------------------------------------------------------------------------------------------------------------
impl_insertRow(sal_Int32 const i_position,Any const & i_heading,Sequence<Any> const & i_rowData,sal_Int32 const i_assumedColCount)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 //------------------------------------------------------------------------------------------------------------------
addRow(const Any & i_heading,const Sequence<Any> & i_data)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 //------------------------------------------------------------------------------------------------------------------
addRows(const Sequence<Any> & i_headings,const Sequence<Sequence<Any>> & i_data)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 //------------------------------------------------------------------------------------------------------------------
insertRow(::sal_Int32 i_index,const Any & i_heading,const Sequence<Any> & i_data)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 //------------------------------------------------------------------------------------------------------------------
insertRows(::sal_Int32 i_index,const Sequence<Any> & i_headings,const Sequence<Sequence<Any>> & i_data)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 //------------------------------------------------------------------------------------------------------------------
removeRow(::sal_Int32 i_rowIndex)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 //------------------------------------------------------------------------------------------------------------------
removeAllRows()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 //------------------------------------------------------------------------------------------------------------------
updateCellData(::sal_Int32 i_columnIndex,::sal_Int32 i_rowIndex,const Any & i_value)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 //------------------------------------------------------------------------------------------------------------------
updateRowData(const Sequence<::sal_Int32> & i_columnIndexes,::sal_Int32 i_rowIndex,const Sequence<Any> & i_values)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 //------------------------------------------------------------------------------------------------------------------
updateRowHeading(::sal_Int32 i_rowIndex,const Any & i_heading)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 //------------------------------------------------------------------------------------------------------------------
updateCellToolTip(::sal_Int32 i_columnIndex,::sal_Int32 i_rowIndex,const Any & i_value)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 //------------------------------------------------------------------------------------------------------------------
updateRowToolTip(::sal_Int32 i_rowIndex,const Any & i_value)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 //------------------------------------------------------------------------------------------------------------------
addGridDataListener(const Reference<grid::XGridDataListener> & i_listener)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 //------------------------------------------------------------------------------------------------------------------
removeGridDataListener(const Reference<grid::XGridDataListener> & i_listener)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 //------------------------------------------------------------------------------------------------------------------
disposing()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 //------------------------------------------------------------------------------------------------------------------
getImplementationName()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 //------------------------------------------------------------------------------------------------------------------
supportsService(const::rtl::OUString & ServiceName)437 sal_Bool SAL_CALL DefaultGridDataModel::supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException)
438 {
439 return ServiceName.equalsAscii( szServiceName_DefaultGridDataModel );
440 }
441
442 //------------------------------------------------------------------------------------------------------------------
getSupportedServiceNames()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 //------------------------------------------------------------------------------------------------------------------
createClone()451 Reference< XCloneable > SAL_CALL DefaultGridDataModel::createClone( ) throw (RuntimeException)
452 {
453 return new DefaultGridDataModel( *this );
454 }
455
456 //......................................................................................................................
457 } // namespace toolkit
458 //......................................................................................................................
459
DefaultGridDataModel_CreateInstance(const Reference<XMultiServiceFactory> &)460 Reference< XInterface > SAL_CALL DefaultGridDataModel_CreateInstance( const Reference< XMultiServiceFactory >& )
461 {
462 return Reference < XInterface >( ( ::cppu::OWeakObject* ) new ::toolkit::DefaultGridDataModel() );
463 }
464