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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 116 DefaultGridColumnModel::~DefaultGridColumnModel() 117 { 118 } 119 120 //------------------------------------------------------------------------------------------------------------------ 121 ::sal_Int32 SAL_CALL DefaultGridColumnModel::getColumnCount() throw (RuntimeException) 122 { 123 return m_aColumns.size(); 124 } 125 126 //------------------------------------------------------------------------------------------------------------------ 127 Reference< XGridColumn > SAL_CALL DefaultGridColumnModel::createColumn( ) throw (RuntimeException) 128 { 129 ::comphelper::ComponentGuard aGuard( *this, rBHelper ); 130 return new GridColumn(); 131 } 132 133 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------------------------------------------ 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 //---------------------------------------------------------------------------------------------------------------------- 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