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