LCOV - code coverage report
Current view: top level - forms/source/xforms - binding.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 0 583 0.0 %
Date: 2015-06-13 12:38:46 Functions: 0 85 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11