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_sc.hxx" 26 #include "cellvaluebinding.hxx" 27 #include <tools/debug.hxx> 28 #include <rtl/math.hxx> 29 #include <com/sun/star/table/XCellRange.hpp> 30 #include <com/sun/star/sheet/XCellAddressable.hpp> 31 #include <com/sun/star/sheet/XCellRangeData.hpp> 32 #include <com/sun/star/container/XIndexAccess.hpp> 33 #include <com/sun/star/beans/PropertyAttribute.hpp> 34 #include <com/sun/star/beans/NamedValue.hpp> 35 #include <com/sun/star/util/XNumberFormatsSupplier.hpp> 36 #include <com/sun/star/util/XNumberFormatTypes.hpp> 37 #include <com/sun/star/util/NumberFormat.hpp> 38 39 //......................................................................... 40 namespace calc 41 { 42 //......................................................................... 43 44 #define PROP_HANDLE_BOUND_CELL 1 45 46 using namespace ::com::sun::star::uno; 47 using namespace ::com::sun::star::lang; 48 using namespace ::com::sun::star::table; 49 using namespace ::com::sun::star::text; 50 using namespace ::com::sun::star::sheet; 51 using namespace ::com::sun::star::container; 52 using namespace ::com::sun::star::beans; 53 using namespace ::com::sun::star::util; 54 using namespace ::com::sun::star::form::binding; 55 56 //===================================================================== 57 //= OCellValueBinding 58 //===================================================================== DBG_NAME(OCellValueBinding) const59 DBG_NAME( OCellValueBinding ) 60 //--------------------------------------------------------------------- 61 #ifdef DBG_UTIL 62 const char* OCellValueBinding::checkConsistency_static( const void* _pThis ) 63 { 64 return static_cast< const OCellValueBinding* >( _pThis )->checkConsistency( ); 65 } 66 checkConsistency() const67 const char* OCellValueBinding::checkConsistency( ) const 68 { 69 const char* pAssertion = NULL; 70 if ( m_xCellText.is() && !m_xCell.is() ) 71 // there are places (e.g. getSupportedTypes) which rely on the fact 72 // that m_xCellText.is() implies m_xCell.is() 73 pAssertion = "cell references inconsistent!"; 74 75 // TODO: place any additional checks here to ensure consistency of this instance 76 return pAssertion; 77 } 78 #endif 79 80 //--------------------------------------------------------------------- OCellValueBinding(const Reference<XSpreadsheetDocument> & _rxDocument,sal_Bool _bListPos)81 OCellValueBinding::OCellValueBinding( const Reference< XSpreadsheetDocument >& _rxDocument, sal_Bool _bListPos ) 82 :OCellValueBinding_Base( m_aMutex ) 83 ,OCellValueBinding_PBase( OCellValueBinding_Base::rBHelper ) 84 ,m_xDocument( _rxDocument ) 85 ,m_aModifyListeners( m_aMutex ) 86 ,m_bInitialized( sal_False ) 87 ,m_bListPos( _bListPos ) 88 { 89 DBG_CTOR( OCellValueBinding, checkConsistency_static ); 90 91 // register our property at the base class 92 CellAddress aInitialPropValue; 93 registerPropertyNoMember( 94 ::rtl::OUString::createFromAscii( "BoundCell" ), 95 PROP_HANDLE_BOUND_CELL, 96 PropertyAttribute::BOUND | PropertyAttribute::READONLY, 97 ::getCppuType( &aInitialPropValue ), 98 &aInitialPropValue 99 ); 100 101 // TODO: implement a ReadOnly property as required by the service, 102 // which probably maps to the cell being locked 103 } 104 105 //--------------------------------------------------------------------- ~OCellValueBinding()106 OCellValueBinding::~OCellValueBinding( ) 107 { 108 if ( !OCellValueBinding_Base::rBHelper.bDisposed ) 109 { 110 acquire(); // prevent duplicate dtor 111 dispose(); 112 } 113 114 DBG_DTOR( OCellValueBinding, checkConsistency_static ); 115 } 116 117 //-------------------------------------------------------------------- IMPLEMENT_FORWARD_XINTERFACE2(OCellValueBinding,OCellValueBinding_Base,OCellValueBinding_PBase)118 IMPLEMENT_FORWARD_XINTERFACE2( OCellValueBinding, OCellValueBinding_Base, OCellValueBinding_PBase ) 119 120 //-------------------------------------------------------------------- 121 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCellValueBinding, OCellValueBinding_Base, OCellValueBinding_PBase ) 122 123 //-------------------------------------------------------------------- 124 void SAL_CALL OCellValueBinding::disposing() 125 { 126 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 127 128 Reference<XModifyBroadcaster> xBroadcaster( m_xCell, UNO_QUERY ); 129 if ( xBroadcaster.is() ) 130 { 131 xBroadcaster->removeModifyListener( this ); 132 } 133 134 // OCellValueBinding_Base::disposing(); 135 WeakAggComponentImplHelperBase::disposing(); 136 137 // TODO: clean up here whatever you need to clean up (e.g. deregister as XEventListener 138 // for the cell) 139 } 140 141 //-------------------------------------------------------------------- getPropertySetInfo()142 Reference< XPropertySetInfo > SAL_CALL OCellValueBinding::getPropertySetInfo( ) throw(RuntimeException) 143 { 144 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 145 return createPropertySetInfo( getInfoHelper() ) ; 146 } 147 148 //-------------------------------------------------------------------- getInfoHelper()149 ::cppu::IPropertyArrayHelper& SAL_CALL OCellValueBinding::getInfoHelper() 150 { 151 return *OCellValueBinding_PABase::getArrayHelper(); 152 } 153 154 //-------------------------------------------------------------------- createArrayHelper() const155 ::cppu::IPropertyArrayHelper* OCellValueBinding::createArrayHelper( ) const 156 { 157 Sequence< Property > aProps; 158 describeProperties( aProps ); 159 return new ::cppu::OPropertyArrayHelper(aProps); 160 } 161 162 //-------------------------------------------------------------------- getFastPropertyValue(Any & _rValue,sal_Int32 _nHandle) const163 void SAL_CALL OCellValueBinding::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const 164 { 165 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 166 DBG_ASSERT( _nHandle == PROP_HANDLE_BOUND_CELL, "OCellValueBinding::getFastPropertyValue: invalid handle!" ); 167 // we only have this one property .... 168 (void)_nHandle; // avoid warning in product version 169 170 _rValue.clear(); 171 Reference< XCellAddressable > xCellAddress( m_xCell, UNO_QUERY ); 172 if ( xCellAddress.is() ) 173 _rValue <<= xCellAddress->getCellAddress( ); 174 } 175 176 //-------------------------------------------------------------------- getSupportedValueTypes()177 Sequence< Type > SAL_CALL OCellValueBinding::getSupportedValueTypes( ) throw (RuntimeException) 178 { 179 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 180 checkDisposed( ); 181 checkInitialized( ); 182 183 sal_Int32 nCount = m_xCellText.is() ? 3 : m_xCell.is() ? 1 : 0; 184 if ( m_bListPos ) 185 ++nCount; 186 187 Sequence< Type > aTypes( nCount ); 188 if ( m_xCell.is() ) 189 { 190 // an XCell can be used to set/get "double" values 191 aTypes[0] = ::getCppuType( static_cast< double* >( NULL ) ); 192 if ( m_xCellText.is() ) 193 { 194 // an XTextRange can be used to set/get "string" values 195 aTypes[1] = ::getCppuType( static_cast< ::rtl::OUString* >( NULL ) ); 196 // and additionally, we use it to handle booleans 197 aTypes[2] = ::getCppuType( static_cast< sal_Bool* >( NULL ) ); 198 } 199 200 // add sal_Int32 only if constructed as ListPositionCellBinding 201 if ( m_bListPos ) 202 aTypes[nCount-1] = ::getCppuType( static_cast< sal_Int32* >( NULL ) ); 203 } 204 205 return aTypes; 206 } 207 208 //-------------------------------------------------------------------- supportsType(const Type & aType)209 sal_Bool SAL_CALL OCellValueBinding::supportsType( const Type& aType ) throw (RuntimeException) 210 { 211 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 212 checkDisposed( ); 213 checkInitialized( ); 214 215 // look up in our sequence 216 Sequence< Type > aSupportedTypes( getSupportedValueTypes() ); 217 const Type* pTypes = aSupportedTypes.getConstArray(); 218 const Type* pTypesEnd = aSupportedTypes.getConstArray() + aSupportedTypes.getLength(); 219 while ( pTypes != pTypesEnd ) 220 if ( aType.equals( *pTypes++ ) ) 221 return sal_True; 222 223 return sal_False; 224 } 225 226 //-------------------------------------------------------------------- getValue(const Type & aType)227 Any SAL_CALL OCellValueBinding::getValue( const Type& aType ) throw (IncompatibleTypesException, RuntimeException) 228 { 229 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 230 checkDisposed( ); 231 checkInitialized( ); 232 checkValueType( aType ); 233 234 Any aReturn; 235 switch ( aType.getTypeClass() ) 236 { 237 case TypeClass_STRING: 238 DBG_ASSERT( m_xCellText.is(), "OCellValueBinding::getValue: don't have a text!" ); 239 if ( m_xCellText.is() ) 240 aReturn <<= m_xCellText->getString(); 241 else 242 aReturn <<= ::rtl::OUString(); 243 break; 244 245 case TypeClass_BOOLEAN: 246 DBG_ASSERT( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" ); 247 if ( m_xCell.is() ) 248 { 249 // check if the cell has a numeric value (this might go into a helper function): 250 251 sal_Bool bHasValue = sal_False; 252 CellContentType eCellType = m_xCell->getType(); 253 if ( eCellType == CellContentType_VALUE ) 254 bHasValue = sal_True; 255 else if ( eCellType == CellContentType_FORMULA ) 256 { 257 // check if the formula result is a value 258 if ( m_xCell->getError() == 0 ) 259 { 260 Reference<XPropertySet> xProp( m_xCell, UNO_QUERY ); 261 if ( xProp.is() ) 262 { 263 CellContentType eResultType; 264 if ( (xProp->getPropertyValue(::rtl::OUString::createFromAscii( "FormulaResultType" ) ) >>= eResultType) && eResultType == CellContentType_VALUE ) 265 bHasValue = sal_True; 266 } 267 } 268 } 269 270 if ( bHasValue ) 271 { 272 // 0 is "unchecked", any other value is "checked", regardless of number format 273 double nCellValue = m_xCell->getValue(); 274 sal_Bool bBoolValue = ( nCellValue != 0.0 ); 275 aReturn <<= bBoolValue; 276 } 277 // empty cells, text cells and text or error formula results: leave return value empty 278 } 279 break; 280 281 case TypeClass_DOUBLE: 282 DBG_ASSERT( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" ); 283 if ( m_xCell.is() ) 284 aReturn <<= m_xCell->getValue(); 285 else 286 aReturn <<= (double)0; 287 break; 288 289 case TypeClass_LONG: 290 DBG_ASSERT( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" ); 291 if ( m_xCell.is() ) 292 { 293 // The list position value in the cell is 1-based. 294 // We subtract 1 from any cell value (no special handling for 0 or negative values). 295 296 sal_Int32 nValue = (sal_Int32) rtl::math::approxFloor( m_xCell->getValue() ); 297 --nValue; 298 299 aReturn <<= nValue; 300 } 301 else 302 aReturn <<= (sal_Int32)0; 303 break; 304 305 default: 306 DBG_ERROR( "OCellValueBinding::getValue: unreachable code!" ); 307 // a type other than double and string should never have survived the checkValueType 308 // above 309 } 310 return aReturn; 311 } 312 313 //-------------------------------------------------------------------- setValue(const Any & aValue)314 void SAL_CALL OCellValueBinding::setValue( const Any& aValue ) throw (IncompatibleTypesException, NoSupportException, RuntimeException) 315 { 316 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 317 checkDisposed( ); 318 checkInitialized( ); 319 if ( aValue.hasValue() ) 320 checkValueType( aValue.getValueType() ); 321 322 switch ( aValue.getValueType().getTypeClass() ) 323 { 324 case TypeClass_STRING: 325 { 326 DBG_ASSERT( m_xCellText.is(), "OCellValueBinding::setValue: don't have a text!" ); 327 328 ::rtl::OUString sText; 329 aValue >>= sText; 330 if ( m_xCellText.is() ) 331 m_xCellText->setString( sText ); 332 } 333 break; 334 335 case TypeClass_BOOLEAN: 336 { 337 DBG_ASSERT( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" ); 338 339 // boolean is stored as values 0 or 1 340 // TODO: set the number format to boolean if no format is set? 341 342 sal_Bool bValue( sal_False ); 343 aValue >>= bValue; 344 double nCellValue = bValue ? 1.0 : 0.0; 345 346 if ( m_xCell.is() ) 347 m_xCell->setValue( nCellValue ); 348 349 setBooleanFormat(); 350 } 351 break; 352 353 case TypeClass_DOUBLE: 354 { 355 DBG_ASSERT( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" ); 356 357 double nValue = 0; 358 aValue >>= nValue; 359 if ( m_xCell.is() ) 360 m_xCell->setValue( nValue ); 361 } 362 break; 363 364 case TypeClass_LONG: 365 { 366 DBG_ASSERT( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" ); 367 368 sal_Int32 nValue = 0; 369 aValue >>= nValue; // list index from control layer (0-based) 370 ++nValue; // the list position value in the cell is 1-based 371 if ( m_xCell.is() ) 372 m_xCell->setValue( nValue ); 373 } 374 break; 375 376 case TypeClass_VOID: 377 { 378 // #N/A error value can only be set using XCellRangeData 379 380 Reference<XCellRangeData> xData( m_xCell, UNO_QUERY ); 381 DBG_ASSERT( xData.is(), "OCellValueBinding::setValue: don't have XCellRangeData!" ); 382 if ( xData.is() ) 383 { 384 Sequence<Any> aInner(1); // one empty element 385 Sequence< Sequence<Any> > aOuter( &aInner, 1 ); // one row 386 xData->setDataArray( aOuter ); 387 } 388 } 389 break; 390 391 default: 392 DBG_ERROR( "OCellValueBinding::setValue: unreachable code!" ); 393 // a type other than double and string should never have survived the checkValueType 394 // above 395 } 396 } 397 //-------------------------------------------------------------------- setBooleanFormat()398 void OCellValueBinding::setBooleanFormat() 399 { 400 // set boolean number format if not already set 401 402 ::rtl::OUString sPropName( ::rtl::OUString::createFromAscii( "NumberFormat" ) ); 403 Reference<XPropertySet> xCellProp( m_xCell, UNO_QUERY ); 404 Reference<XNumberFormatsSupplier> xSupplier( m_xDocument, UNO_QUERY ); 405 if ( xSupplier.is() && xCellProp.is() ) 406 { 407 Reference<XNumberFormats> xFormats(xSupplier->getNumberFormats()); 408 Reference<XNumberFormatTypes> xTypes( xFormats, UNO_QUERY ); 409 if ( xTypes.is() ) 410 { 411 Locale aLocale; 412 sal_Bool bWasBoolean = sal_False; 413 414 sal_Int32 nOldIndex = ::comphelper::getINT32( xCellProp->getPropertyValue( sPropName ) ); 415 Reference<XPropertySet> xOldFormat; 416 try 417 { 418 xOldFormat.set(xFormats->getByKey( nOldIndex )); 419 } 420 catch ( Exception& ) 421 { 422 // non-existing format - can happen, use defaults 423 } 424 if ( xOldFormat.is() ) 425 { 426 // use the locale of the existing format 427 xOldFormat->getPropertyValue( ::rtl::OUString::createFromAscii( "Locale" ) ) >>= aLocale; 428 429 sal_Int16 nOldType = ::comphelper::getINT16( 430 xOldFormat->getPropertyValue( ::rtl::OUString::createFromAscii( "Type" ) ) ); 431 if ( nOldType & NumberFormat::LOGICAL ) 432 bWasBoolean = sal_True; 433 } 434 435 if ( !bWasBoolean ) 436 { 437 sal_Int32 nNewIndex = xTypes->getStandardFormat( NumberFormat::LOGICAL, aLocale ); 438 xCellProp->setPropertyValue( sPropName, makeAny( nNewIndex ) ); 439 } 440 } 441 } 442 } 443 444 //-------------------------------------------------------------------- checkDisposed() const445 void OCellValueBinding::checkDisposed( ) const SAL_THROW( ( DisposedException ) ) 446 { 447 if ( OCellValueBinding_Base::rBHelper.bInDispose || OCellValueBinding_Base::rBHelper.bDisposed ) 448 throw DisposedException(); 449 // TODO: is it worth having an error message here? 450 } 451 452 //-------------------------------------------------------------------- checkInitialized()453 void OCellValueBinding::checkInitialized() SAL_THROW( ( RuntimeException ) ) 454 { 455 if ( !m_bInitialized ) 456 throw RuntimeException(); 457 // TODO: error message 458 } 459 460 //-------------------------------------------------------------------- checkValueType(const Type & _rType) const461 void OCellValueBinding::checkValueType( const Type& _rType ) const SAL_THROW( ( IncompatibleTypesException ) ) 462 { 463 OCellValueBinding* pNonConstThis = const_cast< OCellValueBinding* >( this ); 464 if ( !pNonConstThis->supportsType( _rType ) ) 465 { 466 ::rtl::OUString sMessage( RTL_CONSTASCII_USTRINGPARAM( "The given type (" ) ); 467 sMessage += _rType.getTypeName(); 468 sMessage += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ") is not supported by this binding." ) ); 469 // TODO: localize this error message 470 471 throw IncompatibleTypesException( sMessage, *pNonConstThis ); 472 // TODO: alternatively use a type converter service for this? 473 } 474 } 475 476 //-------------------------------------------------------------------- getImplementationName()477 ::rtl::OUString SAL_CALL OCellValueBinding::getImplementationName( ) throw (RuntimeException) 478 { 479 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 480 481 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.sheet.OCellValueBinding" ) ); 482 } 483 484 //-------------------------------------------------------------------- supportsService(const::rtl::OUString & _rServiceName)485 sal_Bool SAL_CALL OCellValueBinding::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException) 486 { 487 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 488 489 Sequence< ::rtl::OUString > aSupportedServices( getSupportedServiceNames() ); 490 const ::rtl::OUString* pLookup = aSupportedServices.getConstArray(); 491 const ::rtl::OUString* pLookupEnd = aSupportedServices.getConstArray() + aSupportedServices.getLength(); 492 while ( pLookup != pLookupEnd ) 493 if ( *pLookup++ == _rServiceName ) 494 return sal_True; 495 496 return sal_False; 497 } 498 499 //-------------------------------------------------------------------- getSupportedServiceNames()500 Sequence< ::rtl::OUString > SAL_CALL OCellValueBinding::getSupportedServiceNames( ) throw (RuntimeException) 501 { 502 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 503 504 Sequence< ::rtl::OUString > aServices( m_bListPos ? 3 : 2 ); 505 aServices[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.table.CellValueBinding" ) ); 506 aServices[ 1 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.binding.ValueBinding" ) ); 507 if ( m_bListPos ) 508 aServices[ 2 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.table.ListPositionCellBinding" ) ); 509 return aServices; 510 } 511 512 //-------------------------------------------------------------------- addModifyListener(const Reference<XModifyListener> & _rxListener)513 void SAL_CALL OCellValueBinding::addModifyListener( const Reference< XModifyListener >& _rxListener ) throw (RuntimeException) 514 { 515 if ( _rxListener.is() ) 516 m_aModifyListeners.addInterface( _rxListener ); 517 } 518 519 //-------------------------------------------------------------------- removeModifyListener(const Reference<XModifyListener> & _rxListener)520 void SAL_CALL OCellValueBinding::removeModifyListener( const Reference< XModifyListener >& _rxListener ) throw (RuntimeException) 521 { 522 if ( _rxListener.is() ) 523 m_aModifyListeners.removeInterface( _rxListener ); 524 } 525 526 //-------------------------------------------------------------------- notifyModified()527 void OCellValueBinding::notifyModified() 528 { 529 EventObject aEvent; 530 aEvent.Source.set(*this); 531 532 ::cppu::OInterfaceIteratorHelper aIter( m_aModifyListeners ); 533 while ( aIter.hasMoreElements() ) 534 { 535 try 536 { 537 static_cast< XModifyListener* >( aIter.next() )->modified( aEvent ); 538 } 539 catch( const RuntimeException& ) 540 { 541 // silent this 542 } 543 catch( const Exception& ) 544 { 545 DBG_ERROR( "OCellValueBinding::notifyModified: caught a (non-runtime) exception!" ); 546 } 547 } 548 } 549 550 //-------------------------------------------------------------------- modified(const EventObject &)551 void SAL_CALL OCellValueBinding::modified( const EventObject& /* aEvent */ ) throw (RuntimeException) 552 { 553 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 554 555 notifyModified(); 556 } 557 558 //-------------------------------------------------------------------- disposing(const EventObject & aEvent)559 void SAL_CALL OCellValueBinding::disposing( const EventObject& aEvent ) throw (RuntimeException) 560 { 561 DBG_CHKTHIS( OCellValueBinding, checkConsistency_static ); 562 563 Reference<XInterface> xCellInt( m_xCell, UNO_QUERY ); 564 if ( xCellInt == aEvent.Source ) 565 { 566 // release references to cell object 567 m_xCell.clear(); 568 m_xCellText.clear(); 569 } 570 } 571 572 //-------------------------------------------------------------------- initialize(const Sequence<Any> & _rArguments)573 void SAL_CALL OCellValueBinding::initialize( const Sequence< Any >& _rArguments ) throw (Exception, RuntimeException) 574 { 575 if ( m_bInitialized ) 576 throw Exception(); 577 // TODO: error message 578 579 // get the cell address 580 CellAddress aAddress; 581 sal_Bool bFoundAddress = sal_False; 582 583 const Any* pLoop = _rArguments.getConstArray(); 584 const Any* pLoopEnd = _rArguments.getConstArray() + _rArguments.getLength(); 585 for ( ; ( pLoop != pLoopEnd ) && !bFoundAddress; ++pLoop ) 586 { 587 NamedValue aValue; 588 if ( *pLoop >>= aValue ) 589 { 590 if ( aValue.Name.equalsAscii( "BoundCell" ) ) 591 { 592 if ( aValue.Value >>= aAddress ) 593 bFoundAddress = sal_True; 594 } 595 } 596 } 597 598 if ( !bFoundAddress ) 599 // TODO: error message 600 throw Exception(); 601 602 // get the cell object 603 try 604 { 605 // first the sheets collection 606 Reference< XIndexAccess > xSheets; 607 if ( m_xDocument.is() ) 608 xSheets.set(xSheets.query( m_xDocument->getSheets( ) )); 609 DBG_ASSERT( xSheets.is(), "OCellValueBinding::initialize: could not retrieve the sheets!" ); 610 611 if ( xSheets.is() ) 612 { 613 // the concrete sheet 614 Reference< XCellRange > xSheet(xSheets->getByIndex( aAddress.Sheet ), UNO_QUERY); 615 DBG_ASSERT( xSheet.is(), "OCellValueBinding::initialize: NULL sheet, but no exception!" ); 616 617 // the concrete cell 618 if ( xSheet.is() ) 619 { 620 m_xCell.set(xSheet->getCellByPosition( aAddress.Column, aAddress.Row )); 621 Reference< XCellAddressable > xAddressAccess( m_xCell, UNO_QUERY ); 622 DBG_ASSERT( xAddressAccess.is(), "OCellValueBinding::initialize: either NULL cell, or cell without address access!" ); 623 } 624 } 625 } 626 catch( const Exception& ) 627 { 628 DBG_ERROR( "OCellValueBinding::initialize: caught an exception while retrieving the cell object!" ); 629 } 630 631 if ( !m_xCell.is() ) 632 throw Exception(); 633 // TODO error message 634 635 m_xCellText.set(m_xCellText.query( m_xCell )); 636 637 Reference<XModifyBroadcaster> xBroadcaster( m_xCell, UNO_QUERY ); 638 if ( xBroadcaster.is() ) 639 { 640 xBroadcaster->addModifyListener( this ); 641 } 642 643 // TODO: add as XEventListener to the cell, so we get notified when it dies, 644 // and can dispose ourself then 645 646 // TODO: somehow add as listener so we get notified when the address of the cell changes 647 // We need to forward this as change in our BoundCell property to our property change listeners 648 649 // TODO: be an XModifyBroadcaster, so that changes in our cell can be notified 650 // to the BindableValue which is/will be bound to this instance. 651 652 m_bInitialized = sal_True; 653 // TODO: place your code here 654 } 655 656 657 //......................................................................... 658 } // namespace calc 659 //......................................................................... 660