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