Avoid potential negative array index access to cached text.
[LibreOffice.git] / toolkit / source / controls / grid / defaultgridcolumnmodel.cxx
blob5e1a085ba06f7f8d8091ba05b06822c9e4cf3246
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 .
21 #include "gridcolumn.hxx"
23 #include <com/sun/star/awt/grid/XGridColumnModel.hpp>
24 #include <com/sun/star/awt/grid/XGridColumn.hpp>
25 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
26 #include <com/sun/star/lang/XServiceInfo.hpp>
27 #include <com/sun/star/uno/XComponentContext.hpp>
29 #include <comphelper/sequence.hxx>
30 #include <comphelper/servicehelper.hxx>
31 #include <comphelper/componentguard.hxx>
32 #include <comphelper/interfacecontainer4.hxx>
33 #include <comphelper/compbase.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 #include <o3tl/safeint.hxx>
36 #include <rtl/ref.hxx>
37 #include <sal/log.hxx>
38 #include <comphelper/diagnose_ex.hxx>
40 #include <vector>
42 using namespace css::awt;
43 using namespace css::awt::grid;
44 using namespace css::container;
45 using namespace css::lang;
46 using namespace css::uno;
47 using namespace toolkit;
49 namespace {
51 typedef ::comphelper::WeakComponentImplHelper < css::awt::grid::XGridColumnModel
52 , css::lang::XServiceInfo
53 > DefaultGridColumnModel_Base;
55 class DefaultGridColumnModel : public DefaultGridColumnModel_Base
57 public:
58 DefaultGridColumnModel();
59 DefaultGridColumnModel( DefaultGridColumnModel const & i_copySource );
61 // XGridColumnModel
62 virtual ::sal_Int32 SAL_CALL getColumnCount() override;
63 virtual css::uno::Reference< css::awt::grid::XGridColumn > SAL_CALL createColumn( ) override;
64 virtual ::sal_Int32 SAL_CALL addColumn(const css::uno::Reference< css::awt::grid::XGridColumn > & column) override;
65 virtual void SAL_CALL removeColumn( ::sal_Int32 i_columnIndex ) override;
66 virtual css::uno::Sequence< css::uno::Reference< css::awt::grid::XGridColumn > > SAL_CALL getColumns() override;
67 virtual css::uno::Reference< css::awt::grid::XGridColumn > SAL_CALL getColumn(::sal_Int32 index) override;
68 virtual void SAL_CALL setDefaultColumns(sal_Int32 rowElements) override;
70 // XServiceInfo
71 virtual OUString SAL_CALL getImplementationName( ) override;
72 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
73 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
75 // XContainer
76 virtual void SAL_CALL addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
77 virtual void SAL_CALL removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
79 // XCloneable
80 virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override;
82 // OComponentHelper
83 virtual void disposing( std::unique_lock<std::mutex>& ) override;
85 private:
86 typedef ::std::vector< rtl::Reference< GridColumn > > Columns;
88 ::comphelper::OInterfaceContainerHelper4<XContainerListener> m_aContainerListeners;
89 Columns m_aColumns;
92 DefaultGridColumnModel::DefaultGridColumnModel()
96 DefaultGridColumnModel::DefaultGridColumnModel( DefaultGridColumnModel const & i_copySource )
98 Columns aColumns;
99 aColumns.reserve( i_copySource.m_aColumns.size() );
102 for ( Columns::const_iterator col = i_copySource.m_aColumns.begin();
103 col != i_copySource.m_aColumns.end();
104 ++col
107 rtl::Reference< GridColumn > const xClone( new GridColumn(**col) );
109 xClone->setIndex( col - i_copySource.m_aColumns.begin() );
111 aColumns.push_back( xClone );
114 catch( const Exception& )
116 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
118 if ( aColumns.size() == i_copySource.m_aColumns.size() )
119 m_aColumns.swap( aColumns );
122 ::sal_Int32 SAL_CALL DefaultGridColumnModel::getColumnCount()
124 return m_aColumns.size();
128 Reference< XGridColumn > SAL_CALL DefaultGridColumnModel::createColumn( )
130 std::unique_lock aGuard(m_aMutex);
131 throwIfDisposed(aGuard);
132 return new GridColumn();
136 ::sal_Int32 SAL_CALL DefaultGridColumnModel::addColumn( const Reference< XGridColumn > & i_column )
138 std::unique_lock aGuard(m_aMutex);
139 throwIfDisposed(aGuard);
141 GridColumn* const pGridColumn = dynamic_cast<GridColumn*>( i_column.get() );
142 if ( pGridColumn == nullptr )
143 throw css::lang::IllegalArgumentException( "invalid column implementation", *this, 1 );
145 m_aColumns.push_back( pGridColumn );
146 sal_Int32 index = m_aColumns.size() - 1;
147 pGridColumn->setIndex( index );
149 // fire insertion notifications
150 ContainerEvent aEvent;
151 aEvent.Source = *this;
152 aEvent.Accessor <<= index;
153 aEvent.Element <<= i_column;
155 m_aContainerListeners.notifyEach( aGuard, &XContainerListener::elementInserted, aEvent );
157 return index;
161 void SAL_CALL DefaultGridColumnModel::removeColumn( ::sal_Int32 i_columnIndex )
163 std::unique_lock aGuard(m_aMutex);
164 throwIfDisposed(aGuard);
166 if ( ( i_columnIndex < 0 ) || ( o3tl::make_unsigned( i_columnIndex ) >= m_aColumns.size() ) )
167 throw css::lang::IndexOutOfBoundsException( OUString(), *this );
169 Columns::iterator const pos = m_aColumns.begin() + i_columnIndex;
170 Reference< XGridColumn > const xColumn( *pos );
171 m_aColumns.erase( pos );
173 // update indexes of all subsequent columns
174 sal_Int32 columnIndex( i_columnIndex );
175 for ( Columns::iterator updatePos = m_aColumns.begin() + columnIndex;
176 updatePos != m_aColumns.end();
177 ++updatePos, ++columnIndex
180 GridColumn* pColumnImpl = updatePos->get();
181 pColumnImpl->setIndex( columnIndex );
184 // fire removal notifications
185 ContainerEvent aEvent;
186 aEvent.Source = *this;
187 aEvent.Accessor <<= i_columnIndex;
188 aEvent.Element <<= xColumn;
190 m_aContainerListeners.notifyEach( aGuard, &XContainerListener::elementRemoved, aEvent );
192 aGuard.unlock();
194 // dispose the removed column
197 xColumn->dispose();
199 catch( const Exception& )
201 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
206 Sequence< Reference< XGridColumn > > SAL_CALL DefaultGridColumnModel::getColumns()
208 std::unique_lock aGuard(m_aMutex);
209 throwIfDisposed(aGuard);
210 return ::comphelper::containerToSequence<Reference<XGridColumn>>( m_aColumns );
214 Reference< XGridColumn > SAL_CALL DefaultGridColumnModel::getColumn(::sal_Int32 index)
216 std::unique_lock aGuard(m_aMutex);
217 throwIfDisposed(aGuard);
219 if ( index >=0 && o3tl::make_unsigned(index) < m_aColumns.size())
220 return m_aColumns[index];
222 throw css::lang::IndexOutOfBoundsException();
226 void SAL_CALL DefaultGridColumnModel::setDefaultColumns(sal_Int32 rowElements)
228 ::std::vector< ContainerEvent > aRemovedColumns;
229 ::std::vector< ContainerEvent > aInsertedColumns;
231 std::unique_lock aGuard(m_aMutex);
232 throwIfDisposed(aGuard);
234 // remove existing columns
235 while ( !m_aColumns.empty() )
237 const size_t lastColIndex = m_aColumns.size() - 1;
239 ContainerEvent aEvent;
240 aEvent.Source = *this;
241 aEvent.Accessor <<= sal_Int32( lastColIndex );
242 aEvent.Element <<= Reference<XGridColumn>(m_aColumns[ lastColIndex ]);
243 aRemovedColumns.push_back( aEvent );
245 m_aColumns.erase( m_aColumns.begin() + lastColIndex );
248 // add new columns
249 for ( sal_Int32 i=0; i<rowElements; ++i )
251 ::rtl::Reference< GridColumn > const pGridColumn = new GridColumn();
252 OUString colTitle = "Column " + OUString::number( i + 1 );
253 pGridColumn->setTitle( colTitle );
254 pGridColumn->setColumnWidth( 80 /* APPFONT */ );
255 pGridColumn->setFlexibility( 1 );
256 pGridColumn->setResizeable( true );
257 pGridColumn->setDataColumnIndex( i );
259 ContainerEvent aEvent;
260 aEvent.Source = *this;
261 aEvent.Accessor <<= i;
262 aEvent.Element <<= Reference<XGridColumn>(pGridColumn);
263 aInsertedColumns.push_back( aEvent );
265 m_aColumns.push_back( pGridColumn );
266 pGridColumn->setIndex( i );
269 // fire removal notifications
270 for (const auto& rEvent : aRemovedColumns)
272 m_aContainerListeners.notifyEach( aGuard, &XContainerListener::elementRemoved, rEvent );
275 // fire insertion notifications
276 for (const auto& rEvent : aInsertedColumns)
278 m_aContainerListeners.notifyEach( aGuard, &XContainerListener::elementInserted, rEvent );
281 aGuard.unlock();
283 // dispose removed columns
284 for (const auto& rEvent : aRemovedColumns)
288 const Reference< XComponent > xColComp( rEvent.Element, UNO_QUERY );
289 if (xColComp)
290 xColComp->dispose();
292 catch( const Exception& )
294 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
300 OUString SAL_CALL DefaultGridColumnModel::getImplementationName( )
302 return "stardiv.Toolkit.DefaultGridColumnModel";
305 sal_Bool SAL_CALL DefaultGridColumnModel::supportsService( const OUString& i_serviceName )
307 return cppu::supportsService(this, i_serviceName);
310 Sequence< OUString > SAL_CALL DefaultGridColumnModel::getSupportedServiceNames( )
312 return { "com.sun.star.awt.grid.DefaultGridColumnModel" };
316 void SAL_CALL DefaultGridColumnModel::addContainerListener( const Reference< XContainerListener >& i_listener )
318 std::unique_lock aGuard(m_aMutex);
319 if ( i_listener.is() )
320 m_aContainerListeners.addInterface( aGuard, i_listener );
324 void SAL_CALL DefaultGridColumnModel::removeContainerListener( const Reference< XContainerListener >& i_listener )
326 std::unique_lock aGuard(m_aMutex);
327 if ( i_listener.is() )
328 m_aContainerListeners.removeInterface( aGuard, i_listener );
332 void DefaultGridColumnModel::disposing( std::unique_lock<std::mutex>& rGuard )
334 DefaultGridColumnModel_Base::disposing(rGuard);
336 EventObject aEvent( *this );
337 m_aContainerListeners.disposeAndClear( rGuard, aEvent );
339 // remove, dispose and clear columns
340 while ( !m_aColumns.empty() )
344 m_aColumns[ 0 ]->dispose();
346 catch( const Exception& )
348 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
351 m_aColumns.erase( m_aColumns.begin() );
354 Columns().swap(m_aColumns);
358 Reference< css::util::XCloneable > SAL_CALL DefaultGridColumnModel::createClone( )
360 std::unique_lock aGuard(m_aMutex);
361 throwIfDisposed(aGuard);
362 return new DefaultGridColumnModel( *this );
367 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
368 stardiv_Toolkit_DefaultGridColumnModel_get_implementation(
369 css::uno::XComponentContext *,
370 css::uno::Sequence<css::uno::Any> const &)
372 return cppu::acquire(new DefaultGridColumnModel());
375 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */