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