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

Generated by: LCOV version 1.10