1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <strings.hrc>
22 #include <frm_resource.hxx>
23 #include <property.hxx>
24 #include <services.hxx>
26 #include <com/sun/star/awt/XTextComponent.hpp>
27 #include <com/sun/star/awt/XWindow.hpp>
28 #include <com/sun/star/beans/PropertyAttribute.hpp>
29 #include <com/sun/star/form/FormComponentType.hpp>
30 #include <com/sun/star/form/XForm.hpp>
31 #include <com/sun/star/form/XLoadable.hpp>
32 #include <com/sun/star/form/binding/IncompatibleTypesException.hpp>
33 #include <com/sun/star/io/IOException.hpp>
34 #include <com/sun/star/io/XMarkableStream.hpp>
35 #include <com/sun/star/lang/DisposedException.hpp>
36 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
37 #include <com/sun/star/sdb/XRowSetChangeBroadcaster.hpp>
38 #include <com/sun/star/sdb/XRowSetSupplier.hpp>
39 #include <com/sun/star/sdbc/ColumnValue.hpp>
40 #include <com/sun/star/sdbc/DataType.hpp>
41 #include <com/sun/star/sdbc/SQLException.hpp>
42 #include <com/sun/star/util/VetoException.hpp>
43 #include <com/sun/star/util/XModifyBroadcaster.hpp>
45 #include <comphelper/basicio.hxx>
46 #include <comphelper/guarding.hxx>
47 #include <comphelper/property.hxx>
48 #include <connectivity/dbtools.hxx>
49 #include <cppuhelper/exc_hlp.hxx>
50 #include <cppuhelper/supportsservice.hxx>
51 #include <tools/debug.hxx>
52 #include <comphelper/diagnose_ex.hxx>
53 #include <sal/log.hxx>
59 using namespace ::com::sun::star::uno
;
60 using namespace ::com::sun::star::sdb
;
61 using namespace ::com::sun::star::sdbc
;
62 using namespace ::com::sun::star::sdbcx
;
63 using namespace ::com::sun::star::beans
;
64 using namespace ::com::sun::star::container
;
65 using namespace ::com::sun::star::form
;
66 using namespace ::com::sun::star::awt
;
67 using namespace ::com::sun::star::io
;
68 using namespace ::com::sun::star::lang
;
69 using namespace ::com::sun::star::util
;
70 using namespace ::com::sun::star::form::binding
;
71 using namespace ::com::sun::star::form::validation
;
72 using namespace ::dbtools
;
73 using namespace ::comphelper
;
75 // FieldChangeNotifier
76 void ControlModelLock::impl_notifyAll_nothrow()
78 m_rModel
.firePropertyChanges( m_aHandles
, m_aOldValues
, m_aNewValues
, OControlModel::LockAccess() );
81 void ControlModelLock::addPropertyNotification( const sal_Int32 _nHandle
, const Any
& _rOldValue
, const Any
& _rNewValue
)
83 assert( m_aHandles
.size() == m_aOldValues
.size() && m_aOldValues
.size() == m_aNewValues
.size() );
85 m_aHandles
.push_back( _nHandle
);
86 m_aOldValues
.push_back( _rOldValue
);
87 m_aNewValues
.push_back( _rNewValue
);
92 class FieldChangeNotifier
95 explicit FieldChangeNotifier(ControlModelLock
& _rLock
)
97 , m_rModel( dynamic_cast< OBoundControlModel
& >( _rLock
.getModel() ) )
99 m_xOldField
= m_rModel
.getField();
102 ~FieldChangeNotifier()
104 Reference
< XPropertySet
> xNewField( m_rModel
.getField() );
105 if ( m_xOldField
!= xNewField
)
106 m_rLock
.addPropertyNotification( PROPERTY_ID_BOUNDFIELD
, Any( m_xOldField
), Any( xNewField
) );
110 ControlModelLock
& m_rLock
;
111 OBoundControlModel
& m_rModel
;
112 Reference
< XPropertySet
> m_xOldField
;
117 // base class for form layer controls
118 OControl::OControl( const Reference
< XComponentContext
>& _rxContext
, const OUString
& _rAggregateService
, const bool _bSetDelegator
)
119 :OComponentHelper(m_aMutex
)
120 ,m_xContext( _rxContext
)
122 // Aggregate VCL Control
123 // Increment the RefCount for aggregates, because the aggregate by itself increments the RefCount in the setDelegator
124 osl_atomic_increment( &m_refCount
);
126 m_xAggregate
.set(_rxContext
->getServiceManager()->createInstanceWithContext(_rAggregateService
, _rxContext
), css::uno::UNO_QUERY
);
127 m_xControl
.set(m_xAggregate
, css::uno::UNO_QUERY
);
129 osl_atomic_decrement( &m_refCount
);
131 if ( _bSetDelegator
)
135 OControl::~OControl()
140 void OControl::doResetDelegator()
142 if ( m_xAggregate
.is() )
143 m_xAggregate
->setDelegator( nullptr );
146 void OControl::doSetDelegator()
148 osl_atomic_increment( &m_refCount
);
149 if ( m_xAggregate
.is() )
150 { // those brackets are important for some compilers, don't remove!
151 // (they ensure that the temporary object created in the line below
152 // is destroyed *before* the refcount-decrement)
153 m_xAggregate
->setDelegator( static_cast< XWeak
* >( this ) );
155 osl_atomic_decrement( &m_refCount
);
159 Any SAL_CALL
OControl::queryAggregation( const Type
& _rType
)
161 // ask the base class
162 Any
aReturn( OComponentHelper::queryAggregation(_rType
) );
163 // ask our own interfaces
164 if (!aReturn
.hasValue())
166 aReturn
= OControl_BASE::queryInterface(_rType
);
168 if (!aReturn
.hasValue() && m_xAggregate
.is())
169 aReturn
= m_xAggregate
->queryAggregation(_rType
);
175 Sequence
<sal_Int8
> SAL_CALL
OControl::getImplementationId()
177 return css::uno::Sequence
<sal_Int8
>();
180 Sequence
<Type
> SAL_CALL
OControl::getTypes()
182 TypeBag
aTypes( _getTypes() );
184 Reference
< XTypeProvider
> xProv
;
185 if ( query_aggregation( m_xAggregate
, xProv
) )
186 aTypes
.addTypes( xProv
->getTypes() );
188 return aTypes
.getTypes();
191 Sequence
<Type
> OControl::_getTypes()
193 return TypeBag( OComponentHelper::getTypes(), OControl_BASE::getTypes() ).getTypes();
197 void OControl::disposing()
199 OComponentHelper::disposing();
201 m_aWindowStateGuard
.attach( nullptr, nullptr );
203 Reference
< XComponent
> xComp
;
204 if (query_aggregation(m_xAggregate
, xComp
))
209 sal_Bool SAL_CALL
OControl::supportsService(const OUString
& _rsServiceName
)
211 return cppu::supportsService(this, _rsServiceName
);
214 Sequence
< OUString
> OControl::getAggregateServiceNames() const
216 Sequence
< OUString
> aAggServices
;
217 Reference
< XServiceInfo
> xInfo
;
218 if ( query_aggregation( m_xAggregate
, xInfo
) )
219 aAggServices
= xInfo
->getSupportedServiceNames();
224 Sequence
<OUString
> SAL_CALL
OControl::getSupportedServiceNames()
226 // no own supported service names
227 return getAggregateServiceNames();
231 void SAL_CALL
OControl::disposing(const css::lang::EventObject
& _rEvent
)
233 Reference
< XInterface
> xAggAsIface
;
234 query_aggregation(m_xAggregate
, xAggAsIface
);
236 // does the disposing come from the aggregate?
237 if (xAggAsIface
!= Reference
< XInterface
>(_rEvent
.Source
, UNO_QUERY
))
238 { // no -> forward it
239 Reference
<css::lang::XEventListener
> xListener
;
240 if (query_aggregation(m_xAggregate
, xListener
))
241 xListener
->disposing(_rEvent
);
246 void SAL_CALL
OControl::setContext(const Reference
< XInterface
>& Context
)
249 m_xControl
->setContext(Context
);
252 Reference
< XInterface
> SAL_CALL
OControl::getContext()
254 return m_xControl
.is() ? m_xControl
->getContext() : Reference
< XInterface
>();
257 void OControl::impl_resetStateGuard_nothrow()
259 Reference
< XWindow2
> xWindow
;
260 Reference
< XControlModel
> xModel
;
263 xWindow
.set( getPeer(), UNO_QUERY
);
266 catch( const Exception
& )
268 DBG_UNHANDLED_EXCEPTION("forms.component");
270 m_aWindowStateGuard
.attach( xWindow
, xModel
);
273 void SAL_CALL
OControl::createPeer(const Reference
<XToolkit
>& _rxToolkit
, const Reference
<XWindowPeer
>& _rxParent
)
275 if ( m_xControl
.is() )
277 m_xControl
->createPeer( _rxToolkit
, _rxParent
);
278 impl_resetStateGuard_nothrow();
282 Reference
<XWindowPeer
> SAL_CALL
OControl::getPeer()
284 return m_xControl
.is() ? m_xControl
->getPeer() : Reference
<XWindowPeer
>();
287 sal_Bool SAL_CALL
OControl::setModel(const Reference
<XControlModel
>& Model
)
289 if ( !m_xControl
.is() )
292 bool bSuccess
= m_xControl
->setModel( Model
);
293 impl_resetStateGuard_nothrow();
297 Reference
<XControlModel
> SAL_CALL
OControl::getModel()
299 return m_xControl
.is() ? m_xControl
->getModel() : Reference
<XControlModel
>();
302 Reference
<XView
> SAL_CALL
OControl::getView()
304 return m_xControl
.is() ? m_xControl
->getView() : Reference
<XView
>();
307 void SAL_CALL
OControl::setDesignMode(sal_Bool bOn
)
310 m_xControl
->setDesignMode(bOn
);
313 sal_Bool SAL_CALL
OControl::isDesignMode()
315 return !m_xControl
.is() || m_xControl
->isDesignMode();
318 sal_Bool SAL_CALL
OControl::isTransparent()
320 return !m_xControl
.is() || m_xControl
->isTransparent();
323 OBoundControl::OBoundControl( const Reference
< XComponentContext
>& _rxContext
,
324 const OUString
& _rAggregateService
, const bool _bSetDelegator
)
325 :OControl( _rxContext
, _rAggregateService
, _bSetDelegator
)
330 OBoundControl::~OBoundControl()
334 Sequence
< Type
> OBoundControl::_getTypes()
336 return TypeBag( OControl::_getTypes(), OBoundControl_BASE::getTypes() ).getTypes();
339 Any SAL_CALL
OBoundControl::queryAggregation(const Type
& _rType
)
343 // XTypeProvider first - don't ask the OBoundControl_BASE, it would deliver incomplete types
344 if ( _rType
.equals( cppu::UnoType
<XTypeProvider
>::get() ) )
345 aReturn
= OControl::queryAggregation( _rType
);
347 // ask our own interfaces
348 // (do this first (except XTypeProvider ) - we want to "overwrite" XPropertiesChangeListener)
349 if ( !aReturn
.hasValue() )
350 aReturn
= OBoundControl_BASE::queryInterface( _rType
);
352 // ask the base class
353 if ( !aReturn
.hasValue() )
354 aReturn
= OControl::queryAggregation( _rType
);
359 sal_Bool SAL_CALL
OBoundControl::getLock()
364 void SAL_CALL
OBoundControl::setLock(sal_Bool _bLock
)
366 if (m_bLocked
== bool(_bLock
))
369 osl::MutexGuard
aGuard(m_aMutex
);
374 void OBoundControl::_setLock(bool _bLock
)
376 // try to set the text component to readonly
377 Reference
< XWindowPeer
> xPeer
= getPeer();
378 Reference
< XTextComponent
> xText( xPeer
, UNO_QUERY
);
381 xText
->setEditable( !_bLock
);
384 // disable the window
385 Reference
< XWindow
> xComp( xPeer
, UNO_QUERY
);
387 xComp
->setEnable( !_bLock
);
391 sal_Bool SAL_CALL
OBoundControl::setModel( const Reference
< XControlModel
>& _rxModel
)
393 return OControl::setModel( _rxModel
);
396 void SAL_CALL
OBoundControl::disposing(const EventObject
& Source
)
399 OControl::disposing(Source
);
402 void OBoundControl::disposing()
404 OControl::disposing();
408 Sequence
<sal_Int8
> SAL_CALL
OControlModel::getImplementationId()
410 return css::uno::Sequence
<sal_Int8
>();
413 Sequence
<Type
> SAL_CALL
OControlModel::getTypes()
415 TypeBag
aTypes( _getTypes() );
417 Reference
< XTypeProvider
> xProv
;
419 if ( query_aggregation( m_xAggregate
, xProv
) )
420 aTypes
.addTypes( xProv
->getTypes() );
422 return aTypes
.getTypes();
425 Sequence
<Type
> OControlModel::_getTypes()
427 return TypeBag( OComponentHelper::getTypes(),
428 OPropertySetAggregationHelper::getTypes(),
429 OControlModel_BASE::getTypes()
433 Any SAL_CALL
OControlModel::queryAggregation(const Type
& _rType
)
436 Any
aReturn(OComponentHelper::queryAggregation(_rType
));
439 if (!aReturn
.hasValue())
441 aReturn
= OControlModel_BASE::queryInterface(_rType
);
443 // our own interfaces
444 if (!aReturn
.hasValue())
446 aReturn
= OPropertySetAggregationHelper::queryInterface(_rType
);
448 if (!aReturn
.hasValue() && m_xAggregate
.is() && !_rType
.equals(cppu::UnoType
<XCloneable
>::get()))
449 aReturn
= m_xAggregate
->queryAggregation(_rType
);
455 void OControlModel::readHelpTextCompatibly(const css::uno::Reference
< css::io::XObjectInputStream
>& _rxInStream
)
458 ::comphelper::operator>>( _rxInStream
, sHelpText
);
461 if (m_xAggregateSet
.is())
462 m_xAggregateSet
->setPropertyValue(PROPERTY_HELPTEXT
, Any(sHelpText
));
464 catch(const Exception
&)
466 DBG_UNHANDLED_EXCEPTION("forms.component");
467 SAL_WARN("forms.component", "OControlModel::readHelpTextCompatibly: could not forward the property value to the aggregate!");
471 void OControlModel::writeHelpTextCompatibly(const css::uno::Reference
< css::io::XObjectOutputStream
>& _rxOutStream
)
476 if (m_xAggregateSet
.is())
477 m_xAggregateSet
->getPropertyValue(PROPERTY_HELPTEXT
) >>= sHelpText
;
479 catch(const Exception
&)
481 DBG_UNHANDLED_EXCEPTION("forms.component");
482 SAL_WARN("forms.component", "OControlModel::writeHelpTextCompatibly: could not retrieve the property value from the aggregate!");
484 ::comphelper::operator<<( _rxOutStream
, sHelpText
);
487 OControlModel::OControlModel(
488 const Reference
<XComponentContext
>& _rxContext
,
489 const OUString
& _rUnoControlModelTypeName
,
490 const OUString
& rDefault
, const bool _bSetDelegator
)
491 :OComponentHelper(m_aMutex
)
492 ,OPropertySetAggregationHelper(OComponentHelper::rBHelper
)
493 ,m_xContext( _rxContext
)
495 ,m_aPropertyBagHelper( *this )
496 ,m_nTabIndex(FRM_DEFAULT_TABINDEX
)
497 ,m_nClassId(FormComponentType::CONTROL
)
498 ,m_bNativeLook( false )
499 ,m_bStandardTheme( false )
500 ,m_bGenerateVbEvents( false )
501 ,m_nControlTypeinMSO(0) // 0 : default value is create from AOO
502 ,m_nObjIDinMSO(INVALID_OBJ_ID_IN_MSO
)
503 // form controls are usually embedded into documents, not dialogs, and in documents
504 // the native look is ugly...
507 if (_rUnoControlModelTypeName
.isEmpty()) // the is a model we have to aggregate
510 osl_atomic_increment(&m_refCount
);
512 m_xAggregate
.set(m_xContext
->getServiceManager()->createInstanceWithContext(_rUnoControlModelTypeName
, m_xContext
), UNO_QUERY
);
513 setAggregation(m_xAggregate
);
515 if ( m_xAggregateSet
.is() )
519 if ( !rDefault
.isEmpty() )
520 m_xAggregateSet
->setPropertyValue( PROPERTY_DEFAULTCONTROL
, Any( rDefault
) );
522 catch( const Exception
& )
524 TOOLS_WARN_EXCEPTION("forms.component", "OControlModel::OControlModel");
531 // Refcount is at NULL again
532 osl_atomic_decrement(&m_refCount
);
535 OControlModel::OControlModel( const OControlModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
, const bool _bCloneAggregate
, const bool _bSetDelegator
)
536 :OComponentHelper( m_aMutex
)
537 ,OPropertySetAggregationHelper( OComponentHelper::rBHelper
)
538 ,m_xContext( _rxFactory
)
540 ,m_aPropertyBagHelper( *this )
541 ,m_nTabIndex( FRM_DEFAULT_TABINDEX
)
542 ,m_nClassId( FormComponentType::CONTROL
)
544 DBG_ASSERT( _pOriginal
, "OControlModel::OControlModel: invalid original!" );
547 m_aName
= _pOriginal
->m_aName
;
548 m_aTag
= _pOriginal
->m_aTag
;
549 m_nTabIndex
= _pOriginal
->m_nTabIndex
;
550 m_nClassId
= _pOriginal
->m_nClassId
;
551 m_bNativeLook
= _pOriginal
->m_bNativeLook
;
552 m_bStandardTheme
= _pOriginal
->m_bStandardTheme
;
553 m_bGenerateVbEvents
= _pOriginal
->m_bGenerateVbEvents
;
554 m_nControlTypeinMSO
= _pOriginal
->m_nControlTypeinMSO
;
555 m_nObjIDinMSO
= _pOriginal
->m_nObjIDinMSO
;
557 if ( !_bCloneAggregate
)
560 // temporarily increment refcount because of temporary references to ourself in the following
561 osl_atomic_increment( &m_refCount
);
563 // transfer the (only, at the very moment!) ref count
564 m_xAggregate
= createAggregateClone( _pOriginal
);
566 // set aggregation (retrieve other direct interfaces of the aggregate)
567 setAggregation( m_xAggregate
);
570 // set the delegator, if allowed by our derived class
571 if ( _bSetDelegator
)
574 // decrement ref count
575 osl_atomic_decrement( &m_refCount
);
578 OControlModel::~OControlModel()
580 // release the aggregate
584 void OControlModel::clonedFrom( const OControlModel
* /*_pOriginal*/ )
586 // nothing to do in this base class
589 void OControlModel::doResetDelegator()
591 if (m_xAggregate
.is())
592 m_xAggregate
->setDelegator(nullptr);
595 void OControlModel::doSetDelegator()
597 osl_atomic_increment(&m_refCount
);
598 if (m_xAggregate
.is())
600 m_xAggregate
->setDelegator(static_cast<XWeak
*>(this));
602 osl_atomic_decrement(&m_refCount
);
606 Reference
< XInterface
> SAL_CALL
OControlModel::getParent()
611 void SAL_CALL
OControlModel::setParent(const Reference
< XInterface
>& _rxParent
)
613 osl::MutexGuard
aGuard(m_aMutex
);
615 Reference
<XComponent
> xComp(m_xParent
, UNO_QUERY
);
617 xComp
->removeEventListener(static_cast<XPropertiesChangeListener
*>(this));
619 m_xParent
= _rxParent
;
620 xComp
.set(m_xParent
, css::uno::UNO_QUERY
);
623 xComp
->addEventListener(static_cast<XPropertiesChangeListener
*>(this));
627 OUString SAL_CALL
OControlModel::getName()
632 OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME
) >>= aReturn
;
634 catch (const css::beans::UnknownPropertyException
&)
636 css::uno::Any
a(cppu::getCaughtException());
637 throw WrappedTargetRuntimeException(
638 "OControlModel::getName",
646 void SAL_CALL
OControlModel::setName(const OUString
& _rName
)
650 setFastPropertyValue(PROPERTY_ID_NAME
, Any(_rName
));
652 catch (const css::beans::UnknownPropertyException
&)
654 css::uno::Any
a(cppu::getCaughtException());
655 throw WrappedTargetRuntimeException(
656 "OControlModel::setName",
664 sal_Bool SAL_CALL
OControlModel::supportsService(const OUString
& _rServiceName
)
666 return cppu::supportsService(this, _rServiceName
);
669 Sequence
< OUString
> OControlModel::getAggregateServiceNames() const
671 Sequence
< OUString
> aAggServices
;
672 Reference
< XServiceInfo
> xInfo
;
673 if ( query_aggregation( m_xAggregate
, xInfo
) )
674 aAggServices
= xInfo
->getSupportedServiceNames();
678 Sequence
<OUString
> SAL_CALL
OControlModel::getSupportedServiceNames()
680 return ::comphelper::concatSequences(
681 getAggregateServiceNames(),
682 getSupportedServiceNames_Static()
686 Sequence
< OUString
> OControlModel::getSupportedServiceNames_Static()
688 return { FRM_SUN_FORMCOMPONENT
, "com.sun.star.form.FormControlModel" };
692 void SAL_CALL
OControlModel::disposing(const css::lang::EventObject
& _rSource
)
694 // release the parent
695 if (_rSource
.Source
== m_xParent
)
697 osl::MutexGuard
aGuard(m_aMutex
);
702 Reference
<css::lang::XEventListener
> xEvtLst
;
703 if (query_aggregation(m_xAggregate
, xEvtLst
))
705 osl::MutexGuard
aGuard(m_aMutex
);
706 xEvtLst
->disposing(_rSource
);
712 void OControlModel::disposing()
714 OPropertySetAggregationHelper::disposing();
716 Reference
<css::lang::XComponent
> xComp
;
717 if (query_aggregation(m_xAggregate
, xComp
))
720 setParent(Reference
<XFormComponent
>());
722 m_aPropertyBagHelper
.dispose();
725 void OControlModel::writeAggregate( const Reference
< XObjectOutputStream
>& _rxOutStream
) const
727 Reference
< XPersistObject
> xPersist
;
728 if ( query_aggregation( m_xAggregate
, xPersist
) )
729 xPersist
->write( _rxOutStream
);
732 void OControlModel::readAggregate( const Reference
< XObjectInputStream
>& _rxInStream
)
734 Reference
< XPersistObject
> xPersist
;
735 if ( query_aggregation( m_xAggregate
, xPersist
) )
736 xPersist
->read( _rxInStream
);
739 void SAL_CALL
OControlModel::write(const Reference
<css::io::XObjectOutputStream
>& _rxOutStream
)
741 osl::MutexGuard
aGuard(m_aMutex
);
743 // 1. writing the UnoControls
744 Reference
<css::io::XMarkableStream
> xMark(_rxOutStream
, UNO_QUERY
);
748 ResourceManager::loadString(RID_STR_INVALIDSTREAM
),
749 static_cast< ::cppu::OWeakObject
* >( this )
753 sal_Int32 nMark
= xMark
->createMark();
756 _rxOutStream
->writeLong(nLen
);
758 writeAggregate( _rxOutStream
);
760 // determining the length
761 nLen
= xMark
->offsetToMark(nMark
) - 4;
762 xMark
->jumpToMark(nMark
);
763 _rxOutStream
->writeLong(nLen
);
764 xMark
->jumpToFurthest();
765 xMark
->deleteMark(nMark
);
767 // 2. writing a version number
768 _rxOutStream
->writeShort(0x0003);
770 // 3. writing the general properties
771 ::comphelper::operator<<( _rxOutStream
, m_aName
);
772 _rxOutStream
->writeShort(m_nTabIndex
);
773 ::comphelper::operator<<( _rxOutStream
, m_aTag
); // 3rd version
776 // don't write any new members here: this wouldn't be compatible with older versions, as OControlModel
777 // is a base class which is called in derived classes "read" method. So if you increment the version
778 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
779 // in anything from data loss to crash.
783 void OControlModel::read(const Reference
<css::io::XObjectInputStream
>& InStream
)
785 osl::MutexGuard
aGuard(m_aMutex
);
787 Reference
<css::io::XMarkableStream
> xMark(InStream
, UNO_QUERY
);
791 ResourceManager::loadString(RID_STR_INVALIDSTREAM
),
792 static_cast< ::cppu::OWeakObject
* >( this )
796 // 1. reading the UnoControls
797 sal_Int32 nLen
= InStream
->readLong();
800 sal_Int32 nMark
= xMark
->createMark();
804 readAggregate( InStream
);
807 catch( const Exception
& )
809 DBG_UNHANDLED_EXCEPTION("forms.component");
812 xMark
->jumpToMark(nMark
);
813 InStream
->skipBytes(nLen
);
814 xMark
->deleteMark(nMark
);
817 // 2. reading the version number
818 sal_uInt16 nVersion
= InStream
->readShort();
820 // 3. reading the general properties
821 ::comphelper::operator>>( InStream
, m_aName
);
822 m_nTabIndex
= InStream
->readShort();
824 if (nVersion
> 0x0002)
825 ::comphelper::operator>>( InStream
, m_aTag
);
827 // we had a version where we wrote the help text
828 if (nVersion
== 0x0004)
829 readHelpTextCompatibly(InStream
);
831 DBG_ASSERT(nVersion
< 5, "OControlModel::read : suspicious version number !");
832 // 4 was the version where we wrote the help text
833 // later versions shouldn't exist (see write for a detailed comment)
836 PropertyState
OControlModel::getPropertyStateByHandle( sal_Int32 _nHandle
)
838 // simply compare the current and the default value
839 Any aCurrentValue
= getPropertyDefaultByHandle( _nHandle
);
840 Any aDefaultValue
; getFastPropertyValue( aDefaultValue
, _nHandle
);
842 bool bEqual
= aCurrentValue
== aDefaultValue
;
843 return bEqual
? PropertyState_DEFAULT_VALUE
: PropertyState_DIRECT_VALUE
;
846 void OControlModel::setPropertyToDefaultByHandle( sal_Int32 _nHandle
)
848 Any aDefault
= getPropertyDefaultByHandle( _nHandle
);
850 Any aConvertedValue
, aOldValue
;
851 if ( convertFastPropertyValue( aConvertedValue
, aOldValue
, _nHandle
, aDefault
) )
853 setFastPropertyValue_NoBroadcast( _nHandle
, aConvertedValue
);
854 // TODO: fire the property change
858 Any
OControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle
) const
863 case PROPERTY_ID_NAME
:
864 case PROPERTY_ID_TAG
:
865 aReturn
<<= OUString();
867 case PROPERTY_ID_CLASSID
:
868 aReturn
<<= sal_Int16(FormComponentType::CONTROL
);
870 case PROPERTY_ID_TABINDEX
:
871 aReturn
<<= sal_Int16(FRM_DEFAULT_TABINDEX
);
873 case PROPERTY_ID_NATIVE_LOOK
:
876 case PROPERTY_ID_STANDARD_THEME
:
879 case PROPERTY_ID_GENERATEVBAEVENTS
:
882 // added for exporting OCX control
883 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
884 aReturn
<<= sal_Int16(0);
886 case PROPERTY_ID_OBJ_ID_IN_MSO
:
887 aReturn
<<= sal_uInt16(INVALID_OBJ_ID_IN_MSO
);
890 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
891 m_aPropertyBagHelper
.getDynamicPropertyDefaultByHandle( _nHandle
, aReturn
);
893 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle
);
898 void OControlModel::getFastPropertyValue( Any
& _rValue
, sal_Int32 _nHandle
) const
902 case PROPERTY_ID_NAME
:
905 case PROPERTY_ID_TAG
:
908 case PROPERTY_ID_CLASSID
:
909 _rValue
<<= m_nClassId
;
911 case PROPERTY_ID_TABINDEX
:
912 _rValue
<<= m_nTabIndex
;
914 case PROPERTY_ID_NATIVE_LOOK
:
915 _rValue
<<= m_bNativeLook
;
917 case PROPERTY_ID_STANDARD_THEME
:
918 _rValue
<<= m_bStandardTheme
;
920 case PROPERTY_ID_GENERATEVBAEVENTS
:
921 _rValue
<<= m_bGenerateVbEvents
;
923 // added for exporting OCX control
924 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
925 _rValue
<<= m_nControlTypeinMSO
;
927 case PROPERTY_ID_OBJ_ID_IN_MSO
:
928 _rValue
<<= m_nObjIDinMSO
;
931 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
932 m_aPropertyBagHelper
.getDynamicFastPropertyValue( _nHandle
, _rValue
);
934 OPropertySetAggregationHelper::getFastPropertyValue( _rValue
, _nHandle
);
939 sal_Bool
OControlModel::convertFastPropertyValue(
940 Any
& _rConvertedValue
, Any
& _rOldValue
, sal_Int32 _nHandle
, const Any
& _rValue
)
942 bool bModified(false);
945 case PROPERTY_ID_NAME
:
946 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aName
);
948 case PROPERTY_ID_TAG
:
949 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aTag
);
951 case PROPERTY_ID_TABINDEX
:
952 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_nTabIndex
);
954 case PROPERTY_ID_NATIVE_LOOK
:
955 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_bNativeLook
);
957 case PROPERTY_ID_STANDARD_THEME
:
958 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_bStandardTheme
);
960 case PROPERTY_ID_GENERATEVBAEVENTS
:
961 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_bGenerateVbEvents
);
963 // added for exporting OCX control
964 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
965 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_nControlTypeinMSO
);
967 case PROPERTY_ID_OBJ_ID_IN_MSO
:
968 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_nObjIDinMSO
);
971 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
972 bModified
= m_aPropertyBagHelper
.convertDynamicFastPropertyValue( _nHandle
, _rValue
, _rConvertedValue
, _rOldValue
);
974 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle
);
980 void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle
, const Any
& _rValue
)
984 case PROPERTY_ID_NAME
:
985 DBG_ASSERT(_rValue
.getValueType() == cppu::UnoType
<OUString
>::get(),
986 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
989 case PROPERTY_ID_TAG
:
990 DBG_ASSERT(_rValue
.getValueType() == cppu::UnoType
<OUString
>::get(),
991 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
994 case PROPERTY_ID_TABINDEX
:
995 DBG_ASSERT(_rValue
.getValueType() == cppu::UnoType
<sal_Int16
>::get(),
996 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
997 _rValue
>>= m_nTabIndex
;
999 case PROPERTY_ID_NATIVE_LOOK
:
1000 OSL_VERIFY( _rValue
>>= m_bNativeLook
);
1002 case PROPERTY_ID_STANDARD_THEME
:
1003 OSL_VERIFY( _rValue
>>= m_bStandardTheme
);
1005 case PROPERTY_ID_GENERATEVBAEVENTS
:
1006 OSL_VERIFY( _rValue
>>= m_bGenerateVbEvents
);
1008 // added for exporting OCX control
1009 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
1010 OSL_VERIFY( _rValue
>>= m_nControlTypeinMSO
);
1012 case PROPERTY_ID_OBJ_ID_IN_MSO
:
1013 OSL_VERIFY( _rValue
>>= m_nObjIDinMSO
);
1016 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
1017 m_aPropertyBagHelper
.setDynamicFastPropertyValue( _nHandle
, _rValue
);
1019 SAL_WARN("forms.component", "OControlModel::setFastPropertyValue_NoBroadcast: unknown handle " << _nHandle
);
1024 void OControlModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
1027 css::beans::Property
* pProperties
= _rProps
.getArray();
1028 *pProperties
++ = css::beans::Property(PROPERTY_CLASSID
, PROPERTY_ID_CLASSID
, cppu::UnoType
<sal_Int16
>::get(), css::beans::PropertyAttribute::READONLY
| css::beans::PropertyAttribute::TRANSIENT
);
1029 *pProperties
++ = css::beans::Property(PROPERTY_NAME
, PROPERTY_ID_NAME
, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::BOUND
);
1030 *pProperties
++ = css::beans::Property(PROPERTY_NATIVE_LOOK
, PROPERTY_ID_NATIVE_LOOK
, cppu::UnoType
<bool>::get(),
1031 css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::TRANSIENT
);
1032 *pProperties
++ = css::beans::Property(PROPERTY_STANDARD_THEME
, PROPERTY_ID_STANDARD_THEME
, cppu::UnoType
<bool>::get(),
1033 css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::TRANSIENT
);
1034 *pProperties
++ = css::beans::Property(PROPERTY_TAG
, PROPERTY_ID_TAG
, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::BOUND
);
1035 *pProperties
++ = css::beans::Property(PROPERTY_GENERATEVBAEVENTS
, PROPERTY_ID_GENERATEVBAEVENTS
, cppu::UnoType
<sal_Bool
>::get(), css::beans::PropertyAttribute::TRANSIENT
);
1036 *pProperties
++ = css::beans::Property(PROPERTY_CONTROL_TYPE_IN_MSO
, PROPERTY_ID_CONTROL_TYPE_IN_MSO
, cppu::UnoType
<sal_Int16
>::get(), css::beans::PropertyAttribute::BOUND
);
1037 *pProperties
++ = css::beans::Property(PROPERTY_OBJ_ID_IN_MSO
, PROPERTY_ID_OBJ_ID_IN_MSO
, cppu::UnoType
<cppu::UnoUnsignedShortType
>::get(), css::beans::PropertyAttribute::BOUND
);
1038 DBG_ASSERT( pProperties
== _rProps
.getArray() + _rProps
.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
1041 void OControlModel::describeAggregateProperties( Sequence
< Property
>& /* [out] */ _rAggregateProps
) const
1043 if ( m_xAggregateSet
.is() )
1045 Reference
< XPropertySetInfo
> xPSI( m_xAggregateSet
->getPropertySetInfo() );
1047 _rAggregateProps
= xPSI
->getProperties();
1051 ::osl::Mutex
& OControlModel::getMutex()
1056 void OControlModel::describeFixedAndAggregateProperties( Sequence
< Property
>& _out_rFixedProperties
, Sequence
< Property
>& _out_rAggregateProperties
) const
1058 describeFixedProperties( _out_rFixedProperties
);
1059 describeAggregateProperties( _out_rAggregateProperties
);
1062 Reference
< XMultiPropertySet
> OControlModel::getPropertiesInterface()
1067 Reference
< XPropertySetInfo
> SAL_CALL
OControlModel::getPropertySetInfo()
1069 return createPropertySetInfo( getInfoHelper() );
1072 ::cppu::IPropertyArrayHelper
& OControlModel::getInfoHelper()
1074 return m_aPropertyBagHelper
.getInfoHelper();
1077 void SAL_CALL
OControlModel::addProperty( const OUString
& _rName
, ::sal_Int16 _nAttributes
, const Any
& _rInitialValue
)
1079 m_aPropertyBagHelper
.addProperty( _rName
, _nAttributes
, _rInitialValue
);
1082 void SAL_CALL
OControlModel::removeProperty( const OUString
& _rName
)
1084 m_aPropertyBagHelper
.removeProperty( _rName
);
1087 Sequence
< PropertyValue
> SAL_CALL
OControlModel::getPropertyValues()
1089 return m_aPropertyBagHelper
.getPropertyValues();
1092 void SAL_CALL
OControlModel::setPropertyValues( const Sequence
< PropertyValue
>& _rProps
)
1094 m_aPropertyBagHelper
.setPropertyValues( _rProps
);
1097 void OControlModel::lockInstance( LockAccess
)
1100 osl_atomic_increment( &m_lockCount
);
1103 oslInterlockedCount
OControlModel::unlockInstance( LockAccess
)
1105 OSL_ENSURE( m_lockCount
> 0, "OControlModel::unlockInstance: not locked!" );
1106 oslInterlockedCount lockCount
= osl_atomic_decrement( &m_lockCount
);
1111 void OControlModel::firePropertyChanges( const std::vector
< sal_Int32
>& _rHandles
, const std::vector
< Any
>& _rOldValues
,
1112 const std::vector
< Any
>& _rNewValues
, LockAccess
)
1114 OPropertySetHelper::fire(
1115 const_cast< std::vector
< sal_Int32
>& >( _rHandles
).data(),
1123 // OBoundControlModel
1124 Any SAL_CALL
OBoundControlModel::queryAggregation( const Type
& _rType
)
1126 Any
aReturn( OControlModel::queryAggregation(_rType
) );
1127 if (!aReturn
.hasValue())
1129 aReturn
= OBoundControlModel_BASE1::queryInterface(_rType
);
1131 if ( !aReturn
.hasValue() && m_bCommitable
)
1132 aReturn
= OBoundControlModel_COMMITTING::queryInterface( _rType
);
1134 if ( !aReturn
.hasValue() && m_bSupportsExternalBinding
)
1135 aReturn
= OBoundControlModel_BINDING::queryInterface( _rType
);
1137 if ( !aReturn
.hasValue() && m_bSupportsValidation
)
1138 aReturn
= OBoundControlModel_VALIDATION::queryInterface( _rType
);
1143 OBoundControlModel::OBoundControlModel(
1144 const Reference
< XComponentContext
>& _rxFactory
,
1145 const OUString
& _rUnoControlModelTypeName
, const OUString
& _rDefault
,
1146 const bool _bCommitable
, const bool _bSupportExternalBinding
, const bool _bSupportsValidation
)
1147 :OControlModel( _rxFactory
, _rUnoControlModelTypeName
, _rDefault
, false )
1148 ,OPropertyChangeListener( m_aMutex
)
1149 ,m_nValuePropertyAggregateHandle( -1 )
1150 ,m_nFieldType( DataType::OTHER
)
1151 ,m_bValuePropertyMayBeVoid( false )
1152 ,m_aResetHelper( *this, m_aMutex
)
1153 ,m_aUpdateListeners(m_aMutex
)
1154 ,m_aFormComponentListeners( m_aMutex
)
1155 ,m_bInputRequired( false )
1156 ,m_bFormListening( false )
1159 ,m_bCommitable(_bCommitable
)
1160 ,m_bSupportsExternalBinding( _bSupportExternalBinding
)
1161 ,m_bSupportsValidation( _bSupportsValidation
)
1162 ,m_bForwardValueChanges(true)
1163 ,m_bTransferringValue( false )
1164 ,m_bIsCurrentValueValid( true )
1165 ,m_bBindingControlsRO( false )
1166 ,m_bBindingControlsEnable( false )
1167 ,m_eControlValueChangeInstigator( eOther
)
1168 ,m_aLabelServiceName(FRM_SUN_COMPONENT_FIXEDTEXT
)
1170 // start property listening at the aggregate
1171 implInitAggMultiplexer( );
1174 OBoundControlModel::OBoundControlModel(
1175 const OBoundControlModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
)
1176 :OControlModel( _pOriginal
, _rxFactory
, true, false )
1177 ,OPropertyChangeListener( m_aMutex
)
1178 ,m_nValuePropertyAggregateHandle( _pOriginal
->m_nValuePropertyAggregateHandle
)
1179 ,m_nFieldType( DataType::OTHER
)
1180 ,m_bValuePropertyMayBeVoid( _pOriginal
->m_bValuePropertyMayBeVoid
)
1181 ,m_aResetHelper( *this, m_aMutex
)
1182 ,m_aUpdateListeners( m_aMutex
)
1183 ,m_aFormComponentListeners( m_aMutex
)
1184 ,m_xValidator( _pOriginal
->m_xValidator
)
1185 ,m_bInputRequired( false )
1186 ,m_bFormListening( false )
1188 ,m_bRequired( false )
1189 ,m_bCommitable( _pOriginal
->m_bCommitable
)
1190 ,m_bSupportsExternalBinding( _pOriginal
->m_bSupportsExternalBinding
)
1191 ,m_bSupportsValidation( _pOriginal
->m_bSupportsValidation
)
1192 ,m_bForwardValueChanges( true )
1193 ,m_bTransferringValue( false )
1194 ,m_bIsCurrentValueValid( _pOriginal
->m_bIsCurrentValueValid
)
1195 ,m_bBindingControlsRO( false )
1196 ,m_bBindingControlsEnable( false )
1197 ,m_eControlValueChangeInstigator( eOther
)
1199 // start property listening at the aggregate
1200 implInitAggMultiplexer( );
1201 m_aLabelServiceName
= _pOriginal
->m_aLabelServiceName
;
1202 m_sValuePropertyName
= _pOriginal
->m_sValuePropertyName
;
1203 m_nValuePropertyAggregateHandle
= _pOriginal
->m_nValuePropertyAggregateHandle
;
1204 m_bValuePropertyMayBeVoid
= _pOriginal
->m_bValuePropertyMayBeVoid
;
1205 m_aValuePropertyType
= _pOriginal
->m_aValuePropertyType
;
1206 m_aControlSource
= _pOriginal
->m_aControlSource
;
1207 m_bInputRequired
= _pOriginal
->m_bInputRequired
;
1208 // m_xLabelControl, though being a property, is not to be cloned, not even the reference will be transferred.
1209 // (the former should be clear - a clone of the object we're only referencing does not make sense)
1210 // (the second would violate the restriction for label controls that they're part of the
1211 // same form component hierarchy - we ourself are no part, yet, so we can't have a label control)
1212 // start listening for changes at the value property
1213 implInitValuePropertyListening( );
1216 OBoundControlModel::~OBoundControlModel()
1218 if ( !OComponentHelper::rBHelper
.bDisposed
)
1224 doResetDelegator( );
1225 OSL_ENSURE( m_pAggPropMultiplexer
, "OBoundControlModel::~OBoundControlModel: what about my property multiplexer?" );
1226 if ( m_pAggPropMultiplexer
)
1228 m_pAggPropMultiplexer
->dispose();
1229 m_pAggPropMultiplexer
= nullptr;
1233 void OBoundControlModel::clonedFrom( const OControlModel
* _pOriginal
)
1235 const OBoundControlModel
* pBoundOriginal
= static_cast< const OBoundControlModel
* >( _pOriginal
);
1236 // the value binding can be handled as if somebody called setValueBinding here
1237 // By definition, bindings can be share between bindables
1238 if ( !(pBoundOriginal
&& pBoundOriginal
->m_xExternalBinding
.is()) )
1243 setValueBinding( pBoundOriginal
->m_xExternalBinding
);
1246 catch( const Exception
& )
1248 DBG_UNHANDLED_EXCEPTION("forms.component");
1252 void OBoundControlModel::implInitAggMultiplexer( )
1254 osl_atomic_increment( &m_refCount
);
1255 if ( m_xAggregateSet
.is() )
1257 m_pAggPropMultiplexer
= new OPropertyChangeMultiplexer( this, m_xAggregateSet
, false );
1260 osl_atomic_decrement( &m_refCount
);
1264 void OBoundControlModel::implInitValuePropertyListening( ) const
1266 // start listening for changes at the value property
1267 // There are three pre-requisites for this to be done:
1268 // 1. We support external value bindings. In this case, the changes in the control value need to
1269 // be propagated to the external binding immediately when they happen
1270 // 2. We support external validation. In this case, we need to listen for changes in the value
1271 // property, since we need to revalidate then.
1272 // 3. We are not committable. In this case, changes in the control value need to be propagated
1273 // to the database column immediately when they happen.
1274 if ( m_bSupportsExternalBinding
|| m_bSupportsValidation
|| !m_bCommitable
)
1276 OSL_ENSURE( m_pAggPropMultiplexer
, "OBoundControlModel::implInitValuePropertyListening: no multiplexer!" );
1277 if ( m_pAggPropMultiplexer
&& !m_sValuePropertyName
.isEmpty() )
1278 m_pAggPropMultiplexer
->addProperty( m_sValuePropertyName
);
1282 void OBoundControlModel::initOwnValueProperty( const OUString
& i_rValuePropertyName
)
1284 OSL_PRECOND( m_sValuePropertyName
.isEmpty() && -1 == m_nValuePropertyAggregateHandle
,
1285 "OBoundControlModel::initOwnValueProperty: value property is already initialized!" );
1286 OSL_ENSURE( !i_rValuePropertyName
.isEmpty(), "OBoundControlModel::initOwnValueProperty: invalid property name!" );
1287 m_sValuePropertyName
= i_rValuePropertyName
;
1290 void OBoundControlModel::initValueProperty( const OUString
& _rValuePropertyName
, sal_Int32 _nValuePropertyExternalHandle
)
1292 OSL_PRECOND( m_sValuePropertyName
.isEmpty() && -1 == m_nValuePropertyAggregateHandle
,
1293 "OBoundControlModel::initValueProperty: value property is already initialized!" );
1294 OSL_ENSURE( !_rValuePropertyName
.isEmpty(), "OBoundControlModel::initValueProperty: invalid property name!" );
1295 OSL_ENSURE( _nValuePropertyExternalHandle
!= -1, "OBoundControlModel::initValueProperty: invalid property handle!" );
1297 m_sValuePropertyName
= _rValuePropertyName
;
1298 m_nValuePropertyAggregateHandle
= getOriginalHandle( _nValuePropertyExternalHandle
);
1299 OSL_ENSURE( m_nValuePropertyAggregateHandle
!= -1, "OBoundControlModel::initValueProperty: unable to find the original handle!" );
1301 if ( m_nValuePropertyAggregateHandle
!= -1 )
1303 Reference
< XPropertySetInfo
> xPropInfo( m_xAggregateSet
->getPropertySetInfo(), UNO_SET_THROW
);
1304 Property aValuePropDesc
= xPropInfo
->getPropertyByName( m_sValuePropertyName
);
1305 m_aValuePropertyType
= aValuePropDesc
.Type
;
1306 m_bValuePropertyMayBeVoid
= ( aValuePropDesc
.Attributes
& PropertyAttribute::MAYBEVOID
) != 0;
1309 // start listening for changes at the value property
1310 implInitValuePropertyListening( );
1313 void OBoundControlModel::suspendValueListening( )
1315 OSL_PRECOND( !m_sValuePropertyName
.isEmpty(), "OBoundControlModel::suspendValueListening: don't have a value property!" );
1316 OSL_PRECOND( m_pAggPropMultiplexer
, "OBoundControlModel::suspendValueListening: I *am* not listening!" );
1318 if ( m_pAggPropMultiplexer
)
1319 m_pAggPropMultiplexer
->lock();
1322 void OBoundControlModel::resumeValueListening( )
1324 OSL_PRECOND( !m_sValuePropertyName
.isEmpty(), "OBoundControlModel::resumeValueListening: don't have a value property!" );
1325 OSL_PRECOND( m_pAggPropMultiplexer
, "OBoundControlModel::resumeValueListening: I *am* not listening at all!" );
1326 OSL_PRECOND( !m_pAggPropMultiplexer
|| m_pAggPropMultiplexer
->locked(), "OBoundControlModel::resumeValueListening: listening not suspended currently!" );
1327 if ( m_pAggPropMultiplexer
)
1328 m_pAggPropMultiplexer
->unlock();
1331 Sequence
< Type
> OBoundControlModel::_getTypes()
1334 OControlModel::_getTypes(),
1335 OBoundControlModel_BASE1::getTypes()
1338 if ( m_bCommitable
)
1339 aTypes
.addTypes( OBoundControlModel_COMMITTING::getTypes() );
1341 if ( m_bSupportsExternalBinding
)
1342 aTypes
.addTypes( OBoundControlModel_BINDING::getTypes() );
1344 if ( m_bSupportsValidation
)
1345 aTypes
.addTypes( OBoundControlModel_VALIDATION::getTypes() );
1346 return aTypes
.getTypes();
1350 void OBoundControlModel::disposing()
1352 OControlModel::disposing();
1354 osl::MutexGuard
aGuard(m_aMutex
);
1356 if ( m_pAggPropMultiplexer
)
1357 m_pAggPropMultiplexer
->dispose();
1359 // notify all our listeners
1360 css::lang::EventObject
aEvt( static_cast< XWeak
* >( this ) );
1361 m_aUpdateListeners
.disposeAndClear( aEvt
);
1362 m_aResetHelper
.disposing();
1364 // disconnect from our database column
1365 // TODO: could we replace the following 5 lines with a call to impl_disconnectDatabaseColumn_noNotify?
1366 // The only more thing which it does is calling onDisconnectedDbColumn - could this
1367 // cause trouble? At least when we continue to call OControlModel::disposing before, it *may*.
1370 getField()->removePropertyChangeListener( PROPERTY_VALUE
, this );
1374 m_xCursor
= nullptr;
1375 Reference
< XComponent
> xComp( m_xLabelControl
, UNO_QUERY
);
1377 xComp
->removeEventListener(static_cast< XEventListener
* >( static_cast< XPropertyChangeListener
* >( this ) ) );
1378 // disconnect from our external value binding
1379 if ( hasExternalValueBinding() )
1380 disconnectExternalValueBinding();
1381 // ditto for the validator
1382 if ( hasValidator() )
1383 disconnectValidator( );
1386 void OBoundControlModel::onValuePropertyChange( ControlModelLock
& i_rControLock
)
1388 if ( hasExternalValueBinding() )
1390 // the control value changed, while we have an external value binding
1391 // -> forward the value to it
1392 if ( m_eControlValueChangeInstigator
!= eExternalBinding
)
1393 transferControlValueToExternal( i_rControLock
);
1396 else if ( !m_bCommitable
&& m_xColumnUpdate
.is() )
1398 // the control value changed, while we are bound to a database column,
1399 // but not committable (which means changes in the control have to be reflected to
1400 // the underlying database column immediately)
1401 // -> forward the value to the database column
1402 if ( m_eControlValueChangeInstigator
!= eDbColumnBinding
)
1403 commitControlValueToDbColumn( false );
1406 // validate the new value
1407 if ( m_bSupportsValidation
)
1408 recheckValidity( true );
1411 void OBoundControlModel::_propertyChanged( const PropertyChangeEvent
& _rEvt
)
1413 ControlModelLock
aLock( *this );
1414 OSL_ENSURE( _rEvt
.PropertyName
== m_sValuePropertyName
,
1415 "OBoundControlModel::_propertyChanged: where did this come from (1)?" );
1416 OSL_ENSURE( m_pAggPropMultiplexer
&& !m_pAggPropMultiplexer
->locked(),
1417 "OBoundControlModel::_propertyChanged: where did this come from (2)?" );
1418 if ( _rEvt
.PropertyName
== m_sValuePropertyName
)
1420 onValuePropertyChange( aLock
);
1424 void OBoundControlModel::startAggregatePropertyListening( const OUString
& _rPropertyName
)
1426 OSL_PRECOND( m_pAggPropMultiplexer
, "OBoundControlModel::startAggregatePropertyListening: no multiplexer!" );
1427 OSL_ENSURE( !_rPropertyName
.isEmpty(), "OBoundControlModel::startAggregatePropertyListening: invalid property name!" );
1428 if ( m_pAggPropMultiplexer
&& !_rPropertyName
.isEmpty() )
1430 m_pAggPropMultiplexer
->addProperty( _rPropertyName
);
1434 void OBoundControlModel::doFormListening( const bool _bStart
)
1436 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::doFormListening: external value binding should overrule the database binding!" );
1437 if ( isFormListening() == _bStart
)
1439 if ( m_xAmbientForm
.is() )
1440 _bStart
? m_xAmbientForm
->addLoadListener( this ) : m_xAmbientForm
->removeLoadListener( this );
1441 Reference
< XLoadable
> xParentLoadable( getParent(), UNO_QUERY
);
1442 if ( getParent().is() && !xParentLoadable
.is() )
1444 // if our parent does not directly support the XLoadable interface, then it might support the
1445 // XRowSetSupplier/XRowSetChangeBroadcaster interfaces. In this case we have to listen for changes
1446 // broadcasted by the latter.
1447 Reference
< XRowSetChangeBroadcaster
> xRowSetBroadcaster( getParent(), UNO_QUERY
);
1448 if ( xRowSetBroadcaster
.is() )
1449 _bStart
? xRowSetBroadcaster
->addRowSetChangeListener( this ) : xRowSetBroadcaster
->removeRowSetChangeListener( this );
1452 m_bFormListening
= _bStart
&& m_xAmbientForm
.is();
1456 void SAL_CALL
OBoundControlModel::setParent(const Reference
<XInterface
>& _rxParent
)
1458 ControlModelLock
aLock( *this );
1459 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
1460 if ( getParent() == _rxParent
)
1462 // disconnect from database column (which is controlled by parent, directly or indirectly)
1464 impl_disconnectDatabaseColumn_noNotify();
1465 // log off old listeners
1466 if ( isFormListening() )
1467 doFormListening( false );
1468 // actually set the new parent
1469 OControlModel::setParent( _rxParent
);
1470 // a new parent means a new ambient form
1471 impl_determineAmbientForm_nothrow();
1472 if ( !hasExternalValueBinding() )
1474 // log on new listeners
1475 doFormListening( true );
1476 // re-connect to database column of the new parent
1477 if ( m_xAmbientForm
.is() && m_xAmbientForm
->isLoaded() )
1478 impl_connectDatabaseColumn_noNotify( false );
1483 void SAL_CALL
OBoundControlModel::disposing(const css::lang::EventObject
& _rEvent
)
1485 ControlModelLock
aLock( *this );
1486 if ( _rEvent
.Source
== getField() )
1491 else if ( _rEvent
.Source
== m_xLabelControl
)
1493 Reference
<XPropertySet
> xOldValue
= m_xLabelControl
;
1494 m_xLabelControl
= nullptr;
1495 // fire a propertyChanged (when we leave aLock's scope)
1496 aLock
.addPropertyNotification( PROPERTY_ID_CONTROLLABEL
, Any( xOldValue
), Any( m_xLabelControl
) );
1499 else if ( _rEvent
.Source
== m_xExternalBinding
)
1500 { // *first* check for the external binding
1501 disconnectExternalValueBinding( );
1504 else if ( _rEvent
.Source
== m_xValidator
)
1505 { // *then* check for the validator. Reason is that bindings may also act as validator at the same
1506 // time, in this case, the validator is automatically revoked when the binding is revoked
1507 disconnectValidator( );
1511 OControlModel::disposing(_rEvent
);
1515 css::uno::Sequence
<OUString
> SAL_CALL
OBoundControlModel::getSupportedServiceNames()
1517 return ::comphelper::combineSequences(
1518 getAggregateServiceNames(),
1519 getSupportedServiceNames_Static()
1523 Sequence
< OUString
> OBoundControlModel::getSupportedServiceNames_Static()
1525 Sequence
<OUString
> aOwnServiceNames
{ "com.sun.star.form.DataAwareControlModel" };
1526 return ::comphelper::concatSequences(
1527 OControlModel::getSupportedServiceNames_Static(),
1533 void SAL_CALL
OBoundControlModel::write( const Reference
<css::io::XObjectOutputStream
>& _rxOutStream
)
1535 OControlModel::write(_rxOutStream
);
1536 osl::MutexGuard
aGuard(m_aMutex
);
1538 _rxOutStream
->writeShort(0x0002);
1540 ::comphelper::operator<<( _rxOutStream
, m_aControlSource
);
1541 // !!! IMPORTANT NOTE !!!
1542 // don't write any new members here: this wouldn't be compatible with older versions, as OBoundControlModel
1543 // is a base class which is called in derived classes "read" method. So if you increment the version
1544 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
1545 // in anything from data loss to crash.
1546 // (use writeCommonProperties instead, this is called in derived classes write-method)
1550 void OBoundControlModel::defaultCommonProperties()
1552 Reference
<css::lang::XComponent
> xComp(m_xLabelControl
, UNO_QUERY
);
1554 xComp
->removeEventListener(static_cast<css::lang::XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
1555 m_xLabelControl
= nullptr;
1558 void OBoundControlModel::readCommonProperties(const Reference
<css::io::XObjectInputStream
>& _rxInStream
)
1560 sal_Int32 nLen
= _rxInStream
->readLong();
1561 Reference
<css::io::XMarkableStream
> xMark(_rxInStream
, UNO_QUERY
);
1562 DBG_ASSERT(xMark
.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !");
1563 sal_Int32 nMark
= xMark
->createMark();
1564 // read the reference to the label control
1565 Reference
<css::io::XPersistObject
> xPersist
;
1566 sal_Int32 nUsedFlag
;
1567 nUsedFlag
= _rxInStream
->readLong();
1569 xPersist
= _rxInStream
->readObject();
1570 m_xLabelControl
.set(xPersist
, css::uno::UNO_QUERY
);
1571 Reference
< XComponent
> xComp( m_xLabelControl
, UNO_QUERY
);
1573 xComp
->addEventListener(static_cast<css::lang::XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
1574 // read any other new common properties here
1575 // skip the remaining bytes
1576 xMark
->jumpToMark(nMark
);
1577 _rxInStream
->skipBytes(nLen
);
1578 xMark
->deleteMark(nMark
);
1581 void OBoundControlModel::writeCommonProperties(const Reference
<css::io::XObjectOutputStream
>& _rxOutStream
)
1583 Reference
<css::io::XMarkableStream
> xMark(_rxOutStream
, UNO_QUERY
);
1584 DBG_ASSERT(xMark
.is(), "OBoundControlModel::writeCommonProperties : can only work with markable streams !");
1585 sal_Int32 nMark
= xMark
->createMark();
1586 // a placeholder where we will write the overall length (later in this method)
1588 _rxOutStream
->writeLong(nLen
);
1589 // write the reference to the label control
1590 Reference
<css::io::XPersistObject
> xPersist(m_xLabelControl
, UNO_QUERY
);
1591 sal_Int32 nUsedFlag
= 0;
1594 _rxOutStream
->writeLong(nUsedFlag
);
1596 _rxOutStream
->writeObject(xPersist
);
1597 // write any other new common properties here
1598 // write the correct length at the beginning of the block
1599 nLen
= xMark
->offsetToMark(nMark
) - sizeof(nLen
);
1600 xMark
->jumpToMark(nMark
);
1601 _rxOutStream
->writeLong(nLen
);
1602 xMark
->jumpToFurthest();
1603 xMark
->deleteMark(nMark
);
1606 void SAL_CALL
OBoundControlModel::read( const Reference
< css::io::XObjectInputStream
>& _rxInStream
)
1608 OControlModel::read(_rxInStream
);
1609 osl::MutexGuard
aGuard(m_aMutex
);
1610 _rxInStream
->readShort(); // version;
1611 ::comphelper::operator>>( _rxInStream
, m_aControlSource
);
1614 void OBoundControlModel::getFastPropertyValue(Any
& rValue
, sal_Int32 nHandle
) const
1618 case PROPERTY_ID_INPUT_REQUIRED
:
1619 rValue
<<= m_bInputRequired
;
1621 case PROPERTY_ID_CONTROLSOURCEPROPERTY
:
1622 rValue
<<= m_sValuePropertyName
;
1624 case PROPERTY_ID_CONTROLSOURCE
:
1625 rValue
<<= m_aControlSource
;
1627 case PROPERTY_ID_BOUNDFIELD
:
1628 rValue
<<= getField();
1630 case PROPERTY_ID_CONTROLLABEL
:
1631 if (!m_xLabelControl
.is())
1634 rValue
<<= m_xLabelControl
;
1637 OControlModel::getFastPropertyValue(rValue
, nHandle
);
1641 sal_Bool
OBoundControlModel::convertFastPropertyValue(
1642 Any
& _rConvertedValue
, Any
& _rOldValue
,
1646 bool bModified(false);
1649 case PROPERTY_ID_INPUT_REQUIRED
:
1650 bModified
= tryPropertyValue( _rConvertedValue
, _rOldValue
, _rValue
, m_bInputRequired
);
1652 case PROPERTY_ID_CONTROLSOURCE
:
1653 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aControlSource
);
1655 case PROPERTY_ID_BOUNDFIELD
:
1656 SAL_WARN("forms.component", "OBoundControlModel::convertFastPropertyValue: BoundField should be a read-only property !" );
1657 throw css::lang::IllegalArgumentException();
1658 case PROPERTY_ID_CONTROLLABEL
:
1659 if (!_rValue
.hasValue())
1660 { // property set to void
1661 _rConvertedValue
= Any();
1662 getFastPropertyValue(_rOldValue
, _nHandle
);
1663 bModified
= m_xLabelControl
.is();
1668 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_xLabelControl
);
1669 if (!m_xLabelControl
.is())
1670 // an empty interface is interpreted as VOID
1676 bModified
= OControlModel::convertFastPropertyValue(_rConvertedValue
, _rOldValue
, _nHandle
, _rValue
);
1681 Any
OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle
) const
1686 case PROPERTY_ID_INPUT_REQUIRED
:
1689 case PROPERTY_ID_CONTROLSOURCE
:
1690 aDefault
<<= OUString();
1692 case PROPERTY_ID_CONTROLLABEL
:
1693 aDefault
<<= Reference
< XPropertySet
>();
1699 void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle
, const Any
& rValue
)
1703 case PROPERTY_ID_INPUT_REQUIRED
:
1704 OSL_VERIFY( rValue
>>= m_bInputRequired
);
1706 case PROPERTY_ID_CONTROLSOURCE
:
1707 OSL_VERIFY( rValue
>>= m_aControlSource
);
1709 case PROPERTY_ID_BOUNDFIELD
:
1710 SAL_WARN("forms.component", "OBoundControlModel::setFastPropertyValue_NoBroadcast : BoundField should be a read-only property !");
1711 throw css::lang::IllegalArgumentException();
1712 case PROPERTY_ID_CONTROLLABEL
:
1714 if ( rValue
.hasValue() && ( rValue
.getValueTypeClass() != TypeClass_INTERFACE
) )
1715 throw css::lang::IllegalArgumentException();
1716 Reference
< XInterface
> xNewValue( rValue
, UNO_QUERY
);
1717 if ( !xNewValue
.is() )
1718 { // set property to "void"
1719 Reference
< XComponent
> xComp( m_xLabelControl
, UNO_QUERY
);
1721 xComp
->removeEventListener( static_cast< XPropertyChangeListener
* >( this ) );
1722 m_xLabelControl
= nullptr;
1726 Reference
< XControlModel
> xAsModel ( xNewValue
, UNO_QUERY
);
1727 Reference
< XServiceInfo
> xAsServiceInfo ( xAsModel
, UNO_QUERY
);
1728 Reference
< XPropertySet
> xAsPropSet ( xAsServiceInfo
, UNO_QUERY
);
1729 Reference
< XChild
> xAsChild ( xAsPropSet
, UNO_QUERY
);
1730 if ( !xAsChild
.is() || !xAsServiceInfo
->supportsService( m_aLabelServiceName
) )
1732 throw css::lang::IllegalArgumentException();
1735 // Check if we and the given model have a common ancestor (up to the forms collection)
1736 Reference
<XChild
> xCont(this);
1737 Reference
< XInterface
> xMyTopLevel
= xCont
->getParent();
1738 while (xMyTopLevel
.is())
1740 Reference
<XForm
> xAsForm(xMyTopLevel
, UNO_QUERY
);
1744 Reference
<XChild
> xLoopAsChild(xMyTopLevel
, UNO_QUERY
);
1745 xMyTopLevel
= xLoopAsChild
.is() ? xLoopAsChild
->getParent() : Reference
< XInterface
>();
1748 Reference
< XInterface
> xNewTopLevel
= xAsChild
->getParent();
1749 while (xNewTopLevel
.is())
1751 Reference
<XForm
> xAsForm(xNewTopLevel
, UNO_QUERY
);
1754 Reference
<XChild
> xLoopAsChild(xNewTopLevel
, UNO_QUERY
);
1755 xNewTopLevel
= xLoopAsChild
.is() ? xLoopAsChild
->getParent() : Reference
< XInterface
>();
1758 if (xNewTopLevel
!= xMyTopLevel
)
1760 // the both objects don't belong to the same forms collection -> not acceptable
1761 throw css::lang::IllegalArgumentException();
1764 m_xLabelControl
= xAsPropSet
;
1765 Reference
<css::lang::XComponent
> xComp(m_xLabelControl
, UNO_QUERY
);
1767 xComp
->addEventListener(static_cast<css::lang::XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
1772 OControlModel::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
1776 // XPropertyChangeListener
1777 void SAL_CALL
OBoundControlModel::propertyChange( const PropertyChangeEvent
& evt
)
1779 // if the DBColumn value changed, transfer it to the control
1780 if ( evt
.PropertyName
== PROPERTY_VALUE
)
1782 OSL_ENSURE( evt
.Source
== getField(), "OBoundControlModel::propertyChange: value changes from components other than our database column?" );
1783 osl::MutexGuard
aGuard(m_aMutex
);
1784 if ( m_bForwardValueChanges
&& m_xColumn
.is() )
1785 transferDbValueToControl();
1790 OSL_ENSURE( evt
.Source
== m_xExternalBinding
, "OBoundControlModel::propertyChange: where did this come from?" );
1791 // our binding has properties which can control properties of ourself
1792 OUString sBindingControlledProperty
;
1793 bool bForwardToLabelControl
= false;
1794 if ( evt
.PropertyName
== PROPERTY_READONLY
)
1796 sBindingControlledProperty
= PROPERTY_READONLY
;
1799 else if ( evt
.PropertyName
== PROPERTY_RELEVANT
)
1801 sBindingControlledProperty
= PROPERTY_ENABLED
;
1802 bForwardToLabelControl
= true;
1809 setPropertyValue( sBindingControlledProperty
, evt
.NewValue
);
1810 if ( bForwardToLabelControl
&& m_xLabelControl
.is() )
1811 m_xLabelControl
->setPropertyValue( sBindingControlledProperty
, evt
.NewValue
);
1814 catch( const Exception
& )
1816 DBG_UNHANDLED_EXCEPTION("forms.component");
1817 SAL_WARN("forms.component", "OBoundControlModel::propertyChange: could not adjust my binding-controlled property!");
1823 void SAL_CALL
OBoundControlModel::onRowSetChanged( const EventObject
& /*i_Event*/ )
1825 ControlModelLock
aLock( *this );
1826 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
1827 // disconnect from database column (which is controlled by parent, directly or indirectly)
1829 impl_disconnectDatabaseColumn_noNotify();
1830 // log off old listeners
1831 if ( isFormListening() )
1832 doFormListening( false );
1833 // determine the new ambient form
1834 impl_determineAmbientForm_nothrow();
1835 // log on new listeners
1836 doFormListening( true );
1837 // re-connect to database column if needed and possible
1838 if ( m_xAmbientForm
.is() && m_xAmbientForm
->isLoaded() )
1839 impl_connectDatabaseColumn_noNotify( false );
1843 void SAL_CALL
OBoundControlModel::addUpdateListener(const Reference
<XUpdateListener
>& _rxListener
)
1845 m_aUpdateListeners
.addInterface(_rxListener
);
1848 void SAL_CALL
OBoundControlModel::removeUpdateListener(const Reference
< XUpdateListener
>& _rxListener
)
1850 m_aUpdateListeners
.removeInterface(_rxListener
);
1853 sal_Bool SAL_CALL
OBoundControlModel::commit()
1855 ControlModelLock
aLock( *this );
1856 OSL_PRECOND( m_bCommitable
, "OBoundControlModel::commit: invalid call (I'm not committable!) " );
1857 if ( hasExternalValueBinding() )
1859 // in most cases, no action is required: For most derivees, we know the value property of
1860 // our control (see initValueProperty), and when an external binding is active, we
1861 // instantly forward all changes in this property to the external binding.
1862 if ( m_sValuePropertyName
.isEmpty() )
1863 // but for those derivees which did not use this feature, we need an
1864 // explicit transfer
1865 transferControlValueToExternal( aLock
);
1869 OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" );
1870 // we reach this only if we're not working with an external binding
1873 ::comphelper::OInterfaceIteratorHelper3
aIter( m_aUpdateListeners
);
1875 aEvent
.Source
= static_cast< XWeak
* >( this );
1876 bool bSuccess
= true;
1879 while (aIter
.hasMoreElements() && bSuccess
)
1880 bSuccess
= aIter
.next()->approveUpdate( aEvent
);
1887 if ( m_xColumnUpdate
.is() )
1888 bSuccess
= commitControlValueToDbColumn( false );
1891 catch(const Exception
&)
1901 m_aUpdateListeners
.notifyEach( &XUpdateListener::updated
, aEvent
);
1906 void OBoundControlModel::resetField()
1908 m_xColumnUpdate
.clear();
1911 m_nFieldType
= DataType::OTHER
;
1914 void OBoundControlModel::connectToField(const Reference
<XRowSet
>& rForm
)
1916 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::connectToField: invalid call (have an external binding)!" );
1917 // if there's a connection to the database
1918 if (!(rForm
.is() && getConnection(rForm
).is()))
1921 // determine field and PropertyChangeListener
1923 Reference
<XPropertySet
> xFieldCandidate
;
1926 Reference
<XColumnsSupplier
> xColumnsSupplier(m_xCursor
, UNO_QUERY
);
1927 DBG_ASSERT(xColumnsSupplier
.is(), "OBoundControlModel::connectToField : the row set should support the css::sdb::ResultSet service !");
1928 if (xColumnsSupplier
.is())
1930 Reference
<XNameAccess
> xColumns
= xColumnsSupplier
->getColumns();
1931 if (xColumns
.is() && xColumns
->hasByName(m_aControlSource
))
1933 OSL_VERIFY( xColumns
->getByName(m_aControlSource
) >>= xFieldCandidate
);
1942 sal_Int32 nFieldType
= DataType::OTHER
;
1943 if ( xFieldCandidate
.is() )
1945 xFieldCandidate
->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
;
1946 if ( approveDbColumnType( nFieldType
) )
1947 impl_setField_noNotify( xFieldCandidate
);
1951 impl_setField_noNotify( nullptr );
1952 if ( m_xField
.is() )
1954 if ( m_xField
->getPropertySetInfo()->hasPropertyByName( PROPERTY_VALUE
) )
1956 m_nFieldType
= nFieldType
;
1957 // listen to changing values
1958 m_xField
->addPropertyChangeListener( PROPERTY_VALUE
, this );
1959 m_xColumnUpdate
.set( m_xField
, UNO_QUERY
);
1960 m_xColumn
.set( m_xField
, UNO_QUERY
);
1961 sal_Int32 nNullableFlag
= ColumnValue::NO_NULLS
;
1962 m_xField
->getPropertyValue(PROPERTY_ISNULLABLE
) >>= nNullableFlag
;
1963 // tdf#122319 - don't allow nullable form components if input is required
1964 m_bRequired
= (ColumnValue::NO_NULLS
== nNullableFlag
|| m_bInputRequired
);
1965 // we're optimistic: in case of ColumnValue_NULLABLE_UNKNOWN we assume nullability...
1969 SAL_WARN("forms.component", "OBoundControlModel::connectToField: property " << PROPERTY_VALUE
<< " not supported!");
1970 impl_setField_noNotify( nullptr );
1977 catch( const Exception
& )
1979 DBG_UNHANDLED_EXCEPTION("forms.component");
1984 void OBoundControlModel::initFromField( const Reference
< XRowSet
>& _rxRowSet
)
1986 // but only if the rowset is positioned on a valid record
1987 if ( !(hasField() && _rxRowSet
.is()) )
1990 bool shouldTransfer(!_rxRowSet
->isBeforeFirst() && !_rxRowSet
->isAfterLast());
1991 if (!shouldTransfer
)
1993 const Reference
< XPropertySet
> xPS(_rxRowSet
, UNO_QUERY
);
1996 assert(!shouldTransfer
);
1997 xPS
->getPropertyValue("IsNew") >>= shouldTransfer
;
2000 if ( shouldTransfer
)
2001 transferDbValueToControl();
2003 // reset the field if the row set is empty
2008 bool OBoundControlModel::approveDbColumnType(sal_Int32 _nColumnType
)
2010 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::approveDbColumnType: invalid call (have an external binding)!" );
2011 if ((_nColumnType
== DataType::BINARY
) || (_nColumnType
== DataType::VARBINARY
)
2012 || (_nColumnType
== DataType::LONGVARBINARY
) || (_nColumnType
== DataType::OTHER
)
2013 || (_nColumnType
== DataType::OBJECT
) || (_nColumnType
== DataType::DISTINCT
)
2014 || (_nColumnType
== DataType::STRUCT
) || (_nColumnType
== DataType::ARRAY
)
2015 || (_nColumnType
== DataType::BLOB
) /*|| (_nColumnType == DataType::CLOB)*/
2016 || (_nColumnType
== DataType::REF
) || (_nColumnType
== DataType::SQLNULL
))
2021 void OBoundControlModel::impl_determineAmbientForm_nothrow()
2023 Reference
< XInterface
> xParent( getParent() );
2024 m_xAmbientForm
.set( xParent
, UNO_QUERY
);
2025 if ( !m_xAmbientForm
.is() )
2027 Reference
< XRowSetSupplier
> xSupRowSet( xParent
, UNO_QUERY
);
2028 if ( xSupRowSet
.is() )
2029 m_xAmbientForm
.set( xSupRowSet
->getRowSet(), UNO_QUERY
);
2033 void OBoundControlModel::impl_connectDatabaseColumn_noNotify( bool _bFromReload
)
2035 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2036 // consistency checks
2037 DBG_ASSERT( !( hasField() && !_bFromReload
),
2038 "OBoundControlModel::impl_connectDatabaseColumn_noNotify: the form is just *loaded*, but we already have a field!" );
2040 Reference
< XRowSet
> xRowSet( m_xAmbientForm
, UNO_QUERY
);
2041 OSL_ENSURE( xRowSet
.is(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: no row set!" );
2042 if ( !xRowSet
.is() )
2044 if ( !hasField() || _bFromReload
)
2046 // connect to the column
2047 connectToField( xRowSet
);
2050 // now that we're connected (more or less, even if we did not find a column),
2051 // we definitely want to forward any potentially occurring value changes
2052 m_bForwardValueChanges
= true;
2053 // let derived classes react on this new connection
2055 onConnectedDbColumn( xRowSet
);
2056 // initially transfer the db column value to the control, if we successfully connected to a database column
2058 initFromField( xRowSet
);
2061 void OBoundControlModel::impl_disconnectDatabaseColumn_noNotify()
2063 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_disconnectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2064 // let derived classes react on this
2065 onDisconnectedDbColumn();
2068 getField()->removePropertyChangeListener( PROPERTY_VALUE
, this );
2072 m_xCursor
= nullptr;
2077 void SAL_CALL
OBoundControlModel::loaded( const EventObject
& _rEvent
)
2079 ControlModelLock
aLock( *this );
2080 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2081 OSL_ENSURE( _rEvent
.Source
== m_xAmbientForm
, "OBoundControlModel::loaded: where does this come from?" );
2082 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::loaded: we should never reach this with an external value binding!" );
2083 if ( hasExternalValueBinding() )
2085 impl_connectDatabaseColumn_noNotify( false );
2088 void SAL_CALL
OBoundControlModel::unloaded( const css::lang::EventObject
& /*aEvent*/ )
2090 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloaded: we should never reach this with an external value binding!" );
2093 void SAL_CALL
OBoundControlModel::reloading( const css::lang::EventObject
& /*aEvent*/ )
2095 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloading: we should never reach this with an external value binding!" );
2096 if ( hasExternalValueBinding() )
2098 osl::MutexGuard
aGuard(m_aMutex
);
2099 m_bForwardValueChanges
= false;
2102 void SAL_CALL
OBoundControlModel::unloading(const css::lang::EventObject
& /*aEvent*/)
2104 ControlModelLock
aLock( *this );
2105 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2106 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloading: we should never reach this with an external value binding!" );
2107 if ( hasExternalValueBinding() )
2109 impl_disconnectDatabaseColumn_noNotify();
2112 void SAL_CALL
OBoundControlModel::reloaded( const EventObject
& _rEvent
)
2114 ControlModelLock
aLock( *this );
2115 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2116 OSL_ENSURE( _rEvent
.Source
== m_xAmbientForm
, "OBoundControlModel::reloaded: where does this come from?" );
2117 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloaded: we should never reach this with an external value binding!" );
2118 if ( hasExternalValueBinding() )
2120 impl_connectDatabaseColumn_noNotify( true );
2123 void OBoundControlModel::setControlValue( const Any
& _rValue
, ValueChangeInstigator _eInstigator
)
2125 m_eControlValueChangeInstigator
= _eInstigator
;
2126 doSetControlValue( _rValue
);
2127 m_eControlValueChangeInstigator
= eOther
;
2130 void OBoundControlModel::doSetControlValue( const Any
& _rValue
)
2132 OSL_PRECOND( m_xAggregateFastSet
.is() && m_xAggregateSet
.is(),
2133 "OBoundControlModel::doSetControlValue: invalid aggregate !" );
2134 OSL_PRECOND( !m_sValuePropertyName
.isEmpty() || ( m_nValuePropertyAggregateHandle
!= -1 ),
2135 "OBoundControlModel::doSetControlValue: please override if you have own value property handling!" );
2138 // release our mutex once (it's acquired in one of the calling methods), as setting aggregate properties
2139 // may cause any uno controls belonging to us to lock the solar mutex, which is potentially dangerous with
2140 // our own mutex locked
2141 MutexRelease
aRelease( m_aMutex
);
2142 if ( ( m_nValuePropertyAggregateHandle
!= -1 ) && m_xAggregateFastSet
.is() )
2144 m_xAggregateFastSet
->setFastPropertyValue( m_nValuePropertyAggregateHandle
, _rValue
);
2147 else if ( !m_sValuePropertyName
.isEmpty() && m_xAggregateSet
.is() )
2149 m_xAggregateSet
->setPropertyValue( m_sValuePropertyName
, _rValue
);
2154 catch( const Exception
& )
2156 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::doSetControlValue");
2160 void OBoundControlModel::onConnectedValidator( )
2164 // if we have an external validator, we do not want the control to force invalid
2165 // inputs to the default value. Instead, invalid inputs should be translated
2166 // to NaN (not a number)
2167 Reference
< XPropertySetInfo
> xAggregatePropertyInfo
;
2168 if ( m_xAggregateSet
.is() )
2169 xAggregatePropertyInfo
= m_xAggregateSet
->getPropertySetInfo();
2170 if ( xAggregatePropertyInfo
.is() && xAggregatePropertyInfo
->hasPropertyByName( PROPERTY_ENFORCE_FORMAT
) )
2171 m_xAggregateSet
->setPropertyValue( PROPERTY_ENFORCE_FORMAT
, Any( false ) );
2174 catch( const Exception
& )
2176 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::onConnectedValidator");
2179 recheckValidity( false );
2182 void OBoundControlModel::onDisconnectedValidator( )
2186 Reference
< XPropertySetInfo
> xAggregatePropertyInfo
;
2187 if ( m_xAggregateSet
.is() )
2188 xAggregatePropertyInfo
= m_xAggregateSet
->getPropertySetInfo();
2189 if ( xAggregatePropertyInfo
.is() && xAggregatePropertyInfo
->hasPropertyByName( PROPERTY_ENFORCE_FORMAT
) )
2190 m_xAggregateSet
->setPropertyValue( PROPERTY_ENFORCE_FORMAT
, Any( true ) );
2193 catch( const Exception
& )
2195 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::onDisconnectedValidator");
2198 recheckValidity( false );
2201 void OBoundControlModel::onConnectedExternalValue( )
2203 calculateExternalValueType();
2206 void OBoundControlModel::onConnectedDbColumn( const Reference
< XInterface
>& /*_rxForm*/ )
2208 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onConnectedDbColumn: how this? There's an external value binding!" );
2211 void OBoundControlModel::onDisconnectedDbColumn()
2213 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onDisconnectedDbColumn: how this? There's an external value binding!" );
2217 Any
OBoundControlModel::getDefaultForReset() const
2222 void OBoundControlModel::resetNoBroadcast()
2224 setControlValue( getDefaultForReset(), eOther
);
2227 void OBoundControlModel::addResetListener(const Reference
<XResetListener
>& l
)
2229 m_aResetHelper
.addResetListener( l
);
2232 void OBoundControlModel::removeResetListener(const Reference
<XResetListener
>& l
)
2234 m_aResetHelper
.removeResetListener( l
);
2237 void OBoundControlModel::reset()
2239 if ( !m_aResetHelper
.approveReset() )
2241 ControlModelLock
aLock( *this );
2243 bool bIsNewRecord
= false;
2244 Reference
<XPropertySet
> xSet( m_xCursor
, UNO_QUERY
);
2249 xSet
->getPropertyValue( PROPERTY_ISNEW
) >>= bIsNewRecord
;
2252 catch( const Exception
& )
2254 DBG_UNHANDLED_EXCEPTION("forms.component");
2259 // cursor on an invalid row?
2260 bool bInvalidCursorPosition
= true;
2263 bInvalidCursorPosition
= m_xCursor
.is()
2264 && ( m_xCursor
->isAfterLast()
2265 || m_xCursor
->isBeforeFirst()
2270 catch( const SQLException
& )
2272 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::reset: caught an SQL exception!" );
2275 // #i24495# - don't count the insert row as "invalid"
2277 ( !m_xColumn
.is() // no connection to a database column
2278 || ( m_xCursor
.is() // OR we have an improperly positioned cursor
2279 && bInvalidCursorPosition
2281 || hasExternalValueBinding() // OR we have an external value binding
2283 if ( !bSimpleReset
)
2285 // The default values will be set if and only if the current value of the field which we're bound
2287 // Else, the current field value should be refreshed
2288 // This behaviour is not completely ... "matured": What should happen if the field as well as the
2289 // control have a default value?
2290 bool bIsNull
= true;
2291 // we have to access the field content at least once to get a reliable result by XColumn::wasNull
2294 // normally, we'd do a getString here. However, this is extremely expensive in the case
2295 // of binary fields. Unfortunately, getString is the only method which is guaranteed
2296 // to *always* succeed, all other getXXX methods may fail if the column is asked for a
2297 // non-convertible type
2298 sal_Int32 nFieldType
= DataType::OBJECT
;
2299 getField()->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
;
2300 if ( ( nFieldType
== DataType::BINARY
)
2301 || ( nFieldType
== DataType::VARBINARY
)
2302 || ( nFieldType
== DataType::LONGVARBINARY
)
2303 || ( nFieldType
== DataType::OBJECT
)
2304 /*|| ( nFieldType == DataType::CLOB )*/
2306 m_xColumn
->getBinaryStream();
2307 else if ( nFieldType
== DataType::BLOB
)
2308 m_xColumn
->getBlob();
2310 m_xColumn
->getString();
2311 bIsNull
= m_xColumn
->wasNull();
2314 catch(const Exception
&)
2316 DBG_UNHANDLED_EXCEPTION("forms.component");
2317 SAL_WARN("forms.component", "OBoundControlModel::reset: this should have succeeded in all cases!");
2320 bool bNeedValueTransfer
= true;
2325 // reset the control to its default
2327 // and immediately commit the changes to the DB column, to keep consistency
2328 commitControlValueToDbColumn( true );
2329 bNeedValueTransfer
= false;
2334 if ( bNeedValueTransfer
)
2335 transferDbValueToControl();
2341 // transfer to the external binding, if necessary
2342 if ( hasExternalValueBinding() )
2343 transferControlValueToExternal( aLock
);
2346 // revalidate, if necessary
2347 if ( hasValidator() )
2348 recheckValidity( true );
2350 m_aResetHelper
.notifyResetted();
2353 void OBoundControlModel::impl_setField_noNotify( const Reference
< XPropertySet
>& _rxField
)
2355 DBG_ASSERT( !hasExternalValueBinding(), "OBoundControlModel::impl_setField_noNotify: We have an external value binding!" );
2356 m_xField
= _rxField
;
2359 bool OBoundControlModel::impl_approveValueBinding_nolock( const Reference
< XValueBinding
>& _rxBinding
)
2361 if ( !_rxBinding
.is() )
2363 Sequence
< Type
> aTypeCandidates
;
2366 ::osl::MutexGuard
aGuard( m_aMutex
);
2367 aTypeCandidates
= getSupportedBindingTypes();
2371 for ( auto const & type
: std::as_const(aTypeCandidates
) )
2373 if ( _rxBinding
->supportsType( type
) )
2379 void OBoundControlModel::connectExternalValueBinding(
2380 const Reference
< XValueBinding
>& _rxBinding
, ControlModelLock
& _rInstanceLock
)
2382 OSL_PRECOND( _rxBinding
.is(), "OBoundControlModel::connectExternalValueBinding: invalid binding instance!" );
2383 OSL_PRECOND( !hasExternalValueBinding( ), "OBoundControlModel::connectExternalValueBinding: precond not met (currently have a binding)!" );
2384 // if we're connected to a database column, suspend this
2386 impl_disconnectDatabaseColumn_noNotify();
2387 // suspend listening for load-related events at out ambient form.
2388 // This is because an external value binding overrules a possible database binding.
2389 if ( isFormListening() )
2390 doFormListening( false );
2391 // remember this new binding
2392 m_xExternalBinding
= _rxBinding
;
2394 onConnectedExternalValue();
2397 // add as value listener so we get notified when the value changes
2398 Reference
< XModifyBroadcaster
> xModifiable( m_xExternalBinding
, UNO_QUERY
);
2399 if ( xModifiable
.is() )
2400 xModifiable
->addModifyListener( this );
2401 // add as property change listener for some (possibly present) properties we're
2403 Reference
< XPropertySet
> xBindingProps( m_xExternalBinding
, UNO_QUERY
);
2404 Reference
< XPropertySetInfo
> xBindingPropsInfo( xBindingProps
.is() ? xBindingProps
->getPropertySetInfo() : Reference
< XPropertySetInfo
>() );
2405 if ( xBindingPropsInfo
.is() )
2407 if ( xBindingPropsInfo
->hasPropertyByName( PROPERTY_READONLY
) )
2409 xBindingProps
->addPropertyChangeListener( PROPERTY_READONLY
, this );
2410 m_bBindingControlsRO
= true;
2413 if ( xBindingPropsInfo
->hasPropertyByName( PROPERTY_RELEVANT
) )
2415 xBindingProps
->addPropertyChangeListener( PROPERTY_RELEVANT
, this );
2416 m_bBindingControlsEnable
= true;
2423 catch( const Exception
& )
2425 DBG_UNHANDLED_EXCEPTION("forms.component");
2428 // propagate our new value
2429 transferExternalValueToControl( _rInstanceLock
);
2430 // if the binding is also a validator, use it, too. This is a constraint of the
2431 // com.sun.star.form.binding.ValidatableBindableFormComponent service
2432 if ( !m_bSupportsValidation
)
2437 Reference
< XValidator
> xAsValidator( _rxBinding
, UNO_QUERY
);
2438 if ( xAsValidator
.is() )
2439 setValidator( xAsValidator
);
2442 catch( const Exception
& )
2444 DBG_UNHANDLED_EXCEPTION("forms.component");
2448 void OBoundControlModel::disconnectExternalValueBinding( )
2452 // not listening at the binding anymore
2453 Reference
< XModifyBroadcaster
> xModifiable( m_xExternalBinding
, UNO_QUERY
);
2454 if ( xModifiable
.is() )
2455 xModifiable
->removeModifyListener( this );
2456 // remove as property change listener
2457 Reference
< XPropertySet
> xBindingProps( m_xExternalBinding
, UNO_QUERY
);
2458 if ( m_bBindingControlsRO
)
2459 xBindingProps
->removePropertyChangeListener( PROPERTY_READONLY
, this );
2460 if ( m_bBindingControlsEnable
)
2461 xBindingProps
->removePropertyChangeListener( PROPERTY_RELEVANT
, this );
2464 catch( const Exception
& )
2466 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::disconnectExternalValueBinding");
2469 // if the binding also acts as our validator, disconnect the validator, too
2470 if ( ( m_xExternalBinding
== m_xValidator
) && m_xValidator
.is() )
2471 disconnectValidator( );
2472 // no binding anymore
2473 m_xExternalBinding
.clear();
2474 // be a load listener at our form, again. This was suspended while we had
2475 // an external value binding in place.
2476 doFormListening( true );
2477 // re-connect to database column of the new parent
2478 if ( m_xAmbientForm
.is() && m_xAmbientForm
->isLoaded() )
2479 impl_connectDatabaseColumn_noNotify( false );
2482 void SAL_CALL
OBoundControlModel::setValueBinding( const Reference
< XValueBinding
>& _rxBinding
)
2484 OSL_PRECOND( m_bSupportsExternalBinding
, "OBoundControlModel::setValueBinding: How did you reach this method?" );
2485 // the interface for this method should not have been exposed if we do not
2486 // support binding to external data
2488 if ( _rxBinding
.is() && !impl_approveValueBinding_nolock( _rxBinding
) )
2490 throw IncompatibleTypesException(
2491 ResourceManager::loadString(RID_STR_INCOMPATIBLE_TYPES
),
2496 ControlModelLock
aLock( *this );
2497 // since a ValueBinding overrules any potentially active database binding, the change in a ValueBinding
2498 // might trigger a change in our BoundField.
2499 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2500 // disconnect from the old binding
2501 if ( hasExternalValueBinding() )
2502 disconnectExternalValueBinding( );
2503 // connect to the new binding
2504 if ( _rxBinding
.is() )
2505 connectExternalValueBinding( _rxBinding
, aLock
);
2508 Reference
< XValueBinding
> SAL_CALL
OBoundControlModel::getValueBinding( )
2510 ::osl::MutexGuard
aGuard( m_aMutex
);
2511 OSL_PRECOND( m_bSupportsExternalBinding
, "OBoundControlModel::getValueBinding: How did you reach this method?" );
2512 // the interface for this method should not have been exposed if we do not
2513 // support binding to external data
2514 return m_xExternalBinding
;
2517 void SAL_CALL
OBoundControlModel::modified( const EventObject
& _rEvent
)
2519 ControlModelLock
aLock( *this );
2520 OSL_PRECOND( hasExternalValueBinding(), "OBoundControlModel::modified: Where did this come from?" );
2521 if ( !m_bTransferringValue
&& ( m_xExternalBinding
== _rEvent
.Source
) && m_xExternalBinding
.is() )
2523 transferExternalValueToControl( aLock
);
2527 void OBoundControlModel::transferDbValueToControl( )
2531 setControlValue( translateDbColumnToControlValue(), eDbColumnBinding
);
2534 catch( const Exception
& )
2536 DBG_UNHANDLED_EXCEPTION("forms.component");
2540 void OBoundControlModel::transferExternalValueToControl( ControlModelLock
& _rInstanceLock
)
2542 Reference
< XValueBinding
> xExternalBinding( m_xExternalBinding
);
2543 Type
aValueExchangeType( getExternalValueType() );
2544 _rInstanceLock
.release();
2549 aExternalValue
= xExternalBinding
->getValue( aValueExchangeType
);
2552 catch( const Exception
& )
2554 DBG_UNHANDLED_EXCEPTION("forms.component");
2557 _rInstanceLock
.acquire();
2558 setControlValue( translateExternalValueToControlValue( aExternalValue
), eExternalBinding
);
2561 void OBoundControlModel::transferControlValueToExternal( ControlModelLock
& _rInstanceLock
)
2563 OSL_PRECOND( m_bSupportsExternalBinding
&& hasExternalValueBinding(),
2564 "OBoundControlModel::transferControlValueToExternal: precondition not met!" );
2565 if ( !m_xExternalBinding
.is() )
2568 Any
aExternalValue( translateControlValueToExternalValue() );
2569 m_bTransferringValue
= true;
2570 _rInstanceLock
.release();
2574 m_xExternalBinding
->setValue( aExternalValue
);
2577 catch( const Exception
& )
2579 DBG_UNHANDLED_EXCEPTION("forms.component");
2583 _rInstanceLock
.acquire();
2584 m_bTransferringValue
= false;
2587 Sequence
< Type
> OBoundControlModel::getSupportedBindingTypes()
2589 return Sequence
< Type
>( &m_aValuePropertyType
, 1 );
2592 void OBoundControlModel::calculateExternalValueType()
2594 m_aExternalValueType
= Type();
2595 if ( !m_xExternalBinding
.is() )
2597 const Sequence
< Type
> aTypeCandidates( getSupportedBindingTypes() );
2598 for ( auto const & typeCandidate
: aTypeCandidates
)
2600 if ( m_xExternalBinding
->supportsType( typeCandidate
) )
2602 m_aExternalValueType
= typeCandidate
;
2608 Any
OBoundControlModel::translateExternalValueToControlValue( const Any
& _rExternalValue
) const
2610 OSL_PRECOND( m_bSupportsExternalBinding
&& hasExternalValueBinding(),
2611 "OBoundControlModel::translateExternalValueToControlValue: precondition not met!" );
2612 Any
aControlValue( _rExternalValue
);
2613 // if the external value is VOID, and our value property is not allowed to be VOID,
2614 // then default-construct a value
2615 if ( !aControlValue
.hasValue() && !m_bValuePropertyMayBeVoid
)
2616 aControlValue
.setValue( nullptr, m_aValuePropertyType
);
2618 return aControlValue
;
2621 Any
OBoundControlModel::translateControlValueToExternalValue( ) const
2623 return getControlValue( );
2626 Any
OBoundControlModel::translateControlValueToValidatableValue( ) const
2628 OSL_PRECOND( m_xValidator
.is(), "OBoundControlModel::translateControlValueToValidatableValue: no validator, so why should I?" );
2629 if ( ( m_xValidator
== m_xExternalBinding
) && m_xValidator
.is() )
2630 return translateControlValueToExternalValue();
2631 return getControlValue();
2634 Any
OBoundControlModel::getControlValue( ) const
2636 OSL_PRECOND( m_xAggregateFastSet
.is() && m_xAggregateSet
.is(),
2637 "OBoundControlModel::getControlValue: invalid aggregate !" );
2638 OSL_PRECOND( !m_sValuePropertyName
.isEmpty() || ( m_nValuePropertyAggregateHandle
!= -1 ),
2639 "OBoundControlModel::getControlValue: please override if you have own value property handling!" );
2640 // determine the current control value
2642 if ( ( m_nValuePropertyAggregateHandle
!= -1 ) && m_xAggregateFastSet
.is() )
2644 aControlValue
= m_xAggregateFastSet
->getFastPropertyValue( m_nValuePropertyAggregateHandle
);
2647 else if ( !m_sValuePropertyName
.isEmpty() && m_xAggregateSet
.is() )
2649 aControlValue
= m_xAggregateSet
->getPropertyValue( m_sValuePropertyName
);
2651 return aControlValue
;
2654 void OBoundControlModel::connectValidator( const Reference
< XValidator
>& _rxValidator
)
2656 OSL_PRECOND( _rxValidator
.is(), "OBoundControlModel::connectValidator: invalid validator instance!" );
2657 OSL_PRECOND( !hasValidator( ), "OBoundControlModel::connectValidator: precond not met (have a validator currently)!" );
2658 m_xValidator
= _rxValidator
;
2660 // add as value listener so we get notified when the value changes
2661 if ( m_xValidator
.is() )
2665 m_xValidator
->addValidityConstraintListener( this );
2668 catch( const RuntimeException
& )
2672 onConnectedValidator( );
2675 void OBoundControlModel::disconnectValidator( )
2677 OSL_PRECOND( hasValidator( ), "OBoundControlModel::connectValidator: precond not met (don't have a validator currently)!" );
2679 // add as value listener so we get notified when the value changes
2680 if ( m_xValidator
.is() )
2684 m_xValidator
->removeValidityConstraintListener( this );
2687 catch( const RuntimeException
& )
2692 m_xValidator
.clear();
2694 onDisconnectedValidator( );
2697 void SAL_CALL
OBoundControlModel::setValidator( const Reference
< XValidator
>& _rxValidator
)
2699 osl::MutexGuard
aGuard( m_aMutex
);
2700 OSL_PRECOND( m_bSupportsValidation
, "OBoundControlModel::setValidator: How did you reach this method?" );
2701 // the interface for this method should not have been exposed if we do not
2702 // support validation
2704 // early out if the validator does not change
2705 if ( _rxValidator
== m_xValidator
)
2708 if ( m_xValidator
.is() && ( m_xValidator
== m_xExternalBinding
) )
2709 throw VetoException(
2710 ResourceManager::loadString(RID_STR_INVALID_VALIDATOR
),
2714 // disconnect from the old validator
2715 if ( hasValidator() )
2716 disconnectValidator( );
2718 // connect to the new validator
2719 if ( _rxValidator
.is() )
2720 connectValidator( _rxValidator
);
2723 Reference
< XValidator
> SAL_CALL
OBoundControlModel::getValidator( )
2725 ::osl::MutexGuard
aGuard( m_aMutex
);
2726 OSL_PRECOND( m_bSupportsValidation
, "OBoundControlModel::getValidator: How did you reach this method?" );
2727 // the interface for this method should not have been exposed if we do not
2728 // support validation
2730 return m_xValidator
;
2733 void SAL_CALL
OBoundControlModel::validityConstraintChanged( const EventObject
& /*Source*/ )
2735 osl::MutexGuard
aGuard( m_aMutex
);
2736 OSL_PRECOND( m_bSupportsValidation
, "OBoundControlModel::validityConstraintChanged: How did you reach this method?" );
2737 // the interface for this method should not have been exposed if we do not
2738 // support validation
2740 recheckValidity( false );
2743 sal_Bool SAL_CALL
OBoundControlModel::isValid( )
2745 return m_bIsCurrentValueValid
;
2748 css::uno::Any
OBoundControlModel::getCurrentFormComponentValue() const
2750 if ( hasValidator() )
2751 return translateControlValueToValidatableValue();
2752 return getControlValue();
2755 Any SAL_CALL
OBoundControlModel::getCurrentValue( )
2757 ::osl::MutexGuard
aGuard( m_aMutex
);
2758 return getCurrentFormComponentValue();
2761 void SAL_CALL
OBoundControlModel::addFormComponentValidityListener( const Reference
< validation::XFormComponentValidityListener
>& Listener
)
2763 if ( Listener
.is() )
2764 m_aFormComponentListeners
.addInterface( Listener
);
2767 void SAL_CALL
OBoundControlModel::removeFormComponentValidityListener( const Reference
< validation::XFormComponentValidityListener
>& Listener
)
2769 if ( Listener
.is() )
2770 m_aFormComponentListeners
.removeInterface( Listener
);
2773 void OBoundControlModel::recheckValidity( bool _bForceNotification
)
2777 bool bIsCurrentlyValid
= true;
2778 if ( hasValidator() )
2779 bIsCurrentlyValid
= m_xValidator
->isValid( translateControlValueToValidatableValue() );
2781 if ( ( bIsCurrentlyValid
!= m_bIsCurrentValueValid
) || _bForceNotification
)
2783 m_bIsCurrentValueValid
= bIsCurrentlyValid
;
2785 // release our mutex for the notifications
2786 MutexRelease
aRelease( m_aMutex
);
2787 m_aFormComponentListeners
.notifyEach( &validation::XFormComponentValidityListener::componentValidityChanged
, EventObject( *this ) );
2792 catch( const Exception
& )
2794 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::recheckValidity");
2798 void OBoundControlModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
2800 OControlModel::describeFixedProperties( _rProps
);
2801 sal_Int32 nOldCount
= _rProps
.getLength();
2802 _rProps
.realloc( nOldCount
+ 5);
2803 css::beans::Property
* pProperties
= _rProps
.getArray() + nOldCount
;
2804 *pProperties
++ = css::beans::Property(PROPERTY_CONTROLSOURCE
, PROPERTY_ID_CONTROLSOURCE
, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::BOUND
);
2805 *pProperties
++ = css::beans::Property(PROPERTY_BOUNDFIELD
, PROPERTY_ID_BOUNDFIELD
, cppu::UnoType
<XPropertySet
>::get(),
2806 css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::READONLY
| css::beans::PropertyAttribute::TRANSIENT
);
2807 *pProperties
++ = css::beans::Property(PROPERTY_CONTROLLABEL
, PROPERTY_ID_CONTROLLABEL
, cppu::UnoType
<XPropertySet
>::get(),
2808 css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::MAYBEVOID
);
2809 *pProperties
++ = css::beans::Property(PROPERTY_CONTROLSOURCEPROPERTY
, PROPERTY_ID_CONTROLSOURCEPROPERTY
, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::READONLY
| css::beans::PropertyAttribute::TRANSIENT
);
2810 *pProperties
++ = css::beans::Property(PROPERTY_INPUT_REQUIRED
, PROPERTY_ID_INPUT_REQUIRED
, cppu::UnoType
<bool>::get(),
2811 css::beans::PropertyAttribute::BOUND
);
2812 DBG_ASSERT( pProperties
== _rProps
.getArray() + _rProps
.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
2816 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */