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