bump product version to 5.0.4.1
[LibreOffice.git] / forms / source / component / FormComponent.cxx
blob0e3a00b7ef49e44fd246acb57e45b04df24a1821
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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"
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>
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>
52 #include <functional>
53 #include <algorithm>
55 namespace frm
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;
73 // FieldChangeNotifier
74 void ControlModelLock::impl_notifyAll_nothrow()
76 m_rModel.firePropertyChanges( m_aHandles, m_aOldValues, m_aNewValues, OControlModel::LockAccess() );
79 void ControlModelLock::addPropertyNotification( const sal_Int32 _nHandle, const Any& _rOldValue, const Any& _rNewValue )
81 sal_Int32 nOldLength = m_aHandles.getLength();
82 if ( ( nOldLength != m_aOldValues.getLength() )
83 || ( nOldLength != m_aNewValues.getLength() )
85 throw RuntimeException( OUString(), m_rModel );
87 m_aHandles.realloc( nOldLength + 1 );
88 m_aHandles[ nOldLength ] = _nHandle;
89 m_aOldValues.realloc( nOldLength + 1 );
90 m_aOldValues[ nOldLength ] = _rOldValue;
91 m_aNewValues.realloc( nOldLength + 1 );
92 m_aNewValues[ nOldLength ] = _rNewValue;
95 class FieldChangeNotifier
97 public:
98 FieldChangeNotifier( ControlModelLock& _rLock )
99 :m_rLock( _rLock )
100 ,m_rModel( dynamic_cast< OBoundControlModel& >( _rLock.getModel() ) )
102 m_xOldField = m_rModel.getField();
105 ~FieldChangeNotifier()
107 Reference< XPropertySet > xNewField( m_rModel.getField() );
108 if ( m_xOldField != xNewField )
109 m_rLock.addPropertyNotification( PROPERTY_ID_BOUNDFIELD, makeAny( m_xOldField ), makeAny( xNewField ) );
112 private:
113 ControlModelLock& m_rLock;
114 OBoundControlModel& m_rModel;
115 Reference< XPropertySet > m_xOldField;
118 // base class for form layer controls
119 OControl::OControl( const Reference< XComponentContext >& _rxContext, const OUString& _rAggregateService, const bool _bSetDelegator )
120 :OComponentHelper(m_aMutex)
121 ,m_xContext( _rxContext )
123 // Aggregate VCL Control
124 // Increment the RefCount for aggregates, because the aggregate by itself increments the RefCount in the setDelegator
125 osl_atomic_increment( &m_refCount );
127 m_xAggregate.set(_rxContext->getServiceManager()->createInstanceWithContext(_rAggregateService, _rxContext), css::uno::UNO_QUERY);
128 m_xControl.set(m_xAggregate, css::uno::UNO_QUERY);
130 osl_atomic_decrement( &m_refCount );
132 if ( _bSetDelegator )
133 doSetDelegator();
136 OControl::~OControl()
138 doResetDelegator();
141 void OControl::doResetDelegator()
143 if ( m_xAggregate.is() )
144 m_xAggregate->setDelegator( NULL );
147 void OControl::doSetDelegator()
149 osl_atomic_increment( &m_refCount );
150 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 m_xAggregate->setDelegator( static_cast< XWeak* >( this ) );
156 osl_atomic_decrement( &m_refCount );
159 // UNO Binding
160 Any SAL_CALL OControl::queryAggregation( const Type& _rType ) throw(RuntimeException, std::exception)
162 // ask the base class
163 Any aReturn( OComponentHelper::queryAggregation(_rType) );
164 // ask our own interfaces
165 if (!aReturn.hasValue())
167 aReturn = OControl_BASE::queryInterface(_rType);
168 // ask our aggregate
169 if (!aReturn.hasValue() && m_xAggregate.is())
170 aReturn = m_xAggregate->queryAggregation(_rType);
173 return aReturn;
176 Sequence<sal_Int8> SAL_CALL OControl::getImplementationId() throw(RuntimeException, std::exception)
178 return css::uno::Sequence<sal_Int8>();
181 Sequence<Type> SAL_CALL OControl::getTypes() throw(RuntimeException, std::exception)
183 TypeBag aTypes( _getTypes() );
185 Reference< XTypeProvider > xProv;
186 if ( query_aggregation( m_xAggregate, xProv ) )
187 aTypes.addTypes( xProv->getTypes() );
189 return aTypes.getTypes();
192 Sequence<Type> OControl::_getTypes()
194 return TypeBag( OComponentHelper::getTypes(), OControl_BASE::getTypes() ).getTypes();
197 // OComponentHelper
198 void OControl::disposing()
200 OComponentHelper::disposing();
202 m_aWindowStateGuard.attach( NULL, NULL );
204 Reference< XComponent > xComp;
205 if (query_aggregation(m_xAggregate, xComp))
206 xComp->dispose();
209 // XServiceInfo
210 sal_Bool SAL_CALL OControl::supportsService(const OUString& _rsServiceName) throw ( RuntimeException, std::exception)
212 return cppu::supportsService(this, _rsServiceName);
215 Sequence< OUString > OControl::getAggregateServiceNames()
217 Sequence< OUString > aAggServices;
218 Reference< XServiceInfo > xInfo;
219 if ( query_aggregation( m_xAggregate, xInfo ) )
220 aAggServices = xInfo->getSupportedServiceNames();
222 return aAggServices;
225 Sequence<OUString> SAL_CALL OControl::getSupportedServiceNames() throw(RuntimeException, std::exception)
227 return ::comphelper::concatSequences(
228 getAggregateServiceNames(),
229 getSupportedServiceNames_Static()
233 Sequence< OUString > SAL_CALL OControl::getSupportedServiceNames_Static() throw( RuntimeException )
235 // no own supported service names
236 return Sequence< OUString >();
239 // XEventListener
240 void SAL_CALL OControl::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException, std::exception)
242 Reference< XInterface > xAggAsIface;
243 query_aggregation(m_xAggregate, xAggAsIface);
245 // does the disposing come from the aggregate?
246 if (xAggAsIface != Reference< XInterface >(_rEvent.Source, UNO_QUERY))
247 { // no -> forward it
248 Reference<com::sun::star::lang::XEventListener> xListener;
249 if (query_aggregation(m_xAggregate, xListener))
250 xListener->disposing(_rEvent);
254 // XControl
255 void SAL_CALL OControl::setContext(const Reference< XInterface >& Context) throw (RuntimeException, std::exception)
257 if (m_xControl.is())
258 m_xControl->setContext(Context);
261 Reference< XInterface > SAL_CALL OControl::getContext() throw (RuntimeException, std::exception)
263 return m_xControl.is() ? m_xControl->getContext() : Reference< XInterface >();
266 void OControl::impl_resetStateGuard_nothrow()
268 Reference< XWindow2 > xWindow;
269 Reference< XControlModel > xModel;
272 xWindow.set( getPeer(), UNO_QUERY );
273 xModel.set( getModel(), UNO_QUERY );
275 catch( const Exception& )
277 DBG_UNHANDLED_EXCEPTION();
279 m_aWindowStateGuard.attach( xWindow, xModel );
282 void SAL_CALL OControl::createPeer(const Reference<XToolkit>& _rxToolkit, const Reference<XWindowPeer>& _rxParent) throw (RuntimeException, std::exception)
284 if ( m_xControl.is() )
286 m_xControl->createPeer( _rxToolkit, _rxParent );
287 impl_resetStateGuard_nothrow();
291 Reference<XWindowPeer> SAL_CALL OControl::getPeer() throw ( RuntimeException, std::exception)
293 return m_xControl.is() ? m_xControl->getPeer() : Reference<XWindowPeer>();
296 sal_Bool SAL_CALL OControl::setModel(const Reference<XControlModel>& Model) throw ( RuntimeException, std::exception)
298 if ( !m_xControl.is() )
299 return sal_False;
301 bool bSuccess = m_xControl->setModel( Model );
302 impl_resetStateGuard_nothrow();
303 return bSuccess;
306 Reference<XControlModel> SAL_CALL OControl::getModel() throw ( RuntimeException, std::exception)
308 return m_xControl.is() ? m_xControl->getModel() : Reference<XControlModel>();
311 Reference<XView> SAL_CALL OControl::getView() throw ( RuntimeException, std::exception)
313 return m_xControl.is() ? m_xControl->getView() : Reference<XView>();
316 void SAL_CALL OControl::setDesignMode(sal_Bool bOn) throw ( RuntimeException, std::exception)
318 if (m_xControl.is())
319 m_xControl->setDesignMode(bOn);
322 sal_Bool SAL_CALL OControl::isDesignMode() throw ( RuntimeException, std::exception)
324 return m_xControl.is() ? m_xControl->isDesignMode() : sal_True;
327 sal_Bool SAL_CALL OControl::isTransparent() throw ( RuntimeException, std::exception)
329 return m_xControl.is() ? m_xControl->isTransparent() : sal_True;
332 OBoundControl::OBoundControl( const Reference< XComponentContext >& _rxContext,
333 const OUString& _rAggregateService, const bool _bSetDelegator )
334 :OControl( _rxContext, _rAggregateService, _bSetDelegator )
335 ,m_bLocked(false)
336 ,m_aOriginalFont( EmptyFontDescriptor() )
337 ,m_nOriginalTextLineColor( 0 )
341 OBoundControl::~OBoundControl()
345 Sequence< Type> OBoundControl::_getTypes()
347 return TypeBag( OControl::_getTypes(), OBoundControl_BASE::getTypes() ).getTypes();
350 Any SAL_CALL OBoundControl::queryAggregation(const Type& _rType) throw(RuntimeException, std::exception)
352 Any aReturn;
354 // XTypeProvider first - don't ask the OBoundControl_BASE, it would deliver incomplete types
355 if ( _rType.equals( cppu::UnoType<XTypeProvider>::get() ) )
356 aReturn = OControl::queryAggregation( _rType );
358 // ask our own interfaces
359 // (do this first (except XTypeProvider ) - we want to "overwrite" XPropertiesChangeListener)
360 if ( !aReturn.hasValue() )
361 aReturn = OBoundControl_BASE::queryInterface( _rType );
363 // ask the base class
364 if ( !aReturn.hasValue() )
365 aReturn = OControl::queryAggregation( _rType );
367 return aReturn;
370 sal_Bool SAL_CALL OBoundControl::getLock() throw(RuntimeException, std::exception)
372 return m_bLocked;
375 void SAL_CALL OBoundControl::setLock(sal_Bool _bLock) throw(RuntimeException, std::exception)
377 if (m_bLocked == bool(_bLock))
378 return;
380 osl::MutexGuard aGuard(m_aMutex);
381 _setLock(_bLock);
382 m_bLocked = _bLock;
385 void OBoundControl::_setLock(bool _bLock)
387 // try to set the text component to readonly
388 Reference< XWindowPeer > xPeer = getPeer();
389 Reference< XTextComponent > xText( xPeer, UNO_QUERY );
391 if ( xText.is() )
392 xText->setEditable( !_bLock );
393 else
395 // disable the window
396 Reference< XWindow > xComp( xPeer, UNO_QUERY );
397 if ( xComp.is() )
398 xComp->setEnable( !_bLock );
402 sal_Bool SAL_CALL OBoundControl::setModel( const Reference< XControlModel >& _rxModel ) throw (RuntimeException, std::exception)
404 return OControl::setModel( _rxModel );
407 void SAL_CALL OBoundControl::disposing(const EventObject& Source) throw (RuntimeException, std::exception)
409 // just disambiguate
410 OControl::disposing(Source);
413 void OBoundControl::disposing()
415 OControl::disposing();
418 // OControlModel
419 Sequence<sal_Int8> SAL_CALL OControlModel::getImplementationId() throw(RuntimeException, std::exception)
421 return css::uno::Sequence<sal_Int8>();
424 Sequence<Type> SAL_CALL OControlModel::getTypes() throw(RuntimeException, std::exception)
426 TypeBag aTypes( _getTypes() );
428 Reference< XTypeProvider > xProv;
430 if ( query_aggregation( m_xAggregate, xProv ) )
431 aTypes.addTypes( xProv->getTypes() );
433 return aTypes.getTypes();
436 Sequence<Type> OControlModel::_getTypes()
438 return TypeBag( OComponentHelper::getTypes(),
439 OPropertySetAggregationHelper::getTypes(),
440 OControlModel_BASE::getTypes()
441 ).getTypes();
444 Any SAL_CALL OControlModel::queryAggregation(const Type& _rType) throw (RuntimeException, std::exception)
446 // base class 1
447 Any aReturn(OComponentHelper::queryAggregation(_rType));
449 // base class 2
450 if (!aReturn.hasValue())
452 aReturn = OControlModel_BASE::queryInterface(_rType);
454 // our own interfaces
455 if (!aReturn.hasValue())
457 aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
458 // our aggregate
459 if (!aReturn.hasValue() && m_xAggregate.is() && !_rType.equals(cppu::UnoType<XCloneable>::get()))
460 aReturn = m_xAggregate->queryAggregation(_rType);
463 return aReturn;
466 void OControlModel::readHelpTextCompatibly(const css::uno::Reference< css::io::XObjectInputStream >& _rxInStream)
468 OUString sHelpText;
469 ::comphelper::operator>>( _rxInStream, sHelpText);
472 if (m_xAggregateSet.is())
473 m_xAggregateSet->setPropertyValue(PROPERTY_HELPTEXT, makeAny(sHelpText));
475 catch(const Exception&)
477 SAL_WARN("forms.component", "OControlModel::readHelpTextCompatibly: could not forward the property value to the aggregate!");
478 DBG_UNHANDLED_EXCEPTION();
482 void OControlModel::writeHelpTextCompatibly(const css::uno::Reference< css::io::XObjectOutputStream >& _rxOutStream)
484 OUString sHelpText;
487 if (m_xAggregateSet.is())
488 m_xAggregateSet->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText;
490 catch(const Exception&)
492 SAL_WARN("forms.component", "OControlModel::writeHelpTextCompatibly: could not retrieve the property value from the aggregate!");
493 DBG_UNHANDLED_EXCEPTION();
495 ::comphelper::operator<<( _rxOutStream, sHelpText);
498 OControlModel::OControlModel(
499 const Reference<XComponentContext>& _rxContext,
500 const OUString& _rUnoControlModelTypeName,
501 const OUString& rDefault, const bool _bSetDelegator)
502 :OComponentHelper(m_aMutex)
503 ,OPropertySetAggregationHelper(OComponentHelper::rBHelper)
504 ,m_xContext( _rxContext )
505 ,m_lockCount( 0 )
506 ,m_aPropertyBagHelper( *this )
507 ,m_nTabIndex(FRM_DEFAULT_TABINDEX)
508 ,m_nClassId(FormComponentType::CONTROL)
509 ,m_bNativeLook( false )
510 ,m_bGenerateVbEvents( false )
511 ,m_nControlTypeinMSO(0) // 0 : default value is create from AOO
512 ,m_nObjIDinMSO(INVALID_OBJ_ID_IN_MSO)
513 // form controls are usually embedded into documents, not dialogs, and in documents
514 // the native look is ugly...
515 // #i37342#
517 if (!_rUnoControlModelTypeName.isEmpty()) // the is a model we have to aggregate
519 osl_atomic_increment(&m_refCount);
521 m_xAggregate = Reference<XAggregation>(m_xContext->getServiceManager()->createInstanceWithContext(_rUnoControlModelTypeName, m_xContext), UNO_QUERY);
522 setAggregation(m_xAggregate);
524 if ( m_xAggregateSet.is() )
528 if ( !rDefault.isEmpty() )
529 m_xAggregateSet->setPropertyValue( PROPERTY_DEFAULTCONTROL, makeAny( rDefault ) );
531 catch( const Exception& )
533 SAL_WARN("forms.component", "OControlModel::OControlModel: caught an exception!");
534 DBG_UNHANDLED_EXCEPTION();
538 if (_bSetDelegator)
539 doSetDelegator();
541 // Refcount is at NULL again
542 osl_atomic_decrement(&m_refCount);
546 OControlModel::OControlModel( const OControlModel* _pOriginal, const Reference< XComponentContext>& _rxFactory, const bool _bCloneAggregate, const bool _bSetDelegator )
547 :OComponentHelper( m_aMutex )
548 ,OPropertySetAggregationHelper( OComponentHelper::rBHelper )
549 ,m_xContext( _rxFactory )
550 ,m_lockCount( 0 )
551 ,m_aPropertyBagHelper( *this )
552 ,m_nTabIndex( FRM_DEFAULT_TABINDEX )
553 ,m_nClassId( FormComponentType::CONTROL )
555 DBG_ASSERT( _pOriginal, "OControlModel::OControlModel: invalid original!" );
557 // copy members
558 m_aName = _pOriginal->m_aName;
559 m_aTag = _pOriginal->m_aTag;
560 m_nTabIndex = _pOriginal->m_nTabIndex;
561 m_nClassId = _pOriginal->m_nClassId;
562 m_bNativeLook = _pOriginal->m_bNativeLook;
563 m_bGenerateVbEvents = _pOriginal->m_bGenerateVbEvents;
564 m_nControlTypeinMSO = _pOriginal->m_nControlTypeinMSO;
565 m_nObjIDinMSO = _pOriginal->m_nObjIDinMSO;
567 if ( _bCloneAggregate )
569 // temporarily increment refcount because of temporary references to ourself in the following
570 osl_atomic_increment( &m_refCount );
572 // transfer the (only, at the very moment!) ref count
573 m_xAggregate = createAggregateClone( _pOriginal );
575 // set aggregation (retrieve other direct interfaces of the aggregate)
576 setAggregation( m_xAggregate );
579 // set the delegator, if allowed by our derived class
580 if ( _bSetDelegator )
581 doSetDelegator();
583 // decrement ref count
584 osl_atomic_decrement( &m_refCount );
588 OControlModel::~OControlModel()
590 // release the aggregate
591 doResetDelegator( );
594 void OControlModel::clonedFrom( const OControlModel* /*_pOriginal*/ )
596 // nothing to do in this base class
599 void OControlModel::doResetDelegator()
601 if (m_xAggregate.is())
602 m_xAggregate->setDelegator(NULL);
605 void OControlModel::doSetDelegator()
607 osl_atomic_increment(&m_refCount);
608 if (m_xAggregate.is())
610 m_xAggregate->setDelegator(static_cast<XWeak*>(this));
612 osl_atomic_decrement(&m_refCount);
615 // XChild
616 Reference< XInterface > SAL_CALL OControlModel::getParent() throw(RuntimeException, std::exception)
618 return m_xParent;
621 void SAL_CALL OControlModel::setParent(const Reference< XInterface >& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException, std::exception)
623 osl::MutexGuard aGuard(m_aMutex);
625 Reference<XComponent> xComp(m_xParent, UNO_QUERY);
626 if (xComp.is())
627 xComp->removeEventListener(static_cast<XPropertiesChangeListener*>(this));
629 m_xParent = _rxParent;
630 xComp.set(m_xParent, css::uno::UNO_QUERY);
632 if ( xComp.is() )
633 xComp->addEventListener(static_cast<XPropertiesChangeListener*>(this));
636 // XNamed
637 OUString SAL_CALL OControlModel::getName() throw(RuntimeException, std::exception)
639 OUString aReturn;
642 OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME) >>= aReturn;
644 catch (const css::beans::UnknownPropertyException&)
646 css::uno::Any a(cppu::getCaughtException());
647 throw WrappedTargetRuntimeException(
648 "OControlModel::getName",
649 *const_cast< OControlModel* >( this ),
653 return aReturn;
656 void SAL_CALL OControlModel::setName(const OUString& _rName) throw(RuntimeException, std::exception)
660 setFastPropertyValue(PROPERTY_ID_NAME, makeAny(_rName));
662 catch (const css::beans::UnknownPropertyException&)
664 css::uno::Any a(cppu::getCaughtException());
665 throw WrappedTargetRuntimeException(
666 "OControlModel::setName",
667 *const_cast< OControlModel* >( this ),
673 // XServiceInfo
674 sal_Bool SAL_CALL OControlModel::supportsService(const OUString& _rServiceName) throw ( RuntimeException, std::exception)
676 return cppu::supportsService(this, _rServiceName);
679 Sequence< OUString > OControlModel::getAggregateServiceNames()
681 Sequence< OUString > aAggServices;
682 Reference< XServiceInfo > xInfo;
683 if ( query_aggregation( m_xAggregate, xInfo ) )
684 aAggServices = xInfo->getSupportedServiceNames();
685 return aAggServices;
688 Sequence<OUString> SAL_CALL OControlModel::getSupportedServiceNames() throw(RuntimeException, std::exception)
690 return ::comphelper::concatSequences(
691 getAggregateServiceNames(),
692 getSupportedServiceNames_Static()
696 Sequence< OUString > SAL_CALL OControlModel::getSupportedServiceNames_Static() throw( RuntimeException )
698 Sequence< OUString > aServiceNames( 2 );
699 aServiceNames[ 0 ] = FRM_SUN_FORMCOMPONENT;
700 aServiceNames[ 1 ] = "com.sun.star.form.FormControlModel";
701 return aServiceNames;
704 // XEventListener
705 void SAL_CALL OControlModel::disposing(const com::sun::star::lang::EventObject& _rSource) throw (RuntimeException, std::exception)
707 // release the parent
708 if (_rSource.Source == m_xParent)
710 osl::MutexGuard aGuard(m_aMutex);
711 m_xParent = NULL;
713 else
715 Reference<com::sun::star::lang::XEventListener> xEvtLst;
716 if (query_aggregation(m_xAggregate, xEvtLst))
718 osl::MutexGuard aGuard(m_aMutex);
719 xEvtLst->disposing(_rSource);
724 // OComponentHelper
725 void OControlModel::disposing()
727 OPropertySetAggregationHelper::disposing();
729 Reference<com::sun::star::lang::XComponent> xComp;
730 if (query_aggregation(m_xAggregate, xComp))
731 xComp->dispose();
733 setParent(Reference<XFormComponent>());
735 m_aPropertyBagHelper.dispose();
738 void OControlModel::writeAggregate( const Reference< XObjectOutputStream >& _rxOutStream ) const
740 Reference< XPersistObject > xPersist;
741 if ( query_aggregation( m_xAggregate, xPersist ) )
742 xPersist->write( _rxOutStream );
745 void OControlModel::readAggregate( const Reference< XObjectInputStream >& _rxInStream )
747 Reference< XPersistObject > xPersist;
748 if ( query_aggregation( m_xAggregate, xPersist ) )
749 xPersist->read( _rxInStream );
752 void SAL_CALL OControlModel::write(const Reference<css::io::XObjectOutputStream>& _rxOutStream)
753 throw(css::io::IOException, RuntimeException, std::exception)
755 osl::MutexGuard aGuard(m_aMutex);
757 // 1. writing the UnoControls
758 Reference<css::io::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
759 if ( !xMark.is() )
761 throw IOException(
762 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
763 static_cast< ::cppu::OWeakObject* >( this )
767 sal_Int32 nMark = xMark->createMark();
768 sal_Int32 nLen = 0;
770 _rxOutStream->writeLong(nLen);
772 writeAggregate( _rxOutStream );
774 // determining the length
775 nLen = xMark->offsetToMark(nMark) - 4;
776 xMark->jumpToMark(nMark);
777 _rxOutStream->writeLong(nLen);
778 xMark->jumpToFurthest();
779 xMark->deleteMark(nMark);
781 // 2. writing a version number
782 _rxOutStream->writeShort(0x0003);
784 // 3. writing the general properties
785 ::comphelper::operator<<( _rxOutStream, m_aName);
786 _rxOutStream->writeShort(m_nTabIndex);
787 ::comphelper::operator<<( _rxOutStream, m_aTag); // 3rd version
789 // IMPORTANT NOTE!
790 // don't write any new members here: this wouldn't be compatible with older versions, as OControlModel
791 // is a base class which is called in derived classes "read" method. So if you increment the version
792 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
793 // in anything from data loss to crash.
794 // EOIN!
797 void OControlModel::read(const Reference<css::io::XObjectInputStream>& InStream) throw (::com::sun::star::io::IOException, RuntimeException, std::exception)
799 osl::MutexGuard aGuard(m_aMutex);
801 Reference<css::io::XMarkableStream> xMark(InStream, UNO_QUERY);
802 if ( !xMark.is() )
804 throw IOException(
805 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
806 static_cast< ::cppu::OWeakObject* >( this )
810 // 1. reading the UnoControls
811 sal_Int32 nLen = InStream->readLong();
812 if (nLen)
814 sal_Int32 nMark = xMark->createMark();
818 readAggregate( InStream );
821 catch( const Exception& )
823 DBG_UNHANDLED_EXCEPTION();
826 xMark->jumpToMark(nMark);
827 InStream->skipBytes(nLen);
828 xMark->deleteMark(nMark);
831 // 2. reading the version number
832 sal_uInt16 nVersion = InStream->readShort();
834 // 3. reading the general properties
835 ::comphelper::operator>>( InStream, m_aName);
836 m_nTabIndex = InStream->readShort();
838 if (nVersion > 0x0002)
839 ::comphelper::operator>>( InStream, m_aTag);
841 // we had a version where we wrote the help text
842 if (nVersion == 0x0004)
843 readHelpTextCompatibly(InStream);
845 DBG_ASSERT(nVersion < 5, "OControlModel::read : suspicious version number !");
846 // 4 was the version where we wrote the help text
847 // later versions shouldn't exist (see write for a detailed comment)
850 PropertyState OControlModel::getPropertyStateByHandle( sal_Int32 _nHandle )
852 // simply compare the current and the default value
853 Any aCurrentValue = getPropertyDefaultByHandle( _nHandle );
854 Any aDefaultValue; getFastPropertyValue( aDefaultValue, _nHandle );
856 bool bEqual = uno_type_equalData(
857 const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(),
858 const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(),
859 reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
860 reinterpret_cast< uno_ReleaseFunc >(cpp_release)
862 return bEqual ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
865 void OControlModel::setPropertyToDefaultByHandle( sal_Int32 _nHandle)
867 Any aDefault = getPropertyDefaultByHandle( _nHandle );
869 Any aConvertedValue, aOldValue;
870 if ( convertFastPropertyValue( aConvertedValue, aOldValue, _nHandle, aDefault ) )
872 setFastPropertyValue_NoBroadcast( _nHandle, aConvertedValue );
873 // TODO: fire the property change
877 Any OControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
879 Any aReturn;
880 switch ( _nHandle )
882 case PROPERTY_ID_NAME:
883 case PROPERTY_ID_TAG:
884 aReturn <<= OUString();
885 break;
886 case PROPERTY_ID_CLASSID:
887 aReturn <<= (sal_Int16)FormComponentType::CONTROL;
888 break;
889 case PROPERTY_ID_TABINDEX:
890 aReturn <<= (sal_Int16)FRM_DEFAULT_TABINDEX;
891 break;
892 case PROPERTY_ID_NATIVE_LOOK:
893 aReturn <<= true;
894 break;
895 case PROPERTY_ID_GENERATEVBAEVENTS:
896 aReturn <<= false;
897 break;
898 // added for exporting OCX control
899 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
900 aReturn <<= (sal_Int16)0;
901 break;
902 case PROPERTY_ID_OBJ_ID_IN_MSO:
903 aReturn <<= (sal_uInt16)INVALID_OBJ_ID_IN_MSO;
904 break;
905 default:
906 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
907 m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( _nHandle, aReturn );
908 else
909 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle);
911 return aReturn;
914 void OControlModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
916 switch ( _nHandle )
918 case PROPERTY_ID_NAME:
919 _rValue <<= m_aName;
920 break;
921 case PROPERTY_ID_TAG:
922 _rValue <<= m_aTag;
923 break;
924 case PROPERTY_ID_CLASSID:
925 _rValue <<= m_nClassId;
926 break;
927 case PROPERTY_ID_TABINDEX:
928 _rValue <<= m_nTabIndex;
929 break;
930 case PROPERTY_ID_NATIVE_LOOK:
931 _rValue <<= m_bNativeLook;
932 break;
933 case PROPERTY_ID_GENERATEVBAEVENTS:
934 _rValue <<= m_bGenerateVbEvents;
935 // added for exporting OCX control
936 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
937 _rValue <<= (sal_Int16)m_nControlTypeinMSO;
938 break;
939 case PROPERTY_ID_OBJ_ID_IN_MSO:
940 _rValue <<= (sal_uInt16)m_nObjIDinMSO;
941 break;
942 default:
943 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
944 m_aPropertyBagHelper.getDynamicFastPropertyValue( _nHandle, _rValue );
945 else
946 OPropertySetAggregationHelper::getFastPropertyValue( _rValue, _nHandle );
947 break;
951 sal_Bool OControlModel::convertFastPropertyValue(
952 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
953 throw (com::sun::star::lang::IllegalArgumentException)
955 bool bModified(false);
956 switch (_nHandle)
958 case PROPERTY_ID_NAME:
959 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aName);
960 break;
961 case PROPERTY_ID_TAG:
962 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aTag);
963 break;
964 case PROPERTY_ID_TABINDEX:
965 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nTabIndex);
966 break;
967 case PROPERTY_ID_NATIVE_LOOK:
968 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bNativeLook);
969 break;
970 case PROPERTY_ID_GENERATEVBAEVENTS:
971 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bGenerateVbEvents);
972 break;
973 // added for exporting OCX control
974 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
975 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nControlTypeinMSO);
976 break;
977 case PROPERTY_ID_OBJ_ID_IN_MSO:
978 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nObjIDinMSO);
979 break;
980 default:
981 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
982 bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( _nHandle, _rValue, _rConvertedValue, _rOldValue );
983 else
984 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle);
985 break;
987 return bModified;
990 void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
991 throw (Exception, std::exception)
993 switch (_nHandle)
995 case PROPERTY_ID_NAME:
996 DBG_ASSERT(_rValue.getValueType() == cppu::UnoType<OUString>::get(),
997 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
998 _rValue >>= m_aName;
999 break;
1000 case PROPERTY_ID_TAG:
1001 DBG_ASSERT(_rValue.getValueType() == cppu::UnoType<OUString>::get(),
1002 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1003 _rValue >>= m_aTag;
1004 break;
1005 case PROPERTY_ID_TABINDEX:
1006 DBG_ASSERT(_rValue.getValueType() == cppu::UnoType<sal_Int16>::get(),
1007 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1008 _rValue >>= m_nTabIndex;
1009 break;
1010 case PROPERTY_ID_NATIVE_LOOK:
1011 OSL_VERIFY( _rValue >>= m_bNativeLook );
1012 break;
1013 case PROPERTY_ID_GENERATEVBAEVENTS:
1014 OSL_VERIFY( _rValue >>= m_bGenerateVbEvents );
1015 break;
1016 // added for exporting OCX control
1017 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
1018 OSL_VERIFY( _rValue >>= m_nControlTypeinMSO );
1019 break;
1020 case PROPERTY_ID_OBJ_ID_IN_MSO:
1021 OSL_VERIFY( _rValue >>= m_nObjIDinMSO );
1022 break;
1023 default:
1024 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1025 m_aPropertyBagHelper.setDynamicFastPropertyValue( _nHandle, _rValue );
1026 else
1027 SAL_WARN("forms.component", "OControlModel::setFastPropertyValue_NoBroadcast: unknown handle " << _nHandle );
1028 break;
1032 void OControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
1034 BEGIN_DESCRIBE_BASE_PROPERTIES( 7 )
1035 DECL_PROP2 (CLASSID, sal_Int16, READONLY, TRANSIENT);
1036 DECL_PROP1 (NAME, OUString, BOUND);
1037 DECL_BOOL_PROP2 (NATIVE_LOOK, BOUND, TRANSIENT);
1038 DECL_PROP1 (TAG, OUString, BOUND);
1039 DECL_PROP1 (GENERATEVBAEVENTS, sal_Bool, TRANSIENT);
1040 DECL_PROP1 (CONTROL_TYPE_IN_MSO,sal_Int16, BOUND);
1041 DECL_PROP1 (OBJ_ID_IN_MSO,cppu::UnoUnsignedShortType, BOUND);
1042 END_DESCRIBE_PROPERTIES()
1045 void OControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ _rAggregateProps ) const
1047 if ( m_xAggregateSet.is() )
1049 Reference< XPropertySetInfo > xPSI( m_xAggregateSet->getPropertySetInfo() );
1050 if ( xPSI.is() )
1051 _rAggregateProps = xPSI->getProperties();
1055 ::osl::Mutex& OControlModel::getMutex()
1057 return m_aMutex;
1060 void OControlModel::describeFixedAndAggregateProperties( Sequence< Property >& _out_rFixedProperties, Sequence< Property >& _out_rAggregateProperties ) const
1062 describeFixedProperties( _out_rFixedProperties );
1063 describeAggregateProperties( _out_rAggregateProperties );
1066 Reference< XMultiPropertySet > OControlModel::getPropertiesInterface()
1068 return Reference< XMultiPropertySet >( *this, UNO_QUERY );
1071 Reference< XPropertySetInfo> SAL_CALL OControlModel::getPropertySetInfo() throw( RuntimeException, std::exception)
1073 return createPropertySetInfo( getInfoHelper() );
1076 ::cppu::IPropertyArrayHelper& OControlModel::getInfoHelper()
1078 return m_aPropertyBagHelper.getInfoHelper();
1081 void SAL_CALL OControlModel::addProperty( const OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException, std::exception)
1083 m_aPropertyBagHelper.addProperty( _rName, _nAttributes, _rInitialValue );
1086 void SAL_CALL OControlModel::removeProperty( const OUString& _rName ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException, std::exception)
1088 m_aPropertyBagHelper.removeProperty( _rName );
1091 Sequence< PropertyValue > SAL_CALL OControlModel::getPropertyValues() throw (RuntimeException, std::exception)
1093 return m_aPropertyBagHelper.getPropertyValues();
1096 void SAL_CALL OControlModel::setPropertyValues( const Sequence< PropertyValue >& _rProps ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception)
1098 m_aPropertyBagHelper.setPropertyValues( _rProps );
1101 void OControlModel::lockInstance( LockAccess )
1103 m_aMutex.acquire();
1104 osl_atomic_increment( &m_lockCount );
1107 oslInterlockedCount OControlModel::unlockInstance( LockAccess )
1109 OSL_ENSURE( m_lockCount > 0, "OControlModel::unlockInstance: not locked!" );
1110 oslInterlockedCount lockCount = osl_atomic_decrement( &m_lockCount );
1111 m_aMutex.release();
1112 return lockCount;
1115 void OControlModel::firePropertyChanges( const Sequence< sal_Int32 >& _rHandles, const Sequence< Any >& _rOldValues,
1116 const Sequence< Any >& _rNewValues, LockAccess )
1118 OPropertySetHelper::fire(
1119 const_cast< Sequence< sal_Int32 >& >( _rHandles ).getArray(),
1120 _rNewValues.getConstArray(),
1121 _rOldValues.getConstArray(),
1122 _rHandles.getLength(),
1123 sal_False
1127 // OBoundControlModel
1128 Any SAL_CALL OBoundControlModel::queryAggregation( const Type& _rType ) throw (RuntimeException, std::exception)
1130 Any aReturn( OControlModel::queryAggregation(_rType) );
1131 if (!aReturn.hasValue())
1133 aReturn = OBoundControlModel_BASE1::queryInterface(_rType);
1135 if ( !aReturn.hasValue() && m_bCommitable )
1136 aReturn = OBoundControlModel_COMMITTING::queryInterface( _rType );
1138 if ( !aReturn.hasValue() && m_bSupportsExternalBinding )
1139 aReturn = OBoundControlModel_BINDING::queryInterface( _rType );
1141 if ( !aReturn.hasValue() && m_bSupportsValidation )
1142 aReturn = OBoundControlModel_VALIDATION::queryInterface( _rType );
1144 return aReturn;
1147 OBoundControlModel::OBoundControlModel(
1148 const Reference< XComponentContext>& _rxFactory,
1149 const OUString& _rUnoControlModelTypeName, const OUString& _rDefault,
1150 const bool _bCommitable, const bool _bSupportExternalBinding, const bool _bSupportsValidation )
1151 :OControlModel( _rxFactory, _rUnoControlModelTypeName, _rDefault, false )
1152 ,OPropertyChangeListener( m_aMutex )
1153 ,m_xField()
1154 ,m_xAmbientForm()
1155 ,m_nValuePropertyAggregateHandle( -1 )
1156 ,m_nFieldType( DataType::OTHER )
1157 ,m_bValuePropertyMayBeVoid( false )
1158 ,m_aResetHelper( *this, m_aMutex )
1159 ,m_aUpdateListeners(m_aMutex)
1160 ,m_aFormComponentListeners( m_aMutex )
1161 ,m_bInputRequired( true )
1162 ,m_pAggPropMultiplexer( NULL )
1163 ,m_bFormListening( false )
1164 ,m_bLoaded(false)
1165 ,m_bRequired(false)
1166 ,m_bCommitable(_bCommitable)
1167 ,m_bSupportsExternalBinding( _bSupportExternalBinding )
1168 ,m_bSupportsValidation( _bSupportsValidation )
1169 ,m_bForwardValueChanges(true)
1170 ,m_bTransferingValue( false )
1171 ,m_bIsCurrentValueValid( true )
1172 ,m_bBindingControlsRO( false )
1173 ,m_bBindingControlsEnable( false )
1174 ,m_eControlValueChangeInstigator( eOther )
1175 ,m_aLabelServiceName(FRM_SUN_COMPONENT_FIXEDTEXT)
1177 // start property listening at the aggregate
1178 implInitAggMultiplexer( );
1181 OBoundControlModel::OBoundControlModel(
1182 const OBoundControlModel* _pOriginal, const Reference< XComponentContext>& _rxFactory )
1183 :OControlModel( _pOriginal, _rxFactory, true, false )
1184 ,OPropertyChangeListener( m_aMutex )
1185 ,m_xField()
1186 ,m_xAmbientForm()
1187 ,m_nValuePropertyAggregateHandle( _pOriginal->m_nValuePropertyAggregateHandle )
1188 ,m_nFieldType( DataType::OTHER )
1189 ,m_bValuePropertyMayBeVoid( _pOriginal->m_bValuePropertyMayBeVoid )
1190 ,m_aResetHelper( *this, m_aMutex )
1191 ,m_aUpdateListeners( m_aMutex )
1192 ,m_aFormComponentListeners( m_aMutex )
1193 ,m_xValidator( _pOriginal->m_xValidator )
1194 ,m_bInputRequired( true )
1195 ,m_pAggPropMultiplexer( NULL )
1196 ,m_bFormListening( false )
1197 ,m_bLoaded( false )
1198 ,m_bRequired( false )
1199 ,m_bCommitable( _pOriginal->m_bCommitable )
1200 ,m_bSupportsExternalBinding( _pOriginal->m_bSupportsExternalBinding )
1201 ,m_bSupportsValidation( _pOriginal->m_bSupportsValidation )
1202 ,m_bForwardValueChanges( true )
1203 ,m_bTransferingValue( false )
1204 ,m_bIsCurrentValueValid( _pOriginal->m_bIsCurrentValueValid )
1205 ,m_bBindingControlsRO( false )
1206 ,m_bBindingControlsEnable( false )
1207 ,m_eControlValueChangeInstigator( eOther )
1209 // start property listening at the aggregate
1210 implInitAggMultiplexer( );
1211 m_aLabelServiceName = _pOriginal->m_aLabelServiceName;
1212 m_sValuePropertyName = _pOriginal->m_sValuePropertyName;
1213 m_nValuePropertyAggregateHandle = _pOriginal->m_nValuePropertyAggregateHandle;
1214 m_bValuePropertyMayBeVoid = _pOriginal->m_bValuePropertyMayBeVoid;
1215 m_aValuePropertyType = _pOriginal->m_aValuePropertyType;
1216 m_aControlSource = _pOriginal->m_aControlSource;
1217 m_bInputRequired = _pOriginal->m_bInputRequired;
1218 // m_xLabelControl, though being a property, is not to be cloned, not even the reference will be transferred.
1219 // (the former should be clear - a clone of the object we're only referencing does not make sense)
1220 // (the second would violate the restriction for label controls that they're part of the
1221 // same form component hierarchy - we ourself are no part, yet, so we can't have a label control)
1222 // start listening for changes at the value property
1223 implInitValuePropertyListening( );
1226 OBoundControlModel::~OBoundControlModel()
1228 if ( !OComponentHelper::rBHelper.bDisposed )
1230 acquire();
1231 dispose();
1234 doResetDelegator( );
1235 OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::~OBoundControlModel: what about my property multiplexer?" );
1236 if ( m_pAggPropMultiplexer )
1238 m_pAggPropMultiplexer->dispose();
1239 m_pAggPropMultiplexer->release();
1240 m_pAggPropMultiplexer = NULL;
1244 void OBoundControlModel::clonedFrom( const OControlModel* _pOriginal )
1246 const OBoundControlModel* pBoundOriginal = static_cast< const OBoundControlModel* >( _pOriginal );
1247 // the value binding can be handled as if somebody called setValueBinding here
1248 // By definition, bindings can be share between bindables
1249 if ( pBoundOriginal && pBoundOriginal->m_xExternalBinding.is() )
1253 setValueBinding( pBoundOriginal->m_xExternalBinding );
1256 catch( const Exception& )
1258 DBG_UNHANDLED_EXCEPTION();
1264 void OBoundControlModel::implInitAggMultiplexer( )
1266 osl_atomic_increment( &m_refCount );
1267 if ( m_xAggregateSet.is() )
1269 m_pAggPropMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet, false );
1270 m_pAggPropMultiplexer->acquire();
1273 osl_atomic_decrement( &m_refCount );
1274 doSetDelegator();
1277 void OBoundControlModel::implInitValuePropertyListening( ) const
1279 // start listening for changes at the value property
1280 // There are three pre-requisites for this to be done:
1281 // 1. We support external value bindings. In this case, the changes in the control value need to
1282 // be propagated to the external binding immediately when they happen
1283 // 2. We support external validation. In this case, we need to listen for changes in the value
1284 // property, since we need to revalidate then.
1285 // 3. We are not committable. In this case, changes in the control value need to be propagated
1286 // to the database column immediately when they happen.
1287 if ( m_bSupportsExternalBinding || m_bSupportsValidation || !m_bCommitable )
1289 OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::implInitValuePropertyListening: no multiplexer!" );
1290 if ( m_pAggPropMultiplexer && !m_sValuePropertyName.isEmpty() )
1291 m_pAggPropMultiplexer->addProperty( m_sValuePropertyName );
1295 void OBoundControlModel::initOwnValueProperty( const OUString& i_rValuePropertyName )
1297 OSL_PRECOND( m_sValuePropertyName.isEmpty() && -1 == m_nValuePropertyAggregateHandle,
1298 "OBoundControlModel::initOwnValueProperty: value property is already initialized!" );
1299 OSL_ENSURE( !i_rValuePropertyName.isEmpty(), "OBoundControlModel::initOwnValueProperty: invalid property name!" );
1300 m_sValuePropertyName = i_rValuePropertyName;
1303 void OBoundControlModel::initValueProperty( const OUString& _rValuePropertyName, sal_Int32 _nValuePropertyExternalHandle )
1305 OSL_PRECOND( m_sValuePropertyName.isEmpty() && -1 == m_nValuePropertyAggregateHandle,
1306 "OBoundControlModel::initValueProperty: value property is already initialized!" );
1307 OSL_ENSURE( !_rValuePropertyName.isEmpty(), "OBoundControlModel::initValueProperty: invalid property name!" );
1308 OSL_ENSURE( _nValuePropertyExternalHandle != -1, "OBoundControlModel::initValueProperty: invalid property handle!" );
1310 m_sValuePropertyName = _rValuePropertyName;
1311 m_nValuePropertyAggregateHandle = getOriginalHandle( _nValuePropertyExternalHandle );
1312 OSL_ENSURE( m_nValuePropertyAggregateHandle != -1, "OBoundControlModel::initValueProperty: unable to find the original handle!" );
1314 if ( m_nValuePropertyAggregateHandle != -1 )
1316 Reference< XPropertySetInfo > xPropInfo( m_xAggregateSet->getPropertySetInfo(), UNO_SET_THROW );
1317 Property aValuePropDesc = xPropInfo->getPropertyByName( m_sValuePropertyName );
1318 m_aValuePropertyType = aValuePropDesc.Type;
1319 m_bValuePropertyMayBeVoid = ( aValuePropDesc.Attributes & PropertyAttribute::MAYBEVOID ) != 0;
1322 // start listening for changes at the value property
1323 implInitValuePropertyListening( );
1326 void OBoundControlModel::suspendValueListening( )
1328 OSL_PRECOND( !m_sValuePropertyName.isEmpty(), "OBoundControlModel::suspendValueListening: don't have a value property!" );
1329 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::suspendValueListening: I *am* not listening!" );
1331 if ( m_pAggPropMultiplexer )
1332 m_pAggPropMultiplexer->lock();
1335 void OBoundControlModel::resumeValueListening( )
1337 OSL_PRECOND( !m_sValuePropertyName.isEmpty(), "OBoundControlModel::resumeValueListening: don't have a value property!" );
1338 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::resumeValueListening: I *am* not listening at all!" );
1339 OSL_PRECOND( !m_pAggPropMultiplexer || m_pAggPropMultiplexer->locked(), "OBoundControlModel::resumeValueListening: listening not suspended currently!" );
1340 if ( m_pAggPropMultiplexer )
1341 m_pAggPropMultiplexer->unlock();
1344 Sequence< Type > OBoundControlModel::_getTypes()
1346 TypeBag aTypes(
1347 OControlModel::_getTypes(),
1348 OBoundControlModel_BASE1::getTypes()
1351 if ( m_bCommitable )
1352 aTypes.addTypes( OBoundControlModel_COMMITTING::getTypes() );
1354 if ( m_bSupportsExternalBinding )
1355 aTypes.addTypes( OBoundControlModel_BINDING::getTypes() );
1357 if ( m_bSupportsValidation )
1358 aTypes.addTypes( OBoundControlModel_VALIDATION::getTypes() );
1359 return aTypes.getTypes();
1362 // OComponentHelper
1363 void OBoundControlModel::disposing()
1365 OControlModel::disposing();
1367 ::osl::ClearableMutexGuard aGuard(m_aMutex);
1369 if ( m_pAggPropMultiplexer )
1370 m_pAggPropMultiplexer->dispose();
1372 // notify all our listeners
1373 com::sun::star::lang::EventObject aEvt( static_cast< XWeak* >( this ) );
1374 m_aUpdateListeners.disposeAndClear( aEvt );
1375 m_aResetHelper.disposing();
1377 // disconnect from our database column
1378 // TODO: could we replace the following 5 lines with a call to impl_disconnectDatabaseColumn_noNotify?
1379 // The only more thing which it does is calling onDisconnectedDbColumn - could this
1380 // cause trouble? At least when we continue to call OControlModel::disposing before, it *may*.
1381 if ( hasField() )
1383 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
1384 resetField();
1387 m_xCursor = NULL;
1388 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1389 if ( xComp.is() )
1390 xComp->removeEventListener(static_cast< XEventListener* >( static_cast< XPropertyChangeListener* >( this ) ) );
1391 // disconnect from our external value binding
1392 if ( hasExternalValueBinding() )
1393 disconnectExternalValueBinding();
1394 // dito for the validator
1395 if ( hasValidator() )
1396 disconnectValidator( );
1399 void OBoundControlModel::onValuePropertyChange( ControlModelLock& i_rControLock )
1401 if ( hasExternalValueBinding() )
1403 // the control value changed, while we have an external value binding
1404 // -> forward the value to it
1405 if ( m_eControlValueChangeInstigator != eExternalBinding )
1406 transferControlValueToExternal( i_rControLock );
1409 else if ( !m_bCommitable && m_xColumnUpdate.is() )
1411 // the control value changed, while we are bound to a database column,
1412 // but not committable (which means changes in the control have to be reflected to
1413 // the underlying database column immediately)
1414 // -> forward the value to the database column
1415 if ( m_eControlValueChangeInstigator != eDbColumnBinding )
1416 commitControlValueToDbColumn( false );
1419 // validate the new value
1420 if ( m_bSupportsValidation )
1421 recheckValidity( true );
1424 void OBoundControlModel::_propertyChanged( const PropertyChangeEvent& _rEvt ) throw ( RuntimeException )
1426 ControlModelLock aLock( *this );
1427 OSL_ENSURE( _rEvt.PropertyName == m_sValuePropertyName,
1428 "OBoundControlModel::_propertyChanged: where did this come from (1)?" );
1429 OSL_ENSURE( m_pAggPropMultiplexer && !m_pAggPropMultiplexer->locked(),
1430 "OBoundControlModel::_propertyChanged: where did this come from (2)?" );
1431 if ( _rEvt.PropertyName == m_sValuePropertyName )
1433 onValuePropertyChange( aLock );
1437 void OBoundControlModel::startAggregatePropertyListening( const OUString& _rPropertyName )
1439 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::startAggregatePropertyListening: no multiplexer!" );
1440 OSL_ENSURE( !_rPropertyName.isEmpty(), "OBoundControlModel::startAggregatePropertyListening: invalid property name!" );
1441 if ( m_pAggPropMultiplexer && !_rPropertyName.isEmpty() )
1443 m_pAggPropMultiplexer->addProperty( _rPropertyName );
1447 void OBoundControlModel::doFormListening( const bool _bStart )
1449 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::doFormListening: external value binding should overrule the database binding!" );
1450 if ( isFormListening() == _bStart )
1451 return;
1452 if ( m_xAmbientForm.is() )
1453 _bStart ? m_xAmbientForm->addLoadListener( this ) : m_xAmbientForm->removeLoadListener( this );
1454 Reference< XLoadable > xParentLoadable( getParent(), UNO_QUERY );
1455 if ( getParent().is() && !xParentLoadable.is() )
1457 // if our parent does not directly support the XLoadable interface, then it might support the
1458 // XRowSetSupplier/XRowSetChangeBroadcaster interfaces. In this case we have to listen for changes
1459 // broadcasted by the latter.
1460 Reference< XRowSetChangeBroadcaster > xRowSetBroadcaster( getParent(), UNO_QUERY );
1461 if ( xRowSetBroadcaster.is() )
1462 _bStart ? xRowSetBroadcaster->addRowSetChangeListener( this ) : xRowSetBroadcaster->removeRowSetChangeListener( this );
1465 m_bFormListening = _bStart && m_xAmbientForm.is();
1468 // XChild
1469 void SAL_CALL OBoundControlModel::setParent(const Reference<XInterface>& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException, std::exception)
1471 ControlModelLock aLock( *this );
1472 FieldChangeNotifier aBoundFieldNotifier( aLock );
1473 if ( getParent() == _rxParent )
1474 return;
1475 // disconnect from database column (which is controlled by parent, directly or indirectly)
1476 if ( hasField() )
1477 impl_disconnectDatabaseColumn_noNotify();
1478 // log off old listeners
1479 if ( isFormListening() )
1480 doFormListening( false );
1481 // actually set the new parent
1482 OControlModel::setParent( _rxParent );
1483 // a new parent means a new ambient form
1484 impl_determineAmbientForm_nothrow();
1485 if ( !hasExternalValueBinding() )
1487 // log on new listeners
1488 doFormListening( true );
1489 // re-connect to database column of the new parent
1490 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
1491 impl_connectDatabaseColumn_noNotify( false );
1495 // XEventListener
1496 void SAL_CALL OBoundControlModel::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException, std::exception)
1498 ControlModelLock aLock( *this );
1499 if ( _rEvent.Source == getField() )
1501 resetField();
1504 else if ( _rEvent.Source == m_xLabelControl )
1506 Reference<XPropertySet> xOldValue = m_xLabelControl;
1507 m_xLabelControl = NULL;
1508 // fire a propertyChanged (when we leave aLock's scope)
1509 aLock.addPropertyNotification( PROPERTY_ID_CONTROLLABEL, makeAny( xOldValue ), makeAny( m_xLabelControl ) );
1512 else if ( _rEvent.Source == m_xExternalBinding )
1513 { // *first* check for the external binding
1514 disconnectExternalValueBinding( );
1517 else if ( _rEvent.Source == m_xValidator )
1518 { // *then* check for the validator. Reason is that bindings may also act as validator at the same
1519 // time, in this case, the validator is automatically revoked when the binding is revoked
1520 disconnectValidator( );
1523 else
1524 OControlModel::disposing(_rEvent);
1527 // XServiceInfo
1528 StringSequence SAL_CALL OBoundControlModel::getSupportedServiceNames() throw(RuntimeException, std::exception)
1530 return ::comphelper::combineSequences(
1531 getAggregateServiceNames(),
1532 getSupportedServiceNames_Static()
1536 Sequence< OUString > SAL_CALL OBoundControlModel::getSupportedServiceNames_Static() throw( RuntimeException )
1538 Sequence< OUString > aOwnServiceNames( 1 );
1539 aOwnServiceNames[ 0 ] = "com.sun.star.form.DataAwareControlModel";
1540 return ::comphelper::concatSequences(
1541 OControlModel::getSupportedServiceNames_Static(),
1542 aOwnServiceNames
1546 // XPersist
1547 void SAL_CALL OBoundControlModel::write( const Reference<css::io::XObjectOutputStream>& _rxOutStream ) throw(css::io::IOException, RuntimeException, std::exception)
1549 OControlModel::write(_rxOutStream);
1550 osl::MutexGuard aGuard(m_aMutex);
1551 // Version
1552 _rxOutStream->writeShort(0x0002);
1553 // Controlsource
1554 ::comphelper::operator<<( _rxOutStream, m_aControlSource);
1555 // !!! IMPORTANT NOTE !!!
1556 // don't write any new members here: this wouldn't be compatible with older versions, as OBoundControlModel
1557 // is a base class which is called in derived classes "read" method. So if you increment the version
1558 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
1559 // in anything from data loss to crash.
1560 // (use writeCommonProperties instead, this is called in derived classes write-method)
1561 // !!! EOIN !!!
1564 void OBoundControlModel::defaultCommonProperties()
1566 Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1567 if (xComp.is())
1568 xComp->removeEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1569 m_xLabelControl = NULL;
1572 void OBoundControlModel::readCommonProperties(const Reference<css::io::XObjectInputStream>& _rxInStream)
1574 sal_Int32 nLen = _rxInStream->readLong();
1575 Reference<css::io::XMarkableStream> xMark(_rxInStream, UNO_QUERY);
1576 DBG_ASSERT(xMark.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !");
1577 sal_Int32 nMark = xMark->createMark();
1578 // read the reference to the label control
1579 Reference<css::io::XPersistObject> xPersist;
1580 sal_Int32 nUsedFlag;
1581 nUsedFlag = _rxInStream->readLong();
1582 if (nUsedFlag)
1583 xPersist = _rxInStream->readObject();
1584 m_xLabelControl.set(xPersist, css::uno::UNO_QUERY);
1585 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1586 if (xComp.is())
1587 xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1588 // read any other new common properties here
1589 // skip the remaining bytes
1590 xMark->jumpToMark(nMark);
1591 _rxInStream->skipBytes(nLen);
1592 xMark->deleteMark(nMark);
1595 void OBoundControlModel::writeCommonProperties(const Reference<css::io::XObjectOutputStream>& _rxOutStream)
1597 Reference<css::io::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
1598 DBG_ASSERT(xMark.is(), "OBoundControlModel::writeCommonProperties : can only work with markable streams !");
1599 sal_Int32 nMark = xMark->createMark();
1600 // a placeholder where we will write the overall length (later in this method)
1601 sal_Int32 nLen = 0;
1602 _rxOutStream->writeLong(nLen);
1603 // write the reference to the label control
1604 Reference<css::io::XPersistObject> xPersist(m_xLabelControl, UNO_QUERY);
1605 sal_Int32 nUsedFlag = 0;
1606 if (xPersist.is())
1607 nUsedFlag = 1;
1608 _rxOutStream->writeLong(nUsedFlag);
1609 if (xPersist.is())
1610 _rxOutStream->writeObject(xPersist);
1611 // write any other new common properties here
1612 // write the correct length at the beginning of the block
1613 nLen = xMark->offsetToMark(nMark) - sizeof(nLen);
1614 xMark->jumpToMark(nMark);
1615 _rxOutStream->writeLong(nLen);
1616 xMark->jumpToFurthest();
1617 xMark->deleteMark(nMark);
1620 void SAL_CALL OBoundControlModel::read( const Reference< css::io::XObjectInputStream >& _rxInStream ) throw(css::io::IOException, RuntimeException, std::exception)
1622 OControlModel::read(_rxInStream);
1623 osl::MutexGuard aGuard(m_aMutex);
1624 sal_uInt16 nVersion = _rxInStream->readShort(); (void)nVersion;
1625 ::comphelper::operator>>( _rxInStream, m_aControlSource);
1628 void OBoundControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
1630 switch (nHandle)
1632 case PROPERTY_ID_INPUT_REQUIRED:
1633 rValue <<= m_bInputRequired;
1634 break;
1635 case PROPERTY_ID_CONTROLSOURCEPROPERTY:
1636 rValue <<= m_sValuePropertyName;
1637 break;
1638 case PROPERTY_ID_CONTROLSOURCE:
1639 rValue <<= m_aControlSource;
1640 break;
1641 case PROPERTY_ID_BOUNDFIELD:
1642 rValue <<= getField();
1643 break;
1644 case PROPERTY_ID_CONTROLLABEL:
1645 if (!m_xLabelControl.is())
1646 rValue.clear();
1647 else
1648 rValue <<= m_xLabelControl;
1649 break;
1650 default:
1651 OControlModel::getFastPropertyValue(rValue, nHandle);
1655 sal_Bool OBoundControlModel::convertFastPropertyValue(
1656 Any& _rConvertedValue, Any& _rOldValue,
1657 sal_Int32 _nHandle,
1658 const Any& _rValue)
1659 throw (com::sun::star::lang::IllegalArgumentException)
1661 bool bModified(false);
1662 switch (_nHandle)
1664 case PROPERTY_ID_INPUT_REQUIRED:
1665 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, m_bInputRequired );
1666 break;
1667 case PROPERTY_ID_CONTROLSOURCE:
1668 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aControlSource);
1669 break;
1670 case PROPERTY_ID_BOUNDFIELD:
1671 SAL_WARN("forms.component", "OBoundControlModel::convertFastPropertyValue: BoundField should be a read-only property !" );
1672 throw com::sun::star::lang::IllegalArgumentException();
1673 case PROPERTY_ID_CONTROLLABEL:
1674 if (!_rValue.hasValue())
1675 { // property set to void
1676 _rConvertedValue = Any();
1677 getFastPropertyValue(_rOldValue, _nHandle);
1678 bModified = m_xLabelControl.is();
1681 else
1683 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_xLabelControl);
1684 if (!m_xLabelControl.is())
1685 // an empty interface is interpreted as VOID
1686 _rOldValue.clear();
1689 break;
1690 default:
1691 bModified = OControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
1693 return bModified;
1696 Any OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
1698 Any aDefault;
1699 switch ( _nHandle )
1701 case PROPERTY_ID_INPUT_REQUIRED:
1702 aDefault <<= true;
1703 break;
1704 case PROPERTY_ID_CONTROLSOURCE:
1705 aDefault <<= OUString();
1706 break;
1707 case PROPERTY_ID_CONTROLLABEL:
1708 aDefault <<= Reference< XPropertySet >();
1709 break;
1711 return aDefault;
1714 void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception, std::exception)
1716 switch (nHandle)
1718 case PROPERTY_ID_INPUT_REQUIRED:
1719 OSL_VERIFY( rValue >>= m_bInputRequired );
1720 break;
1721 case PROPERTY_ID_CONTROLSOURCE:
1722 OSL_VERIFY( rValue >>= m_aControlSource );
1723 break;
1724 case PROPERTY_ID_BOUNDFIELD:
1725 SAL_WARN("forms.component", "OBoundControlModel::setFastPropertyValue_NoBroadcast : BoundField should be a read-only property !");
1726 throw com::sun::star::lang::IllegalArgumentException();
1727 case PROPERTY_ID_CONTROLLABEL:
1729 if ( rValue.hasValue() && ( rValue.getValueTypeClass() != TypeClass_INTERFACE ) )
1730 throw com::sun::star::lang::IllegalArgumentException();
1731 Reference< XInterface > xNewValue( rValue, UNO_QUERY );
1732 if ( !xNewValue.is() )
1733 { // set property to "void"
1734 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1735 if ( xComp.is() )
1736 xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
1737 m_xLabelControl = NULL;
1738 break;
1741 Reference< XControlModel > xAsModel ( xNewValue, UNO_QUERY );
1742 Reference< XServiceInfo > xAsServiceInfo ( xAsModel, UNO_QUERY );
1743 Reference< XPropertySet > xAsPropSet ( xAsServiceInfo, UNO_QUERY );
1744 Reference< XChild > xAsChild ( xAsPropSet, UNO_QUERY );
1745 if ( !xAsChild.is() || !xAsServiceInfo->supportsService( m_aLabelServiceName ) )
1747 throw com::sun::star::lang::IllegalArgumentException();
1750 // Check if we and the given model have a common ancestor (up to the forms collection)
1751 Reference<XChild> xCont(
1752 static_cast<XWeak*>(this), css::uno::UNO_QUERY);
1753 Reference< XInterface > xMyTopLevel = xCont->getParent();
1754 while (xMyTopLevel.is())
1756 Reference<XForm> xAsForm(xMyTopLevel, UNO_QUERY);
1757 if (!xAsForm.is())
1758 // found my root
1759 break;
1760 Reference<XChild> xLoopAsChild(xMyTopLevel, UNO_QUERY);
1761 xMyTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1764 Reference< XInterface > xNewTopLevel = xAsChild->getParent();
1765 while (xNewTopLevel.is())
1767 Reference<XForm> xAsForm(xNewTopLevel, UNO_QUERY);
1768 if (!xAsForm.is())
1769 break;
1770 Reference<XChild> xLoopAsChild(xNewTopLevel, UNO_QUERY);
1771 xNewTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1774 if (xNewTopLevel != xMyTopLevel)
1776 // the both objects don't belong to the same forms collection -> not acceptable
1777 throw com::sun::star::lang::IllegalArgumentException();
1780 m_xLabelControl = xAsPropSet;
1781 Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1782 if (xComp.is())
1783 xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1786 break;
1787 default:
1788 OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue );
1792 // XPropertyChangeListener
1793 void SAL_CALL OBoundControlModel::propertyChange( const PropertyChangeEvent& evt ) throw(RuntimeException, std::exception)
1795 // if the DBColumn value changed, transfer it to the control
1796 if ( evt.PropertyName == PROPERTY_VALUE )
1798 OSL_ENSURE( evt.Source == getField(), "OBoundControlModel::propertyChange: value changes from components other than our database column?" );
1799 osl::MutexGuard aGuard(m_aMutex);
1800 if ( m_bForwardValueChanges && m_xColumn.is() )
1801 transferDbValueToControl();
1804 else
1806 OSL_ENSURE( evt.Source == m_xExternalBinding, "OBoundControlModel::propertyChange: where did this come from?" );
1807 // our binding has properties which can control properties of ourself
1808 OUString sBindingControlledProperty;
1809 bool bForwardToLabelControl = false;
1810 if ( evt.PropertyName == PROPERTY_READONLY )
1812 sBindingControlledProperty = PROPERTY_READONLY;
1815 else if ( evt.PropertyName == PROPERTY_RELEVANT )
1817 sBindingControlledProperty = PROPERTY_ENABLED;
1818 bForwardToLabelControl = true;
1821 else
1822 return;
1825 setPropertyValue( sBindingControlledProperty, evt.NewValue );
1826 if ( bForwardToLabelControl && m_xLabelControl.is() )
1827 m_xLabelControl->setPropertyValue( sBindingControlledProperty, evt.NewValue );
1830 catch( const Exception& )
1832 SAL_WARN("forms.component", "OBoundControlModel::propertyChange: could not adjust my binding-controlled property!");
1833 DBG_UNHANDLED_EXCEPTION();
1839 void SAL_CALL OBoundControlModel::onRowSetChanged( const EventObject& /*i_Event*/ ) throw (RuntimeException, std::exception)
1841 ControlModelLock aLock( *this );
1842 FieldChangeNotifier aBoundFieldNotifier( aLock );
1843 // disconnect from database column (which is controlled by parent, directly or indirectly)
1844 if ( hasField() )
1845 impl_disconnectDatabaseColumn_noNotify();
1846 // log off old listeners
1847 if ( isFormListening() )
1848 doFormListening( false );
1849 // determine the new ambient form
1850 impl_determineAmbientForm_nothrow();
1851 // log on new listeners
1852 doFormListening( true );
1853 // re-connect to database column if needed and possible
1854 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
1855 impl_connectDatabaseColumn_noNotify( false );
1858 // XBoundComponent
1859 void SAL_CALL OBoundControlModel::addUpdateListener(const Reference<XUpdateListener>& _rxListener) throw(RuntimeException, std::exception)
1861 m_aUpdateListeners.addInterface(_rxListener);
1864 void SAL_CALL OBoundControlModel::removeUpdateListener(const Reference< XUpdateListener>& _rxListener) throw(RuntimeException, std::exception)
1866 m_aUpdateListeners.removeInterface(_rxListener);
1869 sal_Bool SAL_CALL OBoundControlModel::commit() throw(RuntimeException, std::exception)
1871 ControlModelLock aLock( *this );
1872 OSL_PRECOND( m_bCommitable, "OBoundControlModel::commit: invalid call (I'm not commitable !) " );
1873 if ( hasExternalValueBinding() )
1875 // in most cases, no action is required: For most derivees, we know the value property of
1876 // our control (see initValueProperty), and when an external binding is active, we
1877 // instantly forward all changes in this property to the external binding.
1878 if ( m_sValuePropertyName.isEmpty() )
1879 // but for those derivees which did not use this feature, we need an
1880 // explicit transfer
1881 transferControlValueToExternal( aLock );
1882 return sal_True;
1885 OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" );
1886 // we reach this only if we're not working with an external binding
1887 if ( !hasField() )
1888 return sal_True;
1889 ::cppu::OInterfaceIteratorHelper aIter( m_aUpdateListeners );
1890 EventObject aEvent;
1891 aEvent.Source = static_cast< XWeak* >( this );
1892 bool bSuccess = true;
1893 aLock.release();
1894 // UNSAFE >
1895 while (aIter.hasMoreElements() && bSuccess)
1896 bSuccess = static_cast< XUpdateListener* >( aIter.next() )->approveUpdate( aEvent );
1897 // < UNSAFE
1898 aLock.acquire();
1899 if ( bSuccess )
1903 if ( m_xColumnUpdate.is() )
1904 bSuccess = commitControlValueToDbColumn( false );
1907 catch(const Exception&)
1909 bSuccess = false;
1914 if ( bSuccess )
1916 aLock.release();
1917 m_aUpdateListeners.notifyEach( &XUpdateListener::updated, aEvent );
1919 return bSuccess;
1922 void OBoundControlModel::resetField()
1924 m_xColumnUpdate.clear();
1925 m_xColumn.clear();
1926 m_xField.clear();
1927 m_nFieldType = DataType::OTHER;
1930 bool OBoundControlModel::connectToField(const Reference<XRowSet>& rForm)
1932 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::connectToField: invalid call (have an external binding)!" );
1933 // if there's a connection to the database
1934 if (rForm.is() && getConnection(rForm).is())
1936 // determine field and PropertyChangeListener
1937 m_xCursor = rForm;
1938 Reference<XPropertySet> xFieldCandidate;
1939 if (m_xCursor.is())
1941 Reference<XColumnsSupplier> xColumnsSupplier(m_xCursor, UNO_QUERY);
1942 DBG_ASSERT(xColumnsSupplier.is(), "OBoundControlModel::connectToField : the row set should support the com::sun::star::sdb::ResultSet service !");
1943 if (xColumnsSupplier.is())
1945 Reference<XNameAccess> xColumns(xColumnsSupplier->getColumns(), UNO_QUERY);
1946 if (xColumns.is() && xColumns->hasByName(m_aControlSource))
1948 OSL_VERIFY( xColumns->getByName(m_aControlSource) >>= xFieldCandidate );
1957 sal_Int32 nFieldType = DataType::OTHER;
1958 if ( xFieldCandidate.is() )
1960 xFieldCandidate->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
1961 if ( approveDbColumnType( nFieldType ) )
1962 impl_setField_noNotify( xFieldCandidate );
1965 else
1966 impl_setField_noNotify( NULL );
1967 if ( m_xField.is() )
1969 if ( m_xField->getPropertySetInfo()->hasPropertyByName( PROPERTY_VALUE ) )
1971 m_nFieldType = nFieldType;
1972 // listen to changing values
1973 m_xField->addPropertyChangeListener( PROPERTY_VALUE, this );
1974 m_xColumnUpdate = Reference< XColumnUpdate >( m_xField, UNO_QUERY );
1975 m_xColumn = Reference< XColumn >( m_xField, UNO_QUERY );
1976 sal_Int32 nNullableFlag = ColumnValue::NO_NULLS;
1977 m_xField->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullableFlag;
1978 m_bRequired = (ColumnValue::NO_NULLS == nNullableFlag);
1979 // we're optimistic: in case of ColumnValue_NULLABLE_UNKNOWN we assume nullability...
1981 else
1983 SAL_WARN("forms.component", "OBoundControlModel::connectToField: property " PROPERTY_VALUE " not supported!");
1984 impl_setField_noNotify( NULL );
1991 catch( const Exception& )
1993 DBG_UNHANDLED_EXCEPTION();
1994 resetField();
1998 return hasField();
2001 void OBoundControlModel::initFromField( const Reference< XRowSet >& _rxRowSet )
2003 // but only if the rowset if posisitioned on a valid record
2004 if ( hasField() && _rxRowSet.is() )
2006 if ( !_rxRowSet->isBeforeFirst() && !_rxRowSet->isAfterLast() )
2007 transferDbValueToControl();
2008 else
2009 // reset the field if the row set is empty
2010 // #i30661#
2011 resetNoBroadcast();
2015 bool OBoundControlModel::approveDbColumnType(sal_Int32 _nColumnType)
2017 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::approveDbColumnType: invalid call (have an external binding)!" );
2018 if ((_nColumnType == DataType::BINARY) || (_nColumnType == DataType::VARBINARY)
2019 || (_nColumnType == DataType::LONGVARBINARY) || (_nColumnType == DataType::OTHER)
2020 || (_nColumnType == DataType::OBJECT) || (_nColumnType == DataType::DISTINCT)
2021 || (_nColumnType == DataType::STRUCT) || (_nColumnType == DataType::ARRAY)
2022 || (_nColumnType == DataType::BLOB) /*|| (_nColumnType == DataType::CLOB)*/
2023 || (_nColumnType == DataType::REF) || (_nColumnType == DataType::SQLNULL))
2024 return false;
2025 return true;
2028 void OBoundControlModel::impl_determineAmbientForm_nothrow()
2030 Reference< XInterface > xParent( getParent() );
2031 m_xAmbientForm.set( xParent, UNO_QUERY );
2032 if ( !m_xAmbientForm.is() )
2034 Reference< XRowSetSupplier > xSupRowSet( xParent, UNO_QUERY );
2035 if ( xSupRowSet.is() )
2036 m_xAmbientForm.set( xSupRowSet->getRowSet(), UNO_QUERY );
2040 void OBoundControlModel::impl_connectDatabaseColumn_noNotify( bool _bFromReload )
2042 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2043 // consistency checks
2044 DBG_ASSERT( !( hasField() && !_bFromReload ),
2045 "OBoundControlModel::impl_connectDatabaseColumn_noNotify: the form is just *loaded*, but we already have a field!" );
2046 (void)_bFromReload;
2047 Reference< XRowSet > xRowSet( m_xAmbientForm, UNO_QUERY );
2048 OSL_ENSURE( xRowSet.is(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: no row set!" );
2049 if ( !xRowSet.is() )
2050 return;
2051 if ( !hasField() )
2053 // connect to the column
2054 connectToField( xRowSet );
2057 // now that we're connected (more or less, even if we did not find a column),
2058 // we definitely want to forward any potentially occurring value changes
2059 m_bForwardValueChanges = true;
2060 // let derived classes react on this new connection
2061 m_bLoaded = true;
2062 onConnectedDbColumn( xRowSet );
2063 // initially transfer the db column value to the control, if we successfully connected to a database column
2064 if ( hasField() )
2065 initFromField( xRowSet );
2068 void OBoundControlModel::impl_disconnectDatabaseColumn_noNotify()
2070 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_disconnectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2071 // let derived classes react on this
2072 onDisconnectedDbColumn();
2073 if ( hasField() )
2075 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
2076 resetField();
2079 m_xCursor = NULL;
2080 m_bLoaded = false;
2083 // XLoadListener
2084 void SAL_CALL OBoundControlModel::loaded( const EventObject& _rEvent ) throw(RuntimeException, std::exception)
2086 ControlModelLock aLock( *this );
2087 FieldChangeNotifier aBoundFieldNotifier( aLock );
2088 OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::loaded: where does this come from?" );
2089 (void)_rEvent;
2090 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::loaded: we should never reach this with an external value binding!" );
2091 if ( hasExternalValueBinding() )
2092 return;
2093 impl_connectDatabaseColumn_noNotify( false );
2096 void SAL_CALL OBoundControlModel::unloaded( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException, std::exception)
2098 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloaded: we should never reach this with an external value binding!" );
2101 void SAL_CALL OBoundControlModel::reloading( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException, std::exception)
2103 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloading: we should never reach this with an external value binding!" );
2104 if ( hasExternalValueBinding() )
2105 return;
2106 osl::MutexGuard aGuard(m_aMutex);
2107 m_bForwardValueChanges = false;
2110 void SAL_CALL OBoundControlModel::unloading(const com::sun::star::lang::EventObject& /*aEvent*/) throw(RuntimeException, std::exception)
2112 ControlModelLock aLock( *this );
2113 FieldChangeNotifier aBoundFieldNotifier( aLock );
2114 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloading: we should never reach this with an external value binding!" );
2115 if ( hasExternalValueBinding() )
2116 return;
2117 impl_disconnectDatabaseColumn_noNotify();
2120 void SAL_CALL OBoundControlModel::reloaded( const EventObject& _rEvent ) throw(RuntimeException, std::exception)
2122 ControlModelLock aLock( *this );
2123 FieldChangeNotifier aBoundFieldNotifier( aLock );
2124 OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::reloaded: where does this come from?" );
2125 (void)_rEvent;
2126 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloaded: we should never reach this with an external value binding!" );
2127 if ( hasExternalValueBinding() )
2128 return;
2129 impl_connectDatabaseColumn_noNotify( true );
2132 void OBoundControlModel::setControlValue( const Any& _rValue, ValueChangeInstigator _eInstigator )
2134 m_eControlValueChangeInstigator = _eInstigator;
2135 doSetControlValue( _rValue );
2136 m_eControlValueChangeInstigator = eOther;
2139 void OBoundControlModel::doSetControlValue( const Any& _rValue )
2141 OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2142 "OBoundControlModel::doSetControlValue: invalid aggregate !" );
2143 OSL_PRECOND( !m_sValuePropertyName.isEmpty() || ( m_nValuePropertyAggregateHandle != -1 ),
2144 "OBoundControlModel::doSetControlValue: please override if you have own value property handling!" );
2147 // release our mutex once (it's acquired in one of the calling methods), as setting aggregate properties
2148 // may cause any uno controls belonging to us to lock the solar mutex, which is potentially dangerous with
2149 // our own mutex locked
2150 MutexRelease aRelease( m_aMutex );
2151 if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2153 m_xAggregateFastSet->setFastPropertyValue( m_nValuePropertyAggregateHandle, _rValue );
2156 else if ( !m_sValuePropertyName.isEmpty() && m_xAggregateSet.is() )
2158 m_xAggregateSet->setPropertyValue( m_sValuePropertyName, _rValue );
2163 catch( const Exception& )
2165 SAL_WARN("forms.component", "OBoundControlModel::doSetControlValue: caught an exception!");
2166 DBG_UNHANDLED_EXCEPTION();
2170 void OBoundControlModel::onConnectedValidator( )
2174 // if we have an external validator, we do not want the control to force invalid
2175 // inputs to the default value. Instead, invalid inputs should be translated
2176 // to NaN (not a number)
2177 Reference< XPropertySetInfo > xAggregatePropertyInfo;
2178 if ( m_xAggregateSet.is() )
2179 xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2180 if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2181 m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( false ) );
2184 catch( const Exception& )
2186 SAL_WARN("forms.component", "OBoundControlModel::onConnectedValidator: caught an exception!");
2187 DBG_UNHANDLED_EXCEPTION();
2190 recheckValidity( false );
2193 void OBoundControlModel::onDisconnectedValidator( )
2197 Reference< XPropertySetInfo > xAggregatePropertyInfo;
2198 if ( m_xAggregateSet.is() )
2199 xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2200 if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2201 m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( true ) );
2204 catch( const Exception& )
2206 SAL_WARN("forms.component", "OBoundControlModel::onDisconnectedValidator: caught an exception!");
2207 DBG_UNHANDLED_EXCEPTION();
2210 recheckValidity( false );
2213 void OBoundControlModel::onConnectedExternalValue( )
2215 calculateExternalValueType();
2218 void OBoundControlModel::onConnectedDbColumn( const Reference< XInterface >& /*_rxForm*/ )
2220 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onConnectedDbColumn: how this? There's an external value binding!" );
2223 void OBoundControlModel::onDisconnectedDbColumn()
2225 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onDisconnectedDbColumn: how this? There's an external value binding!" );
2228 // XReset
2229 Any OBoundControlModel::getDefaultForReset() const
2231 return Any();
2234 void OBoundControlModel::resetNoBroadcast()
2236 setControlValue( getDefaultForReset(), eOther );
2239 void OBoundControlModel::addResetListener(const Reference<XResetListener>& l) throw (RuntimeException, std::exception)
2241 m_aResetHelper.addResetListener( l );
2244 void OBoundControlModel::removeResetListener(const Reference<XResetListener>& l) throw (RuntimeException, std::exception)
2246 m_aResetHelper.removeResetListener( l );
2249 void OBoundControlModel::reset() throw (RuntimeException, std::exception)
2251 if ( !m_aResetHelper.approveReset() )
2252 return;
2253 ControlModelLock aLock( *this );
2254 // on a new record?
2255 bool bIsNewRecord = false;
2256 Reference<XPropertySet> xSet( m_xCursor, UNO_QUERY );
2257 if ( xSet.is() )
2261 xSet->getPropertyValue( PROPERTY_ISNEW ) >>= bIsNewRecord;
2264 catch( const Exception& )
2266 DBG_UNHANDLED_EXCEPTION();
2271 // cursor on an invalid row?
2272 bool bInvalidCursorPosition = true;
2275 bInvalidCursorPosition = m_xCursor.is()
2276 && ( m_xCursor->isAfterLast()
2277 || m_xCursor->isBeforeFirst()
2279 && !bIsNewRecord;
2282 catch( const SQLException& )
2284 SAL_WARN("forms.component", "OBoundControlModel::reset: caught an SQL exception!" );
2285 DBG_UNHANDLED_EXCEPTION();
2288 // #i24495# - don't count the insert row as "invalid"
2289 bool bSimpleReset =
2290 ( !m_xColumn.is() // no connection to a database column
2291 || ( m_xCursor.is() // OR we have an improperly positioned cursor
2292 && bInvalidCursorPosition
2294 || hasExternalValueBinding() // OR we have an external value binding
2296 if ( !bSimpleReset )
2298 // The default values will be set if and only if the current value of the field which we're bound
2299 // to is NULL.
2300 // Else, the current field value should be refreshed
2301 // This behaviour is not completely ... "matured": What should happen if the field as well as the
2302 // control have a default value?
2303 bool bIsNull = true;
2304 // we have to access the field content at least once to get a reliable result by XColumn::wasNull
2307 // normally, we'd do a getString here. However, this is extremely expensive in the case
2308 // of binary fields. Unfortunately, getString is the only method which is guaranteed
2309 // to *always* succeed, all other getXXX methods may fail if the column is asked for a
2310 // non-convertible type
2311 sal_Int32 nFieldType = DataType::OBJECT;
2312 getField()->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
2313 if ( ( nFieldType == DataType::BINARY )
2314 || ( nFieldType == DataType::VARBINARY )
2315 || ( nFieldType == DataType::LONGVARBINARY )
2316 || ( nFieldType == DataType::OBJECT )
2317 /*|| ( nFieldType == DataType::CLOB )*/
2319 m_xColumn->getBinaryStream();
2320 else if ( nFieldType == DataType::BLOB )
2321 m_xColumn->getBlob();
2322 else
2323 m_xColumn->getString();
2324 bIsNull = m_xColumn->wasNull();
2327 catch(const Exception&)
2329 SAL_WARN("forms.component", "OBoundControlModel::reset: this should have succeeded in all cases!");
2330 DBG_UNHANDLED_EXCEPTION();
2333 bool bNeedValueTransfer = true;
2334 if ( bIsNull )
2336 if ( bIsNewRecord )
2338 // reset the control to it's default
2339 resetNoBroadcast();
2340 // and immediately commit the changes to the DB column, to keep consistency
2341 commitControlValueToDbColumn( true );
2342 bNeedValueTransfer = false;
2347 if ( bNeedValueTransfer )
2348 transferDbValueToControl();
2351 else
2353 resetNoBroadcast();
2354 // transfer to the external binding, if necessary
2355 if ( hasExternalValueBinding() )
2356 transferControlValueToExternal( aLock );
2359 // revalidate, if necessary
2360 if ( hasValidator() )
2361 recheckValidity( true );
2362 aLock.release();
2363 m_aResetHelper.notifyResetted();
2366 void OBoundControlModel::impl_setField_noNotify( const Reference< XPropertySet>& _rxField )
2368 DBG_ASSERT( !hasExternalValueBinding(), "OBoundControlModel::impl_setField_noNotify: We have an external value binding!" );
2369 m_xField = _rxField;
2372 bool OBoundControlModel::impl_approveValueBinding_nolock( const Reference< XValueBinding >& _rxBinding )
2374 if ( !_rxBinding.is() )
2375 return false;
2376 Sequence< Type > aTypeCandidates;
2378 // SYNCHRONIZED >
2379 ::osl::MutexGuard aGuard( m_aMutex );
2380 aTypeCandidates = getSupportedBindingTypes();
2381 // < SYNCHRONIZED
2384 for ( const Type* pType = aTypeCandidates.getConstArray();
2385 pType != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2386 ++pType
2389 if ( _rxBinding->supportsType( *pType ) )
2390 return true;
2392 return false;
2395 void OBoundControlModel::connectExternalValueBinding(
2396 const Reference< XValueBinding >& _rxBinding, ControlModelLock& _rInstanceLock )
2398 OSL_PRECOND( _rxBinding.is(), "OBoundControlModel::connectExternalValueBinding: invalid binding instance!" );
2399 OSL_PRECOND( !hasExternalValueBinding( ), "OBoundControlModel::connectExternalValueBinding: precond not met (currently have a binding)!" );
2400 // if we're connected to a database column, suspend this
2401 if ( hasField() )
2402 impl_disconnectDatabaseColumn_noNotify();
2403 // suspend listening for load-related events at out ambient form.
2404 // This is because an external value binding overrules a possible database binding.
2405 if ( isFormListening() )
2406 doFormListening( false );
2407 // remember this new binding
2408 m_xExternalBinding = _rxBinding;
2409 // tell the derivee
2410 onConnectedExternalValue();
2413 // add as value listener so we get notified when the value changes
2414 Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2415 if ( xModifiable.is() )
2416 xModifiable->addModifyListener( this );
2417 // add as property change listener for some (possibly present) properties we're
2418 // interested in
2419 Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2420 Reference< XPropertySetInfo > xBindingPropsInfo( xBindingProps.is() ? xBindingProps->getPropertySetInfo() : Reference< XPropertySetInfo >() );
2421 if ( xBindingPropsInfo.is() )
2423 if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_READONLY ) )
2425 xBindingProps->addPropertyChangeListener( PROPERTY_READONLY, this );
2426 m_bBindingControlsRO = true;
2429 if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_RELEVANT ) )
2431 xBindingProps->addPropertyChangeListener( PROPERTY_RELEVANT, this );
2432 m_bBindingControlsEnable = true;
2439 catch( const Exception& )
2441 DBG_UNHANDLED_EXCEPTION();
2444 // propagate our new value
2445 transferExternalValueToControl( _rInstanceLock );
2446 // if the binding is also a validator, use it, too. This is a constraint of the
2447 // com.sun.star.form.binding.ValidatableBindableFormComponent service
2448 if ( m_bSupportsValidation )
2452 Reference< XValidator > xAsValidator( _rxBinding, UNO_QUERY );
2453 if ( xAsValidator.is() )
2454 setValidator( xAsValidator );
2457 catch( const Exception& )
2459 DBG_UNHANDLED_EXCEPTION();
2465 void OBoundControlModel::disconnectExternalValueBinding( )
2469 // not listening at the binding anymore
2470 Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2471 if ( xModifiable.is() )
2472 xModifiable->removeModifyListener( this );
2473 // remove as property change listener
2474 Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2475 if ( m_bBindingControlsRO )
2476 xBindingProps->removePropertyChangeListener( PROPERTY_READONLY, this );
2477 if ( m_bBindingControlsEnable )
2478 xBindingProps->removePropertyChangeListener( PROPERTY_RELEVANT, this );
2481 catch( const Exception& )
2483 SAL_WARN("forms.component", "OBoundControlModel::disconnectExternalValueBinding: caught an exception!");
2484 DBG_UNHANDLED_EXCEPTION();
2487 // if the binding also acts as our validator, disconnect the validator, too
2488 if ( ( m_xExternalBinding == m_xValidator ) && m_xValidator.is() )
2489 disconnectValidator( );
2490 // no binding anymore
2491 m_xExternalBinding.clear();
2492 // be a load listener at our form, again. This was suspended while we had
2493 // an external value binding in place.
2494 doFormListening( true );
2495 // re-connect to database column of the new parent
2496 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
2497 impl_connectDatabaseColumn_noNotify( false );
2500 void SAL_CALL OBoundControlModel::setValueBinding( const Reference< XValueBinding >& _rxBinding ) throw (IncompatibleTypesException, RuntimeException, std::exception)
2502 OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::setValueBinding: How did you reach this method?" );
2503 // the interface for this method should not have been exposed if we do not
2504 // support binding to external data
2505 // allow reset
2506 if ( _rxBinding.is() && !impl_approveValueBinding_nolock( _rxBinding ) )
2508 throw IncompatibleTypesException(
2509 FRM_RES_STRING( RID_STR_INCOMPATIBLE_TYPES ),
2510 *this
2514 ControlModelLock aLock( *this );
2515 // since a ValueBinding overrules any potentially active database binding, the change in a ValueBinding
2516 // might trigger a change in our BoundField.
2517 FieldChangeNotifier aBoundFieldNotifier( aLock );
2518 // disconnect from the old binding
2519 if ( hasExternalValueBinding() )
2520 disconnectExternalValueBinding( );
2521 // connect to the new binding
2522 if ( _rxBinding.is() )
2523 connectExternalValueBinding( _rxBinding, aLock );
2526 Reference< XValueBinding > SAL_CALL OBoundControlModel::getValueBinding( ) throw (RuntimeException, std::exception)
2528 ::osl::MutexGuard aGuard( m_aMutex );
2529 OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::getValueBinding: How did you reach this method?" );
2530 // the interface for this method should not have been exposed if we do not
2531 // support binding to external data
2532 return m_xExternalBinding;
2535 void SAL_CALL OBoundControlModel::modified( const EventObject& _rEvent ) throw ( RuntimeException, std::exception )
2537 ControlModelLock aLock( *this );
2538 OSL_PRECOND( hasExternalValueBinding(), "OBoundControlModel::modified: Where did this come from?" );
2539 if ( !m_bTransferingValue && ( m_xExternalBinding == _rEvent.Source ) && m_xExternalBinding.is() )
2541 transferExternalValueToControl( aLock );
2545 void OBoundControlModel::transferDbValueToControl( )
2549 setControlValue( translateDbColumnToControlValue(), eDbColumnBinding );
2552 catch( const Exception& )
2554 DBG_UNHANDLED_EXCEPTION();
2558 void OBoundControlModel::transferExternalValueToControl( ControlModelLock& _rInstanceLock )
2560 Reference< XValueBinding > xExternalBinding( m_xExternalBinding );
2561 Type aValueExchangeType( getExternalValueType() );
2562 _rInstanceLock.release();
2563 // UNSAFE >
2564 Any aExternalValue;
2567 aExternalValue = xExternalBinding->getValue( aValueExchangeType );
2570 catch( const Exception& )
2572 DBG_UNHANDLED_EXCEPTION();
2574 // < UNSAFE
2575 _rInstanceLock.acquire();
2576 setControlValue( translateExternalValueToControlValue( aExternalValue ), eExternalBinding );
2579 void OBoundControlModel::transferControlValueToExternal( ControlModelLock& _rInstanceLock )
2581 OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2582 "OBoundControlModel::transferControlValueToExternal: precondition not met!" );
2583 if ( m_xExternalBinding.is() )
2585 Any aExternalValue( translateControlValueToExternalValue() );
2586 m_bTransferingValue = true;
2587 _rInstanceLock.release();
2588 // UNSAFE >
2591 m_xExternalBinding->setValue( aExternalValue );
2594 catch( const Exception& )
2596 DBG_UNHANDLED_EXCEPTION();
2599 // < UNSAFE
2600 _rInstanceLock.acquire();
2601 m_bTransferingValue = false;
2605 Sequence< Type > OBoundControlModel::getSupportedBindingTypes()
2607 return Sequence< Type >( &m_aValuePropertyType, 1 );
2610 void OBoundControlModel::calculateExternalValueType()
2612 m_aExternalValueType = Type();
2613 if ( !m_xExternalBinding.is() )
2614 return;
2615 Sequence< Type > aTypeCandidates( getSupportedBindingTypes() );
2616 for ( const Type* pTypeCandidate = aTypeCandidates.getConstArray();
2617 pTypeCandidate != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2618 ++pTypeCandidate
2621 if ( m_xExternalBinding->supportsType( *pTypeCandidate ) )
2623 m_aExternalValueType = *pTypeCandidate;
2624 break;
2629 Any OBoundControlModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
2631 OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2632 "OBoundControlModel::translateExternalValueToControlValue: precondition not met!" );
2633 Any aControlValue( _rExternalValue );
2634 // if the external value is VOID, and our value property is not allowed to be VOID,
2635 // then default-construct a value
2636 if ( !aControlValue.hasValue() && !m_bValuePropertyMayBeVoid )
2637 aControlValue.setValue( NULL, m_aValuePropertyType );
2638 // out of here
2639 return aControlValue;
2642 Any OBoundControlModel::translateControlValueToExternalValue( ) const
2644 return getControlValue( );
2647 Any OBoundControlModel::translateControlValueToValidatableValue( ) const
2649 OSL_PRECOND( m_xValidator.is(), "OBoundControlModel::translateControlValueToValidatableValue: no validator, so why should I?" );
2650 if ( ( m_xValidator == m_xExternalBinding ) && m_xValidator.is() )
2651 return translateControlValueToExternalValue();
2652 return getControlValue();
2655 Any OBoundControlModel::getControlValue( ) const
2657 OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2658 "OBoundControlModel::getControlValue: invalid aggregate !" );
2659 OSL_PRECOND( !m_sValuePropertyName.isEmpty() || ( m_nValuePropertyAggregateHandle != -1 ),
2660 "OBoundControlModel::getControlValue: please override if you have own value property handling!" );
2661 // determine the current control value
2662 Any aControlValue;
2663 if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2665 aControlValue = m_xAggregateFastSet->getFastPropertyValue( m_nValuePropertyAggregateHandle );
2668 else if ( !m_sValuePropertyName.isEmpty() && m_xAggregateSet.is() )
2670 aControlValue = m_xAggregateSet->getPropertyValue( m_sValuePropertyName );
2672 return aControlValue;
2675 void OBoundControlModel::connectValidator( const Reference< XValidator >& _rxValidator )
2677 OSL_PRECOND( _rxValidator.is(), "OBoundControlModel::connectValidator: invalid validator instance!" );
2678 OSL_PRECOND( !hasValidator( ), "OBoundControlModel::connectValidator: precond not met (have a validator currently)!" );
2679 m_xValidator = _rxValidator;
2681 // add as value listener so we get notified when the value changes
2682 if ( m_xValidator.is() )
2686 m_xValidator->addValidityConstraintListener( this );
2689 catch( const RuntimeException& )
2693 onConnectedValidator( );
2696 void OBoundControlModel::disconnectValidator( )
2698 OSL_PRECOND( hasValidator( ), "OBoundControlModel::connectValidator: precond not met (don't have a validator currently)!" );
2700 // add as value listener so we get notified when the value changes
2701 if ( m_xValidator.is() )
2705 m_xValidator->removeValidityConstraintListener( this );
2708 catch( const RuntimeException& )
2713 m_xValidator.clear();
2715 onDisconnectedValidator( );
2718 void SAL_CALL OBoundControlModel::setValidator( const Reference< XValidator >& _rxValidator ) throw (VetoException,RuntimeException, std::exception)
2720 ::osl::ClearableMutexGuard aGuard( m_aMutex );
2721 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::setValidator: How did you reach this method?" );
2722 // the interface for this method should not have been exposed if we do not
2723 // support validation
2725 // early out if the validator does not change
2726 if ( _rxValidator == m_xValidator )
2727 return;
2729 if ( m_xValidator.is() && ( m_xValidator == m_xExternalBinding ) )
2730 throw VetoException(
2731 FRM_RES_STRING( RID_STR_INVALID_VALIDATOR ),
2732 *this
2735 // disconnect from the old validator
2736 if ( hasValidator() )
2737 disconnectValidator( );
2739 // connect to the new validator
2740 if ( _rxValidator.is() )
2741 connectValidator( _rxValidator );
2744 Reference< XValidator > SAL_CALL OBoundControlModel::getValidator( ) throw (RuntimeException, std::exception)
2746 ::osl::MutexGuard aGuard( m_aMutex );
2747 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::getValidator: How did you reach this method?" );
2748 // the interface for this method should not have been exposed if we do not
2749 // support validation
2751 return m_xValidator;
2754 void SAL_CALL OBoundControlModel::validityConstraintChanged( const EventObject& /*Source*/ ) throw (RuntimeException, std::exception)
2756 ::osl::ClearableMutexGuard aGuard( m_aMutex );
2757 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::validityConstraintChanged: How did you reach this method?" );
2758 // the interface for this method should not have been exposed if we do not
2759 // support validation
2761 recheckValidity( false );
2764 sal_Bool SAL_CALL OBoundControlModel::isValid( ) throw (RuntimeException, std::exception)
2766 return m_bIsCurrentValueValid;
2769 ::com::sun::star::uno::Any OBoundControlModel::getCurrentFormComponentValue() const
2771 if ( hasValidator() )
2772 return translateControlValueToValidatableValue();
2773 return getControlValue();
2776 Any SAL_CALL OBoundControlModel::getCurrentValue( ) throw (RuntimeException, std::exception)
2778 ::osl::MutexGuard aGuard( m_aMutex );
2779 return getCurrentFormComponentValue();
2782 void SAL_CALL OBoundControlModel::addFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException, std::exception)
2784 if ( Listener.is() )
2785 m_aFormComponentListeners.addInterface( Listener );
2788 void SAL_CALL OBoundControlModel::removeFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException, std::exception)
2790 if ( Listener.is() )
2791 m_aFormComponentListeners.removeInterface( Listener );
2794 void OBoundControlModel::recheckValidity( bool _bForceNotification )
2798 bool bIsCurrentlyValid = true;
2799 if ( hasValidator() )
2800 bIsCurrentlyValid = m_xValidator->isValid( translateControlValueToValidatableValue() );
2802 if ( ( bIsCurrentlyValid != m_bIsCurrentValueValid ) || _bForceNotification )
2804 m_bIsCurrentValueValid = bIsCurrentlyValid;
2806 // release our mutex for the notifications
2807 MutexRelease aRelease( m_aMutex );
2808 m_aFormComponentListeners.notifyEach( &validation::XFormComponentValidityListener::componentValidityChanged, EventObject( *this ) );
2813 catch( const Exception& )
2815 SAL_WARN("forms.component", "OBoundControlModel::recheckValidity: caught an exception!");
2816 DBG_UNHANDLED_EXCEPTION();
2820 void OBoundControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
2822 BEGIN_DESCRIBE_PROPERTIES( 5, OControlModel )
2823 DECL_PROP1 ( CONTROLSOURCE, OUString, BOUND );
2824 DECL_IFACE_PROP3( BOUNDFIELD, XPropertySet, BOUND, READONLY, TRANSIENT );
2825 DECL_IFACE_PROP2( CONTROLLABEL, XPropertySet, BOUND, MAYBEVOID );
2826 DECL_PROP2 ( CONTROLSOURCEPROPERTY, OUString, READONLY, TRANSIENT );
2827 DECL_BOOL_PROP1 ( INPUT_REQUIRED, BOUND );
2828 END_DESCRIBE_PROPERTIES()
2832 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */