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