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