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