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