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/IllegalArgumentException.hpp>
22 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
23 #include <com/sun/star/lang/XServiceInfo.hpp>
24 #include <com/sun/star/uno/XComponentContext.hpp>
26 #include <comphelper/compbase.hxx>
27 #include <cppuhelper/supportsservice.hxx>
28 #include <o3tl/safeint.hxx>
29 #include <osl/diagnose.h>
34 using namespace ::com::sun::star
;
35 using namespace ::com::sun::star::uno
;
36 using namespace ::com::sun::star::awt
;
37 using namespace ::com::sun::star::awt::grid
;
38 using namespace ::com::sun::star::lang
;
42 typedef ::comphelper::WeakComponentImplHelper
< XMutableGridDataModel
44 > DefaultGridDataModel_Base
;
46 class DefaultGridDataModel
: public DefaultGridDataModel_Base
49 DefaultGridDataModel();
50 DefaultGridDataModel( DefaultGridDataModel
const & i_copySource
);
52 // XMutableGridDataModel
53 virtual void SAL_CALL
addRow( const Any
& i_heading
, const css::uno::Sequence
< css::uno::Any
>& Data
) override
;
54 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
;
55 virtual void SAL_CALL
insertRow( ::sal_Int32 i_index
, const css::uno::Any
& i_heading
, const css::uno::Sequence
< css::uno::Any
>& Data
) override
;
56 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
;
57 virtual void SAL_CALL
removeRow( ::sal_Int32 RowIndex
) override
;
58 virtual void SAL_CALL
removeAllRows( ) override
;
59 virtual void SAL_CALL
updateCellData( ::sal_Int32 ColumnIndex
, ::sal_Int32 RowIndex
, const css::uno::Any
& Value
) override
;
60 virtual void SAL_CALL
updateRowData( const css::uno::Sequence
< ::sal_Int32
>& ColumnIndexes
, ::sal_Int32 RowIndex
, const css::uno::Sequence
< css::uno::Any
>& Values
) override
;
61 virtual void SAL_CALL
updateRowHeading( ::sal_Int32 RowIndex
, const css::uno::Any
& Heading
) override
;
62 virtual void SAL_CALL
updateCellToolTip( ::sal_Int32 ColumnIndex
, ::sal_Int32 RowIndex
, const css::uno::Any
& Value
) override
;
63 virtual void SAL_CALL
updateRowToolTip( ::sal_Int32 RowIndex
, const css::uno::Any
& Value
) override
;
64 virtual void SAL_CALL
addGridDataListener( const css::uno::Reference
< css::awt::grid::XGridDataListener
>& Listener
) override
;
65 virtual void SAL_CALL
removeGridDataListener( const css::uno::Reference
< css::awt::grid::XGridDataListener
>& Listener
) override
;
68 virtual ::sal_Int32 SAL_CALL
getRowCount() override
;
69 virtual ::sal_Int32 SAL_CALL
getColumnCount() override
;
70 virtual css::uno::Any SAL_CALL
getCellData( ::sal_Int32 Column
, ::sal_Int32 Row
) override
;
71 virtual css::uno::Any SAL_CALL
getCellToolTip( ::sal_Int32 Column
, ::sal_Int32 Row
) override
;
72 virtual css::uno::Any SAL_CALL
getRowHeading( ::sal_Int32 RowIndex
) override
;
73 virtual css::uno::Sequence
< css::uno::Any
> SAL_CALL
getRowData( ::sal_Int32 RowIndex
) override
;
76 virtual void disposing( std::unique_lock
<std::mutex
>& ) override
;
79 virtual css::uno::Reference
< css::util::XCloneable
> SAL_CALL
createClone( ) override
;
82 virtual OUString SAL_CALL
getImplementationName( ) override
;
83 virtual sal_Bool SAL_CALL
supportsService( const OUString
& ServiceName
) override
;
84 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames( ) override
;
87 typedef ::std::pair
< Any
, Any
> CellData
;
88 typedef ::std::vector
< CellData
> RowData
;
89 typedef ::std::vector
< RowData
> GridData
;
92 GridDataEvent
const & i_event
,
93 void ( SAL_CALL
css::awt::grid::XGridDataListener::*i_listenerMethod
)( css::awt::grid::GridDataEvent
const & ),
94 std::unique_lock
<std::mutex
>& i_instanceLock
97 void impl_insertRow( std::unique_lock
<std::mutex
>& rGuard
, sal_Int32
const i_position
, Any
const & i_heading
, Sequence
< Any
> const & i_rowData
, sal_Int32
const i_assumedColCount
= -1 );
99 ::sal_Int32
impl_getRowCount(std::unique_lock
<std::mutex
>&) const { return sal_Int32( m_aData
.size() ); }
101 CellData
const & impl_getCellData_throw( std::unique_lock
<std::mutex
>& rGuard
, sal_Int32
const i_columnIndex
, sal_Int32
const i_rowIndex
) const;
102 CellData
& impl_getCellDataAccess_throw( std::unique_lock
<std::mutex
>& rGuard
, sal_Int32
const i_columnIndex
, sal_Int32
const i_rowIndex
);
103 RowData
& impl_getRowDataAccess_throw( std::unique_lock
<std::mutex
>& rGuard
, sal_Int32
const i_rowIndex
, size_t const i_requiredColumnCount
);
106 ::std::vector
< css::uno::Any
> m_aRowHeaders
;
107 sal_Int32 m_nColumnCount
;
108 comphelper::OInterfaceContainerHelper4
<XGridDataListener
> maGridDataListeners
;
111 DefaultGridDataModel::DefaultGridDataModel()
117 DefaultGridDataModel::DefaultGridDataModel( DefaultGridDataModel
const & i_copySource
)
118 :m_aData( i_copySource
.m_aData
)
119 ,m_aRowHeaders( i_copySource
.m_aRowHeaders
)
120 ,m_nColumnCount( i_copySource
.m_nColumnCount
)
124 void DefaultGridDataModel::broadcast( GridDataEvent
const & i_event
,
125 void ( SAL_CALL
XGridDataListener::*i_listenerMethod
)( GridDataEvent
const & ), std::unique_lock
<std::mutex
>& i_instanceLock
)
127 maGridDataListeners
.notifyEach( i_instanceLock
, i_listenerMethod
, i_event
);
131 ::sal_Int32 SAL_CALL
DefaultGridDataModel::getRowCount()
133 std::unique_lock
aGuard(m_aMutex
);
134 throwIfDisposed(aGuard
);
135 return impl_getRowCount(aGuard
);
139 ::sal_Int32 SAL_CALL
DefaultGridDataModel::getColumnCount()
141 std::unique_lock
aGuard(m_aMutex
);
142 throwIfDisposed(aGuard
);
143 return m_nColumnCount
;
147 DefaultGridDataModel::CellData
const & DefaultGridDataModel::impl_getCellData_throw( std::unique_lock
<std::mutex
>& /*rGuard*/, sal_Int32
const i_column
, sal_Int32
const i_row
) const
149 if ( ( i_row
< 0 ) || ( o3tl::make_unsigned( i_row
) > m_aData
.size() )
150 || ( i_column
< 0 ) || ( i_column
> m_nColumnCount
)
152 throw IndexOutOfBoundsException( OUString(), *const_cast< DefaultGridDataModel
* >( this ) );
154 RowData
const & rRow( m_aData
[ i_row
] );
155 if ( o3tl::make_unsigned( i_column
) < rRow
.size() )
156 return rRow
[ i_column
];
158 static CellData s_aEmpty
;
163 DefaultGridDataModel::RowData
& DefaultGridDataModel::impl_getRowDataAccess_throw( std::unique_lock
<std::mutex
>& /*rGuard*/, sal_Int32
const i_rowIndex
, size_t const i_requiredColumnCount
)
165 OSL_ENSURE( i_requiredColumnCount
<= o3tl::make_unsigned( m_nColumnCount
), "DefaultGridDataModel::impl_getRowDataAccess_throw: invalid column count!" );
166 if ( ( i_rowIndex
< 0 ) || ( o3tl::make_unsigned( i_rowIndex
) >= m_aData
.size() ) )
167 throw IndexOutOfBoundsException( OUString(), *this );
169 RowData
& rRowData( m_aData
[ i_rowIndex
] );
170 if ( rRowData
.size() < i_requiredColumnCount
)
171 rRowData
.resize( i_requiredColumnCount
);
176 DefaultGridDataModel::CellData
& DefaultGridDataModel::impl_getCellDataAccess_throw( std::unique_lock
<std::mutex
>& rGuard
, sal_Int32
const i_columnIndex
, sal_Int32
const i_rowIndex
)
178 if ( ( i_columnIndex
< 0 ) || ( i_columnIndex
>= m_nColumnCount
) )
179 throw IndexOutOfBoundsException( OUString(), *this );
181 RowData
& rRowData( impl_getRowDataAccess_throw( rGuard
, i_rowIndex
, size_t( i_columnIndex
+ 1 ) ) );
182 return rRowData
[ i_columnIndex
];
186 Any SAL_CALL
DefaultGridDataModel::getCellData( ::sal_Int32 i_column
, ::sal_Int32 i_row
)
188 std::unique_lock
aGuard(m_aMutex
);
189 throwIfDisposed(aGuard
);
190 return impl_getCellData_throw( aGuard
, i_column
, i_row
).first
;
194 Any SAL_CALL
DefaultGridDataModel::getCellToolTip( ::sal_Int32 i_column
, ::sal_Int32 i_row
)
196 std::unique_lock
aGuard(m_aMutex
);
197 throwIfDisposed(aGuard
);
198 return impl_getCellData_throw( aGuard
, i_column
, i_row
).second
;
202 Any SAL_CALL
DefaultGridDataModel::getRowHeading( ::sal_Int32 i_row
)
204 std::unique_lock
aGuard(m_aMutex
);
205 throwIfDisposed(aGuard
);
207 if ( ( i_row
< 0 ) || ( o3tl::make_unsigned( i_row
) >= m_aRowHeaders
.size() ) )
208 throw IndexOutOfBoundsException( OUString(), *this );
210 return m_aRowHeaders
[ i_row
];
214 Sequence
< Any
> SAL_CALL
DefaultGridDataModel::getRowData( ::sal_Int32 i_rowIndex
)
216 std::unique_lock
aGuard(m_aMutex
);
217 throwIfDisposed(aGuard
);
219 Sequence
< Any
> resultData( m_nColumnCount
);
220 RowData
& rRowData
= impl_getRowDataAccess_throw( aGuard
, i_rowIndex
, m_nColumnCount
);
222 ::std::transform( rRowData
.begin(), rRowData
.end(), resultData
.getArray(),
223 [] ( const CellData
& rCellData
)
224 { return rCellData
.first
; });
229 void DefaultGridDataModel::impl_insertRow( std::unique_lock
<std::mutex
>& /*rGuard*/, sal_Int32
const i_position
, Any
const & i_heading
, Sequence
< Any
> const & i_rowData
, sal_Int32
const i_assumedColCount
)
231 OSL_PRECOND( ( i_assumedColCount
<= 0 ) || ( i_assumedColCount
>= i_rowData
.getLength() ),
232 "DefaultGridDataModel::impl_insertRow: invalid column count!" );
235 m_aRowHeaders
.insert( m_aRowHeaders
.begin() + i_position
, i_heading
);
237 // create new data row
238 RowData
newRow( i_assumedColCount
> 0 ? i_assumedColCount
: i_rowData
.getLength() );
239 RowData::iterator cellData
= newRow
.begin();
240 for ( const Any
& rData
: i_rowData
)
242 cellData
->first
= rData
;
247 m_aData
.insert( m_aData
.begin() + i_position
, newRow
);
251 void SAL_CALL
DefaultGridDataModel::addRow( const Any
& i_heading
, const Sequence
< Any
>& i_data
)
253 insertRow( getRowCount(), i_heading
, i_data
);
257 void SAL_CALL
DefaultGridDataModel::addRows( const Sequence
< Any
>& i_headings
, const Sequence
< Sequence
< Any
> >& i_data
)
259 insertRows( getRowCount(), i_headings
, i_data
);
263 void SAL_CALL
DefaultGridDataModel::insertRow( ::sal_Int32 i_index
, const Any
& i_heading
, const Sequence
< Any
>& i_data
)
265 std::unique_lock
aGuard(m_aMutex
);
266 throwIfDisposed(aGuard
);
268 if ( ( i_index
< 0 ) || ( i_index
> impl_getRowCount(aGuard
) ) )
269 throw IndexOutOfBoundsException( OUString(), *this );
271 // actually insert the row
272 impl_insertRow( aGuard
, i_index
, i_heading
, i_data
);
274 // update column count
275 sal_Int32
const columnCount
= i_data
.getLength();
276 if ( columnCount
> m_nColumnCount
)
277 m_nColumnCount
= columnCount
;
280 GridDataEvent( *this, -1, -1, i_index
, i_index
),
281 &XGridDataListener::rowsInserted
,
287 void SAL_CALL
DefaultGridDataModel::insertRows( ::sal_Int32 i_index
, const Sequence
< Any
>& i_headings
, const Sequence
< Sequence
< Any
> >& i_data
)
289 if ( i_headings
.getLength() != i_data
.getLength() )
290 throw IllegalArgumentException( OUString(), *this, -1 );
292 std::unique_lock
aGuard(m_aMutex
);
293 throwIfDisposed(aGuard
);
295 if ( ( i_index
< 0 ) || ( i_index
> impl_getRowCount(aGuard
) ) )
296 throw IndexOutOfBoundsException( OUString(), *this );
298 sal_Int32
const rowCount
= i_headings
.getLength();
302 // determine max col count in the new data
303 auto pData
= std::max_element(i_data
.begin(), i_data
.end(),
304 [](const Sequence
< Any
>& a
, const Sequence
< Any
>& b
) { return a
.getLength() < b
.getLength(); });
305 sal_Int32 maxColCount
= pData
->getLength();
307 if ( maxColCount
< m_nColumnCount
)
308 maxColCount
= m_nColumnCount
;
310 for ( sal_Int32 row
=0; row
<rowCount
; ++row
)
312 impl_insertRow( aGuard
, i_index
+ row
, i_headings
[row
], i_data
[row
], maxColCount
);
315 if ( maxColCount
> m_nColumnCount
)
316 m_nColumnCount
= maxColCount
;
319 GridDataEvent( *this, -1, -1, i_index
, i_index
+ rowCount
- 1 ),
320 &XGridDataListener::rowsInserted
,
326 void SAL_CALL
DefaultGridDataModel::removeRow( ::sal_Int32 i_rowIndex
)
328 std::unique_lock
aGuard(m_aMutex
);
329 throwIfDisposed(aGuard
);
331 if ( ( i_rowIndex
< 0 ) || ( o3tl::make_unsigned( i_rowIndex
) >= m_aData
.size() ) )
332 throw IndexOutOfBoundsException( OUString(), *this );
334 m_aRowHeaders
.erase( m_aRowHeaders
.begin() + i_rowIndex
);
335 m_aData
.erase( m_aData
.begin() + i_rowIndex
);
338 GridDataEvent( *this, -1, -1, i_rowIndex
, i_rowIndex
),
339 &XGridDataListener::rowsRemoved
,
345 void SAL_CALL
DefaultGridDataModel::removeAllRows( )
347 std::unique_lock
aGuard(m_aMutex
);
348 throwIfDisposed(aGuard
);
350 m_aRowHeaders
.clear();
354 GridDataEvent( *this, -1, -1, -1, -1 ),
355 &XGridDataListener::rowsRemoved
,
361 void SAL_CALL
DefaultGridDataModel::updateCellData( ::sal_Int32 i_columnIndex
, ::sal_Int32 i_rowIndex
, const Any
& i_value
)
363 std::unique_lock
aGuard(m_aMutex
);
364 throwIfDisposed(aGuard
);
366 impl_getCellDataAccess_throw( aGuard
, i_columnIndex
, i_rowIndex
).first
= i_value
;
369 GridDataEvent( *this, i_columnIndex
, i_columnIndex
, i_rowIndex
, i_rowIndex
),
370 &XGridDataListener::dataChanged
,
376 void SAL_CALL
DefaultGridDataModel::updateRowData( const Sequence
< ::sal_Int32
>& i_columnIndexes
, ::sal_Int32 i_rowIndex
, const Sequence
< Any
>& i_values
)
378 std::unique_lock
aGuard(m_aMutex
);
379 throwIfDisposed(aGuard
);
381 if ( ( i_rowIndex
< 0 ) || ( o3tl::make_unsigned( 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
const columnIndex
: i_columnIndexes
)
393 if ( ( columnIndex
< 0 ) || ( columnIndex
> 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 ( o3tl::make_unsigned( columnIndex
) >= rDataRow
.size() )
402 rDataRow
.resize( columnIndex
+ 1 );
404 rDataRow
[ columnIndex
].first
= i_values
[ col
];
407 auto aPair
= ::std::minmax_element( i_columnIndexes
.begin(), i_columnIndexes
.end() );
408 sal_Int32
const firstAffectedColumn
= *aPair
.first
;
409 sal_Int32
const lastAffectedColumn
= *aPair
.second
;
411 GridDataEvent( *this, firstAffectedColumn
, lastAffectedColumn
, i_rowIndex
, i_rowIndex
),
412 &XGridDataListener::dataChanged
,
418 void SAL_CALL
DefaultGridDataModel::updateRowHeading( ::sal_Int32 i_rowIndex
, const Any
& i_heading
)
420 std::unique_lock
aGuard(m_aMutex
);
421 throwIfDisposed(aGuard
);
423 if ( ( i_rowIndex
< 0 ) || ( o3tl::make_unsigned( i_rowIndex
) >= m_aRowHeaders
.size() ) )
424 throw IndexOutOfBoundsException( OUString(), *this );
426 m_aRowHeaders
[ i_rowIndex
] = i_heading
;
429 GridDataEvent( *this, -1, -1, i_rowIndex
, i_rowIndex
),
430 &XGridDataListener::rowHeadingChanged
,
436 void SAL_CALL
DefaultGridDataModel::updateCellToolTip( ::sal_Int32 i_columnIndex
, ::sal_Int32 i_rowIndex
, const Any
& i_value
)
438 std::unique_lock
aGuard(m_aMutex
);
439 throwIfDisposed(aGuard
);
440 impl_getCellDataAccess_throw( aGuard
, i_columnIndex
, i_rowIndex
).second
= i_value
;
444 void SAL_CALL
DefaultGridDataModel::updateRowToolTip( ::sal_Int32 i_rowIndex
, const Any
& i_value
)
446 std::unique_lock
aGuard(m_aMutex
);
447 throwIfDisposed(aGuard
);
449 RowData
& rRowData
= impl_getRowDataAccess_throw( aGuard
, i_rowIndex
, m_nColumnCount
);
450 for ( auto& rCell
: rRowData
)
451 rCell
.second
= i_value
;
455 void SAL_CALL
DefaultGridDataModel::addGridDataListener( const Reference
< grid::XGridDataListener
>& i_listener
)
457 std::unique_lock
aGuard(m_aMutex
);
458 maGridDataListeners
.addInterface( aGuard
, i_listener
);
462 void SAL_CALL
DefaultGridDataModel::removeGridDataListener( const Reference
< grid::XGridDataListener
>& i_listener
)
464 std::unique_lock
aGuard(m_aMutex
);
465 maGridDataListeners
.removeInterface( aGuard
, i_listener
);
469 void DefaultGridDataModel::disposing(std::unique_lock
<std::mutex
>& rGuard
)
471 css::lang::EventObject aEvent
;
472 aEvent
.Source
.set( *this );
473 maGridDataListeners
.disposeAndClear(rGuard
, aEvent
);
475 GridData().swap(m_aData
);
476 std::vector
<Any
>().swap(m_aRowHeaders
);
481 OUString SAL_CALL
DefaultGridDataModel::getImplementationName( )
483 return "stardiv.Toolkit.DefaultGridDataModel";
486 sal_Bool SAL_CALL
DefaultGridDataModel::supportsService( const OUString
& ServiceName
)
488 return cppu::supportsService(this, ServiceName
);
491 Sequence
< OUString
> SAL_CALL
DefaultGridDataModel::getSupportedServiceNames( )
493 return { "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
*
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: */