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