1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
45 enum broadcast_type
{ row_added
, row_removed
, data_changed
};
47 typedef ::cppu::WeakComponentImplHelper
< XMutableGridDataModel
49 > DefaultGridDataModel_Base
;
51 class DefaultGridDataModel
:public ::cppu::BaseMutex
52 ,public DefaultGridDataModel_Base
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
;
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
;
82 virtual void SAL_CALL
disposing() override
;
85 virtual css::uno::Reference
< css::util::XCloneable
> SAL_CALL
createClone( ) override
;
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
;
93 typedef ::std::pair
< Any
, Any
> CellData
;
94 typedef ::std::vector
< CellData
> RowData
;
95 typedef ::std::vector
< RowData
> GridData
;
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
);
112 ::std::vector
< css::uno::Any
> m_aRowHeaders
;
113 sal_Int32 m_nColumnCount
;
116 DefaultGridDataModel::DefaultGridDataModel()
117 :DefaultGridDataModel_Base( m_aMutex
)
124 DefaultGridDataModel::DefaultGridDataModel( DefaultGridDataModel
const & i_copySource
)
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() );
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
;
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
);
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
; });
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!" );
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
;
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
;
284 GridDataEvent( *this, -1, -1, i_index
, i_index
),
285 &XGridDataListener::rowsInserted
,
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();
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
;
323 GridDataEvent( *this, -1, -1, i_index
, i_index
+ rowCount
- 1 ),
324 &XGridDataListener::rowsInserted
,
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
);
341 GridDataEvent( *this, -1, -1, i_rowIndex
, i_rowIndex
),
342 &XGridDataListener::rowsRemoved
,
348 void SAL_CALL
DefaultGridDataModel::removeAllRows( )
350 ::comphelper::ComponentGuard
aGuard( *this, rBHelper
);
352 m_aRowHeaders
.clear();
356 GridDataEvent( *this, -1, -1, -1, -1 ),
357 &XGridDataListener::rowsRemoved
,
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
;
370 GridDataEvent( *this, i_columnIndex
, i_columnIndex
, i_rowIndex
, i_rowIndex
),
371 &XGridDataListener::dataChanged
,
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 )
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() );
410 GridDataEvent( *this, firstAffectedColumn
, lastAffectedColumn
, i_rowIndex
, i_rowIndex
),
411 &XGridDataListener::dataChanged
,
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
;
427 GridDataEvent( *this, -1, -1, i_rowIndex
, i_rowIndex
),
428 &XGridDataListener::rowHeadingChanged
,
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
);
471 m_aData
.swap( aEmptyData
);
473 ::std::vector
< Any
> aEmptyRowHeaders
;
474 m_aRowHeaders
.swap( aEmptyRowHeaders
);
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" };
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: */