1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_toolkit.hxx"
26
27 #include "defaultgridcolumnmodel.hxx"
28 #include "gridcolumn.hxx"
29
30 /** === begin UNO includes === **/
31 #include <com/sun/star/awt/XVclWindowPeer.hpp>
32 /** === end UNO includes === **/
33
34 #include <comphelper/sequence.hxx>
35 #include <comphelper/componentguard.hxx>
36 #include <toolkit/helper/servicenames.hxx>
37 #include <rtl/ustrbuf.hxx>
38 #include <tools/diagnose_ex.h>
39
40 //......................................................................................................................
41 namespace toolkit
42 //......................................................................................................................
43 {
44 /** === begin UNO using === **/
45 using ::com::sun::star::uno::Reference;
46 using ::com::sun::star::lang::XMultiServiceFactory;
47 using ::com::sun::star::uno::RuntimeException;
48 using ::com::sun::star::uno::Sequence;
49 using ::com::sun::star::uno::UNO_QUERY_THROW;
50 using ::com::sun::star::uno::UNO_QUERY;
51 using ::com::sun::star::awt::grid::XGridColumn;
52 using ::com::sun::star::uno::XInterface;
53 using ::com::sun::star::lang::XMultiServiceFactory;
54 using ::com::sun::star::lang::XComponent;
55 using ::com::sun::star::lang::EventObject;
56 using ::com::sun::star::container::XContainerListener;
57 using ::com::sun::star::container::ContainerEvent;
58 using ::com::sun::star::uno::Exception;
59 using ::com::sun::star::lang::IndexOutOfBoundsException;
60 using ::com::sun::star::util::XCloneable;
61 using ::com::sun::star::lang::IllegalArgumentException;
62 /** === end UNO using === **/
63
64 //==================================================================================================================
65 //= DefaultGridColumnModel
66 //==================================================================================================================
67 //------------------------------------------------------------------------------------------------------------------
DefaultGridColumnModel(const Reference<XMultiServiceFactory> & i_factory)68 DefaultGridColumnModel::DefaultGridColumnModel( const Reference< XMultiServiceFactory >& i_factory )
69 :DefaultGridColumnModel_Base( m_aMutex )
70 ,m_aContext( i_factory )
71 ,m_aContainerListeners( m_aMutex )
72 ,m_aColumns()
73 {
74 }
75
76 //------------------------------------------------------------------------------------------------------------------
DefaultGridColumnModel(DefaultGridColumnModel const & i_copySource)77 DefaultGridColumnModel::DefaultGridColumnModel( DefaultGridColumnModel const & i_copySource )
78 :cppu::BaseMutex()
79 ,DefaultGridColumnModel_Base( m_aMutex )
80 ,m_aContext( i_copySource.m_aContext )
81 ,m_aContainerListeners( m_aMutex )
82 ,m_aColumns()
83 {
84 Columns aColumns;
85 aColumns.reserve( i_copySource.m_aColumns.size() );
86 try
87 {
88 for ( Columns::const_iterator col = i_copySource.m_aColumns.begin();
89 col != i_copySource.m_aColumns.end();
90 ++col
91 )
92 {
93 Reference< XCloneable > const xCloneable( *col, UNO_QUERY_THROW );
94 Reference< XGridColumn > const xClone( xCloneable->createClone(), UNO_QUERY_THROW );
95
96 GridColumn* const pGridColumn = GridColumn::getImplementation( xClone );
97 if ( pGridColumn == NULL )
98 throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "invalid clone source implementation" ) ), *this );
99 // that's indeed a RuntimeException, not an IllegalArgumentException or some such:
100 // a DefaultGridColumnModel implementation whose columns are not GridColumn implementations
101 // is borked.
102 pGridColumn->setIndex( col - i_copySource.m_aColumns.begin() );
103
104 aColumns.push_back( xClone );
105 }
106 }
107 catch( const Exception& )
108 {
109 DBG_UNHANDLED_EXCEPTION();
110 }
111 if ( aColumns.size() == i_copySource.m_aColumns.size() )
112 m_aColumns.swap( aColumns );
113 }
114
115 //------------------------------------------------------------------------------------------------------------------
~DefaultGridColumnModel()116 DefaultGridColumnModel::~DefaultGridColumnModel()
117 {
118 }
119
120 //------------------------------------------------------------------------------------------------------------------
getColumnCount()121 ::sal_Int32 SAL_CALL DefaultGridColumnModel::getColumnCount() throw (RuntimeException)
122 {
123 return m_aColumns.size();
124 }
125
126 //------------------------------------------------------------------------------------------------------------------
createColumn()127 Reference< XGridColumn > SAL_CALL DefaultGridColumnModel::createColumn( ) throw (RuntimeException)
128 {
129 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
130 return new GridColumn();
131 }
132
133 //------------------------------------------------------------------------------------------------------------------
addColumn(const Reference<XGridColumn> & i_column)134 ::sal_Int32 SAL_CALL DefaultGridColumnModel::addColumn( const Reference< XGridColumn > & i_column ) throw (RuntimeException, IllegalArgumentException)
135 {
136 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
137
138 GridColumn* const pGridColumn = GridColumn::getImplementation( i_column );
139 if ( pGridColumn == NULL )
140 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "invalid column implementation" ) ), *this, 1 );
141
142 m_aColumns.push_back( i_column );
143 sal_Int32 index = m_aColumns.size() - 1;
144 pGridColumn->setIndex( index );
145
146 // fire insertion notifications
147 ContainerEvent aEvent;
148 aEvent.Source = *this;
149 aEvent.Accessor <<= index;
150 aEvent.Element <<= i_column;
151
152 aGuard.clear();
153 m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
154
155 return index;
156 }
157
158 //------------------------------------------------------------------------------------------------------------------
removeColumn(::sal_Int32 i_columnIndex)159 void SAL_CALL DefaultGridColumnModel::removeColumn( ::sal_Int32 i_columnIndex ) throw (RuntimeException, IndexOutOfBoundsException)
160 {
161 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
162
163 if ( ( i_columnIndex < 0 ) || ( size_t( i_columnIndex ) >= m_aColumns.size() ) )
164 throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
165
166 Columns::iterator const pos = m_aColumns.begin() + i_columnIndex;
167 Reference< XGridColumn > const xColumn( *pos );
168 m_aColumns.erase( pos );
169
170 // update indexes of all subsequent columns
171 sal_Int32 columnIndex( i_columnIndex );
172 for ( Columns::iterator updatePos = m_aColumns.begin() + columnIndex;
173 updatePos != m_aColumns.end();
174 ++updatePos, ++columnIndex
175 )
176 {
177 GridColumn* pColumnImpl = GridColumn::getImplementation( *updatePos );
178 ENSURE_OR_CONTINUE( pColumnImpl, "DefaultGridColumnModel::removeColumn: invalid column implementation!" );
179 pColumnImpl->setIndex( columnIndex );
180 }
181
182 // fire removal notifications
183 ContainerEvent aEvent;
184 aEvent.Source = *this;
185 aEvent.Accessor <<= i_columnIndex;
186 aEvent.Element <<= xColumn;
187
188 aGuard.clear();
189 m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent );
190
191 // dispose the removed column
192 try
193 {
194 Reference< XComponent > const xColComp( xColumn, UNO_QUERY_THROW );
195 xColComp->dispose();
196 }
197 catch( const Exception& )
198 {
199 DBG_UNHANDLED_EXCEPTION();
200 }
201 }
202
203 //------------------------------------------------------------------------------------------------------------------
getColumns()204 Sequence< Reference< XGridColumn > > SAL_CALL DefaultGridColumnModel::getColumns() throw (RuntimeException)
205 {
206 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
207 return ::comphelper::containerToSequence( m_aColumns );
208 }
209
210 //------------------------------------------------------------------------------------------------------------------
getColumn(::sal_Int32 index)211 Reference< XGridColumn > SAL_CALL DefaultGridColumnModel::getColumn(::sal_Int32 index) throw (IndexOutOfBoundsException, RuntimeException)
212 {
213 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
214
215 if ( index >=0 && index < ((sal_Int32)m_aColumns.size()))
216 return m_aColumns[index];
217
218 throw IndexOutOfBoundsException();
219 }
220
221 //------------------------------------------------------------------------------------------------------------------
setDefaultColumns(sal_Int32 rowElements)222 void SAL_CALL DefaultGridColumnModel::setDefaultColumns(sal_Int32 rowElements) throw (RuntimeException)
223 {
224 ::std::vector< ContainerEvent > aRemovedColumns;
225 ::std::vector< ContainerEvent > aInsertedColumns;
226
227 {
228 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
229
230 // remove existing columns
231 while ( !m_aColumns.empty() )
232 {
233 const size_t lastColIndex = m_aColumns.size() - 1;
234
235 ContainerEvent aEvent;
236 aEvent.Source = *this;
237 aEvent.Accessor <<= sal_Int32( lastColIndex );
238 aEvent.Element <<= m_aColumns[ lastColIndex ];
239 aRemovedColumns.push_back( aEvent );
240
241 m_aColumns.erase( m_aColumns.begin() + lastColIndex );
242 }
243
244 // add new columns
245 for ( sal_Int32 i=0; i<rowElements; ++i )
246 {
247 ::rtl::Reference< GridColumn > const pGridColumn = new GridColumn();
248 Reference< XGridColumn > const xColumn( pGridColumn.get() );
249 ::rtl::OUStringBuffer colTitle;
250 colTitle.appendAscii( "Column " );
251 colTitle.append( i + 1 );
252 pGridColumn->setTitle( colTitle.makeStringAndClear() );
253 pGridColumn->setColumnWidth( 80 /* APPFONT */ );
254 pGridColumn->setFlexibility( 1 );
255 pGridColumn->setResizeable( sal_True );
256 pGridColumn->setDataColumnIndex( i );
257
258 ContainerEvent aEvent;
259 aEvent.Source = *this;
260 aEvent.Accessor <<= i;
261 aEvent.Element <<= xColumn;
262 aInsertedColumns.push_back( aEvent );
263
264 m_aColumns.push_back( xColumn );
265 pGridColumn->setIndex( i );
266 }
267 }
268
269 // fire removal notifications
270 for ( ::std::vector< ContainerEvent >::const_iterator event = aRemovedColumns.begin();
271 event != aRemovedColumns.end();
272 ++event
273 )
274 {
275 m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, *event );
276 }
277
278 // fire insertion notifications
279 for ( ::std::vector< ContainerEvent >::const_iterator event = aInsertedColumns.begin();
280 event != aInsertedColumns.end();
281 ++event
282 )
283 {
284 m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, *event );
285 }
286
287 // dispose removed columns
288 for ( ::std::vector< ContainerEvent >::const_iterator event = aRemovedColumns.begin();
289 event != aRemovedColumns.end();
290 ++event
291 )
292 {
293 try
294 {
295 const Reference< XComponent > xColComp( event->Element, UNO_QUERY_THROW );
296 xColComp->dispose();
297 }
298 catch( const Exception& )
299 {
300 DBG_UNHANDLED_EXCEPTION();
301 }
302 }
303 }
304
305 //------------------------------------------------------------------------------------------------------------------
getImplementationName()306 ::rtl::OUString SAL_CALL DefaultGridColumnModel::getImplementationName( ) throw (RuntimeException)
307 {
308 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.toolkit.DefaultGridColumnModel" ) );
309 }
310
311 //------------------------------------------------------------------------------------------------------------------
supportsService(const::rtl::OUString & i_serviceName)312 sal_Bool SAL_CALL DefaultGridColumnModel::supportsService( const ::rtl::OUString& i_serviceName ) throw (RuntimeException)
313 {
314 const Sequence< ::rtl::OUString > aServiceNames( getSupportedServiceNames() );
315 for ( sal_Int32 i=0; i<aServiceNames.getLength(); ++i )
316 if ( aServiceNames[i] == i_serviceName )
317 return sal_True;
318 return sal_False;
319 }
320
321 //------------------------------------------------------------------------------------------------------------------
getSupportedServiceNames()322 Sequence< ::rtl::OUString > SAL_CALL DefaultGridColumnModel::getSupportedServiceNames( ) throw (RuntimeException)
323 {
324 const ::rtl::OUString aServiceName( ::rtl::OUString::createFromAscii( szServiceName_DefaultGridColumnModel ) );
325 const Sequence< ::rtl::OUString > aSeq( &aServiceName, 1 );
326 return aSeq;
327 }
328
329 //------------------------------------------------------------------------------------------------------------------
addContainerListener(const Reference<XContainerListener> & i_listener)330 void SAL_CALL DefaultGridColumnModel::addContainerListener( const Reference< XContainerListener >& i_listener ) throw (RuntimeException)
331 {
332 if ( i_listener.is() )
333 m_aContainerListeners.addInterface( i_listener );
334 }
335
336 //------------------------------------------------------------------------------------------------------------------
removeContainerListener(const Reference<XContainerListener> & i_listener)337 void SAL_CALL DefaultGridColumnModel::removeContainerListener( const Reference< XContainerListener >& i_listener ) throw (RuntimeException)
338 {
339 if ( i_listener.is() )
340 m_aContainerListeners.removeInterface( i_listener );
341 }
342
343 //------------------------------------------------------------------------------------------------------------------
disposing()344 void SAL_CALL DefaultGridColumnModel::disposing()
345 {
346 DefaultGridColumnModel_Base::disposing();
347
348 EventObject aEvent( *this );
349 m_aContainerListeners.disposeAndClear( aEvent );
350
351 ::osl::MutexGuard aGuard( m_aMutex );
352
353 // remove, dispose and clear columns
354 while ( !m_aColumns.empty() )
355 {
356 try
357 {
358 const Reference< XComponent > xColComponent( m_aColumns[ 0 ], UNO_QUERY_THROW );
359 xColComponent->dispose();
360 }
361 catch( const Exception& )
362 {
363 DBG_UNHANDLED_EXCEPTION();
364 }
365
366 m_aColumns.erase( m_aColumns.begin() );
367 }
368
369 Columns aEmpty;
370 m_aColumns.swap( aEmpty );
371 }
372
373 //------------------------------------------------------------------------------------------------------------------
createClone()374 Reference< XCloneable > SAL_CALL DefaultGridColumnModel::createClone( ) throw (RuntimeException)
375 {
376 ::comphelper::ComponentGuard aGuard( *this, rBHelper );
377 return new DefaultGridColumnModel( *this );
378 }
379
380 //......................................................................................................................
381 } // namespace toolkit
382 //......................................................................................................................
383
384 //----------------------------------------------------------------------------------------------------------------------
DefaultGridColumnModel_CreateInstance(const::com::sun::star::uno::Reference<::com::sun::star::lang::XMultiServiceFactory> & _rFactory)385 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL DefaultGridColumnModel_CreateInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rFactory)
386 {
387 return ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface >( ( ::cppu::OWeakObject* ) new ::toolkit::DefaultGridColumnModel( _rFactory ) );
388 }
389