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