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 { 494 if( ! isLive() ) 495 throw RuntimeException( EXCEPT("Binding not initialized") ); 496 } 497 498 void Binding::checkModel() 499 { 500 if( ! mxModel.is() ) 501 throw RuntimeException( EXCEPT("Binding has no Model") ); 502 } 503 504 bool Binding::isLive() const 505 { 506 const Model* pModel = getModelImpl(); 507 return ( pModel != NULL ) ? pModel->isInitialized() : false; 508 } 509 510 Model* Binding::getModelImpl() const 511 { 512 return getModelImpl( mxModel ); 513 } 514 515 Model* Binding::getModelImpl( const Model_t& xModel ) const 516 { 517 Reference<XUnoTunnel> xTunnel( xModel, UNO_QUERY ); 518 Model* pModel = xTunnel.is() 519 ? reinterpret_cast<Model*>( 520 xTunnel->getSomething( Model::getUnoTunnelID() ) ) 521 : NULL; 522 return pModel; 523 } 524 525 void lcl_addListenerToNode( Reference<XNode> xNode, 526 Reference<XEventListener> xListener ) 527 { 528 Reference<XEventTarget> xTarget( xNode, UNO_QUERY ); 529 if( xTarget.is() ) 530 { 531 xTarget->addEventListener( OUSTRING("DOMCharacterDataModified"), 532 xListener, false ); 533 xTarget->addEventListener( OUSTRING("DOMCharacterDataModified"), 534 xListener, true ); 535 xTarget->addEventListener( OUSTRING("DOMAttrModified"), 536 xListener, false ); 537 xTarget->addEventListener( OUSTRING("DOMAttrModified"), 538 xListener, true ); 539 xTarget->addEventListener( OUSTRING("DOMAttrModified"), 540 xListener, true ); 541 xTarget->addEventListener( OUSTRING("xforms-generic"), 542 xListener, true ); 543 } 544 } 545 546 void lcl_removeListenerFromNode( Reference<XNode> xNode, 547 Reference<XEventListener> xListener ) 548 { 549 Reference<XEventTarget> xTarget( xNode, UNO_QUERY ); 550 if( xTarget.is() ) 551 { 552 xTarget->removeEventListener( OUSTRING("DOMCharacterDataModified"), 553 xListener, false ); 554 xTarget->removeEventListener( OUSTRING("DOMCharacterDataModified"), 555 xListener, true ); 556 xTarget->removeEventListener( OUSTRING("DOMAttrModified"), 557 xListener, false ); 558 xTarget->removeEventListener( OUSTRING("DOMAttrModified"), 559 xListener, true ); 560 xTarget->removeEventListener( OUSTRING("xforms-generic"), 561 xListener, true ); 562 } 563 } 564 565 ::std::vector<EvaluationContext> Binding::_getMIPEvaluationContexts() const 566 { 567 OSL_ENSURE( getModelImpl() != NULL, "need model impl" ); 568 569 // iterate over nodes of bind expression and create 570 // EvaluationContext for each 571 PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); 572 ::std::vector<EvaluationContext> aVector; 573 sal_Int32 nCount = 0; // count nodes for context position 574 for( PathExpression::NodeVector_t::iterator aIter = aNodes.begin(); 575 aIter != aNodes.end(); 576 aIter++, nCount++ ) 577 { 578 OSL_ENSURE( aIter->is(), "no node?" ); 579 580 // create proper evaluation context for this MIP 581 aVector.push_back( EvaluationContext( *aIter, getModel(), 582 getBindingNamespaces(), 583 nCount, aNodes.size() ) ); 584 } 585 return aVector; 586 } 587 588 void Binding::bind( bool bForceRebind ) 589 { 590 checkModel(); 591 592 // bind() will evaluate this binding as follows: 593 // 1) evaluate the binding expression 594 // 1b) if necessary, create node according to 'lazy author' rules 595 // 2) register suitable listeners on the instance (and remove old ones) 596 // 3) remove old MIPs defined by this binding 597 // 4) for every node in the binding nodeset do: 598 // 1) create proper evaluation context for this MIP 599 // 2) evaluate calculate expression (and push value into instance) 600 // 3) evaluate remaining MIPs 601 // 4) evaluate the locally defined MIPs, and push them to the model 602 603 604 // 1) evaluate the binding expression 605 EvaluationContext aContext = getEvaluationContext(); 606 maBindingExpression.evaluate( aContext ); 607 if( ! maBindingExpression.getNode().is() ) 608 { 609 // 1b) create node (if valid element name) 610 if( isValidQName( maBindingExpression.getExpression(), 611 aContext.mxNamespaces ) ) 612 { 613 aContext.mxContextNode->appendChild( 614 Reference<XNode>( 615 aContext.mxContextNode->getOwnerDocument()->createElement( 616 maBindingExpression.getExpression() ), 617 UNO_QUERY ) ); 618 maBindingExpression.evaluate( aContext ); 619 OSL_ENSURE( maBindingExpression.getNode().is(), 620 "we should bind to the newly inserted node!" ); 621 } 622 } 623 PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); 624 625 // 2) register suitable listeners on the instance (and remove old ones) 626 if( maEventNodes.empty() || bForceRebind ) 627 { 628 for( XNodes_t::iterator aIter = maEventNodes.begin(); 629 aIter != maEventNodes.end(); 630 aIter ++ ) 631 lcl_removeListenerFromNode( *aIter, this ); 632 maEventNodes.clear(); 633 if( isSimpleBinding() ) 634 for( PathExpression::NodeVector_t::iterator aIter = aNodes.begin(); 635 aIter != aNodes.end(); 636 aIter++ ) 637 maEventNodes.push_back( *aIter ); 638 else 639 maEventNodes.push_back( 640 Reference<XNode>( aContext.mxContextNode->getOwnerDocument(), 641 UNO_QUERY_THROW ) ); 642 for( PathExpression::NodeVector_t::iterator aIter2 = maEventNodes.begin(); 643 aIter2 != maEventNodes.end(); 644 aIter2 ++ ) 645 lcl_addListenerToNode( *aIter2, this ); 646 } 647 648 // 3) remove old MIPs defined by this binding 649 Model* pModel = getModelImpl(); 650 OSL_ENSURE( pModel != NULL, "need model" ); 651 pModel->removeMIPs( this ); 652 653 // 4) calculate all MIPs 654 ::std::vector<EvaluationContext> aMIPContexts = _getMIPEvaluationContexts(); 655 for( ::std::vector<EvaluationContext>::iterator aIter = aMIPContexts.begin(); 656 aIter != aMIPContexts.end(); 657 aIter++ ) 658 { 659 EvaluationContext& rContext = *aIter; 660 661 // evaluate calculate expression (and push value into instance) 662 // (prevent recursion using mbInCalculate 663 if( ! maCalculate.isEmptyExpression() ) 664 { 665 if( ! mbInCalculate ) 666 { 667 mbInCalculate = true; 668 maCalculate.evaluate( rContext ); 669 pModel->setSimpleContent( rContext.mxContextNode, 670 maCalculate.getString() ); 671 mbInCalculate = false; 672 } 673 } 674 675 // now evaluate remaining MIPs in the appropriate context 676 maReadonly.evaluate( rContext ); 677 maRelevant.evaluate( rContext ); 678 maRequired.evaluate( rContext ); 679 maConstraint.evaluate( rContext ); 680 // type is static; does not need updating 681 682 // evaluate the locally defined MIPs, and push them to the model 683 pModel->addMIP( this, rContext.mxContextNode, getLocalMIP() ); 684 } 685 } 686 687 688 // helper for Binding::valueModified 689 void lcl_modified( const Binding::XModifyListener_t xListener, 690 const Reference<XInterface> xSource ) 691 { 692 OSL_ENSURE( xListener.is(), "no listener?" ); 693 xListener->modified( EventObject( xSource ) ); 694 } 695 696 // helper for Binding::valueModified 697 void lcl_listentry( const Binding::XListEntryListener_t xListener, 698 const Reference<XInterface> xSource ) 699 { 700 OSL_ENSURE( xListener.is(), "no listener?" ); 701 // TODO: send fine granular events 702 xListener->allEntriesChanged( EventObject( xSource ) ); 703 } 704 705 // helper for Binding::valueModified 706 void lcl_validate( const Binding::XValidityConstraintListener_t xListener, 707 const Reference<XInterface> xSource ) 708 { 709 OSL_ENSURE( xListener.is(), "no listener?" ); 710 xListener->validityConstraintChanged( EventObject( xSource ) ); 711 } 712 713 714 void Binding::valueModified() 715 { 716 // defer notifications, if so desired 717 if( mnDeferModifyNotifications > 0 ) 718 { 719 mbValueModified = true; 720 return; 721 } 722 mbValueModified = false; 723 724 // query MIP used by our first node (also note validity) 725 Reference<XNode> xNode = maBindingExpression.getNode(); 726 maMIP = getModelImpl()->queryMIP( xNode ); 727 728 // distribute MIPs _used_ by this binding 729 if( xNode.is() ) 730 { 731 notifyAndCachePropertyValue( HANDLE_ReadOnly ); 732 notifyAndCachePropertyValue( HANDLE_Relevant ); 733 } 734 735 // iterate over _value_ listeners and send each a modified signal, 736 // using this object as source (will also update validity, because 737 // control will query once the value has changed) 738 Reference<XInterface> xSource = static_cast<XPropertySet*>( this ); 739 ::std::for_each( maModifyListeners.begin(), 740 maModifyListeners.end(), 741 ::std::bind2nd( ::std::ptr_fun( lcl_modified ), xSource ) ); 742 ::std::for_each( maListEntryListeners.begin(), 743 maListEntryListeners.end(), 744 ::std::bind2nd( ::std::ptr_fun( lcl_listentry ), xSource ) ); 745 ::std::for_each( maValidityListeners.begin(), 746 maValidityListeners.end(), 747 ::std::bind2nd( ::std::ptr_fun( lcl_validate ), xSource ) ); 748 749 // now distribute MIPs to childs 750 if( xNode.is() ) 751 distributeMIP( xNode->getFirstChild() ); 752 } 753 754 void Binding::distributeMIP( const XNode_t & rxNode ) { 755 756 typedef com::sun::star::xforms::XFormsEventConcrete XFormsEvent_t; 757 OUString sEventName( RTL_CONSTASCII_USTRINGPARAM("xforms-generic") ); 758 XFormsEvent_t *pEvent = new XFormsEvent_t; 759 pEvent->initXFormsEvent(sEventName, sal_True, sal_False); 760 Reference<XEvent> xEvent(pEvent); 761 762 // naive depth-first traversal 763 XNode_t xNode( rxNode ); 764 while(xNode.is()) { 765 766 // notifications should be triggered at the 767 // leaf nodes first, bubbling upwards the hierarchy. 768 XNode_t child(xNode->getFirstChild()); 769 if(child.is()) 770 distributeMIP(child); 771 772 // we're standing at a particular node somewhere 773 // below the one which changed a property (MIP). 774 // bindings which are listening at this node will receive 775 // a notification message about what exactly happened. 776 Reference< XEventTarget > target(xNode,UNO_QUERY); 777 target->dispatchEvent(xEvent); 778 779 xNode = xNode->getNextSibling(); 780 }; 781 } 782 783 void Binding::bindingModified() 784 { 785 // defer notifications, if so desired 786 if( mnDeferModifyNotifications > 0 ) 787 { 788 mbBindingModified = true; 789 return; 790 } 791 mbBindingModified = false; 792 793 // rebind (if live); then call valueModified 794 // A binding should be inert until its model is fully constructed. 795 if( isLive() ) 796 { 797 bind( true ); 798 valueModified(); 799 } 800 } 801 802 803 MIP Binding::getLocalMIP() const 804 { 805 MIP aMIP; 806 807 if( maReadonly.hasValue() ) 808 aMIP.setReadonly( maReadonly.getBool( false ) ); 809 if( maRelevant.hasValue() ) 810 aMIP.setRelevant( maRelevant.getBool( true ) ); 811 if( maRequired.hasValue() ) 812 aMIP.setRequired( maRequired.getBool( false ) ); 813 if( maConstraint.hasValue() ) 814 { 815 aMIP.setConstraint( maConstraint.getBool( true ) ); 816 if( ! aMIP.isConstraint() ) 817 aMIP.setConstraintExplanation( msExplainConstraint ); 818 } 819 if( msTypeName.getLength() > 0 ) 820 aMIP.setTypeName( msTypeName ); 821 822 // calculate: only handle presence of calculate; value set elsewhere 823 aMIP.setHasCalculate( !maCalculate.isEmptyExpression() ); 824 825 return aMIP; 826 } 827 828 Binding::XDataType_t Binding::getDataType() 829 { 830 OSL_ENSURE( getModel().is(), "need model" ); 831 OSL_ENSURE( getModel()->getDataTypeRepository().is(), "need types" ); 832 833 Reference<XDataTypeRepository> xRepository( 834 getModel()->getDataTypeRepository(), UNO_QUERY ); 835 OUString sTypeName = maMIP.getTypeName(); 836 837 return ( xRepository.is() && xRepository->hasByName( sTypeName ) ) 838 ? Reference<XDataType>( xRepository->getByName( sTypeName ), UNO_QUERY) 839 : Reference<XDataType>( NULL ); 840 } 841 842 bool Binding::isValid_DataType() 843 { 844 Reference<XDataType> xDataType = getDataType(); 845 return xDataType.is() 846 ? xDataType->validate( maBindingExpression.getString() ) 847 : true; 848 } 849 850 rtl::OUString Binding::explainInvalid_DataType() 851 { 852 Reference<XDataType> xDataType = getDataType(); 853 return xDataType.is() 854 ? xDataType->explainInvalid( maBindingExpression.getString() ) 855 : OUString(); 856 } 857 858 void Binding::clear() 859 { 860 // remove MIPs contributed by this binding 861 Model* pModel = getModelImpl(); 862 if( pModel != NULL ) 863 pModel->removeMIPs( this ); 864 865 // remove all references 866 for( XNodes_t::iterator aIter = maEventNodes.begin(); 867 aIter != maEventNodes.end(); 868 aIter ++ ) 869 lcl_removeListenerFromNode( *aIter, this ); 870 maEventNodes.clear(); 871 872 // clear expressions 873 maBindingExpression.clear(); 874 maReadonly.clear(); 875 maRelevant.clear(); 876 maRequired.clear(); 877 maConstraint.clear(); 878 maCalculate.clear(); 879 880 // TODO: what about our listeners? 881 } 882 883 884 void lcl_removeOtherNamespaces( const Binding::XNameContainer_t& xFrom, 885 Binding::XNameContainer_t& xTo ) 886 { 887 OSL_ENSURE( xFrom.is(), "no source" ); 888 OSL_ENSURE( xTo.is(), "no target" ); 889 890 // iterate over name in source 891 Sequence<OUString> aNames = xTo->getElementNames(); 892 sal_Int32 nNames = aNames.getLength(); 893 const OUString* pNames = aNames.getConstArray(); 894 for( sal_Int32 i = 0; i < nNames; i++ ) 895 { 896 const OUString& rName = pNames[i]; 897 898 if( ! xFrom->hasByName( rName ) ) 899 xTo->removeByName( rName ); 900 } 901 } 902 903 /** copy namespaces from one namespace container into another 904 * @param bOverwrite true: overwrite namespaces in target 905 * false: do not overwrite namespaces in target 906 * @param bMove true: move namespaces (i.e., delete in source) 907 * false: copy namespaces (do not modify source) 908 * @param bFromSource true: use elements from source 909 * false: use only elements from target 910 */ 911 void lcl_copyNamespaces( const Binding::XNameContainer_t& xFrom, 912 Binding::XNameContainer_t& xTo, 913 bool bOverwrite ) 914 { 915 OSL_ENSURE( xFrom.is(), "no source" ); 916 OSL_ENSURE( xTo.is(), "no target" ); 917 918 // iterate over name in source 919 Sequence<OUString> aNames = xFrom->getElementNames(); 920 sal_Int32 nNames = aNames.getLength(); 921 const OUString* pNames = aNames.getConstArray(); 922 for( sal_Int32 i = 0; i < nNames; i++ ) 923 { 924 const OUString& rName = pNames[i]; 925 926 // determine whether to copy the value, and whether to delete 927 // it in the source: 928 929 bool bInTarget = xTo->hasByName( rName ); 930 931 // we copy: if property is in target, and 932 // if bOverwrite is set, or when the namespace prefix is free 933 bool bCopy = bOverwrite || ! bInTarget; 934 935 // and now... ACTION! 936 if( bCopy ) 937 { 938 if( bInTarget ) 939 xTo->replaceByName( rName, xFrom->getByName( rName ) ); 940 else 941 xTo->insertByName( rName, xFrom->getByName( rName ) ); 942 } 943 } 944 } 945 946 // implement get*Namespaces() 947 // (identical for both variants) 948 Binding::XNameContainer_t Binding::_getNamespaces() const 949 { 950 XNameContainer_t xNamespaces = new NameContainer<OUString>(); 951 lcl_copyNamespaces( mxNamespaces, xNamespaces, true ); 952 953 // merge model's with binding's own namespaces 954 Model* pModel = getModelImpl(); 955 if( pModel != NULL ) 956 lcl_copyNamespaces( pModel->getNamespaces(), xNamespaces, false ); 957 958 return xNamespaces; 959 } 960 961 // implement set*Namespaces() 962 // bBinding = true: setBindingNamespaces, otherwise: setModelNamespaces 963 void Binding::_setNamespaces( const XNameContainer_t& rNamespaces, 964 bool bBinding ) 965 { 966 Model* pModel = getModelImpl(); 967 XNameContainer_t xModelNamespaces = ( pModel != NULL ) 968 ? pModel->getNamespaces() 969 : NULL; 970 OSL_ENSURE( ( pModel != NULL ) == xModelNamespaces.is(), "no model nmsp?"); 971 972 // remove deleted namespaces 973 lcl_removeOtherNamespaces( rNamespaces, mxNamespaces ); 974 if( !bBinding && xModelNamespaces.is() ) 975 lcl_removeOtherNamespaces( rNamespaces, xModelNamespaces ); 976 977 // copy namespaces as appropriate 978 Sequence<OUString> aNames = rNamespaces->getElementNames(); 979 sal_Int32 nNames = aNames.getLength(); 980 const OUString* pNames = aNames.getConstArray(); 981 for( sal_Int32 i = 0; i < nNames; i++ ) 982 { 983 const OUString& rName = pNames[i]; 984 Any aValue = rNamespaces->getByName( rName ); 985 986 // determine whether the namespace should go into model's or 987 // into binding's namespaces 988 bool bLocal = 989 ! xModelNamespaces.is() 990 || mxNamespaces->hasByName( rName ) 991 || ( bBinding 992 && xModelNamespaces.is() 993 && xModelNamespaces->hasByName( rName ) ); 994 995 // write namespace into the appropriate namespace container 996 XNameContainer_t& rWhich = bLocal ? mxNamespaces : xModelNamespaces; 997 OSL_ENSURE( rWhich.is(), "whoops" ); 998 if( rWhich->hasByName( rName ) ) 999 rWhich->replaceByName( rName, aValue ); 1000 else 1001 rWhich->insertByName( rName, aValue ); 1002 1003 // always 'promote' namespaces from binding to model, if equal 1004 if( xModelNamespaces.is() 1005 && xModelNamespaces->hasByName( rName ) 1006 && mxNamespaces->hasByName( rName ) 1007 && xModelNamespaces->getByName( rName ) == mxNamespaces->getByName( rName ) ) 1008 { 1009 mxNamespaces->removeByName( rName ); 1010 } 1011 } 1012 1013 // ... done. But we modified the binding! 1014 bindingModified(); 1015 } 1016 1017 void Binding::_checkBindingID() 1018 { 1019 if( getModel().is() ) 1020 { 1021 Reference<XNameAccess> xBindings( getModel()->getBindings(), UNO_QUERY_THROW ); 1022 if( msBindingID.getLength() == 0 ) 1023 { 1024 // no binding ID? then make one up! 1025 OUString sIDPrefix = getResource( RID_STR_XFORMS_BINDING_UI_NAME ); 1026 sIDPrefix += String::CreateFromAscii( " " ); 1027 sal_Int32 nNumber = 0; 1028 OUString sName; 1029 do 1030 { 1031 nNumber++; 1032 sName = sIDPrefix + OUString::valueOf( nNumber ); 1033 } 1034 while( xBindings->hasByName( sName ) ); 1035 setBindingID( sName ); 1036 } 1037 } 1038 } 1039 1040 1041 1042 1043 // 1044 // XValueBinding 1045 // 1046 1047 Binding::Sequence_Type_t Binding::getSupportedValueTypes() 1048 { 1049 return Convert::get().getTypes(); 1050 } 1051 1052 sal_Bool Binding::supportsType( const Type_t& rType ) 1053 { 1054 return Convert::get().hasType( rType ); 1055 } 1056 1057 Binding::Any_t Binding::getValue( const Type_t& rType ) 1058 { 1059 // first, check for model 1060 checkLive(); 1061 1062 // second, check for type 1063 if( ! supportsType( rType ) ) 1064 throw IncompatibleTypesException( EXCEPT( "type unsupported" ) ); 1065 1066 // return string value (if present; else return empty Any) 1067 Binding::Any_t result = Any(); 1068 if(maBindingExpression.hasValue()) { 1069 rtl::OUString pathExpr(maBindingExpression.getString()); 1070 Convert &rConvert = Convert::get(); 1071 result = rConvert.toAny(pathExpr,rType); 1072 } 1073 1074 // return maBindingExpression.hasValue() 1075 // ? Convert::get().toAny( maBindingExpression.getString(), rType ) 1076 // : Any(); 1077 1078 return result; 1079 } 1080 1081 void Binding::setValue( const Any_t& aValue ) 1082 { 1083 // first, check for model 1084 checkLive(); 1085 1086 // check for supported type 1087 if( ! supportsType( aValue.getValueType() ) ) 1088 throw IncompatibleTypesException( EXCEPT( "type unsupported" ) ); 1089 1090 if( maBindingExpression.hasValue() ) 1091 { 1092 Binding::XNode_t xNode = maBindingExpression.getNode(); 1093 if( xNode.is() ) 1094 { 1095 OUString sValue = Convert::get().toXSD( aValue ); 1096 bool bSuccess = getModelImpl()->setSimpleContent( xNode, sValue ); 1097 if( ! bSuccess ) 1098 throw InvalidBindingStateException( EXCEPT( "can't set value" ) ); 1099 } 1100 else 1101 throw InvalidBindingStateException( EXCEPT( "no suitable node found" ) ); 1102 } 1103 else 1104 throw InvalidBindingStateException( EXCEPT( "no suitable node found" ) ); 1105 } 1106 1107 1108 // 1109 // XListEntry Source 1110 // 1111 1112 sal_Int32 Binding::getListEntryCount() 1113 { 1114 // first, check for model 1115 checkLive(); 1116 1117 // return size of node list 1118 return maBindingExpression.getNodeList().size(); 1119 } 1120 1121 void lcl_getString( const Reference<XNode>& xNode, OUStringBuffer& rBuffer ) 1122 { 1123 if( xNode->getNodeType() == NodeType_TEXT_NODE 1124 || xNode->getNodeType() == NodeType_ATTRIBUTE_NODE ) 1125 { 1126 rBuffer.append( xNode->getNodeValue() ); 1127 } 1128 else 1129 { 1130 for( Reference<XNode> xChild = xNode->getFirstChild(); 1131 xChild.is(); 1132 xChild = xChild->getNextSibling() ) 1133 { 1134 lcl_getString( xChild, rBuffer ); 1135 } 1136 } 1137 } 1138 1139 OUString lcl_getString( const Reference<XNode>& xNode ) 1140 { 1141 OUStringBuffer aBuffer; 1142 lcl_getString( xNode, aBuffer ); 1143 return aBuffer.makeStringAndClear(); 1144 } 1145 1146 OUString Binding::getListEntry( sal_Int32 nPosition ) 1147 { 1148 // first, check for model 1149 checkLive(); 1150 1151 // check bounds and return proper item 1152 PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); 1153 if( nPosition < 0 || nPosition >= static_cast<sal_Int32>( aNodes.size() ) ) 1154 throw IndexOutOfBoundsException( EXCEPT("") ); 1155 return lcl_getString( aNodes[ nPosition ] ); 1156 } 1157 1158 Sequence<OUString> Binding::getAllListEntries() 1159 { 1160 // first, check for model 1161 checkLive(); 1162 1163 // create sequence of string values 1164 PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); 1165 Sequence<OUString> aSequence( aNodes.size() ); 1166 OUString* pSequence = aSequence.getArray(); 1167 for( sal_Int32 n = 0; n < aSequence.getLength(); n++ ) 1168 { 1169 pSequence[n] = lcl_getString( aNodes[n] ); 1170 } 1171 1172 return aSequence; 1173 } 1174 1175 void Binding::addListEntryListener( const XListEntryListener_t& xListener ) 1176 { 1177 OSL_ENSURE( xListener.is(), "need listener!" ); 1178 if( ::std::find( maListEntryListeners.begin(), 1179 maListEntryListeners.end(), 1180 xListener) 1181 == maListEntryListeners.end() ) 1182 maListEntryListeners.push_back( xListener ); 1183 } 1184 1185 void Binding::removeListEntryListener( const XListEntryListener_t& xListener ) 1186 { 1187 XListEntryListeners_t::iterator aIter = 1188 ::std::find( maListEntryListeners.begin(), maListEntryListeners.end(), 1189 xListener ); 1190 if( aIter != maListEntryListeners.end() ) 1191 maListEntryListeners.erase( aIter ); 1192 } 1193 1194 1195 // 1196 // XValidator 1197 // 1198 1199 sal_Bool Binding::isValid( const Any_t& ) 1200 { 1201 // first, check for model 1202 checkLive(); 1203 1204 // ignore value; determine validate only on current data 1205 return isValid(); 1206 } 1207 1208 rtl::OUString Binding::explainInvalid( 1209 const Any_t& /*Value*/ ) 1210 { 1211 // first, check for model 1212 checkLive(); 1213 1214 // ignore value; determine explanation only on current data 1215 return explainInvalid(); 1216 } 1217 1218 void Binding::addValidityConstraintListener( 1219 const XValidityConstraintListener_t& xListener ) 1220 { 1221 OSL_ENSURE( xListener.is(), "need listener!" ); 1222 if( ::std::find(maValidityListeners.begin(), maValidityListeners.end(), xListener) 1223 == maValidityListeners.end() ) 1224 maValidityListeners.push_back( xListener ); 1225 } 1226 1227 void Binding::removeValidityConstraintListener( 1228 const XValidityConstraintListener_t& xListener ) 1229 { 1230 XValidityConstraintListeners_t::iterator aIter = 1231 ::std::find( maValidityListeners.begin(), maValidityListeners.end(), 1232 xListener ); 1233 if( aIter != maValidityListeners.end() ) 1234 maValidityListeners.erase( aIter ); 1235 } 1236 1237 1238 1239 // 1240 // xml::dom::event::XEventListener 1241 // 1242 1243 void Binding::handleEvent( const XEvent_t& xEvent ) 1244 { 1245 OUString sType(xEvent->getType()); 1246 //OUString sEventMIPChanged(RTL_CONSTASCII_USTRINGPARAM("xforms-generic")); 1247 //if(sType.equals(sEventMIPChanged)) { 1248 if(!sType.compareToAscii("xforms-generic")) { 1249 1250 // the modification of the 'mnDeferModifyNotifications'-member 1251 // is necessary to prevent infinite notification looping. 1252 // This can happened in case the binding which caused 1253 // the notification chain is listening to those events 1254 // as well... 1255 bool bPreserveValueModified = mbValueModified; 1256 mnDeferModifyNotifications++; 1257 valueModified(); 1258 --mnDeferModifyNotifications; 1259 mbValueModified = bPreserveValueModified; 1260 return; 1261 } 1262 1263 // if we're a dynamic binding, we better re-bind, too! 1264 bind( false ); 1265 1266 // our value was maybe modified 1267 valueModified(); 1268 } 1269 1270 1271 // 1272 // lang::XUnoTunnel 1273 // 1274 1275 sal_Int64 Binding::getSomething( const IntSequence_t& xId ) 1276 { 1277 return reinterpret_cast<sal_Int64>( ( xId == getUnoTunnelID() ) ? this : NULL ); 1278 } 1279 1280 // 1281 // XCloneable 1282 // 1283 1284 Binding::XCloneable_t SAL_CALL Binding::createClone() 1285 { 1286 Reference< XPropertySet > xClone; 1287 1288 Model* pModel = getModelImpl(); 1289 if ( pModel ) 1290 xClone = pModel->cloneBinding( this ); 1291 else 1292 { 1293 xClone = new Binding; 1294 copy( this, xClone ); 1295 } 1296 return XCloneable_t( xClone, UNO_QUERY ); 1297 } 1298 1299 // 1300 // property set implementations 1301 // 1302 1303 #define REGISTER_PROPERTY( property, type ) \ 1304 registerProperty( PROPERTY( property, type ), \ 1305 new DirectPropertyAccessor< Binding, type >( this, &Binding::set##property, &Binding::get##property ) ); 1306 1307 #define REGISTER_PROPERTY_RO( property, type ) \ 1308 registerProperty( PROPERTY_RO( property, type ), \ 1309 new DirectPropertyAccessor< Binding, type >( this, NULL, &Binding::get##property ) ); 1310 1311 #define REGISTER_BOOL_PROPERTY_RO( property ) \ 1312 registerProperty( PROPERTY_RO( property, sal_Bool ), \ 1313 new BooleanPropertyAccessor< Binding, bool >( this, NULL, &Binding::get##property ) ); 1314 1315 void Binding::initializePropertySet() 1316 { 1317 REGISTER_PROPERTY ( BindingID, OUString ); 1318 REGISTER_PROPERTY ( BindingExpression, OUString ); 1319 REGISTER_PROPERTY_RO ( Model, Model_t ); 1320 REGISTER_PROPERTY ( BindingNamespaces, XNameContainer_t ); 1321 REGISTER_PROPERTY ( ModelNamespaces, XNameContainer_t ); 1322 REGISTER_PROPERTY_RO ( ModelID, OUString ); 1323 REGISTER_PROPERTY ( ReadonlyExpression, OUString ); 1324 REGISTER_PROPERTY ( RelevantExpression, OUString ); 1325 REGISTER_PROPERTY ( RequiredExpression, OUString ); 1326 REGISTER_PROPERTY ( ConstraintExpression, OUString ); 1327 REGISTER_PROPERTY ( CalculateExpression, OUString ); 1328 REGISTER_PROPERTY ( Type, OUString ); 1329 REGISTER_PROPERTY_RO ( ReadOnly, bool ); 1330 REGISTER_PROPERTY_RO ( Relevant, bool ); 1331 REGISTER_BOOL_PROPERTY_RO( ExternalData ); 1332 1333 initializePropertyValueCache( HANDLE_ReadOnly ); 1334 initializePropertyValueCache( HANDLE_Relevant ); 1335 initializePropertyValueCache( HANDLE_ExternalData ); 1336 } 1337 1338 void Binding::addModifyListener( 1339 const XModifyListener_t& xListener ) 1340 { 1341 OSL_ENSURE( xListener.is(), "need listener!" ); 1342 if( ::std::find( maModifyListeners.begin(), maModifyListeners.end(), xListener ) 1343 == maModifyListeners.end() ) 1344 maModifyListeners.push_back( xListener ); 1345 1346 // HACK: currently, we have to 'push' some MIPs to the control 1347 // (read-only, relevant, etc.) To enable this, we need to update 1348 // the control at least once when it registers here. 1349 valueModified(); 1350 } 1351 1352 void Binding::removeModifyListener( 1353 const XModifyListener_t& xListener ) 1354 { 1355 ModifyListeners_t::iterator aIter = 1356 ::std::find( maModifyListeners.begin(), maModifyListeners.end(), xListener ); 1357 if( aIter != maModifyListeners.end() ) 1358 maModifyListeners.erase( aIter ); 1359 } 1360 1361 1362 1363 1364 rtl::OUString Binding::getName() 1365 { 1366 return getBindingID(); 1367 } 1368 1369 void SAL_CALL Binding::setName( const rtl::OUString& rName ) 1370 { 1371 // use the XPropertySet methods, so the change in the name is notified to the 1372 // property listeners 1373 setFastPropertyValue( HANDLE_BindingID, makeAny( rName ) ); 1374 } 1375