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