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_extensions.hxx" 26 #include "cellbindinghandler.hxx" 27 #include "formstrings.hxx" 28 #include "formmetadata.hxx" 29 #include "cellbindinghelper.hxx" 30 31 /** === begin UNO includes === **/ 32 #include <com/sun/star/form/binding/XValueBinding.hpp> 33 #include <com/sun/star/table/CellAddress.hpp> 34 #include <com/sun/star/inspection/XObjectInspectorUI.hpp> 35 /** === end UNO includes === **/ 36 #include <tools/debug.hxx> 37 38 //------------------------------------------------------------------------ 39 extern "C" void SAL_CALL createRegistryInfo_CellBindingPropertyHandler() 40 { 41 ::pcr::CellBindingPropertyHandler::registerImplementation(); 42 } 43 44 //........................................................................ 45 namespace pcr 46 { 47 //........................................................................ 48 49 using namespace ::com::sun::star::uno; 50 using namespace ::com::sun::star::table; 51 using namespace ::com::sun::star::lang; 52 using namespace ::com::sun::star::beans; 53 using namespace ::com::sun::star::script; 54 using namespace ::com::sun::star::frame; 55 using namespace ::com::sun::star::inspection; 56 using namespace ::com::sun::star::form::binding; 57 using namespace ::comphelper; 58 59 //==================================================================== 60 //= CellBindingPropertyHandler 61 //==================================================================== 62 DBG_NAME( CellBindingPropertyHandler ) 63 //-------------------------------------------------------------------- 64 CellBindingPropertyHandler::CellBindingPropertyHandler( const Reference< XComponentContext >& _rxContext ) 65 :CellBindingPropertyHandler_Base( _rxContext ) 66 ,m_pCellExchangeConverter( new DefaultEnumRepresentation( *m_pInfoService, ::getCppuType( static_cast< sal_Int16* >( NULL ) ), PROPERTY_ID_CELL_EXCHANGE_TYPE ) ) 67 { 68 DBG_CTOR( CellBindingPropertyHandler, NULL ); 69 } 70 71 //-------------------------------------------------------------------- 72 ::rtl::OUString SAL_CALL CellBindingPropertyHandler::getImplementationName_static( ) throw (RuntimeException) 73 { 74 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.extensions.CellBindingPropertyHandler" ) ); 75 } 76 77 //-------------------------------------------------------------------- 78 Sequence< ::rtl::OUString > SAL_CALL CellBindingPropertyHandler::getSupportedServiceNames_static( ) throw (RuntimeException) 79 { 80 Sequence< ::rtl::OUString > aSupported( 1 ); 81 aSupported[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.inspection.CellBindingPropertyHandler" ) ); 82 return aSupported; 83 } 84 85 //-------------------------------------------------------------------- 86 void CellBindingPropertyHandler::onNewComponent() 87 { 88 PropertyHandlerComponent::onNewComponent(); 89 90 Reference< XModel > xDocument( impl_getContextDocument_nothrow() ); 91 DBG_ASSERT( xDocument.is(), "CellBindingPropertyHandler::onNewComponent: no document!" ); 92 if ( CellBindingHelper::isSpreadsheetDocument( xDocument ) ) 93 m_pHelper.reset( new CellBindingHelper( m_xComponent, xDocument ) ); 94 } 95 96 //-------------------------------------------------------------------- 97 CellBindingPropertyHandler::~CellBindingPropertyHandler( ) 98 { 99 DBG_DTOR( CellBindingPropertyHandler, NULL ); 100 } 101 102 //-------------------------------------------------------------------- 103 Sequence< ::rtl::OUString > SAL_CALL CellBindingPropertyHandler::getActuatingProperties( ) throw (RuntimeException) 104 { 105 Sequence< ::rtl::OUString > aInterestingProperties( 3 ); 106 aInterestingProperties[0] = PROPERTY_LIST_CELL_RANGE; 107 aInterestingProperties[1] = PROPERTY_BOUND_CELL; 108 aInterestingProperties[2] = PROPERTY_CONTROLSOURCE; 109 return aInterestingProperties; 110 } 111 112 //-------------------------------------------------------------------- 113 void SAL_CALL CellBindingPropertyHandler::actuatingPropertyChanged( const ::rtl::OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) throw (NullPointerException, RuntimeException) 114 { 115 ::osl::MutexGuard aGuard( m_aMutex ); 116 PropertyId nActuatingPropId( impl_getPropertyId_throw( _rActuatingPropertyName ) ); 117 OSL_PRECOND( m_pHelper.get(), "CellBindingPropertyHandler::actuatingPropertyChanged: inconsistentcy!" ); 118 // if we survived impl_getPropertyId_throw, we should have a helper, since no helper implies no properties 119 120 OSL_PRECOND( _rxInspectorUI.is(), "FormComponentPropertyHandler::actuatingPropertyChanged: no access to the UI!" ); 121 if ( !_rxInspectorUI.is() ) 122 throw NullPointerException(); 123 124 ::std::vector< PropertyId > aDependentProperties; 125 126 switch ( nActuatingPropId ) 127 { 128 // ----- BoundCell ----- 129 case PROPERTY_ID_BOUND_CELL: 130 { 131 // the SQL-data-binding related properties need to be enabled if and only if 132 // there is *no* valid cell binding 133 Reference< XValueBinding > xBinding; 134 _rNewValue >>= xBinding; 135 136 if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_CELL_EXCHANGE_TYPE ) ) 137 _rxInspectorUI->enablePropertyUI( PROPERTY_CELL_EXCHANGE_TYPE, xBinding.is() ); 138 if ( impl_componentHasProperty_throw( PROPERTY_CONTROLSOURCE ) ) 139 _rxInspectorUI->enablePropertyUI( PROPERTY_CONTROLSOURCE, !xBinding.is() ); 140 141 if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_FILTERPROPOSAL ) ) 142 _rxInspectorUI->enablePropertyUI( PROPERTY_FILTERPROPOSAL, !xBinding.is() ); 143 if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_EMPTY_IS_NULL ) ) 144 _rxInspectorUI->enablePropertyUI( PROPERTY_EMPTY_IS_NULL, !xBinding.is() ); 145 146 aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN ); 147 148 if ( !xBinding.is() && m_pHelper->getCurrentBinding().is() ) 149 { 150 // ensure that the "transfer selection as" property is reset. Since we can't remember 151 // it at the object itself, but derive it from the binding only, we have to normalize 152 // it now that there *is* no binding anymore. 153 setPropertyValue( PROPERTY_CELL_EXCHANGE_TYPE, makeAny( (sal_Int16) 0 ) ); 154 } 155 } 156 break; 157 158 // ----- CellRange ----- 159 case PROPERTY_ID_LIST_CELL_RANGE: 160 { 161 // the list source related properties need to be enabled if and only if 162 // there is *no* valid external list source for the control 163 Reference< XListEntrySource > xSource; 164 _rNewValue >>= xSource; 165 166 _rxInspectorUI->enablePropertyUI( PROPERTY_STRINGITEMLIST, !xSource.is() ); 167 _rxInspectorUI->enablePropertyUI( PROPERTY_LISTSOURCE, !xSource.is() ); 168 _rxInspectorUI->enablePropertyUI( PROPERTY_LISTSOURCETYPE, !xSource.is() ); 169 170 aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN ); 171 172 // also reset the list entries if the cell range is reset 173 // #i28319# - 2004-04-27 - fs@openoffice.org 174 if ( !_bFirstTimeInit ) 175 { 176 try 177 { 178 if ( !xSource.is() ) 179 setPropertyValue( PROPERTY_STRINGITEMLIST, makeAny( Sequence< ::rtl::OUString >() ) ); 180 } 181 catch( const Exception& ) 182 { 183 OSL_ENSURE( sal_False, "OPropertyBrowserController::actuatingPropertyChanged( ListCellRange ): caught an exception while resetting the string items!" ); 184 } 185 } 186 } 187 break; // case PROPERTY_ID_LIST_CELL_RANGE 188 189 // ----- DataField ----- 190 case PROPERTY_ID_CONTROLSOURCE: 191 { 192 ::rtl::OUString sControlSource; 193 _rNewValue >>= sControlSource; 194 if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_BOUND_CELL ) ) 195 _rxInspectorUI->enablePropertyUI( PROPERTY_BOUND_CELL, sControlSource.getLength() == 0 ); 196 } 197 break; // case PROPERTY_ID_CONTROLSOURCE 198 199 default: 200 DBG_ERROR( "CellBindingPropertyHandler::actuatingPropertyChanged: did not register for this property!" ); 201 } 202 203 for ( ::std::vector< PropertyId >::const_iterator loopAffected = aDependentProperties.begin(); 204 loopAffected != aDependentProperties.end(); 205 ++loopAffected 206 ) 207 { 208 impl_updateDependentProperty_nothrow( *loopAffected, _rxInspectorUI ); 209 } 210 } 211 212 //-------------------------------------------------------------------- 213 void CellBindingPropertyHandler::impl_updateDependentProperty_nothrow( PropertyId _nPropId, const Reference< XObjectInspectorUI >& _rxInspectorUI ) const 214 { 215 try 216 { 217 switch ( _nPropId ) 218 { 219 // ----- BoundColumn ----- 220 case PROPERTY_ID_BOUNDCOLUMN: 221 { 222 CellBindingPropertyHandler* pNonConstThis = const_cast< CellBindingPropertyHandler* >( this ); 223 Reference< XValueBinding > xBinding( pNonConstThis->getPropertyValue( PROPERTY_BOUND_CELL ), UNO_QUERY ); 224 Reference< XListEntrySource > xListSource( pNonConstThis->getPropertyValue( PROPERTY_LIST_CELL_RANGE ), UNO_QUERY ); 225 226 if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_BOUNDCOLUMN ) ) 227 _rxInspectorUI->enablePropertyUI( PROPERTY_BOUNDCOLUMN, !xBinding.is() && !xListSource.is() ); 228 } 229 break; // case PROPERTY_ID_BOUNDCOLUMN 230 231 } // switch 232 233 } 234 catch( const Exception& ) 235 { 236 OSL_ENSURE( sal_False, "CellBindingPropertyHandler::impl_updateDependentProperty_nothrow: caught an exception!" ); 237 } 238 } 239 240 //-------------------------------------------------------------------- 241 Any SAL_CALL CellBindingPropertyHandler::getPropertyValue( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException) 242 { 243 ::osl::MutexGuard aGuard( m_aMutex ); 244 PropertyId nPropId( impl_getPropertyId_throw( _rPropertyName ) ); 245 246 OSL_ENSURE( m_pHelper.get(), "CellBindingPropertyHandler::getPropertyValue: inconsistency!" ); 247 // if we survived impl_getPropertyId_throw, we should have a helper, since no helper implies no properties 248 249 Any aReturn; 250 switch ( nPropId ) 251 { 252 case PROPERTY_ID_BOUND_CELL: 253 { 254 Reference< XValueBinding > xBinding( m_pHelper->getCurrentBinding() ); 255 if ( !m_pHelper->isCellBinding( xBinding ) ) 256 xBinding.clear(); 257 258 aReturn <<= xBinding; 259 } 260 break; 261 262 case PROPERTY_ID_LIST_CELL_RANGE: 263 { 264 Reference< XListEntrySource > xSource( m_pHelper->getCurrentListSource() ); 265 if ( !m_pHelper->isCellRangeListSource( xSource ) ) 266 xSource.clear(); 267 268 aReturn <<= xSource; 269 } 270 break; 271 272 case PROPERTY_ID_CELL_EXCHANGE_TYPE: 273 { 274 Reference< XValueBinding > xBinding( m_pHelper->getCurrentBinding() ); 275 aReturn <<= (sal_Int16)( m_pHelper->isCellIntegerBinding( xBinding ) ? 1 : 0 ); 276 } 277 break; 278 279 default: 280 DBG_ERROR( "CellBindingPropertyHandler::getPropertyValue: cannot handle this!" ); 281 break; 282 } 283 return aReturn; 284 } 285 286 //-------------------------------------------------------------------- 287 void SAL_CALL CellBindingPropertyHandler::setPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rValue ) throw (UnknownPropertyException, RuntimeException) 288 { 289 ::osl::MutexGuard aGuard( m_aMutex ); 290 PropertyId nPropId( impl_getPropertyId_throw( _rPropertyName ) ); 291 292 OSL_ENSURE( m_pHelper.get(), "CellBindingPropertyHandler::setPropertyValue: inconsistency!" ); 293 // if we survived impl_getPropertyId_throw, we should have a helper, since no helper implies no properties 294 295 try 296 { 297 Any aOldValue = getPropertyValue( _rPropertyName ); 298 299 switch ( nPropId ) 300 { 301 case PROPERTY_ID_BOUND_CELL: 302 { 303 Reference< XValueBinding > xBinding; 304 _rValue >>= xBinding; 305 m_pHelper->setBinding( xBinding ); 306 } 307 break; 308 309 case PROPERTY_ID_LIST_CELL_RANGE: 310 { 311 Reference< XListEntrySource > xSource; 312 _rValue >>= xSource; 313 m_pHelper->setListSource( xSource ); 314 } 315 break; 316 317 case PROPERTY_ID_CELL_EXCHANGE_TYPE: 318 { 319 sal_Int16 nExchangeType = 0; 320 OSL_VERIFY( _rValue >>= nExchangeType ); 321 322 Reference< XValueBinding > xBinding = m_pHelper->getCurrentBinding( ); 323 if ( xBinding.is() ) 324 { 325 sal_Bool bNeedIntegerBinding = ( nExchangeType == 1 ); 326 if ( (bool)bNeedIntegerBinding != m_pHelper->isCellIntegerBinding( xBinding ) ) 327 { 328 CellAddress aAddress; 329 if ( m_pHelper->getAddressFromCellBinding( xBinding, aAddress ) ) 330 { 331 xBinding = m_pHelper->createCellBindingFromAddress( aAddress, bNeedIntegerBinding ); 332 m_pHelper->setBinding( xBinding ); 333 } 334 } 335 } 336 } 337 break; 338 339 default: 340 DBG_ERROR( "CellBindingPropertyHandler::setPropertyValue: cannot handle this!" ); 341 break; 342 } 343 344 impl_setContextDocumentModified_nothrow(); 345 346 Any aNewValue( getPropertyValue( _rPropertyName ) ); 347 firePropertyChange( _rPropertyName, nPropId, aOldValue, aNewValue ); 348 // TODO/UNOize: can't we make this a part of the base class, for all those "virtual" 349 // properties? Base class'es |setPropertyValue| could call some |doSetPropertyValue|, 350 // and handle the listener notification itself 351 } 352 catch( const Exception& ) 353 { 354 OSL_ENSURE( sal_False, "CellBindingPropertyHandler::setPropertyValue: caught an exception!" ); 355 } 356 } 357 358 //-------------------------------------------------------------------- 359 Any SAL_CALL CellBindingPropertyHandler::convertToPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rControlValue ) throw (UnknownPropertyException, RuntimeException) 360 { 361 ::osl::MutexGuard aGuard( m_aMutex ); 362 Any aPropertyValue; 363 364 OSL_ENSURE( m_pHelper.get(), "CellBindingPropertyHandler::convertToPropertyValue: we have no SupportedProperties!" ); 365 if ( !m_pHelper.get() ) 366 return aPropertyValue; 367 368 PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) ); 369 370 ::rtl::OUString sControlValue; 371 OSL_VERIFY( _rControlValue >>= sControlValue ); 372 switch( nPropId ) 373 { 374 case PROPERTY_ID_LIST_CELL_RANGE: 375 aPropertyValue <<= m_pHelper->createCellListSourceFromStringAddress( sControlValue ); 376 break; 377 378 case PROPERTY_ID_BOUND_CELL: 379 { 380 // if we have the possibility of an integer binding, then we must preserve 381 // this property's value (e.g. if the current binding is an integer binding, then 382 // the newly created one must be, too) 383 bool bIntegerBinding = false; 384 if ( m_pHelper->isCellIntegerBindingAllowed() ) 385 { 386 sal_Int16 nCurrentBindingType = 0; 387 getPropertyValue( PROPERTY_CELL_EXCHANGE_TYPE ) >>= nCurrentBindingType; 388 bIntegerBinding = ( nCurrentBindingType != 0 ); 389 } 390 aPropertyValue <<= m_pHelper->createCellBindingFromStringAddress( sControlValue, bIntegerBinding ); 391 } 392 break; 393 394 case PROPERTY_ID_CELL_EXCHANGE_TYPE: 395 m_pCellExchangeConverter->getValueFromDescription( sControlValue, aPropertyValue ); 396 break; 397 398 default: 399 DBG_ERROR( "CellBindingPropertyHandler::convertToPropertyValue: cannot handle this!" ); 400 break; 401 } 402 403 return aPropertyValue; 404 } 405 406 //-------------------------------------------------------------------- 407 Any SAL_CALL CellBindingPropertyHandler::convertToControlValue( const ::rtl::OUString& _rPropertyName, 408 const Any& _rPropertyValue, const Type& /*_rControlValueType*/ ) throw (UnknownPropertyException, RuntimeException) 409 { 410 ::osl::MutexGuard aGuard( m_aMutex ); 411 Any aControlValue; 412 413 OSL_ENSURE( m_pHelper.get(), "CellBindingPropertyHandler::convertToControlValue: we have no SupportedProperties!" ); 414 if ( !m_pHelper.get() ) 415 return aControlValue; 416 417 PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) ); 418 419 switch ( nPropId ) 420 { 421 case PROPERTY_ID_BOUND_CELL: 422 { 423 Reference< XValueBinding > xBinding; 424 #if OSL_DEBUG_LEVEL > 0 425 sal_Bool bSuccess = 426 #endif 427 _rPropertyValue >>= xBinding; 428 OSL_ENSURE( bSuccess, "CellBindingPropertyHandler::convertToControlValue: invalid value (1)!" ); 429 430 // the only value binding we support so far is linking to spreadsheet cells 431 aControlValue <<= m_pHelper->getStringAddressFromCellBinding( xBinding ); 432 } 433 break; 434 435 case PROPERTY_ID_LIST_CELL_RANGE: 436 { 437 Reference< XListEntrySource > xSource; 438 #if OSL_DEBUG_LEVEL > 0 439 sal_Bool bSuccess = 440 #endif 441 _rPropertyValue >>= xSource; 442 OSL_ENSURE( bSuccess, "CellBindingPropertyHandler::convertToControlValue: invalid value (2)!" ); 443 444 // the only value binding we support so far is linking to spreadsheet cells 445 aControlValue <<= m_pHelper->getStringAddressFromCellListSource( xSource ); 446 } 447 break; 448 449 case PROPERTY_ID_CELL_EXCHANGE_TYPE: 450 aControlValue <<= m_pCellExchangeConverter->getDescriptionForValue( _rPropertyValue ); 451 break; 452 453 default: 454 DBG_ERROR( "CellBindingPropertyHandler::convertToControlValue: cannot handle this!" ); 455 break; 456 } 457 458 return aControlValue; 459 } 460 461 //-------------------------------------------------------------------- 462 Sequence< Property > SAL_CALL CellBindingPropertyHandler::doDescribeSupportedProperties() const 463 { 464 ::std::vector< Property > aProperties; 465 466 bool bAllowCellLinking = m_pHelper.get() && m_pHelper->isCellBindingAllowed(); 467 bool bAllowCellIntLinking = m_pHelper.get() && m_pHelper->isCellIntegerBindingAllowed(); 468 bool bAllowListCellRange = m_pHelper.get() && m_pHelper->isListCellRangeAllowed(); 469 if ( bAllowCellLinking || bAllowListCellRange || bAllowCellIntLinking ) 470 { 471 sal_Int32 nPos = ( bAllowCellLinking ? 1 : 0 ) 472 + ( bAllowListCellRange ? 1 : 0 ) 473 + ( bAllowCellIntLinking ? 1 : 0 ); 474 aProperties.resize( nPos ); 475 476 if ( bAllowCellLinking ) 477 { 478 aProperties[ --nPos ] = Property( PROPERTY_BOUND_CELL, PROPERTY_ID_BOUND_CELL, 479 ::getCppuType( static_cast< ::rtl::OUString* >( NULL ) ), 0 ); 480 } 481 if ( bAllowCellIntLinking ) 482 { 483 aProperties[ --nPos ] = Property( PROPERTY_CELL_EXCHANGE_TYPE, PROPERTY_ID_CELL_EXCHANGE_TYPE, 484 ::getCppuType( static_cast< sal_Int16* >( NULL ) ), 0 ); 485 } 486 if ( bAllowListCellRange ) 487 { 488 aProperties[ --nPos ] = Property( PROPERTY_LIST_CELL_RANGE, PROPERTY_ID_LIST_CELL_RANGE, 489 ::getCppuType( static_cast< ::rtl::OUString* >( NULL ) ), 0 ); 490 } 491 } 492 493 if ( aProperties.empty() ) 494 return Sequence< Property >(); 495 return Sequence< Property >( &(*aProperties.begin()), aProperties.size() ); 496 } 497 498 //........................................................................ 499 } // namespace pcr 500 //........................................................................ 501