Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / toolkit / source / controls / grid / defaultgriddatamodel.cxx
blob10bebd5c87ebaf2ca1cc7f04be7c75ce3a1b76c7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/awt/grid/XMutableGridDataModel.hpp>
21 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
22 #include <com/sun/star/lang/XServiceInfo.hpp>
23 #include <com/sun/star/uno/XComponentContext.hpp>
25 #include <comphelper/componentguard.hxx>
26 #include <cppuhelper/basemutex.hxx>
27 #include <cppuhelper/compbase.hxx>
28 #include <cppuhelper/supportsservice.hxx>
29 #include <toolkit/helper/servicenames.hxx>
30 #include <tools/diagnose_ex.h>
31 #include <toolkit/helper/mutexandbroadcasthelper.hxx>
33 #include <algorithm>
34 #include <functional>
35 #include <vector>
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::uno;
39 using namespace ::com::sun::star::awt;
40 using namespace ::com::sun::star::awt::grid;
41 using namespace ::com::sun::star::lang;
43 namespace {
45 enum broadcast_type { row_added, row_removed, data_changed};
47 typedef ::cppu::WeakComponentImplHelper < XMutableGridDataModel
48 , XServiceInfo
49 > DefaultGridDataModel_Base;
51 class DefaultGridDataModel :public ::cppu::BaseMutex
52 ,public DefaultGridDataModel_Base
54 public:
55 DefaultGridDataModel();
56 DefaultGridDataModel( DefaultGridDataModel const & i_copySource );
58 // XMutableGridDataModel
59 virtual void SAL_CALL addRow( const Any& i_heading, const css::uno::Sequence< css::uno::Any >& Data ) override;
60 virtual void SAL_CALL addRows( const css::uno::Sequence< css::uno::Any>& Headings, const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& Data ) override;
61 virtual void SAL_CALL insertRow( ::sal_Int32 i_index, const css::uno::Any& i_heading, const css::uno::Sequence< css::uno::Any >& Data ) override;
62 virtual void SAL_CALL insertRows( ::sal_Int32 i_index, const css::uno::Sequence< css::uno::Any>& Headings, const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& Data ) override;
63 virtual void SAL_CALL removeRow( ::sal_Int32 RowIndex ) override;
64 virtual void SAL_CALL removeAllRows( ) override;
65 virtual void SAL_CALL updateCellData( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const css::uno::Any& Value ) override;
66 virtual void SAL_CALL updateRowData( const css::uno::Sequence< ::sal_Int32 >& ColumnIndexes, ::sal_Int32 RowIndex, const css::uno::Sequence< css::uno::Any >& Values ) override;
67 virtual void SAL_CALL updateRowHeading( ::sal_Int32 RowIndex, const css::uno::Any& Heading ) override;
68 virtual void SAL_CALL updateCellToolTip( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const css::uno::Any& Value ) override;
69 virtual void SAL_CALL updateRowToolTip( ::sal_Int32 RowIndex, const css::uno::Any& Value ) override;
70 virtual void SAL_CALL addGridDataListener( const css::uno::Reference< css::awt::grid::XGridDataListener >& Listener ) override;
71 virtual void SAL_CALL removeGridDataListener( const css::uno::Reference< css::awt::grid::XGridDataListener >& Listener ) override;
73 // XGridDataModel
74 virtual ::sal_Int32 SAL_CALL getRowCount() override;
75 virtual ::sal_Int32 SAL_CALL getColumnCount() override;
76 virtual css::uno::Any SAL_CALL getCellData( ::sal_Int32 Column, ::sal_Int32 Row ) override;
77 virtual css::uno::Any SAL_CALL getCellToolTip( ::sal_Int32 Column, ::sal_Int32 Row ) override;
78 virtual css::uno::Any SAL_CALL getRowHeading( ::sal_Int32 RowIndex ) override;
79 virtual css::uno::Sequence< css::uno::Any > SAL_CALL getRowData( ::sal_Int32 RowIndex ) override;
81 // OComponentHelper
82 virtual void SAL_CALL disposing() override;
84 // XCloneable
85 virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override;
87 // XServiceInfo
88 virtual OUString SAL_CALL getImplementationName( ) override;
89 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
90 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
92 private:
93 typedef ::std::pair< Any, Any > CellData;
94 typedef ::std::vector< CellData > RowData;
95 typedef ::std::vector< RowData > GridData;
97 void broadcast(
98 GridDataEvent const & i_event,
99 void ( SAL_CALL css::awt::grid::XGridDataListener::*i_listenerMethod )( css::awt::grid::GridDataEvent const & ),
100 ::comphelper::ComponentGuard & i_instanceLock
103 void impl_insertRow( sal_Int32 const i_position, Any const & i_heading, Sequence< Any > const & i_rowData, sal_Int32 const i_assumedColCount = -1 );
105 ::sal_Int32 impl_getRowCount_nolck() const { return sal_Int32( m_aData.size() ); }
107 CellData const & impl_getCellData_throw( sal_Int32 const i_columnIndex, sal_Int32 const i_rowIndex ) const;
108 CellData& impl_getCellDataAccess_throw( sal_Int32 const i_columnIndex, sal_Int32 const i_rowIndex );
109 RowData& impl_getRowDataAccess_throw( sal_Int32 const i_rowIndex, size_t const i_requiredColumnCount );
111 GridData m_aData;
112 ::std::vector< css::uno::Any > m_aRowHeaders;
113 sal_Int32 m_nColumnCount;
116 DefaultGridDataModel::DefaultGridDataModel()
117 :DefaultGridDataModel_Base( m_aMutex )
118 ,m_aRowHeaders()
119 ,m_nColumnCount(0)
124 DefaultGridDataModel::DefaultGridDataModel( DefaultGridDataModel const & i_copySource )
125 :cppu::BaseMutex()
126 ,DefaultGridDataModel_Base( m_aMutex )
127 ,m_aData( i_copySource.m_aData )
128 ,m_aRowHeaders( i_copySource.m_aRowHeaders )
129 ,m_nColumnCount( i_copySource.m_nColumnCount )
133 void DefaultGridDataModel::broadcast( GridDataEvent const & i_event,
134 void ( SAL_CALL XGridDataListener::*i_listenerMethod )( GridDataEvent const & ), ::comphelper::ComponentGuard & i_instanceLock )
136 ::cppu::OInterfaceContainerHelper* pListeners = rBHelper.getContainer( cppu::UnoType<XGridDataListener>::get() );
137 if ( !pListeners )
138 return;
140 i_instanceLock.clear();
141 pListeners->notifyEach( i_listenerMethod, i_event );
145 ::sal_Int32 SAL_CALL DefaultGridDataModel::getRowCount()
147 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
148 return impl_getRowCount_nolck();
152 ::sal_Int32 SAL_CALL DefaultGridDataModel::getColumnCount()
154 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
155 return m_nColumnCount;
159 DefaultGridDataModel::CellData const & DefaultGridDataModel::impl_getCellData_throw( sal_Int32 const i_column, sal_Int32 const i_row ) const
161 if ( ( i_row < 0 ) || ( size_t( i_row ) > m_aData.size() )
162 || ( i_column < 0 ) || ( i_column > m_nColumnCount )
164 throw IndexOutOfBoundsException( OUString(), *const_cast< DefaultGridDataModel* >( this ) );
166 RowData const & rRow( m_aData[ i_row ] );
167 if ( size_t( i_column ) < rRow.size() )
168 return rRow[ i_column ];
170 static CellData s_aEmpty;
171 return s_aEmpty;
175 DefaultGridDataModel::RowData& DefaultGridDataModel::impl_getRowDataAccess_throw( sal_Int32 const i_rowIndex, size_t const i_requiredColumnCount )
177 OSL_ENSURE( i_requiredColumnCount <= size_t( m_nColumnCount ), "DefaultGridDataModel::impl_getRowDataAccess_throw: invalid column count!" );
178 if ( ( i_rowIndex < 0 ) || ( size_t( i_rowIndex ) >= m_aData.size() ) )
179 throw IndexOutOfBoundsException( OUString(), *this );
181 RowData& rRowData( m_aData[ i_rowIndex ] );
182 if ( rRowData.size() < i_requiredColumnCount )
183 rRowData.resize( i_requiredColumnCount );
184 return rRowData;
188 DefaultGridDataModel::CellData& DefaultGridDataModel::impl_getCellDataAccess_throw( sal_Int32 const i_columnIndex, sal_Int32 const i_rowIndex )
190 if ( ( i_columnIndex < 0 ) || ( i_columnIndex >= m_nColumnCount ) )
191 throw IndexOutOfBoundsException( OUString(), *this );
193 RowData& rRowData( impl_getRowDataAccess_throw( i_rowIndex, size_t( i_columnIndex + 1 ) ) );
194 return rRowData[ i_columnIndex ];
198 Any SAL_CALL DefaultGridDataModel::getCellData( ::sal_Int32 i_column, ::sal_Int32 i_row )
200 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
201 return impl_getCellData_throw( i_column, i_row ).first;
205 Any SAL_CALL DefaultGridDataModel::getCellToolTip( ::sal_Int32 i_column, ::sal_Int32 i_row )
207 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
208 return impl_getCellData_throw( i_column, i_row ).second;
212 Any SAL_CALL DefaultGridDataModel::getRowHeading( ::sal_Int32 i_row )
214 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
216 if ( ( i_row < 0 ) || ( size_t( i_row ) >= m_aRowHeaders.size() ) )
217 throw IndexOutOfBoundsException( OUString(), *this );
219 return m_aRowHeaders[ i_row ];
223 Sequence< Any > SAL_CALL DefaultGridDataModel::getRowData( ::sal_Int32 i_rowIndex )
225 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
227 Sequence< Any > resultData( m_nColumnCount );
228 RowData& rRowData = impl_getRowDataAccess_throw( i_rowIndex, m_nColumnCount );
230 ::std::transform( rRowData.begin(), rRowData.end(), resultData.getArray(),
231 [] ( const CellData& rCellData )
232 { return rCellData.first; });
233 return resultData;
237 void DefaultGridDataModel::impl_insertRow( sal_Int32 const i_position, Any const & i_heading, Sequence< Any > const & i_rowData, sal_Int32 const i_assumedColCount )
239 OSL_PRECOND( ( i_assumedColCount <= 0 ) || ( i_assumedColCount >= i_rowData.getLength() ),
240 "DefaultGridDataModel::impl_insertRow: invalid column count!" );
242 // insert heading
243 m_aRowHeaders.insert( m_aRowHeaders.begin() + i_position, i_heading );
245 // create new data row
246 RowData newRow( i_assumedColCount > 0 ? i_assumedColCount : i_rowData.getLength() );
247 RowData::iterator cellData = newRow.begin();
248 for ( const Any* pData = i_rowData.begin(); pData != i_rowData.end(); ++pData, ++cellData )
249 cellData->first = *pData;
251 // insert data row
252 m_aData.insert( m_aData.begin() + i_position, newRow );
256 void SAL_CALL DefaultGridDataModel::addRow( const Any& i_heading, const Sequence< Any >& i_data )
258 insertRow( getRowCount(), i_heading, i_data );
262 void SAL_CALL DefaultGridDataModel::addRows( const Sequence< Any >& i_headings, const Sequence< Sequence< Any > >& i_data )
264 insertRows( getRowCount(), i_headings, i_data );
268 void SAL_CALL DefaultGridDataModel::insertRow( ::sal_Int32 i_index, const Any& i_heading, const Sequence< Any >& i_data )
270 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
272 if ( ( i_index < 0 ) || ( i_index > impl_getRowCount_nolck() ) )
273 throw IndexOutOfBoundsException( OUString(), *this );
275 // actually insert the row
276 impl_insertRow( i_index, i_heading, i_data );
278 // update column count
279 sal_Int32 const columnCount = i_data.getLength();
280 if ( columnCount > m_nColumnCount )
281 m_nColumnCount = columnCount;
283 broadcast(
284 GridDataEvent( *this, -1, -1, i_index, i_index ),
285 &XGridDataListener::rowsInserted,
286 aGuard
291 void SAL_CALL DefaultGridDataModel::insertRows( ::sal_Int32 i_index, const Sequence< Any>& i_headings, const Sequence< Sequence< Any > >& i_data )
293 if ( i_headings.getLength() != i_data.getLength() )
294 throw IllegalArgumentException( OUString(), *this, -1 );
296 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
298 if ( ( i_index < 0 ) || ( i_index > impl_getRowCount_nolck() ) )
299 throw IndexOutOfBoundsException( OUString(), *this );
301 sal_Int32 const rowCount = i_headings.getLength();
302 if ( rowCount == 0 )
303 return;
305 // determine max col count in the new data
306 sal_Int32 maxColCount = 0;
307 for ( sal_Int32 row=0; row<rowCount; ++row )
308 if ( i_data[row].getLength() > maxColCount )
309 maxColCount = i_data[row].getLength();
311 if ( maxColCount < m_nColumnCount )
312 maxColCount = m_nColumnCount;
314 for ( sal_Int32 row=0; row<rowCount; ++row )
316 impl_insertRow( i_index + row, i_headings[row], i_data[row], maxColCount );
319 if ( maxColCount > m_nColumnCount )
320 m_nColumnCount = maxColCount;
322 broadcast(
323 GridDataEvent( *this, -1, -1, i_index, i_index + rowCount - 1 ),
324 &XGridDataListener::rowsInserted,
325 aGuard
330 void SAL_CALL DefaultGridDataModel::removeRow( ::sal_Int32 i_rowIndex )
332 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
334 if ( ( i_rowIndex < 0 ) || ( size_t( i_rowIndex ) >= m_aData.size() ) )
335 throw IndexOutOfBoundsException( OUString(), *this );
337 m_aRowHeaders.erase( m_aRowHeaders.begin() + i_rowIndex );
338 m_aData.erase( m_aData.begin() + i_rowIndex );
340 broadcast(
341 GridDataEvent( *this, -1, -1, i_rowIndex, i_rowIndex ),
342 &XGridDataListener::rowsRemoved,
343 aGuard
348 void SAL_CALL DefaultGridDataModel::removeAllRows( )
350 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
352 m_aRowHeaders.clear();
353 m_aData.clear();
355 broadcast(
356 GridDataEvent( *this, -1, -1, -1, -1 ),
357 &XGridDataListener::rowsRemoved,
358 aGuard
363 void SAL_CALL DefaultGridDataModel::updateCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value )
365 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
367 impl_getCellDataAccess_throw( i_columnIndex, i_rowIndex ).first = i_value;
369 broadcast(
370 GridDataEvent( *this, i_columnIndex, i_columnIndex, i_rowIndex, i_rowIndex ),
371 &XGridDataListener::dataChanged,
372 aGuard
377 void SAL_CALL DefaultGridDataModel::updateRowData( const Sequence< ::sal_Int32 >& i_columnIndexes, ::sal_Int32 i_rowIndex, const Sequence< Any >& i_values )
379 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
381 if ( ( i_rowIndex < 0 ) || ( size_t( i_rowIndex ) >= m_aData.size() ) )
382 throw IndexOutOfBoundsException( OUString(), *this );
384 if ( i_columnIndexes.getLength() != i_values.getLength() )
385 throw IllegalArgumentException( OUString(), *this, 1 );
387 sal_Int32 const columnCount = i_columnIndexes.getLength();
388 if ( columnCount == 0 )
389 return;
391 for ( sal_Int32 col = 0; col < columnCount; ++col )
393 if ( ( i_columnIndexes[col] < 0 ) || ( i_columnIndexes[col] > m_nColumnCount ) )
394 throw IndexOutOfBoundsException( OUString(), *this );
397 RowData& rDataRow = m_aData[ i_rowIndex ];
398 for ( sal_Int32 col = 0; col < columnCount; ++col )
400 sal_Int32 const columnIndex = i_columnIndexes[ col ];
401 if ( size_t( columnIndex ) >= rDataRow.size() )
402 rDataRow.resize( columnIndex + 1 );
404 rDataRow[ columnIndex ].first = i_values[ col ];
407 sal_Int32 const firstAffectedColumn = *::std::min_element( i_columnIndexes.begin(), i_columnIndexes.end() );
408 sal_Int32 const lastAffectedColumn = *::std::max_element( i_columnIndexes.begin(), i_columnIndexes.end() );
409 broadcast(
410 GridDataEvent( *this, firstAffectedColumn, lastAffectedColumn, i_rowIndex, i_rowIndex ),
411 &XGridDataListener::dataChanged,
412 aGuard
417 void SAL_CALL DefaultGridDataModel::updateRowHeading( ::sal_Int32 i_rowIndex, const Any& i_heading )
419 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
421 if ( ( i_rowIndex < 0 ) || ( size_t( i_rowIndex ) >= m_aRowHeaders.size() ) )
422 throw IndexOutOfBoundsException( OUString(), *this );
424 m_aRowHeaders[ i_rowIndex ] = i_heading;
426 broadcast(
427 GridDataEvent( *this, -1, -1, i_rowIndex, i_rowIndex ),
428 &XGridDataListener::rowHeadingChanged,
429 aGuard
434 void SAL_CALL DefaultGridDataModel::updateCellToolTip( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value )
436 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
437 impl_getCellDataAccess_throw( i_columnIndex, i_rowIndex ).second = i_value;
441 void SAL_CALL DefaultGridDataModel::updateRowToolTip( ::sal_Int32 i_rowIndex, const Any& i_value )
443 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
445 RowData& rRowData = impl_getRowDataAccess_throw( i_rowIndex, m_nColumnCount );
446 for ( RowData::iterator cell = rRowData.begin(); cell != rRowData.end(); ++cell )
447 cell->second = i_value;
451 void SAL_CALL DefaultGridDataModel::addGridDataListener( const Reference< grid::XGridDataListener >& i_listener )
453 rBHelper.addListener( cppu::UnoType<XGridDataListener>::get(), i_listener );
457 void SAL_CALL DefaultGridDataModel::removeGridDataListener( const Reference< grid::XGridDataListener >& i_listener )
459 rBHelper.removeListener( cppu::UnoType<XGridDataListener>::get(), i_listener );
463 void SAL_CALL DefaultGridDataModel::disposing()
465 css::lang::EventObject aEvent;
466 aEvent.Source.set( *this );
467 rBHelper.aLC.disposeAndClear( aEvent );
469 ::osl::MutexGuard aGuard( m_aMutex );
470 GridData aEmptyData;
471 m_aData.swap( aEmptyData );
473 ::std::vector< Any > aEmptyRowHeaders;
474 m_aRowHeaders.swap( aEmptyRowHeaders );
476 m_nColumnCount = 0;
480 OUString SAL_CALL DefaultGridDataModel::getImplementationName( )
482 return OUString("stardiv.Toolkit.DefaultGridDataModel");
485 sal_Bool SAL_CALL DefaultGridDataModel::supportsService( const OUString& ServiceName )
487 return cppu::supportsService(this, ServiceName);
490 Sequence< OUString > SAL_CALL DefaultGridDataModel::getSupportedServiceNames( )
492 Sequence<OUString> aSeq { "com.sun.star.awt.grid.DefaultGridDataModel" };
493 return aSeq;
497 Reference< css::util::XCloneable > SAL_CALL DefaultGridDataModel::createClone( )
499 return new DefaultGridDataModel( *this );
504 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
505 stardiv_Toolkit_DefaultGridDataModel_get_implementation(
506 css::uno::XComponentContext *,
507 css::uno::Sequence<css::uno::Any> const &)
509 return cppu::acquire(new DefaultGridDataModel());
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */