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_extensions.hxx" 30 #include "cellbindinghelper.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/FormComponentType.hpp> 34 #include <com/sun/star/form/XGridColumnFactory.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 <com/sun/star/sheet/XSpreadsheet.hpp> 45 #include <unotools/transliterationwrapper.hxx> 46 #include <osl/diagnose.h> 47 #include <tools/diagnose_ex.h> 48 #include "formstrings.hxx" 49 50 #include <functional> 51 #include <algorithm> 52 53 //............................................................................ 54 namespace pcr 55 { 56 //............................................................................ 57 58 using namespace ::com::sun::star::uno; 59 using namespace ::com::sun::star::beans; 60 using namespace ::com::sun::star::frame; 61 using namespace ::com::sun::star::sheet; 62 using namespace ::com::sun::star::container; 63 using namespace ::com::sun::star::drawing; 64 using namespace ::com::sun::star::table; 65 using namespace ::com::sun::star::form; 66 using namespace ::com::sun::star::lang; 67 using namespace ::com::sun::star::i18n; 68 using namespace ::com::sun::star::form::binding; 69 70 namespace 71 { 72 //.................................................................... 73 struct StringCompare : public ::std::unary_function< ::rtl::OUString, bool > 74 { 75 private: 76 ::rtl::OUString m_sReference; 77 78 public: 79 StringCompare( const ::rtl::OUString& _rReference ) : m_sReference( _rReference ) { } 80 81 inline bool operator()( const ::rtl::OUString& _rCompare ) 82 { 83 return ( _rCompare == m_sReference ) ? true : false; 84 } 85 }; 86 } 87 88 //======================================================================== 89 //= CellBindingHelper 90 //======================================================================== 91 //------------------------------------------------------------------------ 92 CellBindingHelper::CellBindingHelper( const Reference< XPropertySet >& _rxControlModel, const Reference< XModel >& _rxContextDocument ) 93 :m_xControlModel( _rxControlModel ) 94 { 95 OSL_ENSURE( m_xControlModel.is(), "CellBindingHelper::CellBindingHelper: invalid control model!" ); 96 97 m_xDocument = m_xDocument.query( _rxContextDocument ); 98 OSL_ENSURE( m_xDocument.is(), "CellBindingHelper::CellBindingHelper: This is no spreadsheet document!" ); 99 100 OSL_ENSURE( isSpreadsheetDocumentWhichSupplies( SERVICE_ADDRESS_CONVERSION ), 101 "CellBindingHelper::CellBindingHelper: the document cannot convert address representations!" ); 102 } 103 104 //------------------------------------------------------------------------ 105 sal_Bool CellBindingHelper::isSpreadsheetDocument( const Reference< XModel >& _rxContextDocument ) 106 { 107 return Reference< XSpreadsheetDocument >::query( _rxContextDocument ).is(); 108 } 109 110 //------------------------------------------------------------------------ 111 sal_Int16 CellBindingHelper::getControlSheetIndex( Reference< XSpreadsheet >& _out_rxSheet ) const 112 { 113 sal_Int16 nSheetIndex = -1; 114 // every sheet has a draw page, and every draw page has a forms collection. 115 // Our control, OTOH, belongs to a forms collection. Match these ... 116 try 117 { 118 // for determining the draw page, we need the forms collection which 119 // the object belongs to. This is the first object up the hierarchy which is 120 // *no* XForm (and, well, no XGridColumnFactory) 121 Reference< XChild > xCheck( m_xControlModel, UNO_QUERY ); 122 Reference< XForm > xParentAsForm; if ( xCheck.is() ) xParentAsForm = xParentAsForm.query( xCheck->getParent() ); 123 Reference< XGridColumnFactory > xParentAsGrid; if ( xCheck.is() ) xParentAsGrid = xParentAsGrid.query( xCheck->getParent() ); 124 125 while ( ( xParentAsForm.is() || xParentAsGrid.is() ) && xCheck.is() ) 126 { 127 xCheck = xCheck.query( xCheck->getParent() ); 128 xParentAsForm = xParentAsForm.query( xCheck.is() ? xCheck->getParent() : (Reference< XInterface >) Reference< XForm >() ); 129 xParentAsGrid = xParentAsGrid.query( xCheck.is() ? xCheck->getParent() : (Reference< XInterface >) Reference< XGridColumnFactory >() ); 130 } 131 Reference< XInterface > xFormsCollection( xCheck.is() ? xCheck->getParent() : Reference< XInterface >() ); 132 133 // now iterate through the sheets 134 Reference< XIndexAccess > xSheets( m_xDocument->getSheets(), UNO_QUERY ); 135 if ( xSheets.is() && xFormsCollection.is() ) 136 { 137 for ( sal_Int32 i = 0; i < xSheets->getCount(); ++i ) 138 { 139 Reference< XDrawPageSupplier > xSuppPage( xSheets->getByIndex( i ), UNO_QUERY_THROW ); 140 Reference< XFormsSupplier > xSuppForms( xSuppPage->getDrawPage(), UNO_QUERY_THROW ); 141 142 if ( xSuppForms->getForms() == xFormsCollection ) 143 { // found it 144 nSheetIndex = (sal_Int16)i; 145 _out_rxSheet.set( xSuppPage, UNO_QUERY_THROW ); 146 break; 147 } 148 } 149 } 150 } 151 catch( const Exception& ) 152 { 153 DBG_UNHANDLED_EXCEPTION(); 154 } 155 156 return nSheetIndex; 157 } 158 159 //------------------------------------------------------------------------ 160 bool CellBindingHelper::convertStringAddress( const ::rtl::OUString& _rAddressDescription, CellAddress& /* [out] */ _rAddress ) const 161 { 162 Any aAddress; 163 return doConvertAddressRepresentations( 164 PROPERTY_UI_REPRESENTATION, 165 makeAny( _rAddressDescription ), 166 PROPERTY_ADDRESS, 167 aAddress, 168 false 169 ) 170 && ( aAddress >>= _rAddress ); 171 } 172 173 //------------------------------------------------------------------------ 174 bool CellBindingHelper::doConvertAddressRepresentations( const ::rtl::OUString& _rInputProperty, const Any& _rInputValue, 175 const ::rtl::OUString& _rOutputProperty, Any& _rOutputValue, bool _bIsRange ) const SAL_THROW(()) 176 { 177 bool bSuccess = false; 178 179 Reference< XPropertySet > xConverter( 180 createDocumentDependentInstance( 181 _bIsRange ? SERVICE_RANGEADDRESS_CONVERSION : SERVICE_ADDRESS_CONVERSION, 182 ::rtl::OUString(), 183 Any() 184 ), 185 UNO_QUERY 186 ); 187 OSL_ENSURE( xConverter.is(), "CellBindingHelper::doConvertAddressRepresentations: could not get a converter service!" ); 188 if ( xConverter.is() ) 189 { 190 try 191 { 192 Reference< XSpreadsheet > xSheet; 193 xConverter->setPropertyValue( PROPERTY_REFERENCE_SHEET, makeAny( (sal_Int32)getControlSheetIndex( xSheet ) ) ); 194 xConverter->setPropertyValue( _rInputProperty, _rInputValue ); 195 _rOutputValue = xConverter->getPropertyValue( _rOutputProperty ); 196 bSuccess = true; 197 } 198 catch( const Exception& ) 199 { 200 OSL_ENSURE( sal_False, "CellBindingHelper::doConvertAddressRepresentations: caught an exception!" ); 201 } 202 } 203 204 return bSuccess; 205 } 206 207 //------------------------------------------------------------------------ 208 bool CellBindingHelper::convertStringAddress( const ::rtl::OUString& _rAddressDescription, 209 CellRangeAddress& /* [out] */ _rAddress ) const 210 { 211 Any aAddress; 212 return doConvertAddressRepresentations( 213 PROPERTY_UI_REPRESENTATION, 214 makeAny( _rAddressDescription ), 215 PROPERTY_ADDRESS, 216 aAddress, 217 true 218 ) 219 && ( aAddress >>= _rAddress ); 220 } 221 222 //------------------------------------------------------------------------ 223 Reference< XValueBinding > CellBindingHelper::createCellBindingFromAddress( const CellAddress& _rAddress, bool _bSupportIntegerExchange ) const 224 { 225 Reference< XValueBinding > xBinding( createDocumentDependentInstance( 226 _bSupportIntegerExchange ? SERVICE_SHEET_CELL_INT_BINDING : SERVICE_SHEET_CELL_BINDING, 227 PROPERTY_BOUND_CELL, 228 makeAny( _rAddress ) 229 ), UNO_QUERY ); 230 231 return xBinding; 232 } 233 234 //------------------------------------------------------------------------ 235 Reference< XValueBinding > CellBindingHelper::createCellBindingFromStringAddress( const ::rtl::OUString& _rAddress, bool _bSupportIntegerExchange ) const 236 { 237 Reference< XValueBinding > xBinding; 238 if ( !m_xDocument.is() ) 239 // very bad ... 240 return xBinding; 241 242 // get the UNO representation of the address 243 CellAddress aAddress; 244 if ( !_rAddress.getLength() || !convertStringAddress( _rAddress, aAddress ) ) 245 return xBinding; 246 247 return createCellBindingFromAddress( aAddress, _bSupportIntegerExchange ); 248 } 249 250 //------------------------------------------------------------------------ 251 Reference< XListEntrySource > CellBindingHelper::createCellListSourceFromStringAddress( const ::rtl::OUString& _rAddress ) const 252 { 253 Reference< XListEntrySource > xSource; 254 255 CellRangeAddress aRangeAddress; 256 if ( !_rAddress.getLength() || !convertStringAddress( _rAddress, aRangeAddress ) ) 257 return xSource; 258 259 // create a range object for this address 260 xSource = xSource.query( createDocumentDependentInstance( 261 SERVICE_SHEET_CELLRANGE_LISTSOURCE, 262 PROPERTY_LIST_CELL_RANGE, 263 makeAny( aRangeAddress ) 264 ) ); 265 266 return xSource; 267 } 268 269 //------------------------------------------------------------------------ 270 Reference< XInterface > CellBindingHelper::createDocumentDependentInstance( const ::rtl::OUString& _rService, const ::rtl::OUString& _rArgumentName, 271 const Any& _rArgumentValue ) const 272 { 273 Reference< XInterface > xReturn; 274 275 Reference< XMultiServiceFactory > xDocumentFactory( m_xDocument, UNO_QUERY ); 276 OSL_ENSURE( xDocumentFactory.is(), "CellBindingHelper::createDocumentDependentInstance: no document service factory!" ); 277 if ( xDocumentFactory.is() ) 278 { 279 try 280 { 281 if ( _rArgumentName.getLength() ) 282 { 283 NamedValue aArg; 284 aArg.Name = _rArgumentName; 285 aArg.Value = _rArgumentValue; 286 287 Sequence< Any > aArgs( 1 ); 288 aArgs[ 0 ] <<= aArg; 289 290 xReturn = xDocumentFactory->createInstanceWithArguments( _rService, aArgs ); 291 } 292 else 293 { 294 xReturn = xDocumentFactory->createInstance( _rService ); 295 } 296 } 297 catch ( const Exception& ) 298 { 299 OSL_ENSURE( sal_False, "CellBindingHelper::createDocumentDependentInstance: could not create the binding at the document!" ); 300 } 301 } 302 return xReturn; 303 } 304 305 //------------------------------------------------------------------------ 306 bool CellBindingHelper::getAddressFromCellBinding( 307 const Reference< XValueBinding >& _rxBinding, CellAddress& _rAddress ) const 308 { 309 OSL_PRECOND( !_rxBinding.is() || isCellBinding( _rxBinding ), "CellBindingHelper::getAddressFromCellBinding: this is no cell binding!" ); 310 311 bool bReturn = false; 312 if ( !m_xDocument.is() ) 313 // very bad ... 314 return bReturn; 315 316 try 317 { 318 Reference< XPropertySet > xBindingProps( _rxBinding, UNO_QUERY ); 319 OSL_ENSURE( xBindingProps.is() || !_rxBinding.is(), "CellBindingHelper::getAddressFromCellBinding: no property set for the binding!" ); 320 if ( xBindingProps.is() ) 321 { 322 CellAddress aAddress; 323 bReturn = (bool)( xBindingProps->getPropertyValue( PROPERTY_BOUND_CELL ) >>= _rAddress ); 324 } 325 } 326 catch( const Exception& ) 327 { 328 OSL_ENSURE( sal_False, "CellBindingHelper::getAddressFromCellBinding: caught an exception!" ); 329 } 330 331 return bReturn; 332 } 333 334 //------------------------------------------------------------------------ 335 ::rtl::OUString CellBindingHelper::getStringAddressFromCellBinding( const Reference< XValueBinding >& _rxBinding ) const 336 { 337 CellAddress aAddress; 338 ::rtl::OUString sAddress; 339 if ( getAddressFromCellBinding( _rxBinding, aAddress ) ) 340 { 341 Any aStringAddress; 342 doConvertAddressRepresentations( PROPERTY_ADDRESS, makeAny( aAddress ), 343 PROPERTY_UI_REPRESENTATION, aStringAddress, false ); 344 345 aStringAddress >>= sAddress; 346 } 347 348 return sAddress; 349 } 350 351 //------------------------------------------------------------------------ 352 ::rtl::OUString CellBindingHelper::getStringAddressFromCellListSource( const Reference< XListEntrySource >& _rxSource ) const 353 { 354 OSL_PRECOND( !_rxSource.is() || isCellRangeListSource( _rxSource ), "CellBindingHelper::getStringAddressFromCellListSource: this is no cell list source!" ); 355 356 ::rtl::OUString sAddress; 357 if ( !m_xDocument.is() ) 358 // very bad ... 359 return sAddress; 360 361 try 362 { 363 Reference< XPropertySet > xSourceProps( _rxSource, UNO_QUERY ); 364 OSL_ENSURE( xSourceProps.is() || !_rxSource.is(), "CellBindingHelper::getStringAddressFromCellListSource: no property set for the list source!" ); 365 if ( xSourceProps.is() ) 366 { 367 CellRangeAddress aRangeAddress; 368 xSourceProps->getPropertyValue( PROPERTY_LIST_CELL_RANGE ) >>= aRangeAddress; 369 370 Any aStringAddress; 371 doConvertAddressRepresentations( PROPERTY_ADDRESS, makeAny( aRangeAddress ), 372 PROPERTY_UI_REPRESENTATION, aStringAddress, true ); 373 aStringAddress >>= sAddress; 374 } 375 } 376 catch( const Exception& ) 377 { 378 OSL_ENSURE( sal_False, "CellBindingHelper::getStringAddressFromCellListSource: caught an exception!" ); 379 } 380 381 return sAddress; 382 } 383 384 //------------------------------------------------------------------------ 385 bool CellBindingHelper::isSpreadsheetDocumentWhichSupplies( const ::rtl::OUString& _rService ) const 386 { 387 bool bYesItIs = false; 388 389 Reference< XServiceInfo > xSI( m_xDocument, UNO_QUERY ); 390 if ( xSI.is() && xSI->supportsService( SERVICE_SPREADSHEET_DOCUMENT ) ) 391 { 392 Reference< XMultiServiceFactory > xDocumentFactory( m_xDocument, UNO_QUERY ); 393 OSL_ENSURE( xDocumentFactory.is(), "CellBindingHelper::isSpreadsheetDocumentWhichSupplies: spreadsheet document, but no factory?" ); 394 395 Sequence< ::rtl::OUString > aAvailableServices; 396 if ( xDocumentFactory.is() ) 397 aAvailableServices = xDocumentFactory->getAvailableServiceNames( ); 398 399 const ::rtl::OUString* pFound = ::std::find_if( 400 aAvailableServices.getConstArray(), 401 aAvailableServices.getConstArray() + aAvailableServices.getLength(), 402 StringCompare( _rService ) 403 ); 404 if ( pFound - aAvailableServices.getConstArray() < aAvailableServices.getLength() ) 405 { 406 bYesItIs = true; 407 } 408 } 409 410 return bYesItIs; 411 } 412 413 //------------------------------------------------------------------------ 414 bool CellBindingHelper::isListCellRangeAllowed( ) const 415 { 416 bool bAllow( false ); 417 418 Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); 419 if ( xSink.is() ) 420 { 421 bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_SHEET_CELLRANGE_LISTSOURCE ); 422 } 423 424 return bAllow; 425 } 426 427 //------------------------------------------------------------------------ 428 bool CellBindingHelper::isCellIntegerBindingAllowed( ) const 429 { 430 bool bAllow( true ); 431 432 // first, we only offer this for controls which allow bindings in general 433 Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); 434 if ( !xBindable.is() ) 435 bAllow = false; 436 437 // then, we must live in a spreadsheet document which can provide the special 438 // service needed for exchanging integer values 439 if ( bAllow ) 440 bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_SHEET_CELL_INT_BINDING ); 441 442 // then, we only offer this for list boxes 443 if ( bAllow ) 444 { 445 try 446 { 447 sal_Int16 nClassId = FormComponentType::CONTROL; 448 m_xControlModel->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId; 449 if ( FormComponentType::LISTBOX != nClassId ) 450 bAllow = false; 451 } 452 catch( const Exception& ) 453 { 454 OSL_ENSURE( sal_False, "CellBindingHelper::isCellIntegerBindingAllowed: caught an exception!" ); 455 // are there really control models which survive isCellBindingAllowed, but don't have a ClassId 456 // property? 457 bAllow = false; 458 } 459 } 460 461 return bAllow; 462 } 463 464 //------------------------------------------------------------------------ 465 bool CellBindingHelper::isCellBindingAllowed( ) const 466 { 467 bool bAllow( false ); 468 469 Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); 470 if ( xBindable.is() ) 471 { 472 // the control can potentially be bound to an external value 473 // Does it live within a Calc document, and is able to supply CellBindings? 474 bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_SHEET_CELL_BINDING ); 475 } 476 477 // disallow for some types 478 // TODO: shouldn't the XBindableValue supply a list of supported types, and we can distingusih 479 // using this list? The current behavior below is somewhat hackish ... 480 if ( bAllow ) 481 { 482 try 483 { 484 sal_Int16 nClassId = FormComponentType::CONTROL; 485 m_xControlModel->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId; 486 if ( ( FormComponentType::DATEFIELD == nClassId ) || ( FormComponentType::TIMEFIELD == nClassId ) ) 487 bAllow = false; 488 } 489 catch( const Exception& ) 490 { 491 OSL_ENSURE( sal_False, "CellBindingHelper::isCellBindingAllowed: caught an exception!" ); 492 bAllow = false; 493 } 494 } 495 return bAllow; 496 } 497 498 //------------------------------------------------------------------------ 499 bool CellBindingHelper::isCellBinding( const Reference< XValueBinding >& _rxBinding ) const 500 { 501 return doesComponentSupport( _rxBinding.get(), SERVICE_SHEET_CELL_BINDING ); 502 } 503 504 //------------------------------------------------------------------------ 505 bool CellBindingHelper::isCellIntegerBinding( const Reference< XValueBinding >& _rxBinding ) const 506 { 507 return doesComponentSupport( _rxBinding.get(), SERVICE_SHEET_CELL_INT_BINDING ); 508 } 509 510 //------------------------------------------------------------------------ 511 bool CellBindingHelper::isCellRangeListSource( const Reference< XListEntrySource >& _rxSource ) const 512 { 513 return doesComponentSupport( _rxSource.get(), SERVICE_SHEET_CELLRANGE_LISTSOURCE ); 514 } 515 516 //------------------------------------------------------------------------ 517 bool CellBindingHelper::doesComponentSupport( const Reference< XInterface >& _rxComponent, const ::rtl::OUString& _rService ) const 518 { 519 bool bDoes = false; 520 Reference< XServiceInfo > xSI( _rxComponent, UNO_QUERY ); 521 bDoes = xSI.is() && xSI->supportsService( _rService ); 522 return bDoes; 523 } 524 525 //------------------------------------------------------------------------ 526 Reference< XValueBinding > CellBindingHelper::getCurrentBinding( ) const 527 { 528 Reference< XValueBinding > xBinding; 529 Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); 530 if ( xBindable.is() ) 531 xBinding = xBindable->getValueBinding(); 532 return xBinding; 533 } 534 535 //------------------------------------------------------------------------ 536 Reference< XListEntrySource > CellBindingHelper::getCurrentListSource( ) const 537 { 538 Reference< XListEntrySource > xSource; 539 Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); 540 if ( xSink.is() ) 541 xSource = xSink->getListEntrySource(); 542 return xSource; 543 } 544 545 //------------------------------------------------------------------------ 546 void CellBindingHelper::setBinding( const Reference< XValueBinding >& _rxBinding ) 547 { 548 Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); 549 OSL_PRECOND( xBindable.is(), "CellBindingHelper::setBinding: the object is not bindable!" ); 550 if ( xBindable.is() ) 551 xBindable->setValueBinding( _rxBinding ); 552 } 553 554 //------------------------------------------------------------------------ 555 void CellBindingHelper::setListSource( const Reference< XListEntrySource >& _rxSource ) 556 { 557 Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); 558 OSL_PRECOND( xSink.is(), "CellBindingHelper::setListSource: the object is no list entry sink!" ); 559 if ( xSink.is() ) 560 xSink->setListEntrySource( _rxSource ); 561 } 562 563 //............................................................................ 564 } // namespace pcr 565 //............................................................................ 566