1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmloff.hxx" 30 #include "formcellbinding.hxx" 31 #include <com/sun/star/form/binding/XBindableValue.hpp> 32 #include <com/sun/star/form/binding/XListEntrySink.hpp> 33 #include <com/sun/star/form/XGridColumnFactory.hpp> 34 #include <com/sun/star/frame/XModel.hpp> 35 #include <com/sun/star/container/XChild.hpp> 36 #include <com/sun/star/container/XNamed.hpp> 37 #include <com/sun/star/drawing/XDrawPageSupplier.hpp> 38 #include <com/sun/star/table/XCellRange.hpp> 39 #include <com/sun/star/form/XFormsSupplier.hpp> 40 #include <com/sun/star/form/XForm.hpp> 41 #include <com/sun/star/lang/XServiceInfo.hpp> 42 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 43 #include <com/sun/star/beans/NamedValue.hpp> 44 #include "strings.hxx" 45 #include <osl/diagnose.h> 46 #include <rtl/logfile.hxx> 47 48 #include <functional> 49 #include <algorithm> 50 51 //............................................................................ 52 namespace xmloff 53 { 54 //............................................................................ 55 56 using namespace ::com::sun::star::uno; 57 using namespace ::com::sun::star::beans; 58 using namespace ::com::sun::star::frame; 59 using namespace ::com::sun::star::sheet; 60 using namespace ::com::sun::star::container; 61 using namespace ::com::sun::star::drawing; 62 using namespace ::com::sun::star::table; 63 using namespace ::com::sun::star::form; 64 using namespace ::com::sun::star::lang; 65 using namespace ::com::sun::star::form::binding; 66 67 namespace 68 { 69 using ::com::sun::star::uno::Reference; 70 using ::com::sun::star::uno::XInterface; 71 using ::com::sun::star::container::XChild; 72 using ::com::sun::star::frame::XModel; 73 using ::com::sun::star::uno::UNO_QUERY; 74 75 //.................................................................... 76 template< class TYPE > 77 Reference< TYPE > getTypedModelNode( const Reference< XInterface >& _rxModelNode ) 78 { 79 Reference< TYPE > xTypedNode( _rxModelNode, UNO_QUERY ); 80 if ( xTypedNode.is() ) 81 return xTypedNode; 82 else 83 { 84 Reference< XChild > xChild( _rxModelNode, UNO_QUERY ); 85 if ( xChild.is() ) 86 return getTypedModelNode< TYPE >( xChild->getParent() ); 87 else 88 return NULL; 89 } 90 } 91 92 //.................................................................... 93 Reference< XModel > getDocument( const Reference< XInterface >& _rxModelNode ) 94 { 95 return getTypedModelNode< XModel >( _rxModelNode ); 96 } 97 98 //.................................................................... 99 struct StringCompare : public ::std::unary_function< ::rtl::OUString, bool > 100 { 101 private: 102 const ::rtl::OUString m_sReference; 103 104 public: 105 StringCompare( const ::rtl::OUString& _rReference ) : m_sReference( _rReference ) { } 106 107 inline bool operator()( const ::rtl::OUString& _rCompare ) 108 { 109 return ( _rCompare == m_sReference ); 110 } 111 }; 112 } 113 114 //======================================================================== 115 //= FormCellBindingHelper 116 //======================================================================== 117 //------------------------------------------------------------------------ 118 FormCellBindingHelper::FormCellBindingHelper( const Reference< XPropertySet >& _rxControlModel, const Reference< XModel >& _rxDocument ) 119 :m_xControlModel( _rxControlModel ) 120 ,m_xDocument( _rxDocument, UNO_QUERY ) 121 { 122 OSL_ENSURE( m_xControlModel.is(), "FormCellBindingHelper::FormCellBindingHelper: invalid control model!" ); 123 124 if ( !m_xDocument.is() ) 125 m_xDocument = m_xDocument.query( getDocument( m_xControlModel ) ); 126 OSL_ENSURE( m_xDocument.is(), "FormCellBindingHelper::FormCellBindingHelper: Did not find the spreadsheet document!" ); 127 } 128 129 //------------------------------------------------------------------------ 130 sal_Bool FormCellBindingHelper::livesInSpreadsheetDocument( const Reference< XPropertySet >& _rxControlModel ) 131 { 132 Reference< XSpreadsheetDocument > xDocument( getDocument( _rxControlModel ), UNO_QUERY ); 133 return xDocument.is(); 134 } 135 136 //------------------------------------------------------------------------ 137 bool FormCellBindingHelper::convertStringAddress( const ::rtl::OUString& _rAddressDescription, CellAddress& /* [out] */ _rAddress, sal_Int16 /*_nAssumeSheet*/ ) const 138 { 139 Any aAddress; 140 return doConvertAddressRepresentations( 141 PROPERTY_FILE_REPRESENTATION, 142 makeAny( _rAddressDescription ), 143 PROPERTY_ADDRESS, 144 aAddress, 145 false 146 ) 147 && ( aAddress >>= _rAddress ); 148 } 149 150 //------------------------------------------------------------------------ 151 bool FormCellBindingHelper::convertStringAddress( const ::rtl::OUString& _rAddressDescription, 152 CellRangeAddress& /* [out] */ _rAddress ) const 153 { 154 Any aAddress; 155 return doConvertAddressRepresentations( 156 PROPERTY_FILE_REPRESENTATION, 157 makeAny( _rAddressDescription ), 158 PROPERTY_ADDRESS, 159 aAddress, 160 true 161 ) 162 && ( aAddress >>= _rAddress ); 163 } 164 165 //------------------------------------------------------------------------ 166 Reference< XValueBinding > FormCellBindingHelper::createCellBindingFromStringAddress( const ::rtl::OUString& _rAddress, bool _bUseIntegerBinding ) const 167 { 168 Reference< XValueBinding > xBinding; 169 if ( !m_xDocument.is() ) 170 // very bad ... 171 return xBinding; 172 173 // get the UNO representation of the address 174 CellAddress aAddress; 175 if ( !_rAddress.getLength() || !convertStringAddress( _rAddress, aAddress ) ) 176 return xBinding; 177 178 xBinding = xBinding.query( createDocumentDependentInstance( 179 _bUseIntegerBinding ? SERVICE_LISTINDEXCELLBINDING : SERVICE_CELLVALUEBINDING, 180 PROPERTY_BOUND_CELL, 181 makeAny( aAddress ) 182 ) ); 183 184 return xBinding; 185 } 186 187 //------------------------------------------------------------------------ 188 Reference< XListEntrySource > FormCellBindingHelper::createCellListSourceFromStringAddress( const ::rtl::OUString& _rAddress ) const 189 { 190 Reference< XListEntrySource > xSource; 191 192 CellRangeAddress aRangeAddress; 193 if ( !convertStringAddress( _rAddress, aRangeAddress ) ) 194 return xSource; 195 196 // create a range object for this address 197 xSource = xSource.query( createDocumentDependentInstance( 198 SERVICE_CELLRANGELISTSOURCE, 199 PROPERTY_LIST_CELL_RANGE, 200 makeAny( aRangeAddress ) 201 ) ); 202 203 return xSource; 204 } 205 206 //------------------------------------------------------------------------ 207 ::rtl::OUString FormCellBindingHelper::getStringAddressFromCellBinding( const Reference< XValueBinding >& _rxBinding ) const 208 { 209 OSL_PRECOND( !_rxBinding.is() || isCellBinding( _rxBinding ), "FormCellBindingHelper::getStringAddressFromCellBinding: this is no cell binding!" ); 210 211 ::rtl::OUString sAddress; 212 try 213 { 214 Reference< XPropertySet > xBindingProps( _rxBinding, UNO_QUERY ); 215 OSL_ENSURE( xBindingProps.is() || !_rxBinding.is(), "FormCellBindingHelper::getStringAddressFromCellBinding: no property set for the binding!" ); 216 if ( xBindingProps.is() ) 217 { 218 CellAddress aAddress; 219 xBindingProps->getPropertyValue( PROPERTY_BOUND_CELL ) >>= aAddress; 220 221 Any aStringAddress; 222 doConvertAddressRepresentations( PROPERTY_ADDRESS, makeAny( aAddress ), 223 PROPERTY_FILE_REPRESENTATION, aStringAddress, false ); 224 225 aStringAddress >>= sAddress; 226 } 227 } 228 catch( const Exception& ) 229 { 230 OSL_ENSURE( sal_False, "FormCellBindingHelper::getStringAddressFromCellBinding: caught an exception!" ); 231 } 232 233 return sAddress; 234 } 235 236 //------------------------------------------------------------------------ 237 ::rtl::OUString FormCellBindingHelper::getStringAddressFromCellListSource( const Reference< XListEntrySource >& _rxSource ) const 238 { 239 OSL_PRECOND( !_rxSource.is() || isCellRangeListSource( _rxSource ), "FormCellBindingHelper::getStringAddressFromCellListSource: this is no cell list source!" ); 240 241 ::rtl::OUString sAddress; 242 try 243 { 244 Reference< XPropertySet > xSourceProps( _rxSource, UNO_QUERY ); 245 OSL_ENSURE( xSourceProps.is() || !_rxSource.is(), "FormCellBindingHelper::getStringAddressFromCellListSource: no property set for the list source!" ); 246 if ( xSourceProps.is() ) 247 { 248 CellRangeAddress aRangeAddress; 249 xSourceProps->getPropertyValue( PROPERTY_LIST_CELL_RANGE ) >>= aRangeAddress; 250 251 Any aStringAddress; 252 doConvertAddressRepresentations( PROPERTY_ADDRESS, makeAny( aRangeAddress ), 253 PROPERTY_FILE_REPRESENTATION, aStringAddress, true ); 254 aStringAddress >>= sAddress; 255 } 256 } 257 catch( const Exception& ) 258 { 259 OSL_ENSURE( sal_False, "FormCellBindingHelper::getStringAddressFromCellListSource: caught an exception!" ); 260 } 261 262 return sAddress; 263 } 264 265 //------------------------------------------------------------------------ 266 bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const Reference< XSpreadsheetDocument >& _rxDocument, const ::rtl::OUString& _rService ) SAL_THROW(()) 267 { 268 bool bYesItIs = false; 269 270 try 271 { 272 Reference< XServiceInfo > xSI( _rxDocument, UNO_QUERY ); 273 if ( xSI.is() && xSI->supportsService( SERVICE_SPREADSHEET_DOCUMENT ) ) 274 { 275 Reference< XMultiServiceFactory > xDocumentFactory( _rxDocument, UNO_QUERY ); 276 OSL_ENSURE( xDocumentFactory.is(), "FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies: spreadsheet document, but no factory?" ); 277 278 Sequence< ::rtl::OUString > aAvailableServices; 279 if ( xDocumentFactory.is() ) 280 aAvailableServices = xDocumentFactory->getAvailableServiceNames( ); 281 282 const ::rtl::OUString* pFound = ::std::find_if( 283 aAvailableServices.getConstArray(), 284 aAvailableServices.getConstArray() + aAvailableServices.getLength(), 285 StringCompare( _rService ) 286 ); 287 if ( pFound - aAvailableServices.getConstArray() < aAvailableServices.getLength() ) 288 { 289 bYesItIs = true; 290 } 291 } 292 } 293 catch( const Exception& ) 294 { 295 OSL_ENSURE( sal_False, "FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies: caught an exception!" ); 296 } 297 298 return bYesItIs; 299 } 300 301 //------------------------------------------------------------------------ 302 bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const ::rtl::OUString& _rService ) const SAL_THROW(()) 303 { 304 return isSpreadsheetDocumentWhichSupplies( m_xDocument, _rService ); 305 } 306 307 //------------------------------------------------------------------------ 308 bool FormCellBindingHelper::isListCellRangeAllowed( const Reference< XModel >& _rxDocument ) 309 { 310 return isSpreadsheetDocumentWhichSupplies( 311 Reference< XSpreadsheetDocument >( _rxDocument, UNO_QUERY ), 312 SERVICE_CELLRANGELISTSOURCE 313 ); 314 } 315 316 //------------------------------------------------------------------------ 317 bool FormCellBindingHelper::isListCellRangeAllowed( ) const 318 { 319 bool bAllow( false ); 320 321 Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); 322 if ( xSink.is() ) 323 { 324 bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_CELLRANGELISTSOURCE ); 325 } 326 327 return bAllow; 328 } 329 330 //------------------------------------------------------------------------ 331 bool FormCellBindingHelper::isCellBindingAllowed( ) const 332 { 333 bool bAllow( false ); 334 335 Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); 336 if ( xBindable.is() ) 337 { 338 // the control can potentially be bound to an external value 339 // Does it live within a Calc document, and is able to supply CellBindings? 340 bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_CELLVALUEBINDING ); 341 } 342 343 return bAllow; 344 } 345 346 //------------------------------------------------------------------------ 347 bool FormCellBindingHelper::isCellBindingAllowed( const Reference< XModel >& _rxDocument ) 348 { 349 return isSpreadsheetDocumentWhichSupplies( 350 Reference< XSpreadsheetDocument >( _rxDocument, UNO_QUERY ), 351 SERVICE_CELLVALUEBINDING 352 ); 353 } 354 355 //------------------------------------------------------------------------ 356 bool FormCellBindingHelper::isCellBinding( const Reference< XValueBinding >& _rxBinding ) const 357 { 358 return doesComponentSupport( _rxBinding.get(), SERVICE_CELLVALUEBINDING ); 359 } 360 361 //------------------------------------------------------------------------ 362 bool FormCellBindingHelper::isCellIntegerBinding( const Reference< XValueBinding >& _rxBinding ) const 363 { 364 return doesComponentSupport( _rxBinding.get(), SERVICE_LISTINDEXCELLBINDING ); 365 } 366 367 //------------------------------------------------------------------------ 368 bool FormCellBindingHelper::isCellRangeListSource( const Reference< XListEntrySource >& _rxSource ) const 369 { 370 return doesComponentSupport( _rxSource.get(), SERVICE_CELLRANGELISTSOURCE ); 371 } 372 373 //------------------------------------------------------------------------ 374 bool FormCellBindingHelper::doesComponentSupport( const Reference< XInterface >& _rxComponent, const ::rtl::OUString& _rService ) const 375 { 376 bool bDoes = false; 377 Reference< XServiceInfo > xSI( _rxComponent, UNO_QUERY ); 378 bDoes = xSI.is() && xSI->supportsService( _rService ); 379 return bDoes; 380 } 381 382 //------------------------------------------------------------------------ 383 Reference< XValueBinding > FormCellBindingHelper::getCurrentBinding( ) const 384 { 385 Reference< XValueBinding > xBinding; 386 Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); 387 if ( xBindable.is() ) 388 xBinding = xBindable->getValueBinding(); 389 return xBinding; 390 } 391 392 //------------------------------------------------------------------------ 393 Reference< XListEntrySource > FormCellBindingHelper::getCurrentListSource( ) const 394 { 395 Reference< XListEntrySource > xSource; 396 Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); 397 if ( xSink.is() ) 398 xSource = xSink->getListEntrySource(); 399 return xSource; 400 } 401 402 //------------------------------------------------------------------------ 403 void FormCellBindingHelper::setBinding( const Reference< XValueBinding >& _rxBinding ) 404 { 405 Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); 406 OSL_PRECOND( xBindable.is(), "FormCellBindingHelper::setBinding: the object is not bindable!" ); 407 if ( xBindable.is() ) 408 xBindable->setValueBinding( _rxBinding ); 409 } 410 411 //------------------------------------------------------------------------ 412 void FormCellBindingHelper::setListSource( const Reference< XListEntrySource >& _rxSource ) 413 { 414 Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); 415 OSL_PRECOND( xSink.is(), "FormCellBindingHelper::setListSource: the object is no list entry sink!" ); 416 if ( xSink.is() ) 417 xSink->setListEntrySource( _rxSource ); 418 } 419 420 //------------------------------------------------------------------------ 421 Reference< XInterface > FormCellBindingHelper::createDocumentDependentInstance( const ::rtl::OUString& _rService, const ::rtl::OUString& _rArgumentName, 422 const Any& _rArgumentValue ) const 423 { 424 Reference< XInterface > xReturn; 425 426 Reference< XMultiServiceFactory > xDocumentFactory( m_xDocument, UNO_QUERY ); 427 OSL_ENSURE( xDocumentFactory.is(), "FormCellBindingHelper::createDocumentDependentInstance: no document service factory!" ); 428 if ( xDocumentFactory.is() ) 429 { 430 try 431 { 432 if ( _rArgumentName.getLength() ) 433 { 434 NamedValue aArg; 435 aArg.Name = _rArgumentName; 436 aArg.Value = _rArgumentValue; 437 438 Sequence< Any > aArgs( 1 ); 439 aArgs[ 0 ] <<= aArg; 440 441 xReturn = xDocumentFactory->createInstanceWithArguments( _rService, aArgs ); 442 } 443 else 444 { 445 xReturn = xDocumentFactory->createInstance( _rService ); 446 } 447 } 448 catch ( const Exception& ) 449 { 450 OSL_ENSURE( sal_False, "FormCellBindingHelper::createDocumentDependentInstance: could not create the binding at the document!" ); 451 } 452 } 453 return xReturn; 454 } 455 456 //------------------------------------------------------------------------ 457 bool FormCellBindingHelper::doConvertAddressRepresentations( const ::rtl::OUString& _rInputProperty, const Any& _rInputValue, 458 const ::rtl::OUString& _rOutputProperty, Any& _rOutputValue, bool _bIsRange ) const SAL_THROW(()) 459 { 460 bool bSuccess = false; 461 462 Reference< XPropertySet > xConverter( 463 createDocumentDependentInstance( 464 _bIsRange ? SERVICE_RANGEADDRESS_CONVERSION : SERVICE_ADDRESS_CONVERSION, 465 ::rtl::OUString(), 466 Any() 467 ), 468 UNO_QUERY 469 ); 470 OSL_ENSURE( xConverter.is(), "FormCellBindingHelper::doConvertAddressRepresentations: could not get a converter service!" ); 471 if ( xConverter.is() ) 472 { 473 try 474 { 475 xConverter->setPropertyValue( _rInputProperty, _rInputValue ); 476 _rOutputValue = xConverter->getPropertyValue( _rOutputProperty ); 477 bSuccess = true; 478 } 479 catch( const Exception& ) 480 { 481 OSL_ENSURE( sal_False, "FormCellBindingHelper::doConvertAddressRepresentations: caught an exception!" ); 482 } 483 } 484 485 return bSuccess; 486 } 487 488 //............................................................................ 489 } // namespace xmloff 490 //............................................................................ 491