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