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

Generated by: LCOV version 1.10