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_forms.hxx" 26 27 #include "binding.hxx" 28 29 #include "model.hxx" 30 #include "unohelper.hxx" 31 #include "NameContainer.hxx" 32 #include "evaluationcontext.hxx" 33 #include "convert.hxx" 34 #include "resourcehelper.hxx" 35 #include "xmlhelper.hxx" 36 #include "xformsevent.hxx" 37 38 #include <rtl/ustrbuf.hxx> 39 #include <osl/diagnose.h> 40 41 #include <tools/diagnose_ex.h> 42 43 #include <algorithm> 44 #include <functional> 45 46 #include <com/sun/star/uno/Any.hxx> 47 #include <com/sun/star/xml/dom/XNodeList.hpp> 48 #include <com/sun/star/xml/dom/XNode.hpp> 49 #include <com/sun/star/xml/dom/XDocument.hpp> 50 #include <com/sun/star/xml/dom/XElement.hpp> 51 #include <com/sun/star/xml/dom/NodeType.hpp> 52 #include <com/sun/star/xml/dom/events/XEventTarget.hpp> 53 #include <com/sun/star/xml/dom/events/XEventListener.hpp> 54 #include <com/sun/star/xml/dom/events/XDocumentEvent.hpp> 55 #include <com/sun/star/lang/XUnoTunnel.hpp> 56 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 57 #include <com/sun/star/container/XSet.hpp> 58 #include <com/sun/star/container/XNameContainer.hpp> 59 60 #include <comphelper/propertysetinfo.hxx> 61 #include <unotools/textsearch.hxx> 62 #include <cppuhelper/typeprovider.hxx> 63 64 using namespace com::sun::star::xml::xpath; 65 using namespace com::sun::star::xml::dom::events; 66 67 using rtl::OUString; 68 using rtl::OUStringBuffer; 69 using std::vector; 70 using xforms::Binding; 71 using xforms::MIP; 72 using xforms::Model; 73 using xforms::getResource; 74 using xforms::EvaluationContext; 75 using com::sun::star::beans::PropertyVetoException; 76 using com::sun::star::beans::UnknownPropertyException; 77 using com::sun::star::beans::XPropertySet; 78 using com::sun::star::container::XSet; 79 using com::sun::star::container::XNameAccess; 80 using com::sun::star::form::binding::IncompatibleTypesException; 81 using com::sun::star::form::binding::InvalidBindingStateException; 82 using com::sun::star::form::binding::XValueBinding; 83 using com::sun::star::lang::EventObject; 84 using com::sun::star::lang::IllegalArgumentException; 85 using com::sun::star::lang::IndexOutOfBoundsException; 86 using com::sun::star::lang::NoSupportException; 87 using com::sun::star::lang::NullPointerException; 88 using com::sun::star::lang::WrappedTargetException; 89 using com::sun::star::lang::XUnoTunnel; 90 using com::sun::star::uno::Any; 91 using com::sun::star::uno::Reference; 92 using com::sun::star::uno::RuntimeException; 93 using com::sun::star::uno::Sequence; 94 using com::sun::star::uno::UNO_QUERY; 95 using com::sun::star::uno::UNO_QUERY_THROW; 96 using com::sun::star::uno::XInterface; 97 using com::sun::star::uno::Exception; 98 using com::sun::star::uno::makeAny; 99 using com::sun::star::util::XModifyListener; 100 using com::sun::star::xforms::XDataTypeRepository; 101 using com::sun::star::xml::dom::NodeType_ATTRIBUTE_NODE; 102 using com::sun::star::xml::dom::NodeType_TEXT_NODE; 103 using com::sun::star::xml::dom::XNode; 104 using com::sun::star::xml::dom::XNodeList; 105 using com::sun::star::xml::dom::events::XEventListener; 106 using com::sun::star::xml::dom::events::XEventTarget; 107 using com::sun::star::xsd::XDataType; 108 109 110 111 112 #define EXCEPT(msg) OUSTRING(msg),static_cast<XValueBinding*>(this) 113 114 #define HANDLE_BindingID 0 115 #define HANDLE_BindingExpression 1 116 #define HANDLE_Model 2 117 #define HANDLE_ModelID 3 118 #define HANDLE_BindingNamespaces 4 119 #define HANDLE_ReadonlyExpression 5 120 #define HANDLE_RelevantExpression 6 121 #define HANDLE_RequiredExpression 7 122 #define HANDLE_ConstraintExpression 8 123 #define HANDLE_CalculateExpression 9 124 #define HANDLE_Type 10 125 #define HANDLE_ReadOnly 11 // from com.sun.star.form.binding.ValueBinding, for interaction with a bound form control 126 #define HANDLE_Relevant 12 // from com.sun.star.form.binding.ValueBinding, for interaction with a bound form control 127 #define HANDLE_ModelNamespaces 13 128 #define HANDLE_ExternalData 14 129 130 131 Binding::Binding() : 132 mxModel(), 133 msBindingID(), 134 maBindingExpression(), 135 maReadonly(), 136 mxNamespaces( new NameContainer<OUString>() ), 137 mbInCalculate( false ), 138 mnDeferModifyNotifications( 0 ), 139 mbValueModified( false ), 140 mbBindingModified( false ) 141 142 { 143 initializePropertySet(); 144 } 145 146 Binding::~Binding() throw() 147 { 148 _setModel(NULL); 149 } 150 151 152 Binding::Model_t Binding::getModel() const 153 { 154 return mxModel; 155 } 156 157 void Binding::_setModel( const Model_t& xModel ) 158 { 159 PropertyChangeNotifier aNotifyModelChange( *this, HANDLE_Model ); 160 PropertyChangeNotifier aNotifyModelIDChange( *this, HANDLE_ModelID ); 161 162 // prepare binding for removal of old model 163 clear(); // remove all cached data (e.g. XPath evaluation results) 164 XNameContainer_t xNamespaces = getModelNamespaces(); // save namespaces 165 166 mxModel = xModel; 167 168 // set namespaces (and move to model, if appropriate) 169 setBindingNamespaces( xNamespaces ); 170 _checkBindingID(); 171 172 notifyAndCachePropertyValue( HANDLE_ExternalData ); 173 } 174 175 176 OUString Binding::getModelID() const 177 { 178 Model* pModel = getModelImpl(); 179 return ( pModel == NULL ) ? OUString() : pModel->getID(); 180 } 181 182 183 Binding::XNodeList_t Binding::getXNodeList() 184 { 185 // first make sure we are bound 186 if( ! maBindingExpression.hasValue() ) 187 bind( sal_False ); 188 189 return maBindingExpression.getXNodeList(); 190 } 191 192 bool Binding::isSimpleBinding() const 193 { 194 return maBindingExpression.isSimpleExpression() 195 && maReadonly.isSimpleExpression() 196 && maRelevant.isSimpleExpression() 197 && maRequired.isSimpleExpression() 198 && maConstraint.isSimpleExpression() 199 && maCalculate.isSimpleExpression(); 200 } 201 202 bool Binding::isSimpleBindingExpression() const 203 { 204 return maBindingExpression.isSimpleExpression(); 205 } 206 207 void Binding::update() 208 { 209 // clear all expressions (to remove cached node references) 210 maBindingExpression.clear(); 211 maReadonly.clear(); 212 maRelevant.clear(); 213 maRequired.clear(); 214 maConstraint.clear(); 215 maCalculate.clear(); 216 217 // let's just pretend the binding has been modified -> full rebind() 218 bindingModified(); 219 } 220 221 void Binding::deferNotifications( bool bDefer ) 222 { 223 mnDeferModifyNotifications += ( bDefer ? 1 : -1 ); 224 OSL_ENSURE( mnDeferModifyNotifications >= 0, "you're deferring too much" ); 225 226 if( mnDeferModifyNotifications == 0 ) 227 { 228 if( mbBindingModified ) 229 bindingModified(); 230 if( mbValueModified ) 231 valueModified(); 232 } 233 234 OSL_ENSURE( ( mnDeferModifyNotifications > 0 ) 235 || ( ! mbBindingModified && ! mbValueModified ), 236 "deferred modifications not delivered?" ); 237 } 238 239 bool Binding::isValid() 240 { 241 // TODO: determine whether node is suitable, not just whether it exists 242 return maBindingExpression.getNode().is() && 243 isValid_DataType() && 244 maMIP.isConstraint() && 245 ( ! maMIP.isRequired() || 246 ( maBindingExpression.hasValue() && 247 maBindingExpression.getString().getLength() > 0 ) ); 248 } 249 250 bool Binding::isUseful() 251 { 252 // we are useful, if 253 // 0) we don't have a model 254 // (at least, in this case we shouldn't be removed from the model) 255 // 1) we have a proper name 256 // 2) we have some MIPs, 257 // 3) we are bound to some control 258 // (this can be assumed if some listeners are set) 259 bool bUseful = 260 getModelImpl() == NULL 261 // || msBindingID.getLength() > 0 262 || msTypeName.getLength() > 0 263 || ! maReadonly.isEmptyExpression() 264 || ! maRelevant.isEmptyExpression() 265 || ! maRequired.isEmptyExpression() 266 || ! maConstraint.isEmptyExpression() 267 || ! maCalculate.isEmptyExpression() 268 || ! maModifyListeners.empty() 269 || ! maListEntryListeners.empty() 270 || ! maValidityListeners.empty(); 271 272 return bUseful; 273 } 274 275 OUString Binding::explainInvalid() 276 { 277 OUString sReason; 278 if( ! maBindingExpression.getNode().is() ) 279 { 280 sReason = ( maBindingExpression.getExpression().getLength() == 0 ) 281 ? getResource( RID_STR_XFORMS_NO_BINDING_EXPRESSION ) 282 : getResource( RID_STR_XFORMS_INVALID_BINDING_EXPRESSION ); 283 } 284 else if( ! isValid_DataType() ) 285 { 286 sReason = explainInvalid_DataType(); 287 if( sReason.getLength() == 0 ) 288 { 289 // no explanation given by data type? Then give generic message 290 sReason = getResource( RID_STR_XFORMS_INVALID_VALUE, 291 maMIP.getTypeName() ); 292 } 293 } 294 else if( ! maMIP.isConstraint() ) 295 { 296 sReason = maMIP.getConstraintExplanation(); 297 } 298 else if( maMIP.isRequired() && maBindingExpression.hasValue() && 299 ( maBindingExpression.getString().getLength() == 0 ) ) 300 { 301 sReason = getResource( RID_STR_XFORMS_REQUIRED ); 302 } 303 // else: no explanation given; should only happen if data is valid 304 305 OSL_ENSURE( ( sReason.getLength() == 0 ) == isValid(), 306 "invalid data should have an explanation!" ); 307 308 return sReason; 309 } 310 311 312 313 EvaluationContext Binding::getEvaluationContext() const 314 { 315 OSL_ENSURE( getModelImpl() != NULL, "need model impl" ); 316 EvaluationContext aContext = getModelImpl()->getEvaluationContext(); 317 aContext.mxNamespaces = getBindingNamespaces(); 318 return aContext; 319 } 320 321 ::std::vector<EvaluationContext> Binding::getMIPEvaluationContexts() 322 { 323 OSL_ENSURE( getModelImpl() != NULL, "need model impl" ); 324 325 // bind (in case we were not bound before) 326 bind( sal_False ); 327 return _getMIPEvaluationContexts(); 328 } 329 330 331 Binding::IntSequence_t Binding::getUnoTunnelID() 332 { 333 static cppu::OImplementationId aImplementationId; 334 return aImplementationId.getImplementationId(); 335 } 336 337 Binding* SAL_CALL Binding::getBinding( const Reference<XPropertySet>& xPropertySet ) 338 { 339 Reference<XUnoTunnel> xTunnel( xPropertySet, UNO_QUERY ); 340 return xTunnel.is() 341 ? reinterpret_cast<Binding*>( xTunnel->getSomething(getUnoTunnelID())) 342 : NULL; 343 } 344 345 346 347 348 OUString Binding::getBindingID() const 349 { 350 return msBindingID; 351 } 352 353 void Binding::setBindingID( const OUString& sBindingID ) 354 { 355 msBindingID = sBindingID; 356 } 357 358 OUString Binding::getBindingExpression() const 359 { 360 return maBindingExpression.getExpression(); 361 } 362 363 void Binding::setBindingExpression( const OUString& sBindingExpression) 364 { 365 maBindingExpression.setExpression( sBindingExpression ); 366 bindingModified(); 367 } 368 369 OUString Binding::getReadonlyExpression() const 370 { 371 return maReadonly.getExpression(); 372 } 373 374 void Binding::setReadonlyExpression( const OUString& sReadonly) 375 { 376 maReadonly.setExpression( sReadonly ); 377 bindingModified(); 378 } 379 380 OUString Binding::getRelevantExpression() const 381 { 382 return maRelevant.getExpression(); 383 } 384 385 void Binding::setRelevantExpression( const OUString& sRelevant ) 386 { 387 maRelevant.setExpression( sRelevant ); 388 bindingModified(); 389 } 390 391 OUString Binding::getRequiredExpression() const 392 { 393 return maRequired.getExpression(); 394 } 395 396 void Binding::setRequiredExpression( const OUString& sRequired ) 397 { 398 maRequired.setExpression( sRequired ); 399 bindingModified(); 400 } 401 402 OUString Binding::getConstraintExpression() const 403 { 404 return maConstraint.getExpression(); 405 } 406 407 void Binding::setConstraintExpression( const OUString& sConstraint ) 408 { 409 maConstraint.setExpression( sConstraint ); 410 msExplainConstraint = getResource( RID_STR_XFORMS_INVALID_CONSTRAINT, 411 sConstraint ); 412 413 // TODO: This should only re-evaluate the constraint, and notify 414 // the validity constraint listeners; instead we currently pretend 415 // the entire binding was notified, which does a little too much. 416 bindingModified(); 417 } 418 419 OUString Binding::getCalculateExpression() const 420 { 421 return maCalculate.getExpression(); 422 } 423 424 void Binding::setCalculateExpression( const OUString& sCalculate ) 425 { 426 maCalculate.setExpression( sCalculate ); 427 bindingModified(); 428 } 429 430 OUString Binding::getType() const 431 { 432 return msTypeName; 433 } 434 435 void Binding::setType( const OUString& sTypeName ) 436 { 437 msTypeName = sTypeName; 438 bindingModified(); 439 } 440 441 Binding::XNameContainer_t Binding::getBindingNamespaces() const 442 { 443 // return _getNamespaces(); 444 return mxNamespaces; 445 } 446 447 void Binding::setBindingNamespaces( const XNameContainer_t& rNamespaces ) 448 { 449 _setNamespaces( rNamespaces, true ); 450 } 451 452 Binding::XNameContainer_t Binding::getModelNamespaces() const 453 { 454 return _getNamespaces(); 455 } 456 457 void Binding::setModelNamespaces( const XNameContainer_t& rNamespaces ) 458 { 459 _setNamespaces( rNamespaces, false ); 460 } 461 462 bool Binding::getReadOnly() const 463 { 464 return maMIP.isReadonly(); 465 } 466 467 bool Binding::getRelevant() const 468 { 469 return maMIP.isRelevant(); 470 } 471 472 bool Binding::getExternalData() const 473 { 474 bool bExternalData = true; 475 if ( !mxModel.is() ) 476 return bExternalData; 477 478 try 479 { 480 Reference< XPropertySet > xModelProps( mxModel, UNO_QUERY_THROW ); 481 OSL_VERIFY( 482 xModelProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExternalData" ) ) ) >>= bExternalData ); 483 } 484 catch( const Exception& ) 485 { 486 DBG_UNHANDLED_EXCEPTION(); 487 } 488 return bExternalData; 489 } 490 491 492 void Binding::checkLive() 493 throw( RuntimeException ) 494 { 495 if( ! isLive() ) 496 throw RuntimeException( EXCEPT("Binding not initialized") ); 497 } 498 499 void Binding::checkModel() 500 throw( RuntimeException ) 501 { 502 if( ! mxModel.is() ) 503 throw RuntimeException( EXCEPT("Binding has no Model") ); 504 } 505 506 bool Binding::isLive() const 507 { 508 const Model* pModel = getModelImpl(); 509 return ( pModel != NULL ) ? pModel->isInitialized() : false; 510 } 511 512 Model* Binding::getModelImpl() const 513 { 514 return getModelImpl( mxModel ); 515 } 516 517 Model* Binding::getModelImpl( const Model_t& xModel ) const 518 { 519 Reference<XUnoTunnel> xTunnel( xModel, UNO_QUERY ); 520 Model* pModel = xTunnel.is() 521 ? reinterpret_cast<Model*>( 522 xTunnel->getSomething( Model::getUnoTunnelID() ) ) 523 : NULL; 524 return pModel; 525 } 526 527 void lcl_addListenerToNode( Reference<XNode> xNode, 528 Reference<XEventListener> xListener ) 529 { 530 Reference<XEventTarget> xTarget( xNode, UNO_QUERY ); 531 if( xTarget.is() ) 532 { 533 xTarget->addEventListener( OUSTRING("DOMCharacterDataModified"), 534 xListener, false ); 535 xTarget->addEventListener( OUSTRING("DOMCharacterDataModified"), 536 xListener, true ); 537 xTarget->addEventListener( OUSTRING("DOMAttrModified"), 538 xListener, false ); 539 xTarget->addEventListener( OUSTRING("DOMAttrModified"), 540 xListener, true ); 541 xTarget->addEventListener( OUSTRING("DOMAttrModified"), 542 xListener, true ); 543 xTarget->addEventListener( OUSTRING("xforms-generic"), 544 xListener, true ); 545 } 546 } 547 548 void lcl_removeListenerFromNode( Reference<XNode> xNode, 549 Reference<XEventListener> xListener ) 550 { 551 Reference<XEventTarget> xTarget( xNode, UNO_QUERY ); 552 if( xTarget.is() ) 553 { 554 xTarget->removeEventListener( OUSTRING("DOMCharacterDataModified"), 555 xListener, false ); 556 xTarget->removeEventListener( OUSTRING("DOMCharacterDataModified"), 557 xListener, true ); 558 xTarget->removeEventListener( OUSTRING("DOMAttrModified"), 559 xListener, false ); 560 xTarget->removeEventListener( OUSTRING("DOMAttrModified"), 561 xListener, true ); 562 xTarget->removeEventListener( OUSTRING("xforms-generic"), 563 xListener, true ); 564 } 565 } 566 567 ::std::vector<EvaluationContext> Binding::_getMIPEvaluationContexts() const 568 { 569 OSL_ENSURE( getModelImpl() != NULL, "need model impl" ); 570 571 // iterate over nodes of bind expression and create 572 // EvaluationContext for each 573 PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); 574 ::std::vector<EvaluationContext> aVector; 575 sal_Int32 nCount = 0; // count nodes for context position 576 for( PathExpression::NodeVector_t::iterator aIter = aNodes.begin(); 577 aIter != aNodes.end(); 578 aIter++, nCount++ ) 579 { 580 OSL_ENSURE( aIter->is(), "no node?" ); 581 582 // create proper evaluation context for this MIP 583 aVector.push_back( EvaluationContext( *aIter, getModel(), 584 getBindingNamespaces(), 585 nCount, aNodes.size() ) ); 586 } 587 return aVector; 588 } 589 590 void Binding::bind( bool bForceRebind ) 591 { 592 checkModel(); 593 594 // bind() will evaluate this binding as follows: 595 // 1) evaluate the binding expression 596 // 1b) if necessary, create node according to 'lazy author' rules 597 // 2) register suitable listeners on the instance (and remove old ones) 598 // 3) remove old MIPs defined by this binding 599 // 4) for every node in the binding nodeset do: 600 // 1) create proper evaluation context for this MIP 601 // 2) evaluate calculate expression (and push value into instance) 602 // 3) evaluate remaining MIPs 603 // 4) evaluate the locally defined MIPs, and push them to the model 604 605 606 // 1) evaluate the binding expression 607 EvaluationContext aContext = getEvaluationContext(); 608 maBindingExpression.evaluate( aContext ); 609 if( ! maBindingExpression.getNode().is() ) 610 { 611 // 1b) create node (if valid element name) 612 if( isValidQName( maBindingExpression.getExpression(), 613 aContext.mxNamespaces ) ) 614 { 615 aContext.mxContextNode->appendChild( 616 Reference<XNode>( 617 aContext.mxContextNode->getOwnerDocument()->createElement( 618 maBindingExpression.getExpression() ), 619 UNO_QUERY ) ); 620 maBindingExpression.evaluate( aContext ); 621 OSL_ENSURE( maBindingExpression.getNode().is(), 622 "we should bind to the newly inserted node!" ); 623 } 624 } 625 PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); 626 627 // 2) register suitable listeners on the instance (and remove old ones) 628 if( maEventNodes.empty() || bForceRebind ) 629 { 630 for( XNodes_t::iterator aIter = maEventNodes.begin(); 631 aIter != maEventNodes.end(); 632 aIter ++ ) 633 lcl_removeListenerFromNode( *aIter, this ); 634 maEventNodes.clear(); 635 if( isSimpleBinding() ) 636 for( PathExpression::NodeVector_t::iterator aIter = aNodes.begin(); 637 aIter != aNodes.end(); 638 aIter++ ) 639 maEventNodes.push_back( *aIter ); 640 else 641 maEventNodes.push_back( 642 Reference<XNode>( aContext.mxContextNode->getOwnerDocument(), 643 UNO_QUERY_THROW ) ); 644 for( PathExpression::NodeVector_t::iterator aIter2 = maEventNodes.begin(); 645 aIter2 != maEventNodes.end(); 646 aIter2 ++ ) 647 lcl_addListenerToNode( *aIter2, this ); 648 } 649 650 // 3) remove old MIPs defined by this binding 651 Model* pModel = getModelImpl(); 652 OSL_ENSURE( pModel != NULL, "need model" ); 653 pModel->removeMIPs( this ); 654 655 // 4) calculate all MIPs 656 ::std::vector<EvaluationContext> aMIPContexts = _getMIPEvaluationContexts(); 657 for( ::std::vector<EvaluationContext>::iterator aIter = aMIPContexts.begin(); 658 aIter != aMIPContexts.end(); 659 aIter++ ) 660 { 661 EvaluationContext& rContext = *aIter; 662 663 // evaluate calculate expression (and push value into instance) 664 // (prevent recursion using mbInCalculate 665 if( ! maCalculate.isEmptyExpression() ) 666 { 667 if( ! mbInCalculate ) 668 { 669 mbInCalculate = true; 670 maCalculate.evaluate( rContext ); 671 pModel->setSimpleContent( rContext.mxContextNode, 672 maCalculate.getString() ); 673 mbInCalculate = false; 674 } 675 } 676 677 // now evaluate remaining MIPs in the apropriate context 678 maReadonly.evaluate( rContext ); 679 maRelevant.evaluate( rContext ); 680 maRequired.evaluate( rContext ); 681 maConstraint.evaluate( rContext ); 682 // type is static; does not need updating 683 684 // evaluate the locally defined MIPs, and push them to the model 685 pModel->addMIP( this, rContext.mxContextNode, getLocalMIP() ); 686 } 687 } 688 689 690 // helper for Binding::valueModified 691 void lcl_modified( const Binding::XModifyListener_t xListener, 692 const Reference<XInterface> xSource ) 693 { 694 OSL_ENSURE( xListener.is(), "no listener?" ); 695 xListener->modified( EventObject( xSource ) ); 696 } 697 698 // helper for Binding::valueModified 699 void lcl_listentry( const Binding::XListEntryListener_t xListener, 700 const Reference<XInterface> xSource ) 701 { 702 OSL_ENSURE( xListener.is(), "no listener?" ); 703 // TODO: send fine granular events 704 xListener->allEntriesChanged( EventObject( xSource ) ); 705 } 706 707 // helper for Binding::valueModified 708 void lcl_validate( const Binding::XValidityConstraintListener_t xListener, 709 const Reference<XInterface> xSource ) 710 { 711 OSL_ENSURE( xListener.is(), "no listener?" ); 712 xListener->validityConstraintChanged( EventObject( xSource ) ); 713 } 714 715 716 void Binding::valueModified() 717 { 718 // defer notifications, if so desired 719 if( mnDeferModifyNotifications > 0 ) 720 { 721 mbValueModified = true; 722 return; 723 } 724 mbValueModified = false; 725 726 // query MIP used by our first node (also note validity) 727 Reference<XNode> xNode = maBindingExpression.getNode(); 728 maMIP = getModelImpl()->queryMIP( xNode ); 729 730 // distribute MIPs _used_ by this binding 731 if( xNode.is() ) 732 { 733 notifyAndCachePropertyValue( HANDLE_ReadOnly ); 734 notifyAndCachePropertyValue( HANDLE_Relevant ); 735 } 736 737 // iterate over _value_ listeners and send each a modified signal, 738 // using this object as source (will also update validity, because 739 // control will query once the value has changed) 740 Reference<XInterface> xSource = static_cast<XPropertySet*>( this ); 741 ::std::for_each( maModifyListeners.begin(), 742 maModifyListeners.end(), 743 ::std::bind2nd( ::std::ptr_fun( lcl_modified ), xSource ) ); 744 ::std::for_each( maListEntryListeners.begin(), 745 maListEntryListeners.end(), 746 ::std::bind2nd( ::std::ptr_fun( lcl_listentry ), xSource ) ); 747 ::std::for_each( maValidityListeners.begin(), 748 maValidityListeners.end(), 749 ::std::bind2nd( ::std::ptr_fun( lcl_validate ), xSource ) ); 750 751 // now distribute MIPs to childs 752 if( xNode.is() ) 753 distributeMIP( xNode->getFirstChild() ); 754 } 755 756 void Binding::distributeMIP( const XNode_t & rxNode ) { 757 758 typedef com::sun::star::xforms::XFormsEventConcrete XFormsEvent_t; 759 OUString sEventName( RTL_CONSTASCII_USTRINGPARAM("xforms-generic") ); 760 XFormsEvent_t *pEvent = new XFormsEvent_t; 761 pEvent->initXFormsEvent(sEventName, sal_True, sal_False); 762 Reference<XEvent> xEvent(pEvent); 763 764 // naive depth-first traversal 765 XNode_t xNode( rxNode ); 766 while(xNode.is()) { 767 768 // notifications should be triggered at the 769 // leaf nodes first, bubbling upwards the hierarchy. 770 XNode_t child(xNode->getFirstChild()); 771 if(child.is()) 772 distributeMIP(child); 773 774 // we're standing at a particular node somewhere 775 // below the one which changed a property (MIP). 776 // bindings which are listening at this node will receive 777 // a notification message about what exactly happened. 778 Reference< XEventTarget > target(xNode,UNO_QUERY); 779 target->dispatchEvent(xEvent); 780 781 xNode = xNode->getNextSibling(); 782 }; 783 } 784 785 void Binding::bindingModified() 786 { 787 // defer notifications, if so desired 788 if( mnDeferModifyNotifications > 0 ) 789 { 790 mbBindingModified = true; 791 return; 792 } 793 mbBindingModified = false; 794 795 // rebind (if live); then call valueModified 796 // A binding should be inert until its model is fully constructed. 797 if( isLive() ) 798 { 799 bind( true ); 800 valueModified(); 801 } 802 } 803 804 805 MIP Binding::getLocalMIP() const 806 { 807 MIP aMIP; 808 809 if( maReadonly.hasValue() ) 810 aMIP.setReadonly( maReadonly.getBool( false ) ); 811 if( maRelevant.hasValue() ) 812 aMIP.setRelevant( maRelevant.getBool( true ) ); 813 if( maRequired.hasValue() ) 814 aMIP.setRequired( maRequired.getBool( false ) ); 815 if( maConstraint.hasValue() ) 816 { 817 aMIP.setConstraint( maConstraint.getBool( true ) ); 818 if( ! aMIP.isConstraint() ) 819 aMIP.setConstraintExplanation( msExplainConstraint ); 820 } 821 if( msTypeName.getLength() > 0 ) 822 aMIP.setTypeName( msTypeName ); 823 824 // calculate: only handle presence of calculate; value set elsewhere 825 aMIP.setHasCalculate( !maCalculate.isEmptyExpression() ); 826 827 return aMIP; 828 } 829 830 Binding::XDataType_t Binding::getDataType() 831 { 832 OSL_ENSURE( getModel().is(), "need model" ); 833 OSL_ENSURE( getModel()->getDataTypeRepository().is(), "need types" ); 834 835 Reference<XDataTypeRepository> xRepository( 836 getModel()->getDataTypeRepository(), UNO_QUERY ); 837 OUString sTypeName = maMIP.getTypeName(); 838 839 return ( xRepository.is() && xRepository->hasByName( sTypeName ) ) 840 ? Reference<XDataType>( xRepository->getByName( sTypeName ), UNO_QUERY) 841 : Reference<XDataType>( NULL ); 842 } 843 844 bool Binding::isValid_DataType() 845 { 846 Reference<XDataType> xDataType = getDataType(); 847 return xDataType.is() 848 ? xDataType->validate( maBindingExpression.getString() ) 849 : true; 850 } 851 852 rtl::OUString Binding::explainInvalid_DataType() 853 { 854 Reference<XDataType> xDataType = getDataType(); 855 return xDataType.is() 856 ? xDataType->explainInvalid( maBindingExpression.getString() ) 857 : OUString(); 858 } 859 860 void Binding::clear() 861 { 862 // remove MIPs contributed by this binding 863 Model* pModel = getModelImpl(); 864 if( pModel != NULL ) 865 pModel->removeMIPs( this ); 866 867 // remove all references 868 for( XNodes_t::iterator aIter = maEventNodes.begin(); 869 aIter != maEventNodes.end(); 870 aIter ++ ) 871 lcl_removeListenerFromNode( *aIter, this ); 872 maEventNodes.clear(); 873 874 // clear expressions 875 maBindingExpression.clear(); 876 maReadonly.clear(); 877 maRelevant.clear(); 878 maRequired.clear(); 879 maConstraint.clear(); 880 maCalculate.clear(); 881 882 // TODO: what about our listeners? 883 } 884 885 886 void lcl_removeOtherNamespaces( const Binding::XNameContainer_t& xFrom, 887 Binding::XNameContainer_t& xTo ) 888 { 889 OSL_ENSURE( xFrom.is(), "no source" ); 890 OSL_ENSURE( xTo.is(), "no target" ); 891 892 // iterate over name in source 893 Sequence<OUString> aNames = xTo->getElementNames(); 894 sal_Int32 nNames = aNames.getLength(); 895 const OUString* pNames = aNames.getConstArray(); 896 for( sal_Int32 i = 0; i < nNames; i++ ) 897 { 898 const OUString& rName = pNames[i]; 899 900 if( ! xFrom->hasByName( rName ) ) 901 xTo->removeByName( rName ); 902 } 903 } 904 905 /** copy namespaces from one namespace container into another 906 * @param bOverwrite true: overwrite namespaces in target 907 * false: do not overwrite namespaces in target 908 * @param bMove true: move namespaces (i.e., delete in source) 909 * false: copy namespaces (do not modify source) 910 * @param bFromSource true: use elements from source 911 * false: use only elements from target 912 */ 913 void lcl_copyNamespaces( const Binding::XNameContainer_t& xFrom, 914 Binding::XNameContainer_t& xTo, 915 bool bOverwrite ) 916 { 917 OSL_ENSURE( xFrom.is(), "no source" ); 918 OSL_ENSURE( xTo.is(), "no target" ); 919 920 // iterate over name in source 921 Sequence<OUString> aNames = xFrom->getElementNames(); 922 sal_Int32 nNames = aNames.getLength(); 923 const OUString* pNames = aNames.getConstArray(); 924 for( sal_Int32 i = 0; i < nNames; i++ ) 925 { 926 const OUString& rName = pNames[i]; 927 928 // determine whether to copy the value, and whether to delete 929 // it in the source: 930 931 bool bInTarget = xTo->hasByName( rName ); 932 933 // we copy: if property is in target, and 934 // if bOverwrite is set, or when the namespace prefix is free 935 bool bCopy = bOverwrite || ! bInTarget; 936 937 // and now... ACTION! 938 if( bCopy ) 939 { 940 if( bInTarget ) 941 xTo->replaceByName( rName, xFrom->getByName( rName ) ); 942 else 943 xTo->insertByName( rName, xFrom->getByName( rName ) ); 944 } 945 } 946 } 947 948 // implement get*Namespaces() 949 // (identical for both variants) 950 Binding::XNameContainer_t Binding::_getNamespaces() const 951 { 952 XNameContainer_t xNamespaces = new NameContainer<OUString>(); 953 lcl_copyNamespaces( mxNamespaces, xNamespaces, true ); 954 955 // merge model's with binding's own namespaces 956 Model* pModel = getModelImpl(); 957 if( pModel != NULL ) 958 lcl_copyNamespaces( pModel->getNamespaces(), xNamespaces, false ); 959 960 return xNamespaces; 961 } 962 963 // implement set*Namespaces() 964 // bBinding = true: setBindingNamespaces, otherwise: setModelNamespaces 965 void Binding::_setNamespaces( const XNameContainer_t& rNamespaces, 966 bool bBinding ) 967 { 968 Model* pModel = getModelImpl(); 969 XNameContainer_t xModelNamespaces = ( pModel != NULL ) 970 ? pModel->getNamespaces() 971 : NULL; 972 OSL_ENSURE( ( pModel != NULL ) == xModelNamespaces.is(), "no model nmsp?"); 973 974 // remove deleted namespaces 975 lcl_removeOtherNamespaces( rNamespaces, mxNamespaces ); 976 if( !bBinding && xModelNamespaces.is() ) 977 lcl_removeOtherNamespaces( rNamespaces, xModelNamespaces ); 978 979 // copy namespaces as appropriate 980 Sequence<OUString> aNames = rNamespaces->getElementNames(); 981 sal_Int32 nNames = aNames.getLength(); 982 const OUString* pNames = aNames.getConstArray(); 983 for( sal_Int32 i = 0; i < nNames; i++ ) 984 { 985 const OUString& rName = pNames[i]; 986 Any aValue = rNamespaces->getByName( rName ); 987 988 // determine whether the namespace should go into model's or 989 // into binding's namespaces 990 bool bLocal = 991 ! xModelNamespaces.is() 992 || mxNamespaces->hasByName( rName ) 993 || ( bBinding 994 && xModelNamespaces.is() 995 && xModelNamespaces->hasByName( rName ) ); 996 997 // write namespace into the appropriate namespace container 998 XNameContainer_t& rWhich = bLocal ? mxNamespaces : xModelNamespaces; 999 OSL_ENSURE( rWhich.is(), "whoops" ); 1000 if( rWhich->hasByName( rName ) ) 1001 rWhich->replaceByName( rName, aValue ); 1002 else 1003 rWhich->insertByName( rName, aValue ); 1004 1005 // always 'promote' namespaces from binding to model, if equal 1006 if( xModelNamespaces.is() 1007 && xModelNamespaces->hasByName( rName ) 1008 && mxNamespaces->hasByName( rName ) 1009 && xModelNamespaces->getByName( rName ) == mxNamespaces->getByName( rName ) ) 1010 { 1011 mxNamespaces->removeByName( rName ); 1012 } 1013 } 1014 1015 // ... done. But we modified the binding! 1016 bindingModified(); 1017 } 1018 1019 void Binding::_checkBindingID() 1020 { 1021 if( getModel().is() ) 1022 { 1023 Reference<XNameAccess> xBindings( getModel()->getBindings(), UNO_QUERY_THROW ); 1024 if( msBindingID.getLength() == 0 ) 1025 { 1026 // no binding ID? then make one up! 1027 OUString sIDPrefix = getResource( RID_STR_XFORMS_BINDING_UI_NAME ); 1028 sIDPrefix += String::CreateFromAscii( " " ); 1029 sal_Int32 nNumber = 0; 1030 OUString sName; 1031 do 1032 { 1033 nNumber++; 1034 sName = sIDPrefix + OUString::valueOf( nNumber ); 1035 } 1036 while( xBindings->hasByName( sName ) ); 1037 setBindingID( sName ); 1038 } 1039 } 1040 } 1041 1042 1043 1044 1045 // 1046 // XValueBinding 1047 // 1048 1049 Binding::Sequence_Type_t Binding::getSupportedValueTypes() 1050 throw( RuntimeException ) 1051 { 1052 return Convert::get().getTypes(); 1053 } 1054 1055 sal_Bool Binding::supportsType( const Type_t& rType ) 1056 throw( RuntimeException ) 1057 { 1058 return Convert::get().hasType( rType ); 1059 } 1060 1061 Binding::Any_t Binding::getValue( const Type_t& rType ) 1062 throw( IncompatibleTypesException, 1063 RuntimeException ) 1064 { 1065 // first, check for model 1066 checkLive(); 1067 1068 // second, check for type 1069 if( ! supportsType( rType ) ) 1070 throw IncompatibleTypesException( EXCEPT( "type unsupported" ) ); 1071 1072 // return string value (if present; else return empty Any) 1073 Binding::Any_t result = Any(); 1074 if(maBindingExpression.hasValue()) { 1075 rtl::OUString pathExpr(maBindingExpression.getString()); 1076 Convert &rConvert = Convert::get(); 1077 result = rConvert.toAny(pathExpr,rType); 1078 } 1079 1080 // return maBindingExpression.hasValue() 1081 // ? Convert::get().toAny( maBindingExpression.getString(), rType ) 1082 // : Any(); 1083 1084 return result; 1085 } 1086 1087 void Binding::setValue( const Any_t& aValue ) 1088 throw( IncompatibleTypesException, 1089 InvalidBindingStateException, 1090 NoSupportException, 1091 RuntimeException ) 1092 { 1093 // first, check for model 1094 checkLive(); 1095 1096 // check for supported type 1097 if( ! supportsType( aValue.getValueType() ) ) 1098 throw IncompatibleTypesException( EXCEPT( "type unsupported" ) ); 1099 1100 if( maBindingExpression.hasValue() ) 1101 { 1102 Binding::XNode_t xNode = maBindingExpression.getNode(); 1103 if( xNode.is() ) 1104 { 1105 OUString sValue = Convert::get().toXSD( aValue ); 1106 bool bSuccess = getModelImpl()->setSimpleContent( xNode, sValue ); 1107 if( ! bSuccess ) 1108 throw InvalidBindingStateException( EXCEPT( "can't set value" ) ); 1109 } 1110 else 1111 throw InvalidBindingStateException( EXCEPT( "no suitable node found" ) ); 1112 } 1113 else 1114 throw InvalidBindingStateException( EXCEPT( "no suitable node found" ) ); 1115 } 1116 1117 1118 // 1119 // XListEntry Source 1120 // 1121 1122 sal_Int32 Binding::getListEntryCount() 1123 throw( RuntimeException ) 1124 { 1125 // first, check for model 1126 checkLive(); 1127 1128 // return size of node list 1129 return maBindingExpression.getNodeList().size(); 1130 } 1131 1132 void lcl_getString( const Reference<XNode>& xNode, OUStringBuffer& rBuffer ) 1133 { 1134 if( xNode->getNodeType() == NodeType_TEXT_NODE 1135 || xNode->getNodeType() == NodeType_ATTRIBUTE_NODE ) 1136 { 1137 rBuffer.append( xNode->getNodeValue() ); 1138 } 1139 else 1140 { 1141 for( Reference<XNode> xChild = xNode->getFirstChild(); 1142 xChild.is(); 1143 xChild = xChild->getNextSibling() ) 1144 { 1145 lcl_getString( xChild, rBuffer ); 1146 } 1147 } 1148 } 1149 1150 OUString lcl_getString( const Reference<XNode>& xNode ) 1151 { 1152 OUStringBuffer aBuffer; 1153 lcl_getString( xNode, aBuffer ); 1154 return aBuffer.makeStringAndClear(); 1155 } 1156 1157 OUString Binding::getListEntry( sal_Int32 nPosition ) 1158 throw( IndexOutOfBoundsException, 1159 RuntimeException ) 1160 { 1161 // first, check for model 1162 checkLive(); 1163 1164 // check bounds and return proper item 1165 PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); 1166 if( nPosition < 0 || nPosition >= static_cast<sal_Int32>( aNodes.size() ) ) 1167 throw IndexOutOfBoundsException( EXCEPT("") ); 1168 return lcl_getString( aNodes[ nPosition ] ); 1169 } 1170 1171 Sequence<OUString> Binding::getAllListEntries() 1172 throw( RuntimeException ) 1173 { 1174 // first, check for model 1175 checkLive(); 1176 1177 // create sequence of string values 1178 PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); 1179 Sequence<OUString> aSequence( aNodes.size() ); 1180 OUString* pSequence = aSequence.getArray(); 1181 for( sal_Int32 n = 0; n < aSequence.getLength(); n++ ) 1182 { 1183 pSequence[n] = lcl_getString( aNodes[n] ); 1184 } 1185 1186 return aSequence; 1187 } 1188 1189 void Binding::addListEntryListener( const XListEntryListener_t& xListener ) 1190 throw( NullPointerException, 1191 RuntimeException ) 1192 { 1193 OSL_ENSURE( xListener.is(), "need listener!" ); 1194 if( ::std::find( maListEntryListeners.begin(), 1195 maListEntryListeners.end(), 1196 xListener) 1197 == maListEntryListeners.end() ) 1198 maListEntryListeners.push_back( xListener ); 1199 } 1200 1201 void Binding::removeListEntryListener( const XListEntryListener_t& xListener ) 1202 throw( NullPointerException, 1203 RuntimeException ) 1204 { 1205 XListEntryListeners_t::iterator aIter = 1206 ::std::find( maListEntryListeners.begin(), maListEntryListeners.end(), 1207 xListener ); 1208 if( aIter != maListEntryListeners.end() ) 1209 maListEntryListeners.erase( aIter ); 1210 } 1211 1212 1213 // 1214 // XValidator 1215 // 1216 1217 sal_Bool Binding::isValid( const Any_t& ) 1218 throw( RuntimeException ) 1219 { 1220 // first, check for model 1221 checkLive(); 1222 1223 // ignore value; determine validate only on current data 1224 return isValid(); 1225 } 1226 1227 rtl::OUString Binding::explainInvalid( 1228 const Any_t& /*Value*/ ) 1229 throw( RuntimeException ) 1230 { 1231 // first, check for model 1232 checkLive(); 1233 1234 // ignore value; determine explanation only on current data 1235 return explainInvalid(); 1236 } 1237 1238 void Binding::addValidityConstraintListener( 1239 const XValidityConstraintListener_t& xListener ) 1240 throw( NullPointerException, 1241 RuntimeException ) 1242 { 1243 OSL_ENSURE( xListener.is(), "need listener!" ); 1244 if( ::std::find(maValidityListeners.begin(), maValidityListeners.end(), xListener) 1245 == maValidityListeners.end() ) 1246 maValidityListeners.push_back( xListener ); 1247 } 1248 1249 void Binding::removeValidityConstraintListener( 1250 const XValidityConstraintListener_t& xListener ) 1251 throw( NullPointerException, 1252 RuntimeException ) 1253 { 1254 XValidityConstraintListeners_t::iterator aIter = 1255 ::std::find( maValidityListeners.begin(), maValidityListeners.end(), 1256 xListener ); 1257 if( aIter != maValidityListeners.end() ) 1258 maValidityListeners.erase( aIter ); 1259 } 1260 1261 1262 1263 // 1264 // xml::dom::event::XEventListener 1265 // 1266 1267 void Binding::handleEvent( const XEvent_t& xEvent ) 1268 throw( RuntimeException ) 1269 { 1270 OUString sType(xEvent->getType()); 1271 //OUString sEventMIPChanged(RTL_CONSTASCII_USTRINGPARAM("xforms-generic")); 1272 //if(sType.equals(sEventMIPChanged)) { 1273 if(!sType.compareToAscii("xforms-generic")) { 1274 1275 // the modification of the 'mnDeferModifyNotifications'-member 1276 // is necessary to prevent infinite notication looping. 1277 // This can happend in case the binding which caused 1278 // the notification chain is listening to those events 1279 // as well... 1280 bool bPreserveValueModified = mbValueModified; 1281 mnDeferModifyNotifications++; 1282 valueModified(); 1283 --mnDeferModifyNotifications; 1284 mbValueModified = bPreserveValueModified; 1285 return; 1286 } 1287 1288 // if we're a dynamic binding, we better re-bind, too! 1289 bind( false ); 1290 1291 // our value was maybe modified 1292 valueModified(); 1293 } 1294 1295 1296 // 1297 // lang::XUnoTunnel 1298 // 1299 1300 sal_Int64 Binding::getSomething( const IntSequence_t& xId ) 1301 throw( RuntimeException ) 1302 { 1303 return reinterpret_cast<sal_Int64>( ( xId == getUnoTunnelID() ) ? this : NULL ); 1304 } 1305 1306 // 1307 // XCloneable 1308 // 1309 1310 Binding::XCloneable_t SAL_CALL Binding::createClone() 1311 throw( RuntimeException ) 1312 { 1313 Reference< XPropertySet > xClone; 1314 1315 Model* pModel = getModelImpl(); 1316 if ( pModel ) 1317 xClone = pModel->cloneBinding( this ); 1318 else 1319 { 1320 xClone = new Binding; 1321 copy( this, xClone ); 1322 } 1323 return XCloneable_t( xClone, UNO_QUERY ); 1324 } 1325 1326 // 1327 // property set implementations 1328 // 1329 1330 #define REGISTER_PROPERTY( property, type ) \ 1331 registerProperty( PROPERTY( property, type ), \ 1332 new DirectPropertyAccessor< Binding, type >( this, &Binding::set##property, &Binding::get##property ) ); 1333 1334 #define REGISTER_PROPERTY_RO( property, type ) \ 1335 registerProperty( PROPERTY_RO( property, type ), \ 1336 new DirectPropertyAccessor< Binding, type >( this, NULL, &Binding::get##property ) ); 1337 1338 #define REGISTER_BOOL_PROPERTY_RO( property ) \ 1339 registerProperty( PROPERTY_RO( property, sal_Bool ), \ 1340 new BooleanPropertyAccessor< Binding, bool >( this, NULL, &Binding::get##property ) ); 1341 1342 void Binding::initializePropertySet() 1343 { 1344 REGISTER_PROPERTY ( BindingID, OUString ); 1345 REGISTER_PROPERTY ( BindingExpression, OUString ); 1346 REGISTER_PROPERTY_RO ( Model, Model_t ); 1347 REGISTER_PROPERTY ( BindingNamespaces, XNameContainer_t ); 1348 REGISTER_PROPERTY ( ModelNamespaces, XNameContainer_t ); 1349 REGISTER_PROPERTY_RO ( ModelID, OUString ); 1350 REGISTER_PROPERTY ( ReadonlyExpression, OUString ); 1351 REGISTER_PROPERTY ( RelevantExpression, OUString ); 1352 REGISTER_PROPERTY ( RequiredExpression, OUString ); 1353 REGISTER_PROPERTY ( ConstraintExpression, OUString ); 1354 REGISTER_PROPERTY ( CalculateExpression, OUString ); 1355 REGISTER_PROPERTY ( Type, OUString ); 1356 REGISTER_PROPERTY_RO ( ReadOnly, bool ); 1357 REGISTER_PROPERTY_RO ( Relevant, bool ); 1358 REGISTER_BOOL_PROPERTY_RO( ExternalData ); 1359 1360 initializePropertyValueCache( HANDLE_ReadOnly ); 1361 initializePropertyValueCache( HANDLE_Relevant ); 1362 initializePropertyValueCache( HANDLE_ExternalData ); 1363 } 1364 1365 void Binding::addModifyListener( 1366 const XModifyListener_t& xListener ) 1367 throw( RuntimeException ) 1368 { 1369 OSL_ENSURE( xListener.is(), "need listener!" ); 1370 if( ::std::find( maModifyListeners.begin(), maModifyListeners.end(), xListener ) 1371 == maModifyListeners.end() ) 1372 maModifyListeners.push_back( xListener ); 1373 1374 // HACK: currently, we have to 'push' some MIPs to the control 1375 // (read-only, relevant, etc.) To enable this, we need to update 1376 // the control at least once when it registers here. 1377 valueModified(); 1378 } 1379 1380 void Binding::removeModifyListener( 1381 const XModifyListener_t& xListener ) 1382 throw( RuntimeException ) 1383 { 1384 ModifyListeners_t::iterator aIter = 1385 ::std::find( maModifyListeners.begin(), maModifyListeners.end(), xListener ); 1386 if( aIter != maModifyListeners.end() ) 1387 maModifyListeners.erase( aIter ); 1388 } 1389 1390 1391 1392 1393 rtl::OUString Binding::getName() 1394 throw( RuntimeException ) 1395 { 1396 return getBindingID(); 1397 } 1398 1399 void SAL_CALL Binding::setName( const rtl::OUString& rName ) 1400 throw( RuntimeException ) 1401 { 1402 // use the XPropertySet methods, so the change in the name is notified to the 1403 // property listeners 1404 setFastPropertyValue( HANDLE_BindingID, makeAny( rName ) ); 1405 } 1406