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 : #include "componenttools.hxx"
20 : #include "FormComponent.hxx"
21 : #include "frm_resource.hrc"
22 : #include "frm_resource.hxx"
23 : #include "property.hrc"
24 : #include "services.hxx"
25 :
26 : #include <com/sun/star/awt/XTextComponent.hpp>
27 : #include <com/sun/star/awt/XVclWindowPeer.hpp>
28 : #include <com/sun/star/awt/XWindow.hpp>
29 : #include <com/sun/star/form/XForm.hpp>
30 : #include <com/sun/star/form/XLoadable.hpp>
31 : #include <com/sun/star/io/XMarkableStream.hpp>
32 : #include <com/sun/star/lang/DisposedException.hpp>
33 : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
34 : #include <com/sun/star/sdb/XRowSetChangeBroadcaster.hpp>
35 : #include <com/sun/star/sdb/XRowSetSupplier.hpp>
36 : #include <com/sun/star/sdbc/ColumnValue.hpp>
37 : #include <com/sun/star/sdbc/DataType.hpp>
38 : #include <com/sun/star/util/XModifyBroadcaster.hpp>
39 :
40 : #include <comphelper/basicio.hxx>
41 : #include <comphelper/guarding.hxx>
42 : #include <comphelper/listenernotification.hxx>
43 : #include <comphelper/property.hxx>
44 : #include <connectivity/dbtools.hxx>
45 : #include <cppuhelper/exc_hlp.hxx>
46 : #include <cppuhelper/queryinterface.hxx>
47 : #include <cppuhelper/supportsservice.hxx>
48 : #include <toolkit/helper/emptyfontdescriptor.hxx>
49 : #include <tools/debug.hxx>
50 : #include <tools/diagnose_ex.h>
51 :
52 : #include <functional>
53 : #include <algorithm>
54 :
55 : namespace frm
56 : {
57 : using namespace ::com::sun::star::uno;
58 : using namespace ::com::sun::star::sdb;
59 : using namespace ::com::sun::star::sdbc;
60 : using namespace ::com::sun::star::sdbcx;
61 : using namespace ::com::sun::star::beans;
62 : using namespace ::com::sun::star::container;
63 : using namespace ::com::sun::star::form;
64 : using namespace ::com::sun::star::awt;
65 : using namespace ::com::sun::star::io;
66 : using namespace ::com::sun::star::lang;
67 : using namespace ::com::sun::star::util;
68 : using namespace ::com::sun::star::form::binding;
69 : using namespace ::com::sun::star::form::validation;
70 : using namespace ::dbtools;
71 : using namespace ::comphelper;
72 :
73 : // FieldChangeNotifier
74 2580 : void ControlModelLock::impl_notifyAll_nothrow()
75 : {
76 2580 : m_rModel.firePropertyChanges( m_aHandles, m_aOldValues, m_aNewValues, OControlModel::LockAccess() );
77 2580 : }
78 :
79 62 : void ControlModelLock::addPropertyNotification( const sal_Int32 _nHandle, const Any& _rOldValue, const Any& _rNewValue )
80 : {
81 62 : sal_Int32 nOldLength = m_aHandles.getLength();
82 124 : if ( ( nOldLength != m_aOldValues.getLength() )
83 62 : || ( nOldLength != m_aNewValues.getLength() )
84 : )
85 0 : throw RuntimeException( OUString(), m_rModel );
86 :
87 62 : m_aHandles.realloc( nOldLength + 1 );
88 62 : m_aHandles[ nOldLength ] = _nHandle;
89 62 : m_aOldValues.realloc( nOldLength + 1 );
90 62 : m_aOldValues[ nOldLength ] = _rOldValue;
91 62 : m_aNewValues.realloc( nOldLength + 1 );
92 62 : m_aNewValues[ nOldLength ] = _rNewValue;
93 62 : }
94 :
95 : class FieldChangeNotifier
96 : {
97 : public:
98 1370 : FieldChangeNotifier( ControlModelLock& _rLock )
99 : :m_rLock( _rLock )
100 1370 : ,m_rModel( dynamic_cast< OBoundControlModel& >( _rLock.getModel() ) )
101 : {
102 1370 : m_xOldField = m_rModel.getField();
103 1370 : }
104 :
105 1370 : ~FieldChangeNotifier()
106 1370 : {
107 1370 : Reference< XPropertySet > xNewField( m_rModel.getField() );
108 1370 : if ( m_xOldField != xNewField )
109 62 : m_rLock.addPropertyNotification( PROPERTY_ID_BOUNDFIELD, makeAny( m_xOldField ), makeAny( xNewField ) );
110 1370 : }
111 :
112 : private:
113 : ControlModelLock& m_rLock;
114 : OBoundControlModel& m_rModel;
115 : Reference< XPropertySet > m_xOldField;
116 : };
117 :
118 : // base class for form layer controls
119 602 : OControl::OControl( const Reference< XComponentContext >& _rxContext, const OUString& _rAggregateService, const bool _bSetDelegator )
120 : :OComponentHelper(m_aMutex)
121 602 : ,m_xContext( _rxContext )
122 : {
123 : // Aggregate VCL Control
124 : // Increment the RefCount for aggregates, because the aggregate by itself increments the RefCount in the setDelegator
125 602 : increment( m_refCount );
126 : {
127 602 : m_xAggregate.set(_rxContext->getServiceManager()->createInstanceWithContext(_rAggregateService, _rxContext), css::uno::UNO_QUERY);
128 602 : m_xControl.set(m_xAggregate, css::uno::UNO_QUERY);
129 : }
130 602 : decrement( m_refCount );
131 :
132 602 : if ( _bSetDelegator )
133 566 : doSetDelegator();
134 602 : }
135 :
136 1048 : OControl::~OControl()
137 : {
138 524 : doResetDelegator();
139 524 : }
140 :
141 536 : void OControl::doResetDelegator()
142 : {
143 536 : if ( m_xAggregate.is() )
144 536 : m_xAggregate->setDelegator( NULL );
145 536 : }
146 :
147 602 : void OControl::doSetDelegator()
148 : {
149 602 : increment( m_refCount );
150 602 : if ( m_xAggregate.is() )
151 : { // those brackets are important for some compilers, don't remove!
152 : // (they ensure that the temporary object created in the line below
153 : // is destroyed *before* the refcount-decrement)
154 602 : m_xAggregate->setDelegator( static_cast< XWeak* >( this ) );
155 : }
156 602 : decrement( m_refCount );
157 602 : }
158 :
159 : // UNO Binding
160 22091 : Any SAL_CALL OControl::queryAggregation( const Type& _rType ) throw(RuntimeException, std::exception)
161 : {
162 : // ask the base class
163 22091 : Any aReturn( OComponentHelper::queryAggregation(_rType) );
164 : // ask our own interfaces
165 22091 : if (!aReturn.hasValue())
166 : {
167 20564 : aReturn = OControl_BASE::queryInterface(_rType);
168 : // ask our aggregate
169 20564 : if (!aReturn.hasValue() && m_xAggregate.is())
170 9792 : aReturn = m_xAggregate->queryAggregation(_rType);
171 : }
172 :
173 22091 : return aReturn;
174 : }
175 :
176 0 : Sequence<sal_Int8> SAL_CALL OControl::getImplementationId() throw(RuntimeException, std::exception)
177 : {
178 0 : return css::uno::Sequence<sal_Int8>();
179 : }
180 :
181 264 : Sequence<Type> SAL_CALL OControl::getTypes() throw(RuntimeException, std::exception)
182 : {
183 264 : TypeBag aTypes( _getTypes() );
184 :
185 528 : Reference< XTypeProvider > xProv;
186 264 : if ( query_aggregation( m_xAggregate, xProv ) )
187 264 : aTypes.addTypes( xProv->getTypes() );
188 :
189 528 : return aTypes.getTypes();
190 : }
191 :
192 148 : Sequence<Type> OControl::_getTypes()
193 : {
194 148 : return TypeBag( OComponentHelper::getTypes(), OControl_BASE::getTypes() ).getTypes();
195 : }
196 :
197 855 : void OControl::initFormControlPeer( const Reference< XWindowPeer >& /*_rxPeer*/ )
198 : {
199 : // nothing to do here
200 855 : }
201 :
202 : // OComponentHelper
203 530 : void OControl::disposing()
204 : {
205 530 : OComponentHelper::disposing();
206 :
207 530 : m_aWindowStateGuard.attach( NULL, NULL );
208 :
209 530 : Reference< XComponent > xComp;
210 530 : if (query_aggregation(m_xAggregate, xComp))
211 530 : xComp->dispose();
212 530 : }
213 :
214 : // XServiceInfo
215 0 : sal_Bool SAL_CALL OControl::supportsService(const OUString& _rsServiceName) throw ( RuntimeException, std::exception)
216 : {
217 0 : return cppu::supportsService(this, _rsServiceName);
218 : }
219 :
220 0 : Sequence< OUString > OControl::getAggregateServiceNames()
221 : {
222 0 : Sequence< OUString > aAggServices;
223 0 : Reference< XServiceInfo > xInfo;
224 0 : if ( query_aggregation( m_xAggregate, xInfo ) )
225 0 : aAggServices = xInfo->getSupportedServiceNames();
226 :
227 0 : return aAggServices;
228 : }
229 :
230 0 : Sequence<OUString> SAL_CALL OControl::getSupportedServiceNames() throw(RuntimeException, std::exception)
231 : {
232 : return ::comphelper::concatSequences(
233 : getAggregateServiceNames(),
234 : getSupportedServiceNames_Static()
235 0 : );
236 : }
237 :
238 0 : Sequence< OUString > SAL_CALL OControl::getSupportedServiceNames_Static() throw( RuntimeException )
239 : {
240 : // no own supported service names
241 0 : return Sequence< OUString >();
242 : }
243 :
244 : // XEventListener
245 1539 : void SAL_CALL OControl::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException, std::exception)
246 : {
247 1539 : Reference< XInterface > xAggAsIface;
248 1539 : query_aggregation(m_xAggregate, xAggAsIface);
249 :
250 : // does the disposing come from the aggregate?
251 1539 : if (xAggAsIface != Reference< XInterface >(_rEvent.Source, UNO_QUERY))
252 : { // no -> forward it
253 1107 : Reference<com::sun::star::lang::XEventListener> xListener;
254 1107 : if (query_aggregation(m_xAggregate, xListener))
255 1107 : xListener->disposing(_rEvent);
256 1539 : }
257 1539 : }
258 :
259 : // XControl
260 728 : void SAL_CALL OControl::setContext(const Reference< XInterface >& Context) throw (RuntimeException, std::exception)
261 : {
262 728 : if (m_xControl.is())
263 728 : m_xControl->setContext(Context);
264 728 : }
265 :
266 26 : Reference< XInterface > SAL_CALL OControl::getContext() throw (RuntimeException, std::exception)
267 : {
268 26 : return m_xControl.is() ? m_xControl->getContext() : Reference< XInterface >();
269 : }
270 :
271 1183 : void OControl::impl_resetStateGuard_nothrow()
272 : {
273 1183 : Reference< XWindow2 > xWindow;
274 2366 : Reference< XControlModel > xModel;
275 : try
276 : {
277 1183 : xWindow.set( getPeer(), UNO_QUERY );
278 1183 : xModel.set( getModel(), UNO_QUERY );
279 : }
280 0 : catch( const Exception& )
281 : {
282 : DBG_UNHANDLED_EXCEPTION();
283 : }
284 2366 : m_aWindowStateGuard.attach( xWindow, xModel );
285 1183 : }
286 :
287 651 : void SAL_CALL OControl::createPeer(const Reference<XToolkit>& _rxToolkit, const Reference<XWindowPeer>& _rxParent) throw (RuntimeException, std::exception)
288 : {
289 651 : if ( m_xControl.is() )
290 : {
291 651 : m_xControl->createPeer( _rxToolkit, _rxParent );
292 651 : initFormControlPeer( getPeer() );
293 651 : impl_resetStateGuard_nothrow();
294 : }
295 651 : }
296 :
297 5014 : Reference<XWindowPeer> SAL_CALL OControl::getPeer() throw ( RuntimeException, std::exception)
298 : {
299 5014 : return m_xControl.is() ? m_xControl->getPeer() : Reference<XWindowPeer>();
300 : }
301 :
302 532 : sal_Bool SAL_CALL OControl::setModel(const Reference<XControlModel>& Model) throw ( RuntimeException, std::exception)
303 : {
304 532 : if ( !m_xControl.is() )
305 0 : return sal_False;
306 :
307 532 : bool bSuccess = m_xControl->setModel( Model );
308 532 : impl_resetStateGuard_nothrow();
309 532 : return bSuccess;
310 : }
311 :
312 3733 : Reference<XControlModel> SAL_CALL OControl::getModel() throw ( RuntimeException, std::exception)
313 : {
314 3733 : return m_xControl.is() ? m_xControl->getModel() : Reference<XControlModel>();
315 : }
316 :
317 26 : Reference<XView> SAL_CALL OControl::getView() throw ( RuntimeException, std::exception)
318 : {
319 26 : return m_xControl.is() ? m_xControl->getView() : Reference<XView>();
320 : }
321 :
322 397 : void SAL_CALL OControl::setDesignMode(sal_Bool bOn) throw ( RuntimeException, std::exception)
323 : {
324 397 : if (m_xControl.is())
325 397 : m_xControl->setDesignMode(bOn);
326 397 : }
327 :
328 18976 : sal_Bool SAL_CALL OControl::isDesignMode() throw ( RuntimeException, std::exception)
329 : {
330 18976 : return m_xControl.is() ? m_xControl->isDesignMode() : sal_True;
331 : }
332 :
333 26 : sal_Bool SAL_CALL OControl::isTransparent() throw ( RuntimeException, std::exception)
334 : {
335 26 : return m_xControl.is() ? m_xControl->isTransparent() : sal_True;
336 : }
337 :
338 326 : OBoundControl::OBoundControl( const Reference< XComponentContext >& _rxContext,
339 : const OUString& _rAggregateService, const bool _bSetDelegator )
340 : :OControl( _rxContext, _rAggregateService, _bSetDelegator )
341 : ,m_bLocked(false)
342 : ,m_aOriginalFont( EmptyFontDescriptor() )
343 326 : ,m_nOriginalTextLineColor( 0 )
344 : {
345 326 : }
346 :
347 264 : OBoundControl::~OBoundControl()
348 : {
349 264 : }
350 :
351 140 : Sequence< Type> OBoundControl::_getTypes()
352 : {
353 140 : return TypeBag( OControl::_getTypes(), OBoundControl_BASE::getTypes() ).getTypes();
354 : }
355 :
356 18823 : Any SAL_CALL OBoundControl::queryAggregation(const Type& _rType) throw(RuntimeException, std::exception)
357 : {
358 18823 : Any aReturn;
359 :
360 : // XTypeProvider first - don't ask the OBoundControl_BASE, it would deliver incomplete types
361 18823 : if ( _rType.equals( cppu::UnoType<XTypeProvider>::get() ) )
362 70 : aReturn = OControl::queryAggregation( _rType );
363 :
364 : // ask our own interfaces
365 : // (do this first (except XTypeProvider ) - we want to "overwrite" XPropertiesChangeListener)
366 18823 : if ( !aReturn.hasValue() )
367 18753 : aReturn = OBoundControl_BASE::queryInterface( _rType );
368 :
369 : // ask the base class
370 18823 : if ( !aReturn.hasValue() )
371 16119 : aReturn = OControl::queryAggregation( _rType );
372 :
373 18823 : return aReturn;
374 : }
375 :
376 44 : sal_Bool SAL_CALL OBoundControl::getLock() throw(RuntimeException, std::exception)
377 : {
378 44 : return m_bLocked;
379 : }
380 :
381 44 : void SAL_CALL OBoundControl::setLock(sal_Bool _bLock) throw(RuntimeException, std::exception)
382 : {
383 44 : if ((m_bLocked ? 1 : 0) == _bLock)
384 44 : return;
385 :
386 44 : osl::MutexGuard aGuard(m_aMutex);
387 44 : _setLock(_bLock);
388 44 : m_bLocked = _bLock;
389 : }
390 :
391 44 : void OBoundControl::_setLock(bool _bLock)
392 : {
393 : // try to set the text component to readonly
394 44 : Reference< XWindowPeer > xPeer = getPeer();
395 88 : Reference< XTextComponent > xText( xPeer, UNO_QUERY );
396 :
397 44 : if ( xText.is() )
398 32 : xText->setEditable( !_bLock );
399 : else
400 : {
401 : // disable the window
402 12 : Reference< XWindow > xComp( xPeer, UNO_QUERY );
403 12 : if ( xComp.is() )
404 12 : xComp->setEnable( !_bLock );
405 44 : }
406 44 : }
407 :
408 262 : sal_Bool SAL_CALL OBoundControl::setModel( const Reference< XControlModel >& _rxModel ) throw (RuntimeException, std::exception)
409 : {
410 262 : return OControl::setModel( _rxModel );
411 : }
412 :
413 674 : void SAL_CALL OBoundControl::disposing(const EventObject& Source) throw (RuntimeException, std::exception)
414 : {
415 : // just disambiguate
416 674 : OControl::disposing(Source);
417 674 : }
418 :
419 270 : void OBoundControl::disposing()
420 : {
421 270 : OControl::disposing();
422 270 : }
423 :
424 : // OControlModel
425 64 : Sequence<sal_Int8> SAL_CALL OControlModel::getImplementationId() throw(RuntimeException, std::exception)
426 : {
427 64 : return css::uno::Sequence<sal_Int8>();
428 : }
429 :
430 172 : Sequence<Type> SAL_CALL OControlModel::getTypes() throw(RuntimeException, std::exception)
431 : {
432 172 : TypeBag aTypes( _getTypes() );
433 :
434 344 : Reference< XTypeProvider > xProv;
435 :
436 172 : if ( query_aggregation( m_xAggregate, xProv ) )
437 172 : aTypes.addTypes( xProv->getTypes() );
438 :
439 344 : return aTypes.getTypes();
440 : }
441 :
442 172 : Sequence<Type> OControlModel::_getTypes()
443 : {
444 : return TypeBag( OComponentHelper::getTypes(),
445 : OPropertySetAggregationHelper::getTypes(),
446 : OControlModel_BASE::getTypes()
447 172 : ).getTypes();
448 : }
449 :
450 211616 : Any SAL_CALL OControlModel::queryAggregation(const Type& _rType) throw (RuntimeException, std::exception)
451 : {
452 : // base class 1
453 211616 : Any aReturn(OComponentHelper::queryAggregation(_rType));
454 :
455 : // base class 2
456 211616 : if (!aReturn.hasValue())
457 : {
458 156606 : aReturn = OControlModel_BASE::queryInterface(_rType);
459 :
460 : // our own interfaces
461 156606 : if (!aReturn.hasValue())
462 : {
463 147324 : aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
464 : // our aggregate
465 147324 : if (!aReturn.hasValue() && m_xAggregate.is() && !_rType.equals(cppu::UnoType<XCloneable>::get()))
466 87017 : aReturn = m_xAggregate->queryAggregation(_rType);
467 : }
468 : }
469 211616 : return aReturn;
470 : }
471 :
472 36 : void OControlModel::readHelpTextCompatibly(const css::uno::Reference< css::io::XObjectInputStream >& _rxInStream)
473 : {
474 36 : OUString sHelpText;
475 36 : ::comphelper::operator>>( _rxInStream, sHelpText);
476 : try
477 : {
478 36 : if (m_xAggregateSet.is())
479 36 : m_xAggregateSet->setPropertyValue(PROPERTY_HELPTEXT, makeAny(sHelpText));
480 : }
481 0 : catch(const Exception&)
482 : {
483 : SAL_WARN("forms.component", "OControlModel::readHelpTextCompatibly: could not forward the property value to the aggregate!");
484 : DBG_UNHANDLED_EXCEPTION();
485 36 : }
486 36 : }
487 :
488 36 : void OControlModel::writeHelpTextCompatibly(const css::uno::Reference< css::io::XObjectOutputStream >& _rxOutStream)
489 : {
490 36 : OUString sHelpText;
491 : try
492 : {
493 36 : if (m_xAggregateSet.is())
494 36 : m_xAggregateSet->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText;
495 : }
496 0 : catch(const Exception&)
497 : {
498 : SAL_WARN("forms.component", "OControlModel::writeHelpTextCompatibly: could not retrieve the property value from the aggregate!");
499 : DBG_UNHANDLED_EXCEPTION();
500 : }
501 36 : ::comphelper::operator<<( _rxOutStream, sHelpText);
502 36 : }
503 :
504 1134 : OControlModel::OControlModel(
505 : const Reference<XComponentContext>& _rxContext,
506 : const OUString& _rUnoControlModelTypeName,
507 : const OUString& rDefault, const bool _bSetDelegator)
508 : :OComponentHelper(m_aMutex)
509 : ,OPropertySetAggregationHelper(OComponentHelper::rBHelper)
510 : ,m_xContext( _rxContext )
511 : ,m_lockCount( 0 )
512 : ,m_aPropertyBagHelper( *this )
513 : ,m_nTabIndex(FRM_DEFAULT_TABINDEX)
514 : ,m_nClassId(FormComponentType::CONTROL)
515 : ,m_bNativeLook( false )
516 : ,m_bGenerateVbEvents( false )
517 : ,m_nControlTypeinMSO(0) // 0 : default value is create from AOO
518 1134 : ,m_nObjIDinMSO(INVALID_OBJ_ID_IN_MSO)
519 : // form controls are usually embedded into documents, not dialogs, and in documents
520 : // the native look is ugly...
521 : // #i37342#
522 : {
523 1134 : if (!_rUnoControlModelTypeName.isEmpty()) // the is a model we have to aggregate
524 : {
525 868 : increment(m_refCount);
526 : {
527 868 : m_xAggregate = Reference<XAggregation>(m_xContext->getServiceManager()->createInstanceWithContext(_rUnoControlModelTypeName, m_xContext), UNO_QUERY);
528 868 : setAggregation(m_xAggregate);
529 :
530 868 : if ( m_xAggregateSet.is() )
531 : {
532 : try
533 : {
534 868 : if ( !rDefault.isEmpty() )
535 734 : m_xAggregateSet->setPropertyValue( PROPERTY_DEFAULTCONTROL, makeAny( rDefault ) );
536 : }
537 0 : catch( const Exception& )
538 : {
539 : SAL_WARN("forms.component", "OControlModel::OControlModel: caught an exception!");
540 : DBG_UNHANDLED_EXCEPTION();
541 : }
542 : }
543 : }
544 868 : if (_bSetDelegator)
545 286 : doSetDelegator();
546 :
547 : // Refcount is at NULL again
548 868 : decrement(m_refCount);
549 : }
550 1134 : }
551 :
552 44 : OControlModel::OControlModel( const OControlModel* _pOriginal, const Reference< XComponentContext>& _rxFactory, const bool _bCloneAggregate, const bool _bSetDelegator )
553 : :OComponentHelper( m_aMutex )
554 : ,OPropertySetAggregationHelper( OComponentHelper::rBHelper )
555 : ,m_xContext( _rxFactory )
556 : ,m_lockCount( 0 )
557 : ,m_aPropertyBagHelper( *this )
558 : ,m_nTabIndex( FRM_DEFAULT_TABINDEX )
559 44 : ,m_nClassId( FormComponentType::CONTROL )
560 : {
561 : DBG_ASSERT( _pOriginal, "OControlModel::OControlModel: invalid original!" );
562 :
563 : // copy members
564 44 : m_aName = _pOriginal->m_aName;
565 44 : m_aTag = _pOriginal->m_aTag;
566 44 : m_nTabIndex = _pOriginal->m_nTabIndex;
567 44 : m_nClassId = _pOriginal->m_nClassId;
568 44 : m_bNativeLook = _pOriginal->m_bNativeLook;
569 44 : m_bGenerateVbEvents = _pOriginal->m_bGenerateVbEvents;
570 44 : m_nControlTypeinMSO = _pOriginal->m_nControlTypeinMSO;
571 44 : m_nObjIDinMSO = _pOriginal->m_nObjIDinMSO;
572 :
573 44 : if ( _bCloneAggregate )
574 : {
575 : // temporarily increment refcount because of temporary references to ourself in the following
576 40 : increment( m_refCount );
577 : {
578 : // transfer the (only, at the very moment!) ref count
579 40 : m_xAggregate = createAggregateClone( _pOriginal );
580 :
581 : // set aggregation (retrieve other direct interfaces of the aggregate)
582 40 : setAggregation( m_xAggregate );
583 : }
584 :
585 : // set the delegator, if allowed by our derived class
586 40 : if ( _bSetDelegator )
587 10 : doSetDelegator();
588 :
589 : // decrement ref count
590 40 : decrement( m_refCount );
591 : }
592 44 : }
593 :
594 2224 : OControlModel::~OControlModel()
595 : {
596 : // release the aggregate
597 1112 : doResetDelegator( );
598 1112 : }
599 :
600 14 : void OControlModel::clonedFrom( const OControlModel* /*_pOriginal*/ )
601 : {
602 : // nothing to do in this base class
603 14 : }
604 :
605 1690 : void OControlModel::doResetDelegator()
606 : {
607 1690 : if (m_xAggregate.is())
608 1632 : m_xAggregate->setDelegator(NULL);
609 1690 : }
610 :
611 1120 : void OControlModel::doSetDelegator()
612 : {
613 1120 : increment(m_refCount);
614 1120 : if (m_xAggregate.is())
615 : {
616 1116 : m_xAggregate->setDelegator(static_cast<XWeak*>(this));
617 : }
618 1120 : decrement(m_refCount);
619 1120 : }
620 :
621 : // XChild
622 9106 : Reference< XInterface > SAL_CALL OControlModel::getParent() throw(RuntimeException, std::exception)
623 : {
624 9106 : return m_xParent;
625 : }
626 :
627 1748 : void SAL_CALL OControlModel::setParent(const Reference< XInterface >& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException, std::exception)
628 : {
629 1748 : osl::MutexGuard aGuard(m_aMutex);
630 :
631 3496 : Reference<XComponent> xComp(m_xParent, UNO_QUERY);
632 1748 : if (xComp.is())
633 518 : xComp->removeEventListener(static_cast<XPropertiesChangeListener*>(this));
634 :
635 1748 : m_xParent = _rxParent;
636 1748 : xComp.set(m_xParent, css::uno::UNO_QUERY);
637 :
638 1748 : if ( xComp.is() )
639 2486 : xComp->addEventListener(static_cast<XPropertiesChangeListener*>(this));
640 1748 : }
641 :
642 : // XNamed
643 376 : OUString SAL_CALL OControlModel::getName() throw(RuntimeException, std::exception)
644 : {
645 376 : OUString aReturn;
646 376 : OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME) >>= aReturn;
647 376 : return aReturn;
648 : }
649 :
650 76 : void SAL_CALL OControlModel::setName(const OUString& _rName) throw(RuntimeException, std::exception)
651 : {
652 : try
653 : {
654 76 : setFastPropertyValue(PROPERTY_ID_NAME, makeAny(_rName));
655 : }
656 0 : catch (const css::beans::UnknownPropertyException&)
657 : {
658 0 : css::uno::Any a(cppu::getCaughtException());
659 : throw WrappedTargetRuntimeException(
660 : "OControlModel::setName",
661 : *const_cast< OControlModel* >( this ),
662 : a
663 0 : );
664 : }
665 76 : }
666 :
667 : // XServiceInfo
668 582 : sal_Bool SAL_CALL OControlModel::supportsService(const OUString& _rServiceName) throw ( RuntimeException, std::exception)
669 : {
670 582 : return cppu::supportsService(this, _rServiceName);
671 : }
672 :
673 668 : Sequence< OUString > OControlModel::getAggregateServiceNames()
674 : {
675 668 : Sequence< OUString > aAggServices;
676 1336 : Reference< XServiceInfo > xInfo;
677 668 : if ( query_aggregation( m_xAggregate, xInfo ) )
678 658 : aAggServices = xInfo->getSupportedServiceNames();
679 1336 : return aAggServices;
680 : }
681 :
682 38 : Sequence<OUString> SAL_CALL OControlModel::getSupportedServiceNames() throw(RuntimeException, std::exception)
683 : {
684 : return ::comphelper::concatSequences(
685 : getAggregateServiceNames(),
686 : getSupportedServiceNames_Static()
687 38 : );
688 : }
689 :
690 838 : Sequence< OUString > SAL_CALL OControlModel::getSupportedServiceNames_Static() throw( RuntimeException )
691 : {
692 838 : Sequence< OUString > aServiceNames( 2 );
693 838 : aServiceNames[ 0 ] = FRM_SUN_FORMCOMPONENT;
694 838 : aServiceNames[ 1 ] = "com.sun.star.form.FormControlModel";
695 838 : return aServiceNames;
696 : }
697 :
698 : // XEventListener
699 526 : void SAL_CALL OControlModel::disposing(const com::sun::star::lang::EventObject& _rSource) throw (RuntimeException, std::exception)
700 : {
701 : // release the parent
702 526 : if (_rSource.Source == m_xParent)
703 : {
704 212 : osl::MutexGuard aGuard(m_aMutex);
705 212 : m_xParent = NULL;
706 : }
707 : else
708 : {
709 314 : Reference<com::sun::star::lang::XEventListener> xEvtLst;
710 314 : if (query_aggregation(m_xAggregate, xEvtLst))
711 : {
712 92 : osl::MutexGuard aGuard(m_aMutex);
713 92 : xEvtLst->disposing(_rSource);
714 314 : }
715 : }
716 526 : }
717 :
718 : // OComponentHelper
719 1114 : void OControlModel::disposing()
720 : {
721 1114 : OPropertySetAggregationHelper::disposing();
722 :
723 1114 : Reference<com::sun::star::lang::XComponent> xComp;
724 1114 : if (query_aggregation(m_xAggregate, xComp))
725 860 : xComp->dispose();
726 :
727 1114 : setParent(Reference<XFormComponent>());
728 :
729 1114 : m_aPropertyBagHelper.dispose();
730 1114 : }
731 :
732 38 : void OControlModel::writeAggregate( const Reference< XObjectOutputStream >& _rxOutStream ) const
733 : {
734 38 : Reference< XPersistObject > xPersist;
735 38 : if ( query_aggregation( m_xAggregate, xPersist ) )
736 32 : xPersist->write( _rxOutStream );
737 38 : }
738 :
739 32 : void OControlModel::readAggregate( const Reference< XObjectInputStream >& _rxInStream )
740 : {
741 32 : Reference< XPersistObject > xPersist;
742 32 : if ( query_aggregation( m_xAggregate, xPersist ) )
743 32 : xPersist->read( _rxInStream );
744 32 : }
745 :
746 42 : void SAL_CALL OControlModel::write(const Reference<css::io::XObjectOutputStream>& _rxOutStream)
747 : throw(css::io::IOException, RuntimeException, std::exception)
748 : {
749 42 : osl::MutexGuard aGuard(m_aMutex);
750 :
751 : // 1. writing the UnoControls
752 84 : Reference<css::io::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
753 42 : if ( !xMark.is() )
754 : {
755 : throw IOException(
756 : FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
757 : static_cast< ::cppu::OWeakObject* >( this )
758 0 : );
759 : }
760 :
761 42 : sal_Int32 nMark = xMark->createMark();
762 42 : sal_Int32 nLen = 0;
763 :
764 42 : _rxOutStream->writeLong(nLen);
765 :
766 42 : writeAggregate( _rxOutStream );
767 :
768 : // determining the length
769 42 : nLen = xMark->offsetToMark(nMark) - 4;
770 42 : xMark->jumpToMark(nMark);
771 42 : _rxOutStream->writeLong(nLen);
772 42 : xMark->jumpToFurthest();
773 42 : xMark->deleteMark(nMark);
774 :
775 : // 2. writing a version number
776 42 : _rxOutStream->writeShort(0x0003);
777 :
778 : // 3. writing the general properties
779 42 : ::comphelper::operator<<( _rxOutStream, m_aName);
780 42 : _rxOutStream->writeShort(m_nTabIndex);
781 84 : ::comphelper::operator<<( _rxOutStream, m_aTag); // 3rd version
782 :
783 : // IMPORTANT NOTE!
784 : // don't write any new members here: this wouldn't be compatible with older versions, as OControlModel
785 : // is a base class which is called in derived classes "read" method. So if you increment the version
786 : // and write new stuff, older office versions will read this in the _derived_ classes, which may result
787 : // in anything from data loss to crash.
788 : // EOIN!
789 42 : }
790 :
791 42 : void OControlModel::read(const Reference<css::io::XObjectInputStream>& InStream) throw (::com::sun::star::io::IOException, RuntimeException, std::exception)
792 : {
793 42 : osl::MutexGuard aGuard(m_aMutex);
794 :
795 84 : Reference<css::io::XMarkableStream> xMark(InStream, UNO_QUERY);
796 42 : if ( !xMark.is() )
797 : {
798 : throw IOException(
799 : FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
800 : static_cast< ::cppu::OWeakObject* >( this )
801 0 : );
802 : }
803 :
804 : // 1. reading the UnoControls
805 42 : sal_Int32 nLen = InStream->readLong();
806 42 : if (nLen)
807 : {
808 36 : sal_Int32 nMark = xMark->createMark();
809 :
810 : try
811 : {
812 36 : readAggregate( InStream );
813 : }
814 :
815 0 : catch( const Exception& )
816 : {
817 : DBG_UNHANDLED_EXCEPTION();
818 : }
819 :
820 36 : xMark->jumpToMark(nMark);
821 36 : InStream->skipBytes(nLen);
822 36 : xMark->deleteMark(nMark);
823 : }
824 :
825 : // 2. reading the version number
826 42 : sal_uInt16 nVersion = InStream->readShort();
827 :
828 : // 3. reading the general properties
829 42 : ::comphelper::operator>>( InStream, m_aName);
830 42 : m_nTabIndex = InStream->readShort();
831 :
832 42 : if (nVersion > 0x0002)
833 42 : ::comphelper::operator>>( InStream, m_aTag);
834 :
835 : // we had a version where we wrote the help text
836 42 : if (nVersion == 0x0004)
837 0 : readHelpTextCompatibly(InStream);
838 :
839 42 : DBG_ASSERT(nVersion < 5, "OControlModel::read : suspicious version number !");
840 : // 4 was the version where we wrote the help text
841 : // later versions shouldn't exist (see write for a detailed comment)
842 42 : }
843 :
844 16 : PropertyState OControlModel::getPropertyStateByHandle( sal_Int32 _nHandle )
845 : {
846 : // simply compare the current and the default value
847 16 : Any aCurrentValue = getPropertyDefaultByHandle( _nHandle );
848 32 : Any aDefaultValue; getFastPropertyValue( aDefaultValue, _nHandle );
849 :
850 : bool bEqual = uno_type_equalData(
851 32 : const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(),
852 32 : const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(),
853 : reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
854 : reinterpret_cast< uno_ReleaseFunc >(cpp_release)
855 48 : );
856 32 : return bEqual ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
857 : }
858 :
859 6 : void OControlModel::setPropertyToDefaultByHandle( sal_Int32 _nHandle)
860 : {
861 6 : Any aDefault = getPropertyDefaultByHandle( _nHandle );
862 :
863 12 : Any aConvertedValue, aOldValue;
864 6 : if ( convertFastPropertyValue( aConvertedValue, aOldValue, _nHandle, aDefault ) )
865 : {
866 0 : setFastPropertyValue_NoBroadcast( _nHandle, aConvertedValue );
867 : // TODO: fire the property change
868 6 : }
869 6 : }
870 :
871 0 : Any OControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
872 : {
873 0 : Any aReturn;
874 0 : switch ( _nHandle )
875 : {
876 : case PROPERTY_ID_NAME:
877 : case PROPERTY_ID_TAG:
878 0 : aReturn <<= OUString();
879 0 : break;
880 : case PROPERTY_ID_CLASSID:
881 0 : aReturn <<= (sal_Int16)FormComponentType::CONTROL;
882 0 : break;
883 : case PROPERTY_ID_TABINDEX:
884 0 : aReturn <<= (sal_Int16)FRM_DEFAULT_TABINDEX;
885 0 : break;
886 : case PROPERTY_ID_NATIVE_LOOK:
887 0 : aReturn <<= true;
888 0 : break;
889 : case PROPERTY_ID_GENERATEVBAEVENTS:
890 0 : aReturn <<= false;
891 0 : break;
892 : // added for exporting OCX control
893 : case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
894 0 : aReturn <<= (sal_Int16)0;
895 0 : break;
896 : case PROPERTY_ID_OBJ_ID_IN_MSO:
897 0 : aReturn <<= (sal_uInt16)INVALID_OBJ_ID_IN_MSO;
898 0 : break;
899 : default:
900 0 : if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
901 0 : m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( _nHandle, aReturn );
902 : else
903 : SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle);
904 : }
905 0 : return aReturn;
906 : }
907 :
908 114788 : void OControlModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
909 : {
910 114788 : switch ( _nHandle )
911 : {
912 : case PROPERTY_ID_NAME:
913 9336 : _rValue <<= m_aName;
914 9336 : break;
915 : case PROPERTY_ID_TAG:
916 2830 : _rValue <<= m_aTag;
917 2830 : break;
918 : case PROPERTY_ID_CLASSID:
919 3633 : _rValue <<= m_nClassId;
920 3633 : break;
921 : case PROPERTY_ID_TABINDEX:
922 5056 : _rValue <<= m_nTabIndex;
923 5056 : break;
924 : case PROPERTY_ID_NATIVE_LOOK:
925 2556 : _rValue <<= m_bNativeLook;
926 2556 : break;
927 : case PROPERTY_ID_GENERATEVBAEVENTS:
928 1763 : _rValue <<= m_bGenerateVbEvents;
929 : // added for exporting OCX control
930 : case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
931 4315 : _rValue <<= (sal_Int16)m_nControlTypeinMSO;
932 4315 : break;
933 : case PROPERTY_ID_OBJ_ID_IN_MSO:
934 2551 : _rValue <<= (sal_uInt16)m_nObjIDinMSO;
935 2551 : break;
936 : default:
937 84511 : if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
938 0 : m_aPropertyBagHelper.getDynamicFastPropertyValue( _nHandle, _rValue );
939 : else
940 84511 : OPropertySetAggregationHelper::getFastPropertyValue( _rValue, _nHandle );
941 84511 : break;
942 : }
943 114788 : }
944 :
945 10311 : sal_Bool OControlModel::convertFastPropertyValue(
946 : Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
947 : throw (com::sun::star::lang::IllegalArgumentException)
948 : {
949 10311 : bool bModified(false);
950 10311 : switch (_nHandle)
951 : {
952 : case PROPERTY_ID_NAME:
953 2519 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aName);
954 2517 : break;
955 : case PROPERTY_ID_TAG:
956 1594 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aTag);
957 1594 : break;
958 : case PROPERTY_ID_TABINDEX:
959 1504 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nTabIndex);
960 1504 : break;
961 : case PROPERTY_ID_NATIVE_LOOK:
962 1460 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bNativeLook);
963 1460 : break;
964 : case PROPERTY_ID_GENERATEVBAEVENTS:
965 188 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bGenerateVbEvents);
966 188 : break;
967 : // added for exporting OCX control
968 : case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
969 1528 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nControlTypeinMSO);
970 1528 : break;
971 : case PROPERTY_ID_OBJ_ID_IN_MSO:
972 1518 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nObjIDinMSO);
973 1518 : break;
974 : default:
975 0 : if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
976 0 : bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( _nHandle, _rValue, _rConvertedValue, _rOldValue );
977 : else
978 : SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle);
979 0 : break;
980 : }
981 10309 : return bModified;
982 : }
983 :
984 3101 : void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
985 : throw (Exception, std::exception)
986 : {
987 3101 : switch (_nHandle)
988 : {
989 : case PROPERTY_ID_NAME:
990 : DBG_ASSERT(_rValue.getValueType() == cppu::UnoType<OUString>::get(),
991 : "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
992 1243 : _rValue >>= m_aName;
993 1243 : break;
994 : case PROPERTY_ID_TAG:
995 : DBG_ASSERT(_rValue.getValueType() == cppu::UnoType<OUString>::get(),
996 : "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
997 384 : _rValue >>= m_aTag;
998 384 : break;
999 : case PROPERTY_ID_TABINDEX:
1000 : DBG_ASSERT(_rValue.getValueType() == getCppuType((const sal_Int16*)NULL),
1001 : "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1002 354 : _rValue >>= m_nTabIndex;
1003 354 : break;
1004 : case PROPERTY_ID_NATIVE_LOOK:
1005 286 : OSL_VERIFY( _rValue >>= m_bNativeLook );
1006 286 : break;
1007 : case PROPERTY_ID_GENERATEVBAEVENTS:
1008 136 : OSL_VERIFY( _rValue >>= m_bGenerateVbEvents );
1009 136 : break;
1010 : // added for exporting OCX control
1011 : case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
1012 354 : OSL_VERIFY( _rValue >>= m_nControlTypeinMSO );
1013 354 : break;
1014 : case PROPERTY_ID_OBJ_ID_IN_MSO:
1015 344 : OSL_VERIFY( _rValue >>= m_nObjIDinMSO );
1016 344 : break;
1017 : default:
1018 0 : if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1019 0 : m_aPropertyBagHelper.setDynamicFastPropertyValue( _nHandle, _rValue );
1020 : else
1021 : SAL_WARN("forms.component", "OControlModel::setFastPropertyValue_NoBroadcast: unknown handle " << _nHandle );
1022 0 : break;
1023 : }
1024 3101 : }
1025 :
1026 1164 : void OControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
1027 : {
1028 1164 : BEGIN_DESCRIBE_BASE_PROPERTIES( 7 )
1029 1164 : DECL_PROP2 (CLASSID, sal_Int16, READONLY, TRANSIENT);
1030 1164 : DECL_PROP1 (NAME, OUString, BOUND);
1031 1164 : DECL_BOOL_PROP2 (NATIVE_LOOK, BOUND, TRANSIENT);
1032 1164 : DECL_PROP1 (TAG, OUString, BOUND);
1033 1164 : DECL_PROP1 (GENERATEVBAEVENTS, sal_Bool, TRANSIENT);
1034 1164 : DECL_PROP1 (CONTROL_TYPE_IN_MSO,sal_Int16, BOUND);
1035 1164 : DECL_PROP1 (OBJ_ID_IN_MSO,sal_uInt16, BOUND);
1036 : END_DESCRIBE_PROPERTIES()
1037 1164 : }
1038 :
1039 1206 : void OControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ _rAggregateProps ) const
1040 : {
1041 1206 : if ( m_xAggregateSet.is() )
1042 : {
1043 1140 : Reference< XPropertySetInfo > xPSI( m_xAggregateSet->getPropertySetInfo() );
1044 1140 : if ( xPSI.is() )
1045 1140 : _rAggregateProps = xPSI->getProperties();
1046 : }
1047 1206 : }
1048 :
1049 1624 : ::osl::Mutex& OControlModel::getMutex()
1050 : {
1051 1624 : return m_aMutex;
1052 : }
1053 :
1054 1206 : void OControlModel::describeFixedAndAggregateProperties( Sequence< Property >& _out_rFixedProperties, Sequence< Property >& _out_rAggregateProperties ) const
1055 : {
1056 1206 : describeFixedProperties( _out_rFixedProperties );
1057 1206 : describeAggregateProperties( _out_rAggregateProperties );
1058 1206 : }
1059 :
1060 304 : Reference< XMultiPropertySet > OControlModel::getPropertiesInterface()
1061 : {
1062 304 : return Reference< XMultiPropertySet >( *this, UNO_QUERY );
1063 : }
1064 :
1065 41655 : Reference< XPropertySetInfo> SAL_CALL OControlModel::getPropertySetInfo() throw( RuntimeException, std::exception)
1066 : {
1067 41655 : return createPropertySetInfo( getInfoHelper() );
1068 : }
1069 :
1070 339310 : ::cppu::IPropertyArrayHelper& OControlModel::getInfoHelper()
1071 : {
1072 339310 : return m_aPropertyBagHelper.getInfoHelper();
1073 : }
1074 :
1075 152 : void SAL_CALL OControlModel::addProperty( const OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException, std::exception)
1076 : {
1077 152 : m_aPropertyBagHelper.addProperty( _rName, _nAttributes, _rInitialValue );
1078 38 : }
1079 :
1080 114 : void SAL_CALL OControlModel::removeProperty( const OUString& _rName ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException, std::exception)
1081 : {
1082 114 : m_aPropertyBagHelper.removeProperty( _rName );
1083 38 : }
1084 :
1085 38 : Sequence< PropertyValue > SAL_CALL OControlModel::getPropertyValues() throw (RuntimeException, std::exception)
1086 : {
1087 38 : return m_aPropertyBagHelper.getPropertyValues();
1088 : }
1089 :
1090 114 : void SAL_CALL OControlModel::setPropertyValues( const Sequence< PropertyValue >& _rProps ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception)
1091 : {
1092 114 : m_aPropertyBagHelper.setPropertyValues( _rProps );
1093 38 : }
1094 :
1095 2632 : void OControlModel::lockInstance( LockAccess )
1096 : {
1097 2632 : m_aMutex.acquire();
1098 2632 : osl_atomic_increment( &m_lockCount );
1099 2632 : }
1100 :
1101 2632 : oslInterlockedCount OControlModel::unlockInstance( LockAccess )
1102 : {
1103 : OSL_ENSURE( m_lockCount > 0, "OControlModel::unlockInstance: not locked!" );
1104 2632 : oslInterlockedCount lockCount = osl_atomic_decrement( &m_lockCount );
1105 2632 : m_aMutex.release();
1106 2632 : return lockCount;
1107 : }
1108 :
1109 2580 : void OControlModel::firePropertyChanges( const Sequence< sal_Int32 >& _rHandles, const Sequence< Any >& _rOldValues,
1110 : const Sequence< Any >& _rNewValues, LockAccess )
1111 : {
1112 : OPropertySetHelper::fire(
1113 : const_cast< Sequence< sal_Int32 >& >( _rHandles ).getArray(),
1114 : _rNewValues.getConstArray(),
1115 : _rOldValues.getConstArray(),
1116 : _rHandles.getLength(),
1117 : sal_False
1118 2580 : );
1119 2580 : }
1120 :
1121 : // OBoundControlModel
1122 159695 : Any SAL_CALL OBoundControlModel::queryAggregation( const Type& _rType ) throw (RuntimeException, std::exception)
1123 : {
1124 159695 : Any aReturn( OControlModel::queryAggregation(_rType) );
1125 159695 : if (!aReturn.hasValue())
1126 : {
1127 5242 : aReturn = OBoundControlModel_BASE1::queryInterface(_rType);
1128 :
1129 5242 : if ( !aReturn.hasValue() && m_bCommitable )
1130 3924 : aReturn = OBoundControlModel_COMMITTING::queryInterface( _rType );
1131 :
1132 5242 : if ( !aReturn.hasValue() && m_bSupportsExternalBinding )
1133 4352 : aReturn = OBoundControlModel_BINDING::queryInterface( _rType );
1134 :
1135 5242 : if ( !aReturn.hasValue() && m_bSupportsValidation )
1136 4086 : aReturn = OBoundControlModel_VALIDATION::queryInterface( _rType );
1137 : }
1138 159695 : return aReturn;
1139 : }
1140 :
1141 582 : OBoundControlModel::OBoundControlModel(
1142 : const Reference< XComponentContext>& _rxFactory,
1143 : const OUString& _rUnoControlModelTypeName, const OUString& _rDefault,
1144 : const bool _bCommitable, const bool _bSupportExternalBinding, const bool _bSupportsValidation )
1145 : :OControlModel( _rxFactory, _rUnoControlModelTypeName, _rDefault, false )
1146 : ,OPropertyChangeListener( m_aMutex )
1147 : ,m_xField()
1148 : ,m_xAmbientForm()
1149 : ,m_nValuePropertyAggregateHandle( -1 )
1150 : ,m_nFieldType( DataType::OTHER )
1151 : ,m_bValuePropertyMayBeVoid( false )
1152 : ,m_aResetHelper( *this, m_aMutex )
1153 : ,m_aUpdateListeners(m_aMutex)
1154 : ,m_aFormComponentListeners( m_aMutex )
1155 : ,m_bInputRequired( true )
1156 : ,m_pAggPropMultiplexer( NULL )
1157 : ,m_bFormListening( false )
1158 : ,m_bLoaded(false)
1159 : ,m_bRequired(false)
1160 : ,m_bCommitable(_bCommitable)
1161 : ,m_bSupportsExternalBinding( _bSupportExternalBinding )
1162 : ,m_bSupportsValidation( _bSupportsValidation )
1163 : ,m_bForwardValueChanges(true)
1164 : ,m_bTransferingValue( false )
1165 : ,m_bIsCurrentValueValid( true )
1166 : ,m_bBindingControlsRO( false )
1167 : ,m_bBindingControlsEnable( false )
1168 : ,m_eControlValueChangeInstigator( eOther )
1169 582 : ,m_aLabelServiceName(FRM_SUN_COMPONENT_FIXEDTEXT)
1170 : {
1171 : // start property listening at the aggregate
1172 582 : implInitAggMultiplexer( );
1173 582 : }
1174 :
1175 30 : OBoundControlModel::OBoundControlModel(
1176 : const OBoundControlModel* _pOriginal, const Reference< XComponentContext>& _rxFactory )
1177 : :OControlModel( _pOriginal, _rxFactory, true, false )
1178 : ,OPropertyChangeListener( m_aMutex )
1179 : ,m_xField()
1180 : ,m_xAmbientForm()
1181 : ,m_nValuePropertyAggregateHandle( _pOriginal->m_nValuePropertyAggregateHandle )
1182 : ,m_nFieldType( DataType::OTHER )
1183 : ,m_bValuePropertyMayBeVoid( _pOriginal->m_bValuePropertyMayBeVoid )
1184 : ,m_aResetHelper( *this, m_aMutex )
1185 : ,m_aUpdateListeners( m_aMutex )
1186 : ,m_aFormComponentListeners( m_aMutex )
1187 : ,m_xValidator( _pOriginal->m_xValidator )
1188 : ,m_bInputRequired( true )
1189 : ,m_pAggPropMultiplexer( NULL )
1190 : ,m_bFormListening( false )
1191 : ,m_bLoaded( false )
1192 : ,m_bRequired( false )
1193 : ,m_bCommitable( _pOriginal->m_bCommitable )
1194 : ,m_bSupportsExternalBinding( _pOriginal->m_bSupportsExternalBinding )
1195 : ,m_bSupportsValidation( _pOriginal->m_bSupportsValidation )
1196 : ,m_bForwardValueChanges( true )
1197 : ,m_bTransferingValue( false )
1198 : ,m_bIsCurrentValueValid( _pOriginal->m_bIsCurrentValueValid )
1199 : ,m_bBindingControlsRO( false )
1200 : ,m_bBindingControlsEnable( false )
1201 30 : ,m_eControlValueChangeInstigator( eOther )
1202 : {
1203 : // start property listening at the aggregate
1204 30 : implInitAggMultiplexer( );
1205 30 : m_aLabelServiceName = _pOriginal->m_aLabelServiceName;
1206 30 : m_sValuePropertyName = _pOriginal->m_sValuePropertyName;
1207 30 : m_nValuePropertyAggregateHandle = _pOriginal->m_nValuePropertyAggregateHandle;
1208 30 : m_bValuePropertyMayBeVoid = _pOriginal->m_bValuePropertyMayBeVoid;
1209 30 : m_aValuePropertyType = _pOriginal->m_aValuePropertyType;
1210 30 : m_aControlSource = _pOriginal->m_aControlSource;
1211 30 : m_bInputRequired = _pOriginal->m_bInputRequired;
1212 : // m_xLabelControl, though being a property, is not to be cloned, not even the reference will be transferred.
1213 : // (the former should be clear - a clone of the object we're only referencing does not make sense)
1214 : // (the second would violate the restriction for label controls that they're part of the
1215 : // same form component hierarchy - we ourself are no part, yet, so we can't have a label control)
1216 : // start listening for changes at the value property
1217 30 : implInitValuePropertyListening( );
1218 30 : }
1219 :
1220 1156 : OBoundControlModel::~OBoundControlModel()
1221 : {
1222 578 : if ( !OComponentHelper::rBHelper.bDisposed )
1223 : {
1224 0 : acquire();
1225 0 : dispose();
1226 : }
1227 :
1228 578 : doResetDelegator( );
1229 : OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::~OBoundControlModel: what about my property multiplexer?" );
1230 578 : if ( m_pAggPropMultiplexer )
1231 : {
1232 578 : m_pAggPropMultiplexer->dispose();
1233 578 : m_pAggPropMultiplexer->release();
1234 578 : m_pAggPropMultiplexer = NULL;
1235 : }
1236 578 : }
1237 :
1238 30 : void OBoundControlModel::clonedFrom( const OControlModel* _pOriginal )
1239 : {
1240 30 : const OBoundControlModel* pBoundOriginal = static_cast< const OBoundControlModel* >( _pOriginal );
1241 : // the value binding can be handled as if somebody called setValueBinding here
1242 : // By definition, bindings can be share between bindables
1243 30 : if ( pBoundOriginal && pBoundOriginal->m_xExternalBinding.is() )
1244 : {
1245 : try
1246 : {
1247 0 : setValueBinding( pBoundOriginal->m_xExternalBinding );
1248 : }
1249 :
1250 0 : catch( const Exception& )
1251 : {
1252 : DBG_UNHANDLED_EXCEPTION();
1253 : }
1254 :
1255 : }
1256 30 : }
1257 :
1258 612 : void OBoundControlModel::implInitAggMultiplexer( )
1259 : {
1260 612 : increment( m_refCount );
1261 612 : if ( m_xAggregateSet.is() )
1262 : {
1263 612 : m_pAggPropMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet, false );
1264 612 : m_pAggPropMultiplexer->acquire();
1265 : }
1266 :
1267 612 : decrement( m_refCount );
1268 612 : doSetDelegator();
1269 612 : }
1270 :
1271 594 : void OBoundControlModel::implInitValuePropertyListening( ) const
1272 : {
1273 : // start listening for changes at the value property
1274 : // There are three pre-requisites for this to be done:
1275 : // 1. We support external value bindings. In this case, the changes in the control value need to
1276 : // be propagated to the external binding immediately when they happen
1277 : // 2. We support external validation. In this case, we need to listen for changes in the value
1278 : // property, since we need to revalidate then.
1279 : // 3. We are not committable. In this case, changes in the control value need to be propagated
1280 : // to the database column immediately when they happen.
1281 594 : if ( m_bSupportsExternalBinding || m_bSupportsValidation || !m_bCommitable )
1282 : {
1283 : OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::implInitValuePropertyListening: no multiplexer!" );
1284 574 : if ( m_pAggPropMultiplexer && !m_sValuePropertyName.isEmpty() )
1285 574 : m_pAggPropMultiplexer->addProperty( m_sValuePropertyName );
1286 : }
1287 594 : }
1288 :
1289 18 : void OBoundControlModel::initOwnValueProperty( const OUString& i_rValuePropertyName )
1290 : {
1291 : OSL_PRECOND( m_sValuePropertyName.isEmpty() && -1 == m_nValuePropertyAggregateHandle,
1292 : "OBoundControlModel::initOwnValueProperty: value property is already initialized!" );
1293 : OSL_ENSURE( !i_rValuePropertyName.isEmpty(), "OBoundControlModel::initOwnValueProperty: invalid property name!" );
1294 18 : m_sValuePropertyName = i_rValuePropertyName;
1295 18 : }
1296 :
1297 564 : void OBoundControlModel::initValueProperty( const OUString& _rValuePropertyName, sal_Int32 _nValuePropertyExternalHandle )
1298 : {
1299 : OSL_PRECOND( m_sValuePropertyName.isEmpty() && -1 == m_nValuePropertyAggregateHandle,
1300 : "OBoundControlModel::initValueProperty: value property is already initialized!" );
1301 : OSL_ENSURE( !_rValuePropertyName.isEmpty(), "OBoundControlModel::initValueProperty: invalid property name!" );
1302 : OSL_ENSURE( _nValuePropertyExternalHandle != -1, "OBoundControlModel::initValueProperty: invalid property handle!" );
1303 :
1304 564 : m_sValuePropertyName = _rValuePropertyName;
1305 564 : m_nValuePropertyAggregateHandle = getOriginalHandle( _nValuePropertyExternalHandle );
1306 : OSL_ENSURE( m_nValuePropertyAggregateHandle != -1, "OBoundControlModel::initValueProperty: unable to find the original handle!" );
1307 :
1308 564 : if ( m_nValuePropertyAggregateHandle != -1 )
1309 : {
1310 564 : Reference< XPropertySetInfo > xPropInfo( m_xAggregateSet->getPropertySetInfo(), UNO_SET_THROW );
1311 1128 : Property aValuePropDesc = xPropInfo->getPropertyByName( m_sValuePropertyName );
1312 564 : m_aValuePropertyType = aValuePropDesc.Type;
1313 1128 : m_bValuePropertyMayBeVoid = ( aValuePropDesc.Attributes & PropertyAttribute::MAYBEVOID ) != 0;
1314 : }
1315 :
1316 : // start listening for changes at the value property
1317 564 : implInitValuePropertyListening( );
1318 564 : }
1319 :
1320 40 : void OBoundControlModel::suspendValueListening( )
1321 : {
1322 : OSL_PRECOND( !m_sValuePropertyName.isEmpty(), "OBoundControlModel::suspendValueListening: don't have a value property!" );
1323 : OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::suspendValueListening: I *am* not listening!" );
1324 :
1325 40 : if ( m_pAggPropMultiplexer )
1326 40 : m_pAggPropMultiplexer->lock();
1327 40 : }
1328 :
1329 40 : void OBoundControlModel::resumeValueListening( )
1330 : {
1331 : OSL_PRECOND( !m_sValuePropertyName.isEmpty(), "OBoundControlModel::resumeValueListening: don't have a value property!" );
1332 : OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::resumeValueListening: I *am* not listening at all!" );
1333 : OSL_PRECOND( !m_pAggPropMultiplexer || m_pAggPropMultiplexer->locked(), "OBoundControlModel::resumeValueListening: listening not suspended currently!" );
1334 40 : if ( m_pAggPropMultiplexer )
1335 40 : m_pAggPropMultiplexer->unlock();
1336 40 : }
1337 :
1338 128 : Sequence< Type > OBoundControlModel::_getTypes()
1339 : {
1340 : TypeBag aTypes(
1341 : OControlModel::_getTypes(),
1342 : OBoundControlModel_BASE1::getTypes()
1343 128 : );
1344 :
1345 128 : if ( m_bCommitable )
1346 88 : aTypes.addTypes( OBoundControlModel_COMMITTING::getTypes() );
1347 :
1348 128 : if ( m_bSupportsExternalBinding )
1349 128 : aTypes.addTypes( OBoundControlModel_BINDING::getTypes() );
1350 :
1351 128 : if ( m_bSupportsValidation )
1352 128 : aTypes.addTypes( OBoundControlModel_VALIDATION::getTypes() );
1353 128 : return aTypes.getTypes();
1354 : }
1355 :
1356 : // OComponentHelper
1357 580 : void OBoundControlModel::disposing()
1358 : {
1359 580 : OControlModel::disposing();
1360 :
1361 580 : ::osl::ClearableMutexGuard aGuard(m_aMutex);
1362 :
1363 580 : if ( m_pAggPropMultiplexer )
1364 580 : m_pAggPropMultiplexer->dispose();
1365 :
1366 : // notify all our listeners
1367 1160 : com::sun::star::lang::EventObject aEvt( static_cast< XWeak* >( this ) );
1368 580 : m_aUpdateListeners.disposeAndClear( aEvt );
1369 580 : m_aResetHelper.disposing();
1370 :
1371 : // disconnect from our database column
1372 : // TODO: could we replace the following 5 lines with a call to impl_disconnectDatabaseColumn_noNotify?
1373 : // The only more thing which it does is calling onDisconnectedDbColumn - could this
1374 : // cause trouble? At least when we continue to call OControlModel::disposing before, it *may*.
1375 580 : if ( hasField() )
1376 : {
1377 0 : getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
1378 0 : resetField();
1379 : }
1380 :
1381 580 : m_xCursor = NULL;
1382 1160 : Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1383 580 : if ( xComp.is() )
1384 0 : xComp->removeEventListener(static_cast< XEventListener* >( static_cast< XPropertyChangeListener* >( this ) ) );
1385 : // disconnect from our external value binding
1386 580 : if ( hasExternalValueBinding() )
1387 18 : disconnectExternalValueBinding();
1388 : // dito for the validator
1389 580 : if ( hasValidator() )
1390 616 : disconnectValidator( );
1391 580 : }
1392 :
1393 648 : void OBoundControlModel::onValuePropertyChange( ControlModelLock& i_rControLock )
1394 : {
1395 648 : if ( hasExternalValueBinding() )
1396 : {
1397 : // the control value changed, while we have an external value binding
1398 : // -> forward the value to it
1399 8 : if ( m_eControlValueChangeInstigator != eExternalBinding )
1400 0 : transferControlValueToExternal( i_rControLock );
1401 : }
1402 :
1403 640 : else if ( !m_bCommitable && m_xColumnUpdate.is() )
1404 : {
1405 : // the control value changed, while we are bound to a database column,
1406 : // but not committable (which means changes in the control have to be reflected to
1407 : // the underlying database column immediately)
1408 : // -> forward the value to the database column
1409 0 : if ( m_eControlValueChangeInstigator != eDbColumnBinding )
1410 0 : commitControlValueToDbColumn( false );
1411 : }
1412 :
1413 : // validate the new value
1414 648 : if ( m_bSupportsValidation )
1415 593 : recheckValidity( true );
1416 648 : }
1417 :
1418 638 : void OBoundControlModel::_propertyChanged( const PropertyChangeEvent& _rEvt ) throw ( RuntimeException )
1419 : {
1420 638 : ControlModelLock aLock( *this );
1421 : OSL_ENSURE( _rEvt.PropertyName == m_sValuePropertyName,
1422 : "OBoundControlModel::_propertyChanged: where did this come from (1)?" );
1423 : OSL_ENSURE( m_pAggPropMultiplexer && !m_pAggPropMultiplexer->locked(),
1424 : "OBoundControlModel::_propertyChanged: where did this come from (2)?" );
1425 638 : if ( _rEvt.PropertyName == m_sValuePropertyName )
1426 : {
1427 638 : onValuePropertyChange( aLock );
1428 638 : }
1429 638 : }
1430 :
1431 128 : void OBoundControlModel::startAggregatePropertyListening( const OUString& _rPropertyName )
1432 : {
1433 : OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::startAggregatePropertyListening: no multiplexer!" );
1434 : OSL_ENSURE( !_rPropertyName.isEmpty(), "OBoundControlModel::startAggregatePropertyListening: invalid property name!" );
1435 128 : if ( m_pAggPropMultiplexer && !_rPropertyName.isEmpty() )
1436 : {
1437 128 : m_pAggPropMultiplexer->addProperty( _rPropertyName );
1438 : }
1439 128 : }
1440 :
1441 1016 : void OBoundControlModel::doFormListening( const bool _bStart )
1442 : {
1443 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::doFormListening: external value binding should overrule the database binding!" );
1444 1016 : if ( isFormListening() == _bStart )
1445 1016 : return;
1446 1016 : if ( m_xAmbientForm.is() )
1447 722 : _bStart ? m_xAmbientForm->addLoadListener( this ) : m_xAmbientForm->removeLoadListener( this );
1448 1016 : Reference< XLoadable > xParentLoadable( getParent(), UNO_QUERY );
1449 1016 : if ( getParent().is() && !xParentLoadable.is() )
1450 : {
1451 : // if our parent does not directly support the XLoadable interface, then it might support the
1452 : // XRowSetSupplier/XRowSetChangeBroadcaster interfaces. In this case we have to listen for changes
1453 : // broadcasted by the latter.
1454 162 : Reference< XRowSetChangeBroadcaster > xRowSetBroadcaster( getParent(), UNO_QUERY );
1455 162 : if ( xRowSetBroadcaster.is() )
1456 162 : _bStart ? xRowSetBroadcaster->addRowSetChangeListener( this ) : xRowSetBroadcaster->removeRowSetChangeListener( this );
1457 : }
1458 :
1459 1016 : m_bFormListening = _bStart && m_xAmbientForm.is();
1460 : }
1461 :
1462 : // XChild
1463 1254 : void SAL_CALL OBoundControlModel::setParent(const Reference<XInterface>& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException, std::exception)
1464 : {
1465 1254 : ControlModelLock aLock( *this );
1466 1928 : FieldChangeNotifier aBoundFieldNotifier( aLock );
1467 1254 : if ( getParent() == _rxParent )
1468 1834 : return;
1469 : // disconnect from database column (which is controlled by parent, directly or indirectly)
1470 674 : if ( hasField() )
1471 0 : impl_disconnectDatabaseColumn_noNotify();
1472 : // log off old listeners
1473 674 : if ( isFormListening() )
1474 250 : doFormListening( false );
1475 : // actually set the new parent
1476 674 : OControlModel::setParent( _rxParent );
1477 : // a new parent means a new ambient form
1478 674 : impl_determineAmbientForm_nothrow();
1479 674 : if ( !hasExternalValueBinding() )
1480 : {
1481 : // log on new listeners
1482 658 : doFormListening( true );
1483 : // re-connect to database column of the new parent
1484 658 : if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
1485 62 : impl_connectDatabaseColumn_noNotify( false );
1486 674 : }
1487 : }
1488 :
1489 : // XEventListener
1490 390 : void SAL_CALL OBoundControlModel::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException, std::exception)
1491 : {
1492 390 : ControlModelLock aLock( *this );
1493 390 : if ( _rEvent.Source == getField() )
1494 : {
1495 62 : resetField();
1496 : }
1497 :
1498 328 : else if ( _rEvent.Source == m_xLabelControl )
1499 : {
1500 0 : Reference<XPropertySet> xOldValue = m_xLabelControl;
1501 0 : m_xLabelControl = NULL;
1502 : // fire a propertyChanged (when we leave aLock's scope)
1503 0 : aLock.addPropertyNotification( PROPERTY_ID_CONTROLLABEL, makeAny( xOldValue ), makeAny( m_xLabelControl ) );
1504 : }
1505 :
1506 328 : else if ( _rEvent.Source == m_xExternalBinding )
1507 : { // *first* check for the external binding
1508 0 : disconnectExternalValueBinding( );
1509 : }
1510 :
1511 328 : else if ( _rEvent.Source == m_xValidator )
1512 : { // *then* check for the validator. Reason is that bindings may also act as validator at the same
1513 : // time, in this case, the validator is automatically revoked when the binding is revoked
1514 0 : disconnectValidator( );
1515 : }
1516 :
1517 : else
1518 328 : OControlModel::disposing(_rEvent);
1519 390 : }
1520 :
1521 : // XServiceInfo
1522 504 : StringSequence SAL_CALL OBoundControlModel::getSupportedServiceNames() throw(RuntimeException, std::exception)
1523 : {
1524 : return ::comphelper::concatSequences(
1525 : getAggregateServiceNames(),
1526 : getSupportedServiceNames_Static()
1527 504 : );
1528 : }
1529 :
1530 504 : Sequence< OUString > SAL_CALL OBoundControlModel::getSupportedServiceNames_Static() throw( RuntimeException )
1531 : {
1532 504 : Sequence< OUString > aOwnServiceNames( 1 );
1533 504 : aOwnServiceNames[ 0 ] = "com.sun.star.form.DataAwareControlModel";
1534 : return ::comphelper::concatSequences(
1535 : OControlModel::getSupportedServiceNames_Static(),
1536 : aOwnServiceNames
1537 504 : );
1538 : }
1539 :
1540 : // XPersist
1541 30 : void SAL_CALL OBoundControlModel::write( const Reference<css::io::XObjectOutputStream>& _rxOutStream ) throw(css::io::IOException, RuntimeException, std::exception)
1542 : {
1543 30 : OControlModel::write(_rxOutStream);
1544 30 : osl::MutexGuard aGuard(m_aMutex);
1545 : // Version
1546 30 : _rxOutStream->writeShort(0x0002);
1547 : // Controlsource
1548 30 : ::comphelper::operator<<( _rxOutStream, m_aControlSource);
1549 : // !!! IMPORTANT NOTE !!!
1550 : // don't write any new members here: this wouldn't be compatible with older versions, as OBoundControlModel
1551 : // is a base class which is called in derived classes "read" method. So if you increment the version
1552 : // and write new stuff, older office versions will read this in the _derived_ classes, which may result
1553 : // in anything from data loss to crash.
1554 : // (use writeCommonProperties instead, this is called in derived classes write-method)
1555 : // !!! EOIN !!!
1556 30 : }
1557 :
1558 0 : void OBoundControlModel::defaultCommonProperties()
1559 : {
1560 0 : Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1561 0 : if (xComp.is())
1562 0 : xComp->removeEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1563 0 : m_xLabelControl = NULL;
1564 0 : }
1565 :
1566 26 : void OBoundControlModel::readCommonProperties(const Reference<css::io::XObjectInputStream>& _rxInStream)
1567 : {
1568 26 : sal_Int32 nLen = _rxInStream->readLong();
1569 26 : Reference<css::io::XMarkableStream> xMark(_rxInStream, UNO_QUERY);
1570 : DBG_ASSERT(xMark.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !");
1571 26 : sal_Int32 nMark = xMark->createMark();
1572 : // read the reference to the label control
1573 52 : Reference<css::io::XPersistObject> xPersist;
1574 : sal_Int32 nUsedFlag;
1575 26 : nUsedFlag = _rxInStream->readLong();
1576 26 : if (nUsedFlag)
1577 0 : xPersist = _rxInStream->readObject();
1578 26 : m_xLabelControl.set(xPersist, css::uno::UNO_QUERY);
1579 52 : Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1580 26 : if (xComp.is())
1581 0 : xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1582 : // read any other new common properties here
1583 : // skip the remaining bytes
1584 26 : xMark->jumpToMark(nMark);
1585 26 : _rxInStream->skipBytes(nLen);
1586 52 : xMark->deleteMark(nMark);
1587 26 : }
1588 :
1589 26 : void OBoundControlModel::writeCommonProperties(const Reference<css::io::XObjectOutputStream>& _rxOutStream)
1590 : {
1591 26 : Reference<css::io::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
1592 : DBG_ASSERT(xMark.is(), "OBoundControlModel::writeCommonProperties : can only work with markable streams !");
1593 26 : sal_Int32 nMark = xMark->createMark();
1594 : // a placeholder where we will write the overall length (later in this method)
1595 26 : sal_Int32 nLen = 0;
1596 26 : _rxOutStream->writeLong(nLen);
1597 : // write the reference to the label control
1598 52 : Reference<css::io::XPersistObject> xPersist(m_xLabelControl, UNO_QUERY);
1599 26 : sal_Int32 nUsedFlag = 0;
1600 26 : if (xPersist.is())
1601 0 : nUsedFlag = 1;
1602 26 : _rxOutStream->writeLong(nUsedFlag);
1603 26 : if (xPersist.is())
1604 0 : _rxOutStream->writeObject(xPersist);
1605 : // write any other new common properties here
1606 : // write the correct length at the beginning of the block
1607 26 : nLen = xMark->offsetToMark(nMark) - sizeof(nLen);
1608 26 : xMark->jumpToMark(nMark);
1609 26 : _rxOutStream->writeLong(nLen);
1610 26 : xMark->jumpToFurthest();
1611 52 : xMark->deleteMark(nMark);
1612 26 : }
1613 :
1614 30 : void SAL_CALL OBoundControlModel::read( const Reference< css::io::XObjectInputStream >& _rxInStream ) throw(css::io::IOException, RuntimeException, std::exception)
1615 : {
1616 30 : OControlModel::read(_rxInStream);
1617 30 : osl::MutexGuard aGuard(m_aMutex);
1618 30 : sal_uInt16 nVersion = _rxInStream->readShort(); (void)nVersion;
1619 30 : ::comphelper::operator>>( _rxInStream, m_aControlSource);
1620 30 : }
1621 :
1622 107822 : void OBoundControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
1623 : {
1624 107822 : switch (nHandle)
1625 : {
1626 : case PROPERTY_ID_INPUT_REQUIRED:
1627 1920 : rValue <<= m_bInputRequired;
1628 1920 : break;
1629 : case PROPERTY_ID_CONTROLSOURCEPROPERTY:
1630 3742 : rValue <<= m_sValuePropertyName;
1631 3742 : break;
1632 : case PROPERTY_ID_CONTROLSOURCE:
1633 2270 : rValue <<= m_aControlSource;
1634 2270 : break;
1635 : case PROPERTY_ID_BOUNDFIELD:
1636 809 : rValue <<= getField();
1637 809 : break;
1638 : case PROPERTY_ID_CONTROLLABEL:
1639 652 : if (!m_xLabelControl.is())
1640 652 : rValue.clear();
1641 : else
1642 0 : rValue <<= m_xLabelControl;
1643 652 : break;
1644 : default:
1645 98429 : OControlModel::getFastPropertyValue(rValue, nHandle);
1646 : }
1647 107822 : }
1648 :
1649 10782 : sal_Bool OBoundControlModel::convertFastPropertyValue(
1650 : Any& _rConvertedValue, Any& _rOldValue,
1651 : sal_Int32 _nHandle,
1652 : const Any& _rValue)
1653 : throw (com::sun::star::lang::IllegalArgumentException)
1654 : {
1655 10782 : bool bModified(false);
1656 10782 : switch (_nHandle)
1657 : {
1658 : case PROPERTY_ID_INPUT_REQUIRED:
1659 1136 : bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, m_bInputRequired );
1660 1136 : break;
1661 : case PROPERTY_ID_CONTROLSOURCE:
1662 1319 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aControlSource);
1663 1319 : break;
1664 : case PROPERTY_ID_BOUNDFIELD:
1665 : SAL_WARN("forms.component", "OBoundControlModel::convertFastPropertyValue: BoundField should be a read-only property !" );
1666 0 : throw com::sun::star::lang::IllegalArgumentException();
1667 : case PROPERTY_ID_CONTROLLABEL:
1668 0 : if (!_rValue.hasValue())
1669 : { // property set to void
1670 0 : _rConvertedValue = Any();
1671 0 : getFastPropertyValue(_rOldValue, _nHandle);
1672 0 : bModified = m_xLabelControl.is();
1673 : }
1674 :
1675 : else
1676 : {
1677 0 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_xLabelControl);
1678 0 : if (!m_xLabelControl.is())
1679 : // an empty interface is interpreted as VOID
1680 0 : _rOldValue.clear();
1681 : }
1682 :
1683 0 : break;
1684 : default:
1685 8327 : bModified = OControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
1686 : }
1687 10782 : return bModified;
1688 : }
1689 :
1690 4 : Any OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
1691 : {
1692 4 : Any aDefault;
1693 4 : switch ( _nHandle )
1694 : {
1695 : case PROPERTY_ID_INPUT_REQUIRED:
1696 0 : aDefault <<= true;
1697 0 : break;
1698 : case PROPERTY_ID_CONTROLSOURCE:
1699 0 : aDefault <<= OUString();
1700 0 : break;
1701 : case PROPERTY_ID_CONTROLLABEL:
1702 0 : aDefault <<= Reference< XPropertySet >();
1703 0 : break;
1704 : }
1705 4 : return aDefault;
1706 : }
1707 :
1708 2688 : void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception, std::exception)
1709 : {
1710 2688 : switch (nHandle)
1711 : {
1712 : case PROPERTY_ID_INPUT_REQUIRED:
1713 196 : OSL_VERIFY( rValue >>= m_bInputRequired );
1714 196 : break;
1715 : case PROPERTY_ID_CONTROLSOURCE:
1716 377 : OSL_VERIFY( rValue >>= m_aControlSource );
1717 377 : break;
1718 : case PROPERTY_ID_BOUNDFIELD:
1719 : SAL_WARN("forms.component", "OBoundControlModel::setFastPropertyValue_NoBroadcast : BoundField should be a read-only property !");
1720 0 : throw com::sun::star::lang::IllegalArgumentException();
1721 : case PROPERTY_ID_CONTROLLABEL:
1722 : {
1723 0 : if ( rValue.hasValue() && ( rValue.getValueTypeClass() != TypeClass_INTERFACE ) )
1724 0 : throw com::sun::star::lang::IllegalArgumentException();
1725 0 : Reference< XInterface > xNewValue( rValue, UNO_QUERY );
1726 0 : if ( !xNewValue.is() )
1727 : { // set property to "void"
1728 0 : Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1729 0 : if ( xComp.is() )
1730 0 : xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
1731 0 : m_xLabelControl = NULL;
1732 0 : break;
1733 : }
1734 :
1735 0 : Reference< XControlModel > xAsModel ( xNewValue, UNO_QUERY );
1736 0 : Reference< XServiceInfo > xAsServiceInfo ( xAsModel, UNO_QUERY );
1737 0 : Reference< XPropertySet > xAsPropSet ( xAsServiceInfo, UNO_QUERY );
1738 0 : Reference< XChild > xAsChild ( xAsPropSet, UNO_QUERY );
1739 0 : if ( !xAsChild.is() || !xAsServiceInfo->supportsService( m_aLabelServiceName ) )
1740 : {
1741 0 : throw com::sun::star::lang::IllegalArgumentException();
1742 : }
1743 :
1744 : // Check if we and the given model have a common ancestor (up to the forms collection)
1745 0 : Reference<XChild> xCont;
1746 0 : query_interface(static_cast<XWeak*>(this), xCont);
1747 0 : Reference< XInterface > xMyTopLevel = xCont->getParent();
1748 0 : while (xMyTopLevel.is())
1749 : {
1750 0 : Reference<XForm> xAsForm(xMyTopLevel, UNO_QUERY);
1751 0 : if (!xAsForm.is())
1752 : // found my root
1753 0 : break;
1754 0 : Reference<XChild> xLoopAsChild(xMyTopLevel, UNO_QUERY);
1755 0 : xMyTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1756 0 : }
1757 :
1758 0 : Reference< XInterface > xNewTopLevel = xAsChild->getParent();
1759 0 : while (xNewTopLevel.is())
1760 : {
1761 0 : Reference<XForm> xAsForm(xNewTopLevel, UNO_QUERY);
1762 0 : if (!xAsForm.is())
1763 0 : break;
1764 0 : Reference<XChild> xLoopAsChild(xNewTopLevel, UNO_QUERY);
1765 0 : xNewTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1766 0 : }
1767 :
1768 0 : if (xNewTopLevel != xMyTopLevel)
1769 : {
1770 : // the both objects don't belong to the same forms collection -> not acceptable
1771 0 : throw com::sun::star::lang::IllegalArgumentException();
1772 : }
1773 :
1774 0 : m_xLabelControl = xAsPropSet;
1775 0 : Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1776 0 : if (xComp.is())
1777 0 : xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1778 : }
1779 :
1780 0 : break;
1781 : default:
1782 2115 : OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue );
1783 : }
1784 2688 : }
1785 :
1786 : // XPropertyChangeListener
1787 0 : void SAL_CALL OBoundControlModel::propertyChange( const PropertyChangeEvent& evt ) throw(RuntimeException, std::exception)
1788 : {
1789 : // if the DBColumn value changed, transfer it to the control
1790 0 : if ( evt.PropertyName.equals( PROPERTY_VALUE ) )
1791 : {
1792 : OSL_ENSURE( evt.Source == getField(), "OBoundControlModel::propertyChange: value changes from components other than our database column?" );
1793 0 : osl::MutexGuard aGuard(m_aMutex);
1794 0 : if ( m_bForwardValueChanges && m_xColumn.is() )
1795 0 : transferDbValueToControl();
1796 : }
1797 :
1798 : else
1799 : {
1800 : OSL_ENSURE( evt.Source == m_xExternalBinding, "OBoundControlModel::propertyChange: where did this come from?" );
1801 : // our binding has properties which can control properties of ourself
1802 0 : OUString sBindingControlledProperty;
1803 0 : bool bForwardToLabelControl = false;
1804 0 : if ( evt.PropertyName.equals( PROPERTY_READONLY ) )
1805 : {
1806 0 : sBindingControlledProperty = PROPERTY_READONLY;
1807 : }
1808 :
1809 0 : else if ( evt.PropertyName.equals( PROPERTY_RELEVANT ) )
1810 : {
1811 0 : sBindingControlledProperty = PROPERTY_ENABLED;
1812 0 : bForwardToLabelControl = true;
1813 : }
1814 :
1815 : else
1816 0 : return;
1817 : try
1818 : {
1819 0 : setPropertyValue( sBindingControlledProperty, evt.NewValue );
1820 0 : if ( bForwardToLabelControl && m_xLabelControl.is() )
1821 0 : m_xLabelControl->setPropertyValue( sBindingControlledProperty, evt.NewValue );
1822 : }
1823 :
1824 0 : catch( const Exception& )
1825 : {
1826 : SAL_WARN("forms.component", "OBoundControlModel::propertyChange: could not adjust my binding-controlled property!");
1827 : DBG_UNHANDLED_EXCEPTION();
1828 0 : }
1829 :
1830 : }
1831 : }
1832 :
1833 20 : void SAL_CALL OBoundControlModel::onRowSetChanged( const EventObject& /*i_Event*/ ) throw (RuntimeException, std::exception)
1834 : {
1835 20 : ControlModelLock aLock( *this );
1836 40 : FieldChangeNotifier aBoundFieldNotifier( aLock );
1837 : // disconnect from database column (which is controlled by parent, directly or indirectly)
1838 20 : if ( hasField() )
1839 0 : impl_disconnectDatabaseColumn_noNotify();
1840 : // log off old listeners
1841 20 : if ( isFormListening() )
1842 20 : doFormListening( false );
1843 : // determine the new ambient form
1844 20 : impl_determineAmbientForm_nothrow();
1845 : // log on new listeners
1846 20 : doFormListening( true );
1847 : // re-connect to database column if needed and possible
1848 20 : if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
1849 20 : impl_connectDatabaseColumn_noNotify( false );
1850 20 : }
1851 :
1852 : // XBoundComponent
1853 0 : void SAL_CALL OBoundControlModel::addUpdateListener(const Reference<XUpdateListener>& _rxListener) throw(RuntimeException, std::exception)
1854 : {
1855 0 : m_aUpdateListeners.addInterface(_rxListener);
1856 0 : }
1857 :
1858 0 : void SAL_CALL OBoundControlModel::removeUpdateListener(const Reference< XUpdateListener>& _rxListener) throw(RuntimeException, std::exception)
1859 : {
1860 0 : m_aUpdateListeners.removeInterface(_rxListener);
1861 0 : }
1862 :
1863 16 : sal_Bool SAL_CALL OBoundControlModel::commit() throw(RuntimeException, std::exception)
1864 : {
1865 16 : ControlModelLock aLock( *this );
1866 : OSL_PRECOND( m_bCommitable, "OBoundControlModel::commit: invalid call (I'm not commitable !) " );
1867 16 : if ( hasExternalValueBinding() )
1868 : {
1869 : // in most cases, no action is required: For most derivees, we know the value property of
1870 : // our control (see initValueProperty), and when an external binding is active, we
1871 : // instantly forward all changes in this property to the external binding.
1872 0 : if ( m_sValuePropertyName.isEmpty() )
1873 : // but for those derivees which did not use this feature, we need an
1874 : // explicit transfer
1875 0 : transferControlValueToExternal( aLock );
1876 0 : return sal_True;
1877 : }
1878 :
1879 : OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" );
1880 : // we reach this only if we're not working with an external binding
1881 16 : if ( !hasField() )
1882 16 : return sal_True;
1883 0 : ::cppu::OInterfaceIteratorHelper aIter( m_aUpdateListeners );
1884 0 : EventObject aEvent;
1885 0 : aEvent.Source = static_cast< XWeak* >( this );
1886 0 : bool bSuccess = true;
1887 0 : aLock.release();
1888 : // UNSAFE >
1889 0 : while (aIter.hasMoreElements() && bSuccess)
1890 0 : bSuccess = static_cast< XUpdateListener* >( aIter.next() )->approveUpdate( aEvent );
1891 : // < UNSAFE
1892 0 : aLock.acquire();
1893 0 : if ( bSuccess )
1894 : {
1895 : try
1896 : {
1897 0 : if ( m_xColumnUpdate.is() )
1898 0 : bSuccess = commitControlValueToDbColumn( false );
1899 : }
1900 :
1901 0 : catch(const Exception&)
1902 : {
1903 0 : bSuccess = false;
1904 : }
1905 :
1906 : }
1907 :
1908 0 : if ( bSuccess )
1909 : {
1910 0 : aLock.release();
1911 0 : m_aUpdateListeners.notifyEach( &XUpdateListener::updated, aEvent );
1912 : }
1913 16 : return bSuccess;
1914 : }
1915 :
1916 62 : void OBoundControlModel::resetField()
1917 : {
1918 62 : m_xColumnUpdate.clear();
1919 62 : m_xColumn.clear();
1920 62 : m_xField.clear();
1921 62 : m_nFieldType = DataType::OTHER;
1922 62 : }
1923 :
1924 62 : bool OBoundControlModel::connectToField(const Reference<XRowSet>& rForm)
1925 : {
1926 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::connectToField: invalid call (have an external binding)!" );
1927 : // if there's a connection to the database
1928 62 : if (rForm.is() && getConnection(rForm).is())
1929 : {
1930 : // determine field and PropertyChangeListener
1931 62 : m_xCursor = rForm;
1932 62 : Reference<XPropertySet> xFieldCandidate;
1933 62 : if (m_xCursor.is())
1934 : {
1935 62 : Reference<XColumnsSupplier> xColumnsSupplier(m_xCursor, UNO_QUERY);
1936 : DBG_ASSERT(xColumnsSupplier.is(), "OBoundControlModel::connectToField : the row set should support the com::sun::star::sdb::ResultSet service !");
1937 62 : if (xColumnsSupplier.is())
1938 : {
1939 62 : Reference<XNameAccess> xColumns(xColumnsSupplier->getColumns(), UNO_QUERY);
1940 62 : if (xColumns.is() && xColumns->hasByName(m_aControlSource))
1941 : {
1942 62 : OSL_VERIFY( xColumns->getByName(m_aControlSource) >>= xFieldCandidate );
1943 62 : }
1944 :
1945 62 : }
1946 :
1947 : }
1948 :
1949 : try
1950 : {
1951 62 : sal_Int32 nFieldType = DataType::OTHER;
1952 62 : if ( xFieldCandidate.is() )
1953 : {
1954 62 : xFieldCandidate->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
1955 62 : if ( approveDbColumnType( nFieldType ) )
1956 62 : impl_setField_noNotify( xFieldCandidate );
1957 : }
1958 :
1959 : else
1960 0 : impl_setField_noNotify( NULL );
1961 62 : if ( m_xField.is() )
1962 : {
1963 62 : if ( m_xField->getPropertySetInfo()->hasPropertyByName( PROPERTY_VALUE ) )
1964 : {
1965 62 : m_nFieldType = nFieldType;
1966 : // listen to changing values
1967 62 : m_xField->addPropertyChangeListener( PROPERTY_VALUE, this );
1968 62 : m_xColumnUpdate = Reference< XColumnUpdate >( m_xField, UNO_QUERY );
1969 62 : m_xColumn = Reference< XColumn >( m_xField, UNO_QUERY );
1970 62 : sal_Int32 nNullableFlag = ColumnValue::NO_NULLS;
1971 62 : m_xField->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullableFlag;
1972 62 : m_bRequired = (ColumnValue::NO_NULLS == nNullableFlag);
1973 : // we're optimistic: in case of ColumnValue_NULLABLE_UNKNOWN we assume nullability...
1974 : }
1975 :
1976 : else
1977 : {
1978 : SAL_WARN("forms.component", "OBoundControlModel::connectToField: property " PROPERTY_VALUE " not supported!");
1979 0 : impl_setField_noNotify( NULL );
1980 : }
1981 :
1982 : }
1983 :
1984 : }
1985 :
1986 0 : catch( const Exception& )
1987 : {
1988 : DBG_UNHANDLED_EXCEPTION();
1989 0 : resetField();
1990 62 : }
1991 :
1992 : }
1993 62 : return hasField();
1994 : }
1995 :
1996 62 : void OBoundControlModel::initFromField( const Reference< XRowSet >& _rxRowSet )
1997 : {
1998 : // but only if the rowset if posisitioned on a valid record
1999 62 : if ( hasField() && _rxRowSet.is() )
2000 : {
2001 62 : if ( !_rxRowSet->isBeforeFirst() && !_rxRowSet->isAfterLast() )
2002 62 : transferDbValueToControl();
2003 : else
2004 : // reset the field if the row set is empty
2005 : // #i30661#
2006 0 : resetNoBroadcast();
2007 : }
2008 62 : }
2009 :
2010 62 : bool OBoundControlModel::approveDbColumnType(sal_Int32 _nColumnType)
2011 : {
2012 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::approveDbColumnType: invalid call (have an external binding)!" );
2013 62 : if ((_nColumnType == DataType::BINARY) || (_nColumnType == DataType::VARBINARY)
2014 62 : || (_nColumnType == DataType::LONGVARBINARY) || (_nColumnType == DataType::OTHER)
2015 62 : || (_nColumnType == DataType::OBJECT) || (_nColumnType == DataType::DISTINCT)
2016 62 : || (_nColumnType == DataType::STRUCT) || (_nColumnType == DataType::ARRAY)
2017 62 : || (_nColumnType == DataType::BLOB) /*|| (_nColumnType == DataType::CLOB)*/
2018 62 : || (_nColumnType == DataType::REF) || (_nColumnType == DataType::SQLNULL))
2019 0 : return false;
2020 62 : return true;
2021 : }
2022 :
2023 694 : void OBoundControlModel::impl_determineAmbientForm_nothrow()
2024 : {
2025 694 : Reference< XInterface > xParent( const_cast< OBoundControlModel* >( this )->getParent() );
2026 694 : m_xAmbientForm.set( xParent, UNO_QUERY );
2027 694 : if ( !m_xAmbientForm.is() )
2028 : {
2029 396 : Reference< XRowSetSupplier > xSupRowSet( xParent, UNO_QUERY );
2030 396 : if ( xSupRowSet.is() )
2031 126 : m_xAmbientForm.set( xSupRowSet->getRowSet(), UNO_QUERY );
2032 694 : }
2033 694 : }
2034 :
2035 62 : void OBoundControlModel::impl_connectDatabaseColumn_noNotify( bool _bFromReload )
2036 : {
2037 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2038 : // consistency checks
2039 : DBG_ASSERT( !( hasField() && !_bFromReload ),
2040 : "OBoundControlModel::impl_connectDatabaseColumn_noNotify: the form is just *loaded*, but we already have a field!" );
2041 : (void)_bFromReload;
2042 62 : Reference< XRowSet > xRowSet( m_xAmbientForm, UNO_QUERY );
2043 : OSL_ENSURE( xRowSet.is(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: no row set!" );
2044 62 : if ( !xRowSet.is() )
2045 62 : return;
2046 62 : if ( !hasField() )
2047 : {
2048 : // connect to the column
2049 62 : connectToField( xRowSet );
2050 : }
2051 :
2052 : // now that we're connected (more or less, even if we did not find a column),
2053 : // we definitely want to forward any potentially occurring value changes
2054 62 : m_bForwardValueChanges = true;
2055 : // let derived classes react on this new connection
2056 62 : m_bLoaded = true;
2057 62 : onConnectedDbColumn( xRowSet );
2058 : // initially transfer the db column value to the control, if we successfully connected to a database column
2059 62 : if ( hasField() )
2060 62 : initFromField( xRowSet );
2061 : }
2062 :
2063 62 : void OBoundControlModel::impl_disconnectDatabaseColumn_noNotify()
2064 : {
2065 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_disconnectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2066 : // let derived classes react on this
2067 62 : onDisconnectedDbColumn();
2068 62 : if ( hasField() )
2069 : {
2070 0 : getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
2071 0 : resetField();
2072 : }
2073 :
2074 62 : m_xCursor = NULL;
2075 62 : m_bLoaded = false;
2076 62 : }
2077 :
2078 : // XLoadListener
2079 0 : void SAL_CALL OBoundControlModel::loaded( const EventObject& _rEvent ) throw(RuntimeException, std::exception)
2080 : {
2081 0 : ControlModelLock aLock( *this );
2082 0 : FieldChangeNotifier aBoundFieldNotifier( aLock );
2083 : OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::loaded: where does this come from?" );
2084 : (void)_rEvent;
2085 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::loaded: we should never reach this with an external value binding!" );
2086 0 : if ( hasExternalValueBinding() )
2087 0 : return;
2088 0 : impl_connectDatabaseColumn_noNotify( false );
2089 : }
2090 :
2091 62 : void SAL_CALL OBoundControlModel::unloaded( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException, std::exception)
2092 : {
2093 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloaded: we should never reach this with an external value binding!" );
2094 62 : }
2095 :
2096 0 : void SAL_CALL OBoundControlModel::reloading( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException, std::exception)
2097 : {
2098 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloading: we should never reach this with an external value binding!" );
2099 0 : if ( hasExternalValueBinding() )
2100 0 : return;
2101 0 : osl::MutexGuard aGuard(m_aMutex);
2102 0 : m_bForwardValueChanges = false;
2103 : }
2104 :
2105 62 : void SAL_CALL OBoundControlModel::unloading(const com::sun::star::lang::EventObject& /*aEvent*/) throw(RuntimeException, std::exception)
2106 : {
2107 62 : ControlModelLock aLock( *this );
2108 124 : FieldChangeNotifier aBoundFieldNotifier( aLock );
2109 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloading: we should never reach this with an external value binding!" );
2110 62 : if ( hasExternalValueBinding() )
2111 62 : return;
2112 124 : impl_disconnectDatabaseColumn_noNotify();
2113 : }
2114 :
2115 0 : void SAL_CALL OBoundControlModel::reloaded( const EventObject& _rEvent ) throw(RuntimeException, std::exception)
2116 : {
2117 0 : ControlModelLock aLock( *this );
2118 0 : FieldChangeNotifier aBoundFieldNotifier( aLock );
2119 : OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::reloaded: where does this come from?" );
2120 : (void)_rEvent;
2121 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloaded: we should never reach this with an external value binding!" );
2122 0 : if ( hasExternalValueBinding() )
2123 0 : return;
2124 0 : impl_connectDatabaseColumn_noNotify( true );
2125 : }
2126 :
2127 466 : void OBoundControlModel::setControlValue( const Any& _rValue, ValueChangeInstigator _eInstigator )
2128 : {
2129 466 : m_eControlValueChangeInstigator = _eInstigator;
2130 466 : doSetControlValue( _rValue );
2131 466 : m_eControlValueChangeInstigator = eOther;
2132 466 : }
2133 :
2134 454 : void OBoundControlModel::doSetControlValue( const Any& _rValue )
2135 : {
2136 : OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2137 : "OBoundControlModel::doSetControlValue: invalid aggregate !" );
2138 : OSL_PRECOND( !m_sValuePropertyName.isEmpty() || ( m_nValuePropertyAggregateHandle != -1 ),
2139 : "OBoundControlModel::doSetControlValue: please override if you have own value property handling!" );
2140 : try
2141 : {
2142 : // release our mutex once (it's acquired in one of the calling methods), as setting aggregate properties
2143 : // may cause any uno controls belonging to us to lock the solar mutex, which is potentially dangerous with
2144 : // our own mutex locked
2145 454 : MutexRelease aRelease( m_aMutex );
2146 454 : if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2147 : {
2148 454 : m_xAggregateFastSet->setFastPropertyValue( m_nValuePropertyAggregateHandle, _rValue );
2149 : }
2150 :
2151 0 : else if ( !m_sValuePropertyName.isEmpty() && m_xAggregateSet.is() )
2152 : {
2153 0 : m_xAggregateSet->setPropertyValue( m_sValuePropertyName, _rValue );
2154 454 : }
2155 :
2156 : }
2157 :
2158 12 : catch( const Exception& )
2159 : {
2160 : SAL_WARN("forms.component", "OBoundControlModel::doSetControlValue: caught an exception!");
2161 : DBG_UNHANDLED_EXCEPTION();
2162 : }
2163 454 : }
2164 :
2165 36 : void OBoundControlModel::onConnectedValidator( )
2166 : {
2167 : try
2168 : {
2169 : // if we have an external validator, we do not want the control to force invalid
2170 : // inputs to the default value. Instead, invalid inputs should be translated
2171 : // to NaN (not a number)
2172 36 : Reference< XPropertySetInfo > xAggregatePropertyInfo;
2173 36 : if ( m_xAggregateSet.is() )
2174 36 : xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2175 36 : if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2176 16 : m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( false ) );
2177 : }
2178 :
2179 0 : catch( const Exception& )
2180 : {
2181 : SAL_WARN("forms.component", "OBoundControlModel::onConnectedValidator: caught an exception!");
2182 : DBG_UNHANDLED_EXCEPTION();
2183 : }
2184 :
2185 36 : recheckValidity( false );
2186 36 : }
2187 :
2188 36 : void OBoundControlModel::onDisconnectedValidator( )
2189 : {
2190 : try
2191 : {
2192 36 : Reference< XPropertySetInfo > xAggregatePropertyInfo;
2193 36 : if ( m_xAggregateSet.is() )
2194 36 : xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2195 36 : if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2196 16 : m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( true ) );
2197 : }
2198 :
2199 0 : catch( const Exception& )
2200 : {
2201 : SAL_WARN("forms.component", "OBoundControlModel::onDisconnectedValidator: caught an exception!");
2202 : DBG_UNHANDLED_EXCEPTION();
2203 : }
2204 :
2205 36 : recheckValidity( false );
2206 36 : }
2207 :
2208 34 : void OBoundControlModel::onConnectedExternalValue( )
2209 : {
2210 34 : calculateExternalValueType();
2211 34 : }
2212 :
2213 34 : void OBoundControlModel::onDisconnectedExternalValue( )
2214 : {
2215 34 : }
2216 :
2217 28 : void OBoundControlModel::onConnectedDbColumn( const Reference< XInterface >& /*_rxForm*/ )
2218 : {
2219 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onConnectedDbColumn: how this? There's an external value binding!" );
2220 28 : }
2221 :
2222 62 : void OBoundControlModel::onDisconnectedDbColumn()
2223 : {
2224 : OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onDisconnectedDbColumn: how this? There's an external value binding!" );
2225 62 : }
2226 :
2227 : // XReset
2228 0 : Any OBoundControlModel::getDefaultForReset() const
2229 : {
2230 0 : return Any();
2231 : }
2232 :
2233 293 : void OBoundControlModel::resetNoBroadcast()
2234 : {
2235 293 : setControlValue( getDefaultForReset(), eOther );
2236 293 : }
2237 :
2238 78 : void OBoundControlModel::addResetListener(const Reference<XResetListener>& l) throw (RuntimeException, std::exception)
2239 : {
2240 78 : m_aResetHelper.addResetListener( l );
2241 78 : }
2242 :
2243 52 : void OBoundControlModel::removeResetListener(const Reference<XResetListener>& l) throw (RuntimeException, std::exception)
2244 : {
2245 52 : m_aResetHelper.removeResetListener( l );
2246 52 : }
2247 :
2248 86 : void OBoundControlModel::reset() throw (RuntimeException, std::exception)
2249 : {
2250 86 : if ( !m_aResetHelper.approveReset() )
2251 112 : return;
2252 60 : ControlModelLock aLock( *this );
2253 : // on a new record?
2254 60 : bool bIsNewRecord = false;
2255 120 : Reference<XPropertySet> xSet( m_xCursor, UNO_QUERY );
2256 60 : if ( xSet.is() )
2257 : {
2258 : try
2259 : {
2260 0 : xSet->getPropertyValue( PROPERTY_ISNEW ) >>= bIsNewRecord;
2261 : }
2262 :
2263 0 : catch( const Exception& )
2264 : {
2265 : DBG_UNHANDLED_EXCEPTION();
2266 : }
2267 :
2268 : }
2269 :
2270 : // cursor on an invalid row?
2271 60 : bool bInvalidCursorPosition = true;
2272 : try
2273 : {
2274 60 : bInvalidCursorPosition = m_xCursor.is()
2275 0 : && ( m_xCursor->isAfterLast()
2276 0 : || m_xCursor->isBeforeFirst()
2277 : )
2278 60 : && !bIsNewRecord;
2279 : }
2280 :
2281 0 : catch( const SQLException& )
2282 : {
2283 : SAL_WARN("forms.component", "OBoundControlModel::reset: caught an SQL exception!" );
2284 : DBG_UNHANDLED_EXCEPTION();
2285 : }
2286 :
2287 : // #i24495# - don't count the insert row as "invalid"
2288 : bool bSimpleReset =
2289 60 : ( !m_xColumn.is() // no connection to a database column
2290 0 : || ( m_xCursor.is() // OR we have an improperly positioned cursor
2291 0 : && bInvalidCursorPosition
2292 : )
2293 60 : || hasExternalValueBinding() // OR we have an external value binding
2294 60 : );
2295 60 : if ( !bSimpleReset )
2296 : {
2297 : // The default values will be set if and only if the current value of the field which we're bound
2298 : // to is NULL.
2299 : // Else, the current field value should be refreshed
2300 : // This behaviour is not completely ... "matured": What should happen if the field as well as the
2301 : // control have a default value?
2302 0 : bool bIsNull = true;
2303 : // we have to access the field content at least once to get a reliable result by XColumn::wasNull
2304 : try
2305 : {
2306 : // normally, we'd do a getString here. However, this is extremely expensive in the case
2307 : // of binary fields. Unfortunately, getString is the only method which is guaranteed
2308 : // to *always* succeed, all other getXXX methods may fail if the column is asked for a
2309 : // non-convertible type
2310 0 : sal_Int32 nFieldType = DataType::OBJECT;
2311 0 : getField()->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
2312 0 : if ( ( nFieldType == DataType::BINARY )
2313 0 : || ( nFieldType == DataType::VARBINARY )
2314 0 : || ( nFieldType == DataType::LONGVARBINARY )
2315 0 : || ( nFieldType == DataType::OBJECT )
2316 : /*|| ( nFieldType == DataType::CLOB )*/
2317 : )
2318 0 : m_xColumn->getBinaryStream();
2319 0 : else if ( nFieldType == DataType::BLOB )
2320 0 : m_xColumn->getBlob();
2321 : else
2322 0 : m_xColumn->getString();
2323 0 : bIsNull = m_xColumn->wasNull();
2324 : }
2325 :
2326 0 : catch(const Exception&)
2327 : {
2328 : SAL_WARN("forms.component", "OBoundControlModel::reset: this should have succeeded in all cases!");
2329 : DBG_UNHANDLED_EXCEPTION();
2330 : }
2331 :
2332 0 : bool bNeedValueTransfer = true;
2333 0 : if ( bIsNull )
2334 : {
2335 0 : if ( bIsNewRecord )
2336 : {
2337 : // reset the control to it's default
2338 0 : resetNoBroadcast();
2339 : // and immediately commit the changes to the DB column, to keep consistency
2340 0 : commitControlValueToDbColumn( true );
2341 0 : bNeedValueTransfer = false;
2342 : }
2343 :
2344 : }
2345 :
2346 0 : if ( bNeedValueTransfer )
2347 0 : transferDbValueToControl();
2348 : }
2349 :
2350 : else
2351 : {
2352 60 : resetNoBroadcast();
2353 : // transfer to the external binding, if necessary
2354 60 : if ( hasExternalValueBinding() )
2355 0 : transferControlValueToExternal( aLock );
2356 : }
2357 :
2358 : // revalidate, if necessary
2359 60 : if ( hasValidator() )
2360 36 : recheckValidity( true );
2361 60 : aLock.release();
2362 120 : m_aResetHelper.notifyResetted();
2363 : }
2364 :
2365 62 : void OBoundControlModel::impl_setField_noNotify( const Reference< XPropertySet>& _rxField )
2366 : {
2367 : DBG_ASSERT( !hasExternalValueBinding(), "OBoundControlModel::impl_setField_noNotify: We have an external value binding!" );
2368 62 : m_xField = _rxField;
2369 62 : }
2370 :
2371 34 : bool OBoundControlModel::impl_approveValueBinding_nolock( const Reference< XValueBinding >& _rxBinding )
2372 : {
2373 34 : if ( !_rxBinding.is() )
2374 0 : return false;
2375 34 : Sequence< Type > aTypeCandidates;
2376 : {
2377 : // SYNCHRONIZED >
2378 34 : ::osl::MutexGuard aGuard( m_aMutex );
2379 34 : aTypeCandidates = getSupportedBindingTypes();
2380 : // < SYNCHRONIZED
2381 : }
2382 :
2383 68 : for ( const Type* pType = aTypeCandidates.getConstArray();
2384 34 : pType != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2385 : ++pType
2386 : )
2387 : {
2388 34 : if ( _rxBinding->supportsType( *pType ) )
2389 34 : return true;
2390 : }
2391 0 : return false;
2392 : }
2393 :
2394 34 : void OBoundControlModel::connectExternalValueBinding(
2395 : const Reference< XValueBinding >& _rxBinding, ControlModelLock& _rInstanceLock )
2396 : {
2397 : OSL_PRECOND( _rxBinding.is(), "OBoundControlModel::connectExternalValueBinding: invalid binding instance!" );
2398 : OSL_PRECOND( !hasExternalValueBinding( ), "OBoundControlModel::connectExternalValueBinding: precond not met (currently have a binding)!" );
2399 : // if we're connected to a database column, suspend this
2400 34 : if ( hasField() )
2401 0 : impl_disconnectDatabaseColumn_noNotify();
2402 : // suspend listening for load-related events at out ambient form.
2403 : // This is because an external value binding overrules a possible database binding.
2404 34 : if ( isFormListening() )
2405 34 : doFormListening( false );
2406 : // remember this new binding
2407 34 : m_xExternalBinding = _rxBinding;
2408 : // tell the derivee
2409 34 : onConnectedExternalValue();
2410 : try
2411 : {
2412 : // add as value listener so we get notified when the value changes
2413 34 : Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2414 34 : if ( xModifiable.is() )
2415 2 : xModifiable->addModifyListener( this );
2416 : // add as property change listener for some (possibly present) properties we're
2417 : // interested in
2418 68 : Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2419 68 : Reference< XPropertySetInfo > xBindingPropsInfo( xBindingProps.is() ? xBindingProps->getPropertySetInfo() : Reference< XPropertySetInfo >() );
2420 34 : if ( xBindingPropsInfo.is() )
2421 : {
2422 2 : if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_READONLY ) )
2423 : {
2424 0 : xBindingProps->addPropertyChangeListener( PROPERTY_READONLY, this );
2425 0 : m_bBindingControlsRO = true;
2426 : }
2427 :
2428 2 : if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_RELEVANT ) )
2429 : {
2430 0 : xBindingProps->addPropertyChangeListener( PROPERTY_RELEVANT, this );
2431 0 : m_bBindingControlsEnable = true;
2432 : }
2433 :
2434 34 : }
2435 :
2436 : }
2437 :
2438 0 : catch( const Exception& )
2439 : {
2440 : DBG_UNHANDLED_EXCEPTION();
2441 : }
2442 :
2443 : // propagate our new value
2444 34 : transferExternalValueToControl( _rInstanceLock );
2445 : // if the binding is also a validator, use it, too. This is a constraint of the
2446 : // com.sun.star.form.binding.ValidatableBindableFormComponent service
2447 34 : if ( m_bSupportsValidation )
2448 : {
2449 : try
2450 : {
2451 34 : Reference< XValidator > xAsValidator( _rxBinding, UNO_QUERY );
2452 34 : if ( xAsValidator.is() )
2453 0 : setValidator( xAsValidator );
2454 : }
2455 :
2456 0 : catch( const Exception& )
2457 : {
2458 : DBG_UNHANDLED_EXCEPTION();
2459 : }
2460 :
2461 : }
2462 34 : }
2463 :
2464 34 : void OBoundControlModel::disconnectExternalValueBinding( )
2465 : {
2466 : try
2467 : {
2468 : // not listening at the binding anymore
2469 34 : Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2470 34 : if ( xModifiable.is() )
2471 2 : xModifiable->removeModifyListener( this );
2472 : // remove as property change listener
2473 68 : Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2474 34 : if ( m_bBindingControlsRO )
2475 0 : xBindingProps->removePropertyChangeListener( PROPERTY_READONLY, this );
2476 34 : if ( m_bBindingControlsEnable )
2477 34 : xBindingProps->removePropertyChangeListener( PROPERTY_RELEVANT, this );
2478 : }
2479 :
2480 0 : catch( const Exception& )
2481 : {
2482 : SAL_WARN("forms.component", "OBoundControlModel::disconnectExternalValueBinding: caught an exception!");
2483 : DBG_UNHANDLED_EXCEPTION();
2484 : }
2485 :
2486 : // if the binding also acts as our validator, disconnect the validator, too
2487 34 : if ( ( m_xExternalBinding == m_xValidator ) && m_xValidator.is() )
2488 0 : disconnectValidator( );
2489 : // no binding anymore
2490 34 : m_xExternalBinding.clear();
2491 : // be a load listener at our form, again. This was suspended while we had
2492 : // an external value binding in place.
2493 34 : doFormListening( true );
2494 : // re-connect to database column of the new parent
2495 34 : if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
2496 0 : impl_connectDatabaseColumn_noNotify( false );
2497 : // tell the derivee
2498 34 : onDisconnectedExternalValue();
2499 34 : }
2500 :
2501 34 : void SAL_CALL OBoundControlModel::setValueBinding( const Reference< XValueBinding >& _rxBinding ) throw (IncompatibleTypesException, RuntimeException, std::exception)
2502 : {
2503 : OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::setValueBinding: How did you reach this method?" );
2504 : // the interface for this method should not have been exposed if we do not
2505 : // support binding to external data
2506 : // allow reset
2507 34 : if ( _rxBinding.is() && !impl_approveValueBinding_nolock( _rxBinding ) )
2508 : {
2509 : throw IncompatibleTypesException(
2510 : FRM_RES_STRING( RID_STR_INCOMPATIBLE_TYPES ),
2511 : *this
2512 0 : );
2513 : }
2514 :
2515 34 : ControlModelLock aLock( *this );
2516 : // since a ValueBinding overrules any potentially active database binding, the change in a ValueBinding
2517 : // might trigger a change in our BoundField.
2518 68 : FieldChangeNotifier aBoundFieldNotifier( aLock );
2519 : // disconnect from the old binding
2520 34 : if ( hasExternalValueBinding() )
2521 16 : disconnectExternalValueBinding( );
2522 : // connect to the new binding
2523 34 : if ( _rxBinding.is() )
2524 68 : connectExternalValueBinding( _rxBinding, aLock );
2525 34 : }
2526 :
2527 316 : Reference< XValueBinding > SAL_CALL OBoundControlModel::getValueBinding( ) throw (RuntimeException, std::exception)
2528 : {
2529 316 : ::osl::MutexGuard aGuard( m_aMutex );
2530 : OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::getValueBinding: How did you reach this method?" );
2531 : // the interface for this method should not have been exposed if we do not
2532 : // support binding to external data
2533 316 : return m_xExternalBinding;
2534 : }
2535 :
2536 0 : void SAL_CALL OBoundControlModel::modified( const EventObject& _rEvent ) throw ( RuntimeException, std::exception )
2537 : {
2538 0 : ControlModelLock aLock( *this );
2539 : OSL_PRECOND( hasExternalValueBinding(), "OBoundControlModel::modified: Where did this come from?" );
2540 0 : if ( !m_bTransferingValue && ( m_xExternalBinding == _rEvent.Source ) && m_xExternalBinding.is() )
2541 : {
2542 0 : transferExternalValueToControl( aLock );
2543 0 : }
2544 0 : }
2545 :
2546 62 : void OBoundControlModel::transferDbValueToControl( )
2547 : {
2548 : try
2549 : {
2550 62 : setControlValue( translateDbColumnToControlValue(), eDbColumnBinding );
2551 : }
2552 :
2553 0 : catch( const Exception& )
2554 : {
2555 : DBG_UNHANDLED_EXCEPTION();
2556 : }
2557 62 : }
2558 :
2559 34 : void OBoundControlModel::transferExternalValueToControl( ControlModelLock& _rInstanceLock )
2560 : {
2561 34 : Reference< XValueBinding > xExternalBinding( m_xExternalBinding );
2562 68 : Type aValueExchangeType( getExternalValueType() );
2563 34 : _rInstanceLock.release();
2564 : // UNSAFE >
2565 68 : Any aExternalValue;
2566 : try
2567 : {
2568 34 : aExternalValue = xExternalBinding->getValue( aValueExchangeType );
2569 : }
2570 :
2571 0 : catch( const Exception& )
2572 : {
2573 : DBG_UNHANDLED_EXCEPTION();
2574 : }
2575 : // < UNSAFE
2576 34 : _rInstanceLock.acquire();
2577 68 : setControlValue( translateExternalValueToControlValue( aExternalValue ), eExternalBinding );
2578 34 : }
2579 :
2580 0 : void OBoundControlModel::transferControlValueToExternal( ControlModelLock& _rInstanceLock )
2581 : {
2582 : OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2583 : "OBoundControlModel::transferControlValueToExternal: precondition not met!" );
2584 0 : if ( m_xExternalBinding.is() )
2585 : {
2586 0 : Any aExternalValue( translateControlValueToExternalValue() );
2587 0 : m_bTransferingValue = true;
2588 0 : _rInstanceLock.release();
2589 : // UNSAFE >
2590 : try
2591 : {
2592 0 : m_xExternalBinding->setValue( aExternalValue );
2593 : }
2594 :
2595 0 : catch( const Exception& )
2596 : {
2597 : DBG_UNHANDLED_EXCEPTION();
2598 : }
2599 :
2600 : // < UNSAFE
2601 0 : _rInstanceLock.acquire();
2602 0 : m_bTransferingValue = false;
2603 : }
2604 0 : }
2605 :
2606 24 : Sequence< Type > OBoundControlModel::getSupportedBindingTypes()
2607 : {
2608 24 : return Sequence< Type >( &m_aValuePropertyType, 1 );
2609 : }
2610 :
2611 86 : void OBoundControlModel::calculateExternalValueType()
2612 : {
2613 86 : m_aExternalValueType = Type();
2614 86 : if ( !m_xExternalBinding.is() )
2615 138 : return;
2616 34 : Sequence< Type > aTypeCandidates( getSupportedBindingTypes() );
2617 68 : for ( const Type* pTypeCandidate = aTypeCandidates.getConstArray();
2618 34 : pTypeCandidate != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2619 : ++pTypeCandidate
2620 : )
2621 : {
2622 34 : if ( m_xExternalBinding->supportsType( *pTypeCandidate ) )
2623 : {
2624 34 : m_aExternalValueType = *pTypeCandidate;
2625 34 : break;
2626 : }
2627 34 : }
2628 : }
2629 :
2630 12 : Any OBoundControlModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
2631 : {
2632 : OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2633 : "OBoundControlModel::translateExternalValueToControlValue: precondition not met!" );
2634 12 : Any aControlValue( _rExternalValue );
2635 : // if the external value is VOID, and our value property is not allowed to be VOID,
2636 : // then default-construct a value
2637 12 : if ( !aControlValue.hasValue() && !m_bValuePropertyMayBeVoid )
2638 0 : aControlValue.setValue( NULL, m_aValuePropertyType );
2639 : // out of here
2640 12 : return aControlValue;
2641 : }
2642 :
2643 0 : Any OBoundControlModel::translateControlValueToExternalValue( ) const
2644 : {
2645 0 : return getControlValue( );
2646 : }
2647 :
2648 90 : Any OBoundControlModel::translateControlValueToValidatableValue( ) const
2649 : {
2650 : OSL_PRECOND( m_xValidator.is(), "OBoundControlModel::translateControlValueToValidatableValue: no validator, so why should I?" );
2651 90 : if ( ( m_xValidator == m_xExternalBinding ) && m_xValidator.is() )
2652 0 : return translateControlValueToExternalValue();
2653 90 : return getControlValue();
2654 : }
2655 :
2656 527 : Any OBoundControlModel::getControlValue( ) const
2657 : {
2658 : OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2659 : "OBoundControlModel::getControlValue: invalid aggregate !" );
2660 : OSL_PRECOND( !m_sValuePropertyName.isEmpty() || ( m_nValuePropertyAggregateHandle != -1 ),
2661 : "OBoundControlModel::getControlValue: please override if you have own value property handling!" );
2662 : // determine the current control value
2663 527 : Any aControlValue;
2664 527 : if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2665 : {
2666 527 : aControlValue = m_xAggregateFastSet->getFastPropertyValue( m_nValuePropertyAggregateHandle );
2667 : }
2668 :
2669 0 : else if ( !m_sValuePropertyName.isEmpty() && m_xAggregateSet.is() )
2670 : {
2671 0 : aControlValue = m_xAggregateSet->getPropertyValue( m_sValuePropertyName );
2672 : }
2673 527 : return aControlValue;
2674 : }
2675 :
2676 36 : void OBoundControlModel::connectValidator( const Reference< XValidator >& _rxValidator )
2677 : {
2678 : OSL_PRECOND( _rxValidator.is(), "OBoundControlModel::connectValidator: invalid validator instance!" );
2679 : OSL_PRECOND( !hasValidator( ), "OBoundControlModel::connectValidator: precond not met (have a validator currently)!" );
2680 36 : m_xValidator = _rxValidator;
2681 :
2682 : // add as value listener so we get notified when the value changes
2683 36 : if ( m_xValidator.is() )
2684 : {
2685 : try
2686 : {
2687 36 : m_xValidator->addValidityConstraintListener( this );
2688 : }
2689 :
2690 0 : catch( const RuntimeException& )
2691 : {
2692 : }
2693 : }
2694 36 : onConnectedValidator( );
2695 36 : }
2696 :
2697 36 : void OBoundControlModel::disconnectValidator( )
2698 : {
2699 : OSL_PRECOND( hasValidator( ), "OBoundControlModel::connectValidator: precond not met (don't have a validator currently)!" );
2700 :
2701 : // add as value listener so we get notified when the value changes
2702 36 : if ( m_xValidator.is() )
2703 : {
2704 : try
2705 : {
2706 36 : m_xValidator->removeValidityConstraintListener( this );
2707 : }
2708 :
2709 0 : catch( const RuntimeException& )
2710 : {
2711 : }
2712 : }
2713 :
2714 36 : m_xValidator.clear();
2715 :
2716 36 : onDisconnectedValidator( );
2717 36 : }
2718 :
2719 36 : void SAL_CALL OBoundControlModel::setValidator( const Reference< XValidator >& _rxValidator ) throw (VetoException,RuntimeException, std::exception)
2720 : {
2721 36 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
2722 : OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::setValidator: How did you reach this method?" );
2723 : // the interface for this method should not have been exposed if we do not
2724 : // support validation
2725 :
2726 : // early out if the validator does not change
2727 36 : if ( _rxValidator == m_xValidator )
2728 36 : return;
2729 :
2730 36 : if ( m_xValidator.is() && ( m_xValidator == m_xExternalBinding ) )
2731 : throw VetoException(
2732 : FRM_RES_STRING( RID_STR_INVALID_VALIDATOR ),
2733 : *this
2734 0 : );
2735 :
2736 : // disconnect from the old validator
2737 36 : if ( hasValidator() )
2738 0 : disconnectValidator( );
2739 :
2740 : // connect to the new validator
2741 36 : if ( _rxValidator.is() )
2742 36 : connectValidator( _rxValidator );
2743 : }
2744 :
2745 80 : Reference< XValidator > SAL_CALL OBoundControlModel::getValidator( ) throw (RuntimeException, std::exception)
2746 : {
2747 80 : ::osl::MutexGuard aGuard( m_aMutex );
2748 : OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::getValidator: How did you reach this method?" );
2749 : // the interface for this method should not have been exposed if we do not
2750 : // support validation
2751 :
2752 80 : return m_xValidator;
2753 : }
2754 :
2755 18 : void SAL_CALL OBoundControlModel::validityConstraintChanged( const EventObject& /*Source*/ ) throw (RuntimeException, std::exception)
2756 : {
2757 18 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
2758 : OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::validityConstraintChanged: How did you reach this method?" );
2759 : // the interface for this method should not have been exposed if we do not
2760 : // support validation
2761 :
2762 18 : recheckValidity( false );
2763 18 : }
2764 :
2765 80 : sal_Bool SAL_CALL OBoundControlModel::isValid( ) throw (RuntimeException, std::exception)
2766 : {
2767 80 : return m_bIsCurrentValueValid;
2768 : }
2769 :
2770 16 : ::com::sun::star::uno::Any OBoundControlModel::getCurrentFormComponentValue() const
2771 : {
2772 16 : if ( hasValidator() )
2773 0 : return translateControlValueToValidatableValue();
2774 16 : return getControlValue();
2775 : }
2776 :
2777 18 : Any SAL_CALL OBoundControlModel::getCurrentValue( ) throw (RuntimeException, std::exception)
2778 : {
2779 18 : ::osl::MutexGuard aGuard( m_aMutex );
2780 18 : return getCurrentFormComponentValue();
2781 : }
2782 :
2783 42 : void SAL_CALL OBoundControlModel::addFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException, std::exception)
2784 : {
2785 42 : if ( Listener.is() )
2786 42 : m_aFormComponentListeners.addInterface( Listener );
2787 42 : }
2788 :
2789 42 : void SAL_CALL OBoundControlModel::removeFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException, std::exception)
2790 : {
2791 42 : if ( Listener.is() )
2792 42 : m_aFormComponentListeners.removeInterface( Listener );
2793 42 : }
2794 :
2795 719 : void OBoundControlModel::recheckValidity( bool _bForceNotification )
2796 : {
2797 : try
2798 : {
2799 719 : bool bIsCurrentlyValid = true;
2800 719 : if ( hasValidator() )
2801 200 : bIsCurrentlyValid = m_xValidator->isValid( translateControlValueToValidatableValue() );
2802 :
2803 719 : if ( ( bIsCurrentlyValid != m_bIsCurrentValueValid ) || _bForceNotification )
2804 : {
2805 665 : m_bIsCurrentValueValid = bIsCurrentlyValid;
2806 :
2807 : // release our mutex for the notifications
2808 665 : MutexRelease aRelease( m_aMutex );
2809 665 : m_aFormComponentListeners.notifyEach( &validation::XFormComponentValidityListener::componentValidityChanged, EventObject( *this ) );
2810 : }
2811 :
2812 : }
2813 :
2814 0 : catch( const Exception& )
2815 : {
2816 : SAL_WARN("forms.component", "OBoundControlModel::recheckValidity: caught an exception!");
2817 : DBG_UNHANDLED_EXCEPTION();
2818 : }
2819 719 : }
2820 :
2821 610 : void OBoundControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
2822 : {
2823 610 : BEGIN_DESCRIBE_PROPERTIES( 5, OControlModel )
2824 610 : DECL_PROP1 ( CONTROLSOURCE, OUString, BOUND );
2825 610 : DECL_IFACE_PROP3( BOUNDFIELD, XPropertySet, BOUND, READONLY, TRANSIENT );
2826 610 : DECL_IFACE_PROP2( CONTROLLABEL, XPropertySet, BOUND, MAYBEVOID );
2827 610 : DECL_PROP2 ( CONTROLSOURCEPROPERTY, OUString, READONLY, TRANSIENT );
2828 610 : DECL_BOOL_PROP1 ( INPUT_REQUIRED, BOUND );
2829 : END_DESCRIBE_PROPERTIES()
2830 610 : }
2831 : }
2832 :
2833 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|