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/form/FormComponentType.hpp>
29 #include <com/sun/star/form/XForm.hpp>
30 #include <com/sun/star/form/XLoadable.hpp>
31 #include <com/sun/star/form/binding/IncompatibleTypesException.hpp>
32 #include <com/sun/star/io/IOException.hpp>
33 #include <com/sun/star/io/XMarkableStream.hpp>
34 #include <com/sun/star/lang/DisposedException.hpp>
35 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
36 #include <com/sun/star/sdb/XRowSetChangeBroadcaster.hpp>
37 #include <com/sun/star/sdb/XRowSetSupplier.hpp>
38 #include <com/sun/star/sdbc/ColumnValue.hpp>
39 #include <com/sun/star/sdbc/DataType.hpp>
40 #include <com/sun/star/sdbc/SQLException.hpp>
41 #include <com/sun/star/util/VetoException.hpp>
42 #include <com/sun/star/util/XModifyBroadcaster.hpp>
44 #include <comphelper/basicio.hxx>
45 #include <comphelper/guarding.hxx>
46 #include <comphelper/interfacecontainer2.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 <tools/diagnose_ex.h>
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
, makeAny( m_xOldField
), makeAny( 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
, makeAny(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_bGenerateVbEvents( false )
500 ,m_nControlTypeinMSO(0) // 0 : default value is create from AOO
501 ,m_nObjIDinMSO(INVALID_OBJ_ID_IN_MSO
)
502 // form controls are usually embedded into documents, not dialogs, and in documents
503 // the native look is ugly...
506 if (_rUnoControlModelTypeName
.isEmpty()) // the is a model we have to aggregate
509 osl_atomic_increment(&m_refCount
);
511 m_xAggregate
.set(m_xContext
->getServiceManager()->createInstanceWithContext(_rUnoControlModelTypeName
, m_xContext
), UNO_QUERY
);
512 setAggregation(m_xAggregate
);
514 if ( m_xAggregateSet
.is() )
518 if ( !rDefault
.isEmpty() )
519 m_xAggregateSet
->setPropertyValue( PROPERTY_DEFAULTCONTROL
, makeAny( rDefault
) );
521 catch( const Exception
& )
523 TOOLS_WARN_EXCEPTION("forms.component", "OControlModel::OControlModel");
530 // Refcount is at NULL again
531 osl_atomic_decrement(&m_refCount
);
534 OControlModel::OControlModel( const OControlModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
, const bool _bCloneAggregate
, const bool _bSetDelegator
)
535 :OComponentHelper( m_aMutex
)
536 ,OPropertySetAggregationHelper( OComponentHelper::rBHelper
)
537 ,m_xContext( _rxFactory
)
539 ,m_aPropertyBagHelper( *this )
540 ,m_nTabIndex( FRM_DEFAULT_TABINDEX
)
541 ,m_nClassId( FormComponentType::CONTROL
)
543 DBG_ASSERT( _pOriginal
, "OControlModel::OControlModel: invalid original!" );
546 m_aName
= _pOriginal
->m_aName
;
547 m_aTag
= _pOriginal
->m_aTag
;
548 m_nTabIndex
= _pOriginal
->m_nTabIndex
;
549 m_nClassId
= _pOriginal
->m_nClassId
;
550 m_bNativeLook
= _pOriginal
->m_bNativeLook
;
551 m_bGenerateVbEvents
= _pOriginal
->m_bGenerateVbEvents
;
552 m_nControlTypeinMSO
= _pOriginal
->m_nControlTypeinMSO
;
553 m_nObjIDinMSO
= _pOriginal
->m_nObjIDinMSO
;
555 if ( !_bCloneAggregate
)
558 // temporarily increment refcount because of temporary references to ourself in the following
559 osl_atomic_increment( &m_refCount
);
561 // transfer the (only, at the very moment!) ref count
562 m_xAggregate
= createAggregateClone( _pOriginal
);
564 // set aggregation (retrieve other direct interfaces of the aggregate)
565 setAggregation( m_xAggregate
);
568 // set the delegator, if allowed by our derived class
569 if ( _bSetDelegator
)
572 // decrement ref count
573 osl_atomic_decrement( &m_refCount
);
576 OControlModel::~OControlModel()
578 // release the aggregate
582 void OControlModel::clonedFrom( const OControlModel
* /*_pOriginal*/ )
584 // nothing to do in this base class
587 void OControlModel::doResetDelegator()
589 if (m_xAggregate
.is())
590 m_xAggregate
->setDelegator(nullptr);
593 void OControlModel::doSetDelegator()
595 osl_atomic_increment(&m_refCount
);
596 if (m_xAggregate
.is())
598 m_xAggregate
->setDelegator(static_cast<XWeak
*>(this));
600 osl_atomic_decrement(&m_refCount
);
604 Reference
< XInterface
> SAL_CALL
OControlModel::getParent()
609 void SAL_CALL
OControlModel::setParent(const Reference
< XInterface
>& _rxParent
)
611 osl::MutexGuard
aGuard(m_aMutex
);
613 Reference
<XComponent
> xComp(m_xParent
, UNO_QUERY
);
615 xComp
->removeEventListener(static_cast<XPropertiesChangeListener
*>(this));
617 m_xParent
= _rxParent
;
618 xComp
.set(m_xParent
, css::uno::UNO_QUERY
);
621 xComp
->addEventListener(static_cast<XPropertiesChangeListener
*>(this));
625 OUString SAL_CALL
OControlModel::getName()
630 OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME
) >>= aReturn
;
632 catch (const css::beans::UnknownPropertyException
&)
634 css::uno::Any
a(cppu::getCaughtException());
635 throw WrappedTargetRuntimeException(
636 "OControlModel::getName",
644 void SAL_CALL
OControlModel::setName(const OUString
& _rName
)
648 setFastPropertyValue(PROPERTY_ID_NAME
, makeAny(_rName
));
650 catch (const css::beans::UnknownPropertyException
&)
652 css::uno::Any
a(cppu::getCaughtException());
653 throw WrappedTargetRuntimeException(
654 "OControlModel::setName",
662 sal_Bool SAL_CALL
OControlModel::supportsService(const OUString
& _rServiceName
)
664 return cppu::supportsService(this, _rServiceName
);
667 Sequence
< OUString
> OControlModel::getAggregateServiceNames() const
669 Sequence
< OUString
> aAggServices
;
670 Reference
< XServiceInfo
> xInfo
;
671 if ( query_aggregation( m_xAggregate
, xInfo
) )
672 aAggServices
= xInfo
->getSupportedServiceNames();
676 Sequence
<OUString
> SAL_CALL
OControlModel::getSupportedServiceNames()
678 return ::comphelper::concatSequences(
679 getAggregateServiceNames(),
680 getSupportedServiceNames_Static()
684 Sequence
< OUString
> OControlModel::getSupportedServiceNames_Static()
686 return { FRM_SUN_FORMCOMPONENT
, "com.sun.star.form.FormControlModel" };
690 void SAL_CALL
OControlModel::disposing(const css::lang::EventObject
& _rSource
)
692 // release the parent
693 if (_rSource
.Source
== m_xParent
)
695 osl::MutexGuard
aGuard(m_aMutex
);
700 Reference
<css::lang::XEventListener
> xEvtLst
;
701 if (query_aggregation(m_xAggregate
, xEvtLst
))
703 osl::MutexGuard
aGuard(m_aMutex
);
704 xEvtLst
->disposing(_rSource
);
710 void OControlModel::disposing()
712 OPropertySetAggregationHelper::disposing();
714 Reference
<css::lang::XComponent
> xComp
;
715 if (query_aggregation(m_xAggregate
, xComp
))
718 setParent(Reference
<XFormComponent
>());
720 m_aPropertyBagHelper
.dispose();
723 void OControlModel::writeAggregate( const Reference
< XObjectOutputStream
>& _rxOutStream
) const
725 Reference
< XPersistObject
> xPersist
;
726 if ( query_aggregation( m_xAggregate
, xPersist
) )
727 xPersist
->write( _rxOutStream
);
730 void OControlModel::readAggregate( const Reference
< XObjectInputStream
>& _rxInStream
)
732 Reference
< XPersistObject
> xPersist
;
733 if ( query_aggregation( m_xAggregate
, xPersist
) )
734 xPersist
->read( _rxInStream
);
737 void SAL_CALL
OControlModel::write(const Reference
<css::io::XObjectOutputStream
>& _rxOutStream
)
739 osl::MutexGuard
aGuard(m_aMutex
);
741 // 1. writing the UnoControls
742 Reference
<css::io::XMarkableStream
> xMark(_rxOutStream
, UNO_QUERY
);
746 FRM_RES_STRING( RID_STR_INVALIDSTREAM
),
747 static_cast< ::cppu::OWeakObject
* >( this )
751 sal_Int32 nMark
= xMark
->createMark();
754 _rxOutStream
->writeLong(nLen
);
756 writeAggregate( _rxOutStream
);
758 // determining the length
759 nLen
= xMark
->offsetToMark(nMark
) - 4;
760 xMark
->jumpToMark(nMark
);
761 _rxOutStream
->writeLong(nLen
);
762 xMark
->jumpToFurthest();
763 xMark
->deleteMark(nMark
);
765 // 2. writing a version number
766 _rxOutStream
->writeShort(0x0003);
768 // 3. writing the general properties
769 ::comphelper::operator<<( _rxOutStream
, m_aName
);
770 _rxOutStream
->writeShort(m_nTabIndex
);
771 ::comphelper::operator<<( _rxOutStream
, m_aTag
); // 3rd version
774 // don't write any new members here: this wouldn't be compatible with older versions, as OControlModel
775 // is a base class which is called in derived classes "read" method. So if you increment the version
776 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
777 // in anything from data loss to crash.
781 void OControlModel::read(const Reference
<css::io::XObjectInputStream
>& InStream
)
783 osl::MutexGuard
aGuard(m_aMutex
);
785 Reference
<css::io::XMarkableStream
> xMark(InStream
, UNO_QUERY
);
789 FRM_RES_STRING( RID_STR_INVALIDSTREAM
),
790 static_cast< ::cppu::OWeakObject
* >( this )
794 // 1. reading the UnoControls
795 sal_Int32 nLen
= InStream
->readLong();
798 sal_Int32 nMark
= xMark
->createMark();
802 readAggregate( InStream
);
805 catch( const Exception
& )
807 DBG_UNHANDLED_EXCEPTION("forms.component");
810 xMark
->jumpToMark(nMark
);
811 InStream
->skipBytes(nLen
);
812 xMark
->deleteMark(nMark
);
815 // 2. reading the version number
816 sal_uInt16 nVersion
= InStream
->readShort();
818 // 3. reading the general properties
819 ::comphelper::operator>>( InStream
, m_aName
);
820 m_nTabIndex
= InStream
->readShort();
822 if (nVersion
> 0x0002)
823 ::comphelper::operator>>( InStream
, m_aTag
);
825 // we had a version where we wrote the help text
826 if (nVersion
== 0x0004)
827 readHelpTextCompatibly(InStream
);
829 DBG_ASSERT(nVersion
< 5, "OControlModel::read : suspicious version number !");
830 // 4 was the version where we wrote the help text
831 // later versions shouldn't exist (see write for a detailed comment)
834 PropertyState
OControlModel::getPropertyStateByHandle( sal_Int32 _nHandle
)
836 // simply compare the current and the default value
837 Any aCurrentValue
= getPropertyDefaultByHandle( _nHandle
);
838 Any aDefaultValue
; getFastPropertyValue( aDefaultValue
, _nHandle
);
840 bool bEqual
= aCurrentValue
== aDefaultValue
;
841 return bEqual
? PropertyState_DEFAULT_VALUE
: PropertyState_DIRECT_VALUE
;
844 void OControlModel::setPropertyToDefaultByHandle( sal_Int32 _nHandle
)
846 Any aDefault
= getPropertyDefaultByHandle( _nHandle
);
848 Any aConvertedValue
, aOldValue
;
849 if ( convertFastPropertyValue( aConvertedValue
, aOldValue
, _nHandle
, aDefault
) )
851 setFastPropertyValue_NoBroadcast( _nHandle
, aConvertedValue
);
852 // TODO: fire the property change
856 Any
OControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle
) const
861 case PROPERTY_ID_NAME
:
862 case PROPERTY_ID_TAG
:
863 aReturn
<<= OUString();
865 case PROPERTY_ID_CLASSID
:
866 aReturn
<<= sal_Int16(FormComponentType::CONTROL
);
868 case PROPERTY_ID_TABINDEX
:
869 aReturn
<<= sal_Int16(FRM_DEFAULT_TABINDEX
);
871 case PROPERTY_ID_NATIVE_LOOK
:
874 case PROPERTY_ID_GENERATEVBAEVENTS
:
877 // added for exporting OCX control
878 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
879 aReturn
<<= sal_Int16(0);
881 case PROPERTY_ID_OBJ_ID_IN_MSO
:
882 aReturn
<<= sal_uInt16(INVALID_OBJ_ID_IN_MSO
);
885 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
886 m_aPropertyBagHelper
.getDynamicPropertyDefaultByHandle( _nHandle
, aReturn
);
888 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle
);
893 void OControlModel::getFastPropertyValue( Any
& _rValue
, sal_Int32 _nHandle
) const
897 case PROPERTY_ID_NAME
:
900 case PROPERTY_ID_TAG
:
903 case PROPERTY_ID_CLASSID
:
904 _rValue
<<= m_nClassId
;
906 case PROPERTY_ID_TABINDEX
:
907 _rValue
<<= m_nTabIndex
;
909 case PROPERTY_ID_NATIVE_LOOK
:
910 _rValue
<<= m_bNativeLook
;
912 case PROPERTY_ID_GENERATEVBAEVENTS
:
913 _rValue
<<= m_bGenerateVbEvents
;
915 // added for exporting OCX control
916 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
917 _rValue
<<= m_nControlTypeinMSO
;
919 case PROPERTY_ID_OBJ_ID_IN_MSO
:
920 _rValue
<<= m_nObjIDinMSO
;
923 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
924 m_aPropertyBagHelper
.getDynamicFastPropertyValue( _nHandle
, _rValue
);
926 OPropertySetAggregationHelper::getFastPropertyValue( _rValue
, _nHandle
);
931 sal_Bool
OControlModel::convertFastPropertyValue(
932 Any
& _rConvertedValue
, Any
& _rOldValue
, sal_Int32 _nHandle
, const Any
& _rValue
)
934 bool bModified(false);
937 case PROPERTY_ID_NAME
:
938 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aName
);
940 case PROPERTY_ID_TAG
:
941 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aTag
);
943 case PROPERTY_ID_TABINDEX
:
944 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_nTabIndex
);
946 case PROPERTY_ID_NATIVE_LOOK
:
947 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_bNativeLook
);
949 case PROPERTY_ID_GENERATEVBAEVENTS
:
950 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_bGenerateVbEvents
);
952 // added for exporting OCX control
953 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
954 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_nControlTypeinMSO
);
956 case PROPERTY_ID_OBJ_ID_IN_MSO
:
957 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_nObjIDinMSO
);
960 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
961 bModified
= m_aPropertyBagHelper
.convertDynamicFastPropertyValue( _nHandle
, _rValue
, _rConvertedValue
, _rOldValue
);
963 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle
);
969 void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle
, const Any
& _rValue
)
973 case PROPERTY_ID_NAME
:
974 DBG_ASSERT(_rValue
.getValueType() == cppu::UnoType
<OUString
>::get(),
975 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
978 case PROPERTY_ID_TAG
:
979 DBG_ASSERT(_rValue
.getValueType() == cppu::UnoType
<OUString
>::get(),
980 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
983 case PROPERTY_ID_TABINDEX
:
984 DBG_ASSERT(_rValue
.getValueType() == cppu::UnoType
<sal_Int16
>::get(),
985 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
986 _rValue
>>= m_nTabIndex
;
988 case PROPERTY_ID_NATIVE_LOOK
:
989 OSL_VERIFY( _rValue
>>= m_bNativeLook
);
991 case PROPERTY_ID_GENERATEVBAEVENTS
:
992 OSL_VERIFY( _rValue
>>= m_bGenerateVbEvents
);
994 // added for exporting OCX control
995 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
996 OSL_VERIFY( _rValue
>>= m_nControlTypeinMSO
);
998 case PROPERTY_ID_OBJ_ID_IN_MSO
:
999 OSL_VERIFY( _rValue
>>= m_nObjIDinMSO
);
1002 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
1003 m_aPropertyBagHelper
.setDynamicFastPropertyValue( _nHandle
, _rValue
);
1005 SAL_WARN("forms.component", "OControlModel::setFastPropertyValue_NoBroadcast: unknown handle " << _nHandle
);
1010 void OControlModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
1012 BEGIN_DESCRIBE_BASE_PROPERTIES( 7 )
1013 DECL_PROP2 (CLASSID
, sal_Int16
, READONLY
, TRANSIENT
);
1014 DECL_PROP1 (NAME
, OUString
, BOUND
);
1015 DECL_BOOL_PROP2 (NATIVE_LOOK
, BOUND
, TRANSIENT
);
1016 DECL_PROP1 (TAG
, OUString
, BOUND
);
1017 DECL_PROP1 (GENERATEVBAEVENTS
, sal_Bool
, TRANSIENT
);
1018 DECL_PROP1 (CONTROL_TYPE_IN_MSO
,sal_Int16
, BOUND
);
1019 DECL_PROP1 (OBJ_ID_IN_MSO
,cppu::UnoUnsignedShortType
, BOUND
);
1020 END_DESCRIBE_PROPERTIES()
1023 void OControlModel::describeAggregateProperties( Sequence
< Property
>& /* [out] */ _rAggregateProps
) const
1025 if ( m_xAggregateSet
.is() )
1027 Reference
< XPropertySetInfo
> xPSI( m_xAggregateSet
->getPropertySetInfo() );
1029 _rAggregateProps
= xPSI
->getProperties();
1033 ::osl::Mutex
& OControlModel::getMutex()
1038 void OControlModel::describeFixedAndAggregateProperties( Sequence
< Property
>& _out_rFixedProperties
, Sequence
< Property
>& _out_rAggregateProperties
) const
1040 describeFixedProperties( _out_rFixedProperties
);
1041 describeAggregateProperties( _out_rAggregateProperties
);
1044 Reference
< XMultiPropertySet
> OControlModel::getPropertiesInterface()
1046 return Reference
< XMultiPropertySet
>( *this, UNO_QUERY
);
1049 Reference
< XPropertySetInfo
> SAL_CALL
OControlModel::getPropertySetInfo()
1051 return createPropertySetInfo( getInfoHelper() );
1054 ::cppu::IPropertyArrayHelper
& OControlModel::getInfoHelper()
1056 return m_aPropertyBagHelper
.getInfoHelper();
1059 void SAL_CALL
OControlModel::addProperty( const OUString
& _rName
, ::sal_Int16 _nAttributes
, const Any
& _rInitialValue
)
1061 m_aPropertyBagHelper
.addProperty( _rName
, _nAttributes
, _rInitialValue
);
1064 void SAL_CALL
OControlModel::removeProperty( const OUString
& _rName
)
1066 m_aPropertyBagHelper
.removeProperty( _rName
);
1069 Sequence
< PropertyValue
> SAL_CALL
OControlModel::getPropertyValues()
1071 return m_aPropertyBagHelper
.getPropertyValues();
1074 void SAL_CALL
OControlModel::setPropertyValues( const Sequence
< PropertyValue
>& _rProps
)
1076 m_aPropertyBagHelper
.setPropertyValues( _rProps
);
1079 void OControlModel::lockInstance( LockAccess
)
1082 osl_atomic_increment( &m_lockCount
);
1085 oslInterlockedCount
OControlModel::unlockInstance( LockAccess
)
1087 OSL_ENSURE( m_lockCount
> 0, "OControlModel::unlockInstance: not locked!" );
1088 oslInterlockedCount lockCount
= osl_atomic_decrement( &m_lockCount
);
1093 void OControlModel::firePropertyChanges( const std::vector
< sal_Int32
>& _rHandles
, const std::vector
< Any
>& _rOldValues
,
1094 const std::vector
< Any
>& _rNewValues
, LockAccess
)
1096 OPropertySetHelper::fire(
1097 const_cast< std::vector
< sal_Int32
>& >( _rHandles
).data(),
1105 // OBoundControlModel
1106 Any SAL_CALL
OBoundControlModel::queryAggregation( const Type
& _rType
)
1108 Any
aReturn( OControlModel::queryAggregation(_rType
) );
1109 if (!aReturn
.hasValue())
1111 aReturn
= OBoundControlModel_BASE1::queryInterface(_rType
);
1113 if ( !aReturn
.hasValue() && m_bCommitable
)
1114 aReturn
= OBoundControlModel_COMMITTING::queryInterface( _rType
);
1116 if ( !aReturn
.hasValue() && m_bSupportsExternalBinding
)
1117 aReturn
= OBoundControlModel_BINDING::queryInterface( _rType
);
1119 if ( !aReturn
.hasValue() && m_bSupportsValidation
)
1120 aReturn
= OBoundControlModel_VALIDATION::queryInterface( _rType
);
1125 OBoundControlModel::OBoundControlModel(
1126 const Reference
< XComponentContext
>& _rxFactory
,
1127 const OUString
& _rUnoControlModelTypeName
, const OUString
& _rDefault
,
1128 const bool _bCommitable
, const bool _bSupportExternalBinding
, const bool _bSupportsValidation
)
1129 :OControlModel( _rxFactory
, _rUnoControlModelTypeName
, _rDefault
, false )
1130 ,OPropertyChangeListener( m_aMutex
)
1133 ,m_nValuePropertyAggregateHandle( -1 )
1134 ,m_nFieldType( DataType::OTHER
)
1135 ,m_bValuePropertyMayBeVoid( false )
1136 ,m_aResetHelper( *this, m_aMutex
)
1137 ,m_aUpdateListeners(m_aMutex
)
1138 ,m_aFormComponentListeners( m_aMutex
)
1139 ,m_bInputRequired( false )
1140 ,m_pAggPropMultiplexer( nullptr )
1141 ,m_bFormListening( false )
1144 ,m_bCommitable(_bCommitable
)
1145 ,m_bSupportsExternalBinding( _bSupportExternalBinding
)
1146 ,m_bSupportsValidation( _bSupportsValidation
)
1147 ,m_bForwardValueChanges(true)
1148 ,m_bTransferringValue( false )
1149 ,m_bIsCurrentValueValid( true )
1150 ,m_bBindingControlsRO( false )
1151 ,m_bBindingControlsEnable( false )
1152 ,m_eControlValueChangeInstigator( eOther
)
1153 ,m_aLabelServiceName(FRM_SUN_COMPONENT_FIXEDTEXT
)
1155 // start property listening at the aggregate
1156 implInitAggMultiplexer( );
1159 OBoundControlModel::OBoundControlModel(
1160 const OBoundControlModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
)
1161 :OControlModel( _pOriginal
, _rxFactory
, true, false )
1162 ,OPropertyChangeListener( m_aMutex
)
1165 ,m_nValuePropertyAggregateHandle( _pOriginal
->m_nValuePropertyAggregateHandle
)
1166 ,m_nFieldType( DataType::OTHER
)
1167 ,m_bValuePropertyMayBeVoid( _pOriginal
->m_bValuePropertyMayBeVoid
)
1168 ,m_aResetHelper( *this, m_aMutex
)
1169 ,m_aUpdateListeners( m_aMutex
)
1170 ,m_aFormComponentListeners( m_aMutex
)
1171 ,m_xValidator( _pOriginal
->m_xValidator
)
1172 ,m_bInputRequired( false )
1173 ,m_pAggPropMultiplexer( nullptr )
1174 ,m_bFormListening( false )
1176 ,m_bRequired( false )
1177 ,m_bCommitable( _pOriginal
->m_bCommitable
)
1178 ,m_bSupportsExternalBinding( _pOriginal
->m_bSupportsExternalBinding
)
1179 ,m_bSupportsValidation( _pOriginal
->m_bSupportsValidation
)
1180 ,m_bForwardValueChanges( true )
1181 ,m_bTransferringValue( false )
1182 ,m_bIsCurrentValueValid( _pOriginal
->m_bIsCurrentValueValid
)
1183 ,m_bBindingControlsRO( false )
1184 ,m_bBindingControlsEnable( false )
1185 ,m_eControlValueChangeInstigator( eOther
)
1187 // start property listening at the aggregate
1188 implInitAggMultiplexer( );
1189 m_aLabelServiceName
= _pOriginal
->m_aLabelServiceName
;
1190 m_sValuePropertyName
= _pOriginal
->m_sValuePropertyName
;
1191 m_nValuePropertyAggregateHandle
= _pOriginal
->m_nValuePropertyAggregateHandle
;
1192 m_bValuePropertyMayBeVoid
= _pOriginal
->m_bValuePropertyMayBeVoid
;
1193 m_aValuePropertyType
= _pOriginal
->m_aValuePropertyType
;
1194 m_aControlSource
= _pOriginal
->m_aControlSource
;
1195 m_bInputRequired
= _pOriginal
->m_bInputRequired
;
1196 // m_xLabelControl, though being a property, is not to be cloned, not even the reference will be transferred.
1197 // (the former should be clear - a clone of the object we're only referencing does not make sense)
1198 // (the second would violate the restriction for label controls that they're part of the
1199 // same form component hierarchy - we ourself are no part, yet, so we can't have a label control)
1200 // start listening for changes at the value property
1201 implInitValuePropertyListening( );
1204 OBoundControlModel::~OBoundControlModel()
1206 if ( !OComponentHelper::rBHelper
.bDisposed
)
1212 doResetDelegator( );
1213 OSL_ENSURE( m_pAggPropMultiplexer
, "OBoundControlModel::~OBoundControlModel: what about my property multiplexer?" );
1214 if ( m_pAggPropMultiplexer
)
1216 m_pAggPropMultiplexer
->dispose();
1217 m_pAggPropMultiplexer
->release();
1218 m_pAggPropMultiplexer
= nullptr;
1222 void OBoundControlModel::clonedFrom( const OControlModel
* _pOriginal
)
1224 const OBoundControlModel
* pBoundOriginal
= static_cast< const OBoundControlModel
* >( _pOriginal
);
1225 // the value binding can be handled as if somebody called setValueBinding here
1226 // By definition, bindings can be share between bindables
1227 if ( !(pBoundOriginal
&& pBoundOriginal
->m_xExternalBinding
.is()) )
1232 setValueBinding( pBoundOriginal
->m_xExternalBinding
);
1235 catch( const Exception
& )
1237 DBG_UNHANDLED_EXCEPTION("forms.component");
1241 void OBoundControlModel::implInitAggMultiplexer( )
1243 osl_atomic_increment( &m_refCount
);
1244 if ( m_xAggregateSet
.is() )
1246 m_pAggPropMultiplexer
= new OPropertyChangeMultiplexer( this, m_xAggregateSet
, false );
1247 m_pAggPropMultiplexer
->acquire();
1250 osl_atomic_decrement( &m_refCount
);
1254 void OBoundControlModel::implInitValuePropertyListening( ) const
1256 // start listening for changes at the value property
1257 // There are three pre-requisites for this to be done:
1258 // 1. We support external value bindings. In this case, the changes in the control value need to
1259 // be propagated to the external binding immediately when they happen
1260 // 2. We support external validation. In this case, we need to listen for changes in the value
1261 // property, since we need to revalidate then.
1262 // 3. We are not committable. In this case, changes in the control value need to be propagated
1263 // to the database column immediately when they happen.
1264 if ( m_bSupportsExternalBinding
|| m_bSupportsValidation
|| !m_bCommitable
)
1266 OSL_ENSURE( m_pAggPropMultiplexer
, "OBoundControlModel::implInitValuePropertyListening: no multiplexer!" );
1267 if ( m_pAggPropMultiplexer
&& !m_sValuePropertyName
.isEmpty() )
1268 m_pAggPropMultiplexer
->addProperty( m_sValuePropertyName
);
1272 void OBoundControlModel::initOwnValueProperty( const OUString
& i_rValuePropertyName
)
1274 OSL_PRECOND( m_sValuePropertyName
.isEmpty() && -1 == m_nValuePropertyAggregateHandle
,
1275 "OBoundControlModel::initOwnValueProperty: value property is already initialized!" );
1276 OSL_ENSURE( !i_rValuePropertyName
.isEmpty(), "OBoundControlModel::initOwnValueProperty: invalid property name!" );
1277 m_sValuePropertyName
= i_rValuePropertyName
;
1280 void OBoundControlModel::initValueProperty( const OUString
& _rValuePropertyName
, sal_Int32 _nValuePropertyExternalHandle
)
1282 OSL_PRECOND( m_sValuePropertyName
.isEmpty() && -1 == m_nValuePropertyAggregateHandle
,
1283 "OBoundControlModel::initValueProperty: value property is already initialized!" );
1284 OSL_ENSURE( !_rValuePropertyName
.isEmpty(), "OBoundControlModel::initValueProperty: invalid property name!" );
1285 OSL_ENSURE( _nValuePropertyExternalHandle
!= -1, "OBoundControlModel::initValueProperty: invalid property handle!" );
1287 m_sValuePropertyName
= _rValuePropertyName
;
1288 m_nValuePropertyAggregateHandle
= getOriginalHandle( _nValuePropertyExternalHandle
);
1289 OSL_ENSURE( m_nValuePropertyAggregateHandle
!= -1, "OBoundControlModel::initValueProperty: unable to find the original handle!" );
1291 if ( m_nValuePropertyAggregateHandle
!= -1 )
1293 Reference
< XPropertySetInfo
> xPropInfo( m_xAggregateSet
->getPropertySetInfo(), UNO_SET_THROW
);
1294 Property aValuePropDesc
= xPropInfo
->getPropertyByName( m_sValuePropertyName
);
1295 m_aValuePropertyType
= aValuePropDesc
.Type
;
1296 m_bValuePropertyMayBeVoid
= ( aValuePropDesc
.Attributes
& PropertyAttribute::MAYBEVOID
) != 0;
1299 // start listening for changes at the value property
1300 implInitValuePropertyListening( );
1303 void OBoundControlModel::suspendValueListening( )
1305 OSL_PRECOND( !m_sValuePropertyName
.isEmpty(), "OBoundControlModel::suspendValueListening: don't have a value property!" );
1306 OSL_PRECOND( m_pAggPropMultiplexer
, "OBoundControlModel::suspendValueListening: I *am* not listening!" );
1308 if ( m_pAggPropMultiplexer
)
1309 m_pAggPropMultiplexer
->lock();
1312 void OBoundControlModel::resumeValueListening( )
1314 OSL_PRECOND( !m_sValuePropertyName
.isEmpty(), "OBoundControlModel::resumeValueListening: don't have a value property!" );
1315 OSL_PRECOND( m_pAggPropMultiplexer
, "OBoundControlModel::resumeValueListening: I *am* not listening at all!" );
1316 OSL_PRECOND( !m_pAggPropMultiplexer
|| m_pAggPropMultiplexer
->locked(), "OBoundControlModel::resumeValueListening: listening not suspended currently!" );
1317 if ( m_pAggPropMultiplexer
)
1318 m_pAggPropMultiplexer
->unlock();
1321 Sequence
< Type
> OBoundControlModel::_getTypes()
1324 OControlModel::_getTypes(),
1325 OBoundControlModel_BASE1::getTypes()
1328 if ( m_bCommitable
)
1329 aTypes
.addTypes( OBoundControlModel_COMMITTING::getTypes() );
1331 if ( m_bSupportsExternalBinding
)
1332 aTypes
.addTypes( OBoundControlModel_BINDING::getTypes() );
1334 if ( m_bSupportsValidation
)
1335 aTypes
.addTypes( OBoundControlModel_VALIDATION::getTypes() );
1336 return aTypes
.getTypes();
1340 void OBoundControlModel::disposing()
1342 OControlModel::disposing();
1344 osl::MutexGuard
aGuard(m_aMutex
);
1346 if ( m_pAggPropMultiplexer
)
1347 m_pAggPropMultiplexer
->dispose();
1349 // notify all our listeners
1350 css::lang::EventObject
aEvt( static_cast< XWeak
* >( this ) );
1351 m_aUpdateListeners
.disposeAndClear( aEvt
);
1352 m_aResetHelper
.disposing();
1354 // disconnect from our database column
1355 // TODO: could we replace the following 5 lines with a call to impl_disconnectDatabaseColumn_noNotify?
1356 // The only more thing which it does is calling onDisconnectedDbColumn - could this
1357 // cause trouble? At least when we continue to call OControlModel::disposing before, it *may*.
1360 getField()->removePropertyChangeListener( PROPERTY_VALUE
, this );
1364 m_xCursor
= nullptr;
1365 Reference
< XComponent
> xComp( m_xLabelControl
, UNO_QUERY
);
1367 xComp
->removeEventListener(static_cast< XEventListener
* >( static_cast< XPropertyChangeListener
* >( this ) ) );
1368 // disconnect from our external value binding
1369 if ( hasExternalValueBinding() )
1370 disconnectExternalValueBinding();
1371 // ditto for the validator
1372 if ( hasValidator() )
1373 disconnectValidator( );
1376 void OBoundControlModel::onValuePropertyChange( ControlModelLock
& i_rControLock
)
1378 if ( hasExternalValueBinding() )
1380 // the control value changed, while we have an external value binding
1381 // -> forward the value to it
1382 if ( m_eControlValueChangeInstigator
!= eExternalBinding
)
1383 transferControlValueToExternal( i_rControLock
);
1386 else if ( !m_bCommitable
&& m_xColumnUpdate
.is() )
1388 // the control value changed, while we are bound to a database column,
1389 // but not committable (which means changes in the control have to be reflected to
1390 // the underlying database column immediately)
1391 // -> forward the value to the database column
1392 if ( m_eControlValueChangeInstigator
!= eDbColumnBinding
)
1393 commitControlValueToDbColumn( false );
1396 // validate the new value
1397 if ( m_bSupportsValidation
)
1398 recheckValidity( true );
1401 void OBoundControlModel::_propertyChanged( const PropertyChangeEvent
& _rEvt
)
1403 ControlModelLock
aLock( *this );
1404 OSL_ENSURE( _rEvt
.PropertyName
== m_sValuePropertyName
,
1405 "OBoundControlModel::_propertyChanged: where did this come from (1)?" );
1406 OSL_ENSURE( m_pAggPropMultiplexer
&& !m_pAggPropMultiplexer
->locked(),
1407 "OBoundControlModel::_propertyChanged: where did this come from (2)?" );
1408 if ( _rEvt
.PropertyName
== m_sValuePropertyName
)
1410 onValuePropertyChange( aLock
);
1414 void OBoundControlModel::startAggregatePropertyListening( const OUString
& _rPropertyName
)
1416 OSL_PRECOND( m_pAggPropMultiplexer
, "OBoundControlModel::startAggregatePropertyListening: no multiplexer!" );
1417 OSL_ENSURE( !_rPropertyName
.isEmpty(), "OBoundControlModel::startAggregatePropertyListening: invalid property name!" );
1418 if ( m_pAggPropMultiplexer
&& !_rPropertyName
.isEmpty() )
1420 m_pAggPropMultiplexer
->addProperty( _rPropertyName
);
1424 void OBoundControlModel::doFormListening( const bool _bStart
)
1426 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::doFormListening: external value binding should overrule the database binding!" );
1427 if ( isFormListening() == _bStart
)
1429 if ( m_xAmbientForm
.is() )
1430 _bStart
? m_xAmbientForm
->addLoadListener( this ) : m_xAmbientForm
->removeLoadListener( this );
1431 Reference
< XLoadable
> xParentLoadable( getParent(), UNO_QUERY
);
1432 if ( getParent().is() && !xParentLoadable
.is() )
1434 // if our parent does not directly support the XLoadable interface, then it might support the
1435 // XRowSetSupplier/XRowSetChangeBroadcaster interfaces. In this case we have to listen for changes
1436 // broadcasted by the latter.
1437 Reference
< XRowSetChangeBroadcaster
> xRowSetBroadcaster( getParent(), UNO_QUERY
);
1438 if ( xRowSetBroadcaster
.is() )
1439 _bStart
? xRowSetBroadcaster
->addRowSetChangeListener( this ) : xRowSetBroadcaster
->removeRowSetChangeListener( this );
1442 m_bFormListening
= _bStart
&& m_xAmbientForm
.is();
1446 void SAL_CALL
OBoundControlModel::setParent(const Reference
<XInterface
>& _rxParent
)
1448 ControlModelLock
aLock( *this );
1449 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
1450 if ( getParent() == _rxParent
)
1452 // disconnect from database column (which is controlled by parent, directly or indirectly)
1454 impl_disconnectDatabaseColumn_noNotify();
1455 // log off old listeners
1456 if ( isFormListening() )
1457 doFormListening( false );
1458 // actually set the new parent
1459 OControlModel::setParent( _rxParent
);
1460 // a new parent means a new ambient form
1461 impl_determineAmbientForm_nothrow();
1462 if ( !hasExternalValueBinding() )
1464 // log on new listeners
1465 doFormListening( true );
1466 // re-connect to database column of the new parent
1467 if ( m_xAmbientForm
.is() && m_xAmbientForm
->isLoaded() )
1468 impl_connectDatabaseColumn_noNotify( false );
1473 void SAL_CALL
OBoundControlModel::disposing(const css::lang::EventObject
& _rEvent
)
1475 ControlModelLock
aLock( *this );
1476 if ( _rEvent
.Source
== getField() )
1481 else if ( _rEvent
.Source
== m_xLabelControl
)
1483 Reference
<XPropertySet
> xOldValue
= m_xLabelControl
;
1484 m_xLabelControl
= nullptr;
1485 // fire a propertyChanged (when we leave aLock's scope)
1486 aLock
.addPropertyNotification( PROPERTY_ID_CONTROLLABEL
, makeAny( xOldValue
), makeAny( m_xLabelControl
) );
1489 else if ( _rEvent
.Source
== m_xExternalBinding
)
1490 { // *first* check for the external binding
1491 disconnectExternalValueBinding( );
1494 else if ( _rEvent
.Source
== m_xValidator
)
1495 { // *then* check for the validator. Reason is that bindings may also act as validator at the same
1496 // time, in this case, the validator is automatically revoked when the binding is revoked
1497 disconnectValidator( );
1501 OControlModel::disposing(_rEvent
);
1505 css::uno::Sequence
<OUString
> SAL_CALL
OBoundControlModel::getSupportedServiceNames()
1507 return ::comphelper::combineSequences(
1508 getAggregateServiceNames(),
1509 getSupportedServiceNames_Static()
1513 Sequence
< OUString
> OBoundControlModel::getSupportedServiceNames_Static()
1515 Sequence
<OUString
> aOwnServiceNames
{ "com.sun.star.form.DataAwareControlModel" };
1516 return ::comphelper::concatSequences(
1517 OControlModel::getSupportedServiceNames_Static(),
1523 void SAL_CALL
OBoundControlModel::write( const Reference
<css::io::XObjectOutputStream
>& _rxOutStream
)
1525 OControlModel::write(_rxOutStream
);
1526 osl::MutexGuard
aGuard(m_aMutex
);
1528 _rxOutStream
->writeShort(0x0002);
1530 ::comphelper::operator<<( _rxOutStream
, m_aControlSource
);
1531 // !!! IMPORTANT NOTE !!!
1532 // don't write any new members here: this wouldn't be compatible with older versions, as OBoundControlModel
1533 // is a base class which is called in derived classes "read" method. So if you increment the version
1534 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
1535 // in anything from data loss to crash.
1536 // (use writeCommonProperties instead, this is called in derived classes write-method)
1540 void OBoundControlModel::defaultCommonProperties()
1542 Reference
<css::lang::XComponent
> xComp(m_xLabelControl
, UNO_QUERY
);
1544 xComp
->removeEventListener(static_cast<css::lang::XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
1545 m_xLabelControl
= nullptr;
1548 void OBoundControlModel::readCommonProperties(const Reference
<css::io::XObjectInputStream
>& _rxInStream
)
1550 sal_Int32 nLen
= _rxInStream
->readLong();
1551 Reference
<css::io::XMarkableStream
> xMark(_rxInStream
, UNO_QUERY
);
1552 DBG_ASSERT(xMark
.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !");
1553 sal_Int32 nMark
= xMark
->createMark();
1554 // read the reference to the label control
1555 Reference
<css::io::XPersistObject
> xPersist
;
1556 sal_Int32 nUsedFlag
;
1557 nUsedFlag
= _rxInStream
->readLong();
1559 xPersist
= _rxInStream
->readObject();
1560 m_xLabelControl
.set(xPersist
, css::uno::UNO_QUERY
);
1561 Reference
< XComponent
> xComp( m_xLabelControl
, UNO_QUERY
);
1563 xComp
->addEventListener(static_cast<css::lang::XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
1564 // read any other new common properties here
1565 // skip the remaining bytes
1566 xMark
->jumpToMark(nMark
);
1567 _rxInStream
->skipBytes(nLen
);
1568 xMark
->deleteMark(nMark
);
1571 void OBoundControlModel::writeCommonProperties(const Reference
<css::io::XObjectOutputStream
>& _rxOutStream
)
1573 Reference
<css::io::XMarkableStream
> xMark(_rxOutStream
, UNO_QUERY
);
1574 DBG_ASSERT(xMark
.is(), "OBoundControlModel::writeCommonProperties : can only work with markable streams !");
1575 sal_Int32 nMark
= xMark
->createMark();
1576 // a placeholder where we will write the overall length (later in this method)
1578 _rxOutStream
->writeLong(nLen
);
1579 // write the reference to the label control
1580 Reference
<css::io::XPersistObject
> xPersist(m_xLabelControl
, UNO_QUERY
);
1581 sal_Int32 nUsedFlag
= 0;
1584 _rxOutStream
->writeLong(nUsedFlag
);
1586 _rxOutStream
->writeObject(xPersist
);
1587 // write any other new common properties here
1588 // write the correct length at the beginning of the block
1589 nLen
= xMark
->offsetToMark(nMark
) - sizeof(nLen
);
1590 xMark
->jumpToMark(nMark
);
1591 _rxOutStream
->writeLong(nLen
);
1592 xMark
->jumpToFurthest();
1593 xMark
->deleteMark(nMark
);
1596 void SAL_CALL
OBoundControlModel::read( const Reference
< css::io::XObjectInputStream
>& _rxInStream
)
1598 OControlModel::read(_rxInStream
);
1599 osl::MutexGuard
aGuard(m_aMutex
);
1600 _rxInStream
->readShort(); // version;
1601 ::comphelper::operator>>( _rxInStream
, m_aControlSource
);
1604 void OBoundControlModel::getFastPropertyValue(Any
& rValue
, sal_Int32 nHandle
) const
1608 case PROPERTY_ID_INPUT_REQUIRED
:
1609 rValue
<<= m_bInputRequired
;
1611 case PROPERTY_ID_CONTROLSOURCEPROPERTY
:
1612 rValue
<<= m_sValuePropertyName
;
1614 case PROPERTY_ID_CONTROLSOURCE
:
1615 rValue
<<= m_aControlSource
;
1617 case PROPERTY_ID_BOUNDFIELD
:
1618 rValue
<<= getField();
1620 case PROPERTY_ID_CONTROLLABEL
:
1621 if (!m_xLabelControl
.is())
1624 rValue
<<= m_xLabelControl
;
1627 OControlModel::getFastPropertyValue(rValue
, nHandle
);
1631 sal_Bool
OBoundControlModel::convertFastPropertyValue(
1632 Any
& _rConvertedValue
, Any
& _rOldValue
,
1636 bool bModified(false);
1639 case PROPERTY_ID_INPUT_REQUIRED
:
1640 bModified
= tryPropertyValue( _rConvertedValue
, _rOldValue
, _rValue
, m_bInputRequired
);
1642 case PROPERTY_ID_CONTROLSOURCE
:
1643 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aControlSource
);
1645 case PROPERTY_ID_BOUNDFIELD
:
1646 SAL_WARN("forms.component", "OBoundControlModel::convertFastPropertyValue: BoundField should be a read-only property !" );
1647 throw css::lang::IllegalArgumentException();
1648 case PROPERTY_ID_CONTROLLABEL
:
1649 if (!_rValue
.hasValue())
1650 { // property set to void
1651 _rConvertedValue
= Any();
1652 getFastPropertyValue(_rOldValue
, _nHandle
);
1653 bModified
= m_xLabelControl
.is();
1658 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_xLabelControl
);
1659 if (!m_xLabelControl
.is())
1660 // an empty interface is interpreted as VOID
1666 bModified
= OControlModel::convertFastPropertyValue(_rConvertedValue
, _rOldValue
, _nHandle
, _rValue
);
1671 Any
OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle
) const
1676 case PROPERTY_ID_INPUT_REQUIRED
:
1679 case PROPERTY_ID_CONTROLSOURCE
:
1680 aDefault
<<= OUString();
1682 case PROPERTY_ID_CONTROLLABEL
:
1683 aDefault
<<= Reference
< XPropertySet
>();
1689 void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle
, const Any
& rValue
)
1693 case PROPERTY_ID_INPUT_REQUIRED
:
1694 OSL_VERIFY( rValue
>>= m_bInputRequired
);
1696 case PROPERTY_ID_CONTROLSOURCE
:
1697 OSL_VERIFY( rValue
>>= m_aControlSource
);
1699 case PROPERTY_ID_BOUNDFIELD
:
1700 SAL_WARN("forms.component", "OBoundControlModel::setFastPropertyValue_NoBroadcast : BoundField should be a read-only property !");
1701 throw css::lang::IllegalArgumentException();
1702 case PROPERTY_ID_CONTROLLABEL
:
1704 if ( rValue
.hasValue() && ( rValue
.getValueTypeClass() != TypeClass_INTERFACE
) )
1705 throw css::lang::IllegalArgumentException();
1706 Reference
< XInterface
> xNewValue( rValue
, UNO_QUERY
);
1707 if ( !xNewValue
.is() )
1708 { // set property to "void"
1709 Reference
< XComponent
> xComp( m_xLabelControl
, UNO_QUERY
);
1711 xComp
->removeEventListener( static_cast< XPropertyChangeListener
* >( this ) );
1712 m_xLabelControl
= nullptr;
1716 Reference
< XControlModel
> xAsModel ( xNewValue
, UNO_QUERY
);
1717 Reference
< XServiceInfo
> xAsServiceInfo ( xAsModel
, UNO_QUERY
);
1718 Reference
< XPropertySet
> xAsPropSet ( xAsServiceInfo
, UNO_QUERY
);
1719 Reference
< XChild
> xAsChild ( xAsPropSet
, UNO_QUERY
);
1720 if ( !xAsChild
.is() || !xAsServiceInfo
->supportsService( m_aLabelServiceName
) )
1722 throw css::lang::IllegalArgumentException();
1725 // Check if we and the given model have a common ancestor (up to the forms collection)
1726 Reference
<XChild
> xCont(
1727 static_cast<XWeak
*>(this), css::uno::UNO_QUERY
);
1728 Reference
< XInterface
> xMyTopLevel
= xCont
->getParent();
1729 while (xMyTopLevel
.is())
1731 Reference
<XForm
> xAsForm(xMyTopLevel
, UNO_QUERY
);
1735 Reference
<XChild
> xLoopAsChild(xMyTopLevel
, UNO_QUERY
);
1736 xMyTopLevel
= xLoopAsChild
.is() ? xLoopAsChild
->getParent() : Reference
< XInterface
>();
1739 Reference
< XInterface
> xNewTopLevel
= xAsChild
->getParent();
1740 while (xNewTopLevel
.is())
1742 Reference
<XForm
> xAsForm(xNewTopLevel
, UNO_QUERY
);
1745 Reference
<XChild
> xLoopAsChild(xNewTopLevel
, UNO_QUERY
);
1746 xNewTopLevel
= xLoopAsChild
.is() ? xLoopAsChild
->getParent() : Reference
< XInterface
>();
1749 if (xNewTopLevel
!= xMyTopLevel
)
1751 // the both objects don't belong to the same forms collection -> not acceptable
1752 throw css::lang::IllegalArgumentException();
1755 m_xLabelControl
= xAsPropSet
;
1756 Reference
<css::lang::XComponent
> xComp(m_xLabelControl
, UNO_QUERY
);
1758 xComp
->addEventListener(static_cast<css::lang::XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
1763 OControlModel::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
1767 // XPropertyChangeListener
1768 void SAL_CALL
OBoundControlModel::propertyChange( const PropertyChangeEvent
& evt
)
1770 // if the DBColumn value changed, transfer it to the control
1771 if ( evt
.PropertyName
== PROPERTY_VALUE
)
1773 OSL_ENSURE( evt
.Source
== getField(), "OBoundControlModel::propertyChange: value changes from components other than our database column?" );
1774 osl::MutexGuard
aGuard(m_aMutex
);
1775 if ( m_bForwardValueChanges
&& m_xColumn
.is() )
1776 transferDbValueToControl();
1781 OSL_ENSURE( evt
.Source
== m_xExternalBinding
, "OBoundControlModel::propertyChange: where did this come from?" );
1782 // our binding has properties which can control properties of ourself
1783 OUString sBindingControlledProperty
;
1784 bool bForwardToLabelControl
= false;
1785 if ( evt
.PropertyName
== PROPERTY_READONLY
)
1787 sBindingControlledProperty
= PROPERTY_READONLY
;
1790 else if ( evt
.PropertyName
== PROPERTY_RELEVANT
)
1792 sBindingControlledProperty
= PROPERTY_ENABLED
;
1793 bForwardToLabelControl
= true;
1800 setPropertyValue( sBindingControlledProperty
, evt
.NewValue
);
1801 if ( bForwardToLabelControl
&& m_xLabelControl
.is() )
1802 m_xLabelControl
->setPropertyValue( sBindingControlledProperty
, evt
.NewValue
);
1805 catch( const Exception
& )
1807 DBG_UNHANDLED_EXCEPTION("forms.component");
1808 SAL_WARN("forms.component", "OBoundControlModel::propertyChange: could not adjust my binding-controlled property!");
1814 void SAL_CALL
OBoundControlModel::onRowSetChanged( const EventObject
& /*i_Event*/ )
1816 ControlModelLock
aLock( *this );
1817 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
1818 // disconnect from database column (which is controlled by parent, directly or indirectly)
1820 impl_disconnectDatabaseColumn_noNotify();
1821 // log off old listeners
1822 if ( isFormListening() )
1823 doFormListening( false );
1824 // determine the new ambient form
1825 impl_determineAmbientForm_nothrow();
1826 // log on new listeners
1827 doFormListening( true );
1828 // re-connect to database column if needed and possible
1829 if ( m_xAmbientForm
.is() && m_xAmbientForm
->isLoaded() )
1830 impl_connectDatabaseColumn_noNotify( false );
1834 void SAL_CALL
OBoundControlModel::addUpdateListener(const Reference
<XUpdateListener
>& _rxListener
)
1836 m_aUpdateListeners
.addInterface(_rxListener
);
1839 void SAL_CALL
OBoundControlModel::removeUpdateListener(const Reference
< XUpdateListener
>& _rxListener
)
1841 m_aUpdateListeners
.removeInterface(_rxListener
);
1844 sal_Bool SAL_CALL
OBoundControlModel::commit()
1846 ControlModelLock
aLock( *this );
1847 OSL_PRECOND( m_bCommitable
, "OBoundControlModel::commit: invalid call (I'm not committable!) " );
1848 if ( hasExternalValueBinding() )
1850 // in most cases, no action is required: For most derivees, we know the value property of
1851 // our control (see initValueProperty), and when an external binding is active, we
1852 // instantly forward all changes in this property to the external binding.
1853 if ( m_sValuePropertyName
.isEmpty() )
1854 // but for those derivees which did not use this feature, we need an
1855 // explicit transfer
1856 transferControlValueToExternal( aLock
);
1860 OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" );
1861 // we reach this only if we're not working with an external binding
1864 ::comphelper::OInterfaceIteratorHelper2
aIter( m_aUpdateListeners
);
1866 aEvent
.Source
= static_cast< XWeak
* >( this );
1867 bool bSuccess
= true;
1870 while (aIter
.hasMoreElements() && bSuccess
)
1871 bSuccess
= static_cast< XUpdateListener
* >( aIter
.next() )->approveUpdate( aEvent
);
1878 if ( m_xColumnUpdate
.is() )
1879 bSuccess
= commitControlValueToDbColumn( false );
1882 catch(const Exception
&)
1892 m_aUpdateListeners
.notifyEach( &XUpdateListener::updated
, aEvent
);
1897 void OBoundControlModel::resetField()
1899 m_xColumnUpdate
.clear();
1902 m_nFieldType
= DataType::OTHER
;
1905 void OBoundControlModel::connectToField(const Reference
<XRowSet
>& rForm
)
1907 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::connectToField: invalid call (have an external binding)!" );
1908 // if there's a connection to the database
1909 if (!(rForm
.is() && getConnection(rForm
).is()))
1912 // determine field and PropertyChangeListener
1914 Reference
<XPropertySet
> xFieldCandidate
;
1917 Reference
<XColumnsSupplier
> xColumnsSupplier(m_xCursor
, UNO_QUERY
);
1918 DBG_ASSERT(xColumnsSupplier
.is(), "OBoundControlModel::connectToField : the row set should support the css::sdb::ResultSet service !");
1919 if (xColumnsSupplier
.is())
1921 Reference
<XNameAccess
> xColumns
= xColumnsSupplier
->getColumns();
1922 if (xColumns
.is() && xColumns
->hasByName(m_aControlSource
))
1924 OSL_VERIFY( xColumns
->getByName(m_aControlSource
) >>= xFieldCandidate
);
1933 sal_Int32 nFieldType
= DataType::OTHER
;
1934 if ( xFieldCandidate
.is() )
1936 xFieldCandidate
->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
;
1937 if ( approveDbColumnType( nFieldType
) )
1938 impl_setField_noNotify( xFieldCandidate
);
1942 impl_setField_noNotify( nullptr );
1943 if ( m_xField
.is() )
1945 if ( m_xField
->getPropertySetInfo()->hasPropertyByName( PROPERTY_VALUE
) )
1947 m_nFieldType
= nFieldType
;
1948 // listen to changing values
1949 m_xField
->addPropertyChangeListener( PROPERTY_VALUE
, this );
1950 m_xColumnUpdate
.set( m_xField
, UNO_QUERY
);
1951 m_xColumn
.set( m_xField
, UNO_QUERY
);
1952 sal_Int32 nNullableFlag
= ColumnValue::NO_NULLS
;
1953 m_xField
->getPropertyValue(PROPERTY_ISNULLABLE
) >>= nNullableFlag
;
1954 m_bRequired
= (ColumnValue::NO_NULLS
== nNullableFlag
);
1955 // we're optimistic: in case of ColumnValue_NULLABLE_UNKNOWN we assume nullability...
1959 SAL_WARN("forms.component", "OBoundControlModel::connectToField: property " PROPERTY_VALUE
" not supported!");
1960 impl_setField_noNotify( nullptr );
1967 catch( const Exception
& )
1969 DBG_UNHANDLED_EXCEPTION("forms.component");
1974 void OBoundControlModel::initFromField( const Reference
< XRowSet
>& _rxRowSet
)
1976 // but only if the rowset is positioned on a valid record
1977 if ( !(hasField() && _rxRowSet
.is()) )
1980 bool shouldTransfer(!_rxRowSet
->isBeforeFirst() && !_rxRowSet
->isAfterLast());
1981 if (!shouldTransfer
)
1983 const Reference
< XPropertySet
> xPS(_rxRowSet
, UNO_QUERY
);
1986 assert(!shouldTransfer
);
1987 xPS
->getPropertyValue("IsNew") >>= shouldTransfer
;
1990 if ( shouldTransfer
)
1991 transferDbValueToControl();
1993 // reset the field if the row set is empty
1998 bool OBoundControlModel::approveDbColumnType(sal_Int32 _nColumnType
)
2000 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::approveDbColumnType: invalid call (have an external binding)!" );
2001 if ((_nColumnType
== DataType::BINARY
) || (_nColumnType
== DataType::VARBINARY
)
2002 || (_nColumnType
== DataType::LONGVARBINARY
) || (_nColumnType
== DataType::OTHER
)
2003 || (_nColumnType
== DataType::OBJECT
) || (_nColumnType
== DataType::DISTINCT
)
2004 || (_nColumnType
== DataType::STRUCT
) || (_nColumnType
== DataType::ARRAY
)
2005 || (_nColumnType
== DataType::BLOB
) /*|| (_nColumnType == DataType::CLOB)*/
2006 || (_nColumnType
== DataType::REF
) || (_nColumnType
== DataType::SQLNULL
))
2011 void OBoundControlModel::impl_determineAmbientForm_nothrow()
2013 Reference
< XInterface
> xParent( getParent() );
2014 m_xAmbientForm
.set( xParent
, UNO_QUERY
);
2015 if ( !m_xAmbientForm
.is() )
2017 Reference
< XRowSetSupplier
> xSupRowSet( xParent
, UNO_QUERY
);
2018 if ( xSupRowSet
.is() )
2019 m_xAmbientForm
.set( xSupRowSet
->getRowSet(), UNO_QUERY
);
2023 void OBoundControlModel::impl_connectDatabaseColumn_noNotify( bool _bFromReload
)
2025 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2026 // consistency checks
2027 DBG_ASSERT( !( hasField() && !_bFromReload
),
2028 "OBoundControlModel::impl_connectDatabaseColumn_noNotify: the form is just *loaded*, but we already have a field!" );
2030 Reference
< XRowSet
> xRowSet( m_xAmbientForm
, UNO_QUERY
);
2031 OSL_ENSURE( xRowSet
.is(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: no row set!" );
2032 if ( !xRowSet
.is() )
2034 if ( !hasField() || _bFromReload
)
2036 // connect to the column
2037 connectToField( xRowSet
);
2040 // now that we're connected (more or less, even if we did not find a column),
2041 // we definitely want to forward any potentially occurring value changes
2042 m_bForwardValueChanges
= true;
2043 // let derived classes react on this new connection
2045 onConnectedDbColumn( xRowSet
);
2046 // initially transfer the db column value to the control, if we successfully connected to a database column
2048 initFromField( xRowSet
);
2051 void OBoundControlModel::impl_disconnectDatabaseColumn_noNotify()
2053 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_disconnectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2054 // let derived classes react on this
2055 onDisconnectedDbColumn();
2058 getField()->removePropertyChangeListener( PROPERTY_VALUE
, this );
2062 m_xCursor
= nullptr;
2067 void SAL_CALL
OBoundControlModel::loaded( const EventObject
& _rEvent
)
2069 ControlModelLock
aLock( *this );
2070 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2071 OSL_ENSURE( _rEvent
.Source
== m_xAmbientForm
, "OBoundControlModel::loaded: where does this come from?" );
2072 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::loaded: we should never reach this with an external value binding!" );
2073 if ( hasExternalValueBinding() )
2075 impl_connectDatabaseColumn_noNotify( false );
2078 void SAL_CALL
OBoundControlModel::unloaded( const css::lang::EventObject
& /*aEvent*/ )
2080 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloaded: we should never reach this with an external value binding!" );
2083 void SAL_CALL
OBoundControlModel::reloading( const css::lang::EventObject
& /*aEvent*/ )
2085 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloading: we should never reach this with an external value binding!" );
2086 if ( hasExternalValueBinding() )
2088 osl::MutexGuard
aGuard(m_aMutex
);
2089 m_bForwardValueChanges
= false;
2092 void SAL_CALL
OBoundControlModel::unloading(const css::lang::EventObject
& /*aEvent*/)
2094 ControlModelLock
aLock( *this );
2095 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2096 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloading: we should never reach this with an external value binding!" );
2097 if ( hasExternalValueBinding() )
2099 impl_disconnectDatabaseColumn_noNotify();
2102 void SAL_CALL
OBoundControlModel::reloaded( const EventObject
& _rEvent
)
2104 ControlModelLock
aLock( *this );
2105 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2106 OSL_ENSURE( _rEvent
.Source
== m_xAmbientForm
, "OBoundControlModel::reloaded: where does this come from?" );
2107 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloaded: we should never reach this with an external value binding!" );
2108 if ( hasExternalValueBinding() )
2110 impl_connectDatabaseColumn_noNotify( true );
2113 void OBoundControlModel::setControlValue( const Any
& _rValue
, ValueChangeInstigator _eInstigator
)
2115 m_eControlValueChangeInstigator
= _eInstigator
;
2116 doSetControlValue( _rValue
);
2117 m_eControlValueChangeInstigator
= eOther
;
2120 void OBoundControlModel::doSetControlValue( const Any
& _rValue
)
2122 OSL_PRECOND( m_xAggregateFastSet
.is() && m_xAggregateSet
.is(),
2123 "OBoundControlModel::doSetControlValue: invalid aggregate !" );
2124 OSL_PRECOND( !m_sValuePropertyName
.isEmpty() || ( m_nValuePropertyAggregateHandle
!= -1 ),
2125 "OBoundControlModel::doSetControlValue: please override if you have own value property handling!" );
2128 // release our mutex once (it's acquired in one of the calling methods), as setting aggregate properties
2129 // may cause any uno controls belonging to us to lock the solar mutex, which is potentially dangerous with
2130 // our own mutex locked
2131 MutexRelease
aRelease( m_aMutex
);
2132 if ( ( m_nValuePropertyAggregateHandle
!= -1 ) && m_xAggregateFastSet
.is() )
2134 m_xAggregateFastSet
->setFastPropertyValue( m_nValuePropertyAggregateHandle
, _rValue
);
2137 else if ( !m_sValuePropertyName
.isEmpty() && m_xAggregateSet
.is() )
2139 m_xAggregateSet
->setPropertyValue( m_sValuePropertyName
, _rValue
);
2144 catch( const Exception
& )
2146 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::doSetControlValue");
2150 void OBoundControlModel::onConnectedValidator( )
2154 // if we have an external validator, we do not want the control to force invalid
2155 // inputs to the default value. Instead, invalid inputs should be translated
2156 // to NaN (not a number)
2157 Reference
< XPropertySetInfo
> xAggregatePropertyInfo
;
2158 if ( m_xAggregateSet
.is() )
2159 xAggregatePropertyInfo
= m_xAggregateSet
->getPropertySetInfo();
2160 if ( xAggregatePropertyInfo
.is() && xAggregatePropertyInfo
->hasPropertyByName( PROPERTY_ENFORCE_FORMAT
) )
2161 m_xAggregateSet
->setPropertyValue( PROPERTY_ENFORCE_FORMAT
, makeAny( false ) );
2164 catch( const Exception
& )
2166 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::onConnectedValidator");
2169 recheckValidity( false );
2172 void OBoundControlModel::onDisconnectedValidator( )
2176 Reference
< XPropertySetInfo
> xAggregatePropertyInfo
;
2177 if ( m_xAggregateSet
.is() )
2178 xAggregatePropertyInfo
= m_xAggregateSet
->getPropertySetInfo();
2179 if ( xAggregatePropertyInfo
.is() && xAggregatePropertyInfo
->hasPropertyByName( PROPERTY_ENFORCE_FORMAT
) )
2180 m_xAggregateSet
->setPropertyValue( PROPERTY_ENFORCE_FORMAT
, makeAny( true ) );
2183 catch( const Exception
& )
2185 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::onDisconnectedValidator");
2188 recheckValidity( false );
2191 void OBoundControlModel::onConnectedExternalValue( )
2193 calculateExternalValueType();
2196 void OBoundControlModel::onConnectedDbColumn( const Reference
< XInterface
>& /*_rxForm*/ )
2198 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onConnectedDbColumn: how this? There's an external value binding!" );
2201 void OBoundControlModel::onDisconnectedDbColumn()
2203 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onDisconnectedDbColumn: how this? There's an external value binding!" );
2207 Any
OBoundControlModel::getDefaultForReset() const
2212 void OBoundControlModel::resetNoBroadcast()
2214 setControlValue( getDefaultForReset(), eOther
);
2217 void OBoundControlModel::addResetListener(const Reference
<XResetListener
>& l
)
2219 m_aResetHelper
.addResetListener( l
);
2222 void OBoundControlModel::removeResetListener(const Reference
<XResetListener
>& l
)
2224 m_aResetHelper
.removeResetListener( l
);
2227 void OBoundControlModel::reset()
2229 if ( !m_aResetHelper
.approveReset() )
2231 ControlModelLock
aLock( *this );
2233 bool bIsNewRecord
= false;
2234 Reference
<XPropertySet
> xSet( m_xCursor
, UNO_QUERY
);
2239 xSet
->getPropertyValue( PROPERTY_ISNEW
) >>= bIsNewRecord
;
2242 catch( const Exception
& )
2244 DBG_UNHANDLED_EXCEPTION("forms.component");
2249 // cursor on an invalid row?
2250 bool bInvalidCursorPosition
= true;
2253 bInvalidCursorPosition
= m_xCursor
.is()
2254 && ( m_xCursor
->isAfterLast()
2255 || m_xCursor
->isBeforeFirst()
2260 catch( const SQLException
& )
2262 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::reset: caught an SQL exception!" );
2265 // #i24495# - don't count the insert row as "invalid"
2267 ( !m_xColumn
.is() // no connection to a database column
2268 || ( m_xCursor
.is() // OR we have an improperly positioned cursor
2269 && bInvalidCursorPosition
2271 || hasExternalValueBinding() // OR we have an external value binding
2273 if ( !bSimpleReset
)
2275 // The default values will be set if and only if the current value of the field which we're bound
2277 // Else, the current field value should be refreshed
2278 // This behaviour is not completely ... "matured": What should happen if the field as well as the
2279 // control have a default value?
2280 bool bIsNull
= true;
2281 // we have to access the field content at least once to get a reliable result by XColumn::wasNull
2284 // normally, we'd do a getString here. However, this is extremely expensive in the case
2285 // of binary fields. Unfortunately, getString is the only method which is guaranteed
2286 // to *always* succeed, all other getXXX methods may fail if the column is asked for a
2287 // non-convertible type
2288 sal_Int32 nFieldType
= DataType::OBJECT
;
2289 getField()->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
;
2290 if ( ( nFieldType
== DataType::BINARY
)
2291 || ( nFieldType
== DataType::VARBINARY
)
2292 || ( nFieldType
== DataType::LONGVARBINARY
)
2293 || ( nFieldType
== DataType::OBJECT
)
2294 /*|| ( nFieldType == DataType::CLOB )*/
2296 m_xColumn
->getBinaryStream();
2297 else if ( nFieldType
== DataType::BLOB
)
2298 m_xColumn
->getBlob();
2300 m_xColumn
->getString();
2301 bIsNull
= m_xColumn
->wasNull();
2304 catch(const Exception
&)
2306 DBG_UNHANDLED_EXCEPTION("forms.component");
2307 SAL_WARN("forms.component", "OBoundControlModel::reset: this should have succeeded in all cases!");
2310 bool bNeedValueTransfer
= true;
2315 // reset the control to its default
2317 // and immediately commit the changes to the DB column, to keep consistency
2318 commitControlValueToDbColumn( true );
2319 bNeedValueTransfer
= false;
2324 if ( bNeedValueTransfer
)
2325 transferDbValueToControl();
2331 // transfer to the external binding, if necessary
2332 if ( hasExternalValueBinding() )
2333 transferControlValueToExternal( aLock
);
2336 // revalidate, if necessary
2337 if ( hasValidator() )
2338 recheckValidity( true );
2340 m_aResetHelper
.notifyResetted();
2343 void OBoundControlModel::impl_setField_noNotify( const Reference
< XPropertySet
>& _rxField
)
2345 DBG_ASSERT( !hasExternalValueBinding(), "OBoundControlModel::impl_setField_noNotify: We have an external value binding!" );
2346 m_xField
= _rxField
;
2349 bool OBoundControlModel::impl_approveValueBinding_nolock( const Reference
< XValueBinding
>& _rxBinding
)
2351 if ( !_rxBinding
.is() )
2353 Sequence
< Type
> aTypeCandidates
;
2356 ::osl::MutexGuard
aGuard( m_aMutex
);
2357 aTypeCandidates
= getSupportedBindingTypes();
2361 for ( auto const & type
: std::as_const(aTypeCandidates
) )
2363 if ( _rxBinding
->supportsType( type
) )
2369 void OBoundControlModel::connectExternalValueBinding(
2370 const Reference
< XValueBinding
>& _rxBinding
, ControlModelLock
& _rInstanceLock
)
2372 OSL_PRECOND( _rxBinding
.is(), "OBoundControlModel::connectExternalValueBinding: invalid binding instance!" );
2373 OSL_PRECOND( !hasExternalValueBinding( ), "OBoundControlModel::connectExternalValueBinding: precond not met (currently have a binding)!" );
2374 // if we're connected to a database column, suspend this
2376 impl_disconnectDatabaseColumn_noNotify();
2377 // suspend listening for load-related events at out ambient form.
2378 // This is because an external value binding overrules a possible database binding.
2379 if ( isFormListening() )
2380 doFormListening( false );
2381 // remember this new binding
2382 m_xExternalBinding
= _rxBinding
;
2384 onConnectedExternalValue();
2387 // add as value listener so we get notified when the value changes
2388 Reference
< XModifyBroadcaster
> xModifiable( m_xExternalBinding
, UNO_QUERY
);
2389 if ( xModifiable
.is() )
2390 xModifiable
->addModifyListener( this );
2391 // add as property change listener for some (possibly present) properties we're
2393 Reference
< XPropertySet
> xBindingProps( m_xExternalBinding
, UNO_QUERY
);
2394 Reference
< XPropertySetInfo
> xBindingPropsInfo( xBindingProps
.is() ? xBindingProps
->getPropertySetInfo() : Reference
< XPropertySetInfo
>() );
2395 if ( xBindingPropsInfo
.is() )
2397 if ( xBindingPropsInfo
->hasPropertyByName( PROPERTY_READONLY
) )
2399 xBindingProps
->addPropertyChangeListener( PROPERTY_READONLY
, this );
2400 m_bBindingControlsRO
= true;
2403 if ( xBindingPropsInfo
->hasPropertyByName( PROPERTY_RELEVANT
) )
2405 xBindingProps
->addPropertyChangeListener( PROPERTY_RELEVANT
, this );
2406 m_bBindingControlsEnable
= true;
2413 catch( const Exception
& )
2415 DBG_UNHANDLED_EXCEPTION("forms.component");
2418 // propagate our new value
2419 transferExternalValueToControl( _rInstanceLock
);
2420 // if the binding is also a validator, use it, too. This is a constraint of the
2421 // com.sun.star.form.binding.ValidatableBindableFormComponent service
2422 if ( !m_bSupportsValidation
)
2427 Reference
< XValidator
> xAsValidator( _rxBinding
, UNO_QUERY
);
2428 if ( xAsValidator
.is() )
2429 setValidator( xAsValidator
);
2432 catch( const Exception
& )
2434 DBG_UNHANDLED_EXCEPTION("forms.component");
2438 void OBoundControlModel::disconnectExternalValueBinding( )
2442 // not listening at the binding anymore
2443 Reference
< XModifyBroadcaster
> xModifiable( m_xExternalBinding
, UNO_QUERY
);
2444 if ( xModifiable
.is() )
2445 xModifiable
->removeModifyListener( this );
2446 // remove as property change listener
2447 Reference
< XPropertySet
> xBindingProps( m_xExternalBinding
, UNO_QUERY
);
2448 if ( m_bBindingControlsRO
)
2449 xBindingProps
->removePropertyChangeListener( PROPERTY_READONLY
, this );
2450 if ( m_bBindingControlsEnable
)
2451 xBindingProps
->removePropertyChangeListener( PROPERTY_RELEVANT
, this );
2454 catch( const Exception
& )
2456 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::disconnectExternalValueBinding");
2459 // if the binding also acts as our validator, disconnect the validator, too
2460 if ( ( m_xExternalBinding
== m_xValidator
) && m_xValidator
.is() )
2461 disconnectValidator( );
2462 // no binding anymore
2463 m_xExternalBinding
.clear();
2464 // be a load listener at our form, again. This was suspended while we had
2465 // an external value binding in place.
2466 doFormListening( true );
2467 // re-connect to database column of the new parent
2468 if ( m_xAmbientForm
.is() && m_xAmbientForm
->isLoaded() )
2469 impl_connectDatabaseColumn_noNotify( false );
2472 void SAL_CALL
OBoundControlModel::setValueBinding( const Reference
< XValueBinding
>& _rxBinding
)
2474 OSL_PRECOND( m_bSupportsExternalBinding
, "OBoundControlModel::setValueBinding: How did you reach this method?" );
2475 // the interface for this method should not have been exposed if we do not
2476 // support binding to external data
2478 if ( _rxBinding
.is() && !impl_approveValueBinding_nolock( _rxBinding
) )
2480 throw IncompatibleTypesException(
2481 FRM_RES_STRING( RID_STR_INCOMPATIBLE_TYPES
),
2486 ControlModelLock
aLock( *this );
2487 // since a ValueBinding overrules any potentially active database binding, the change in a ValueBinding
2488 // might trigger a change in our BoundField.
2489 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2490 // disconnect from the old binding
2491 if ( hasExternalValueBinding() )
2492 disconnectExternalValueBinding( );
2493 // connect to the new binding
2494 if ( _rxBinding
.is() )
2495 connectExternalValueBinding( _rxBinding
, aLock
);
2498 Reference
< XValueBinding
> SAL_CALL
OBoundControlModel::getValueBinding( )
2500 ::osl::MutexGuard
aGuard( m_aMutex
);
2501 OSL_PRECOND( m_bSupportsExternalBinding
, "OBoundControlModel::getValueBinding: How did you reach this method?" );
2502 // the interface for this method should not have been exposed if we do not
2503 // support binding to external data
2504 return m_xExternalBinding
;
2507 void SAL_CALL
OBoundControlModel::modified( const EventObject
& _rEvent
)
2509 ControlModelLock
aLock( *this );
2510 OSL_PRECOND( hasExternalValueBinding(), "OBoundControlModel::modified: Where did this come from?" );
2511 if ( !m_bTransferringValue
&& ( m_xExternalBinding
== _rEvent
.Source
) && m_xExternalBinding
.is() )
2513 transferExternalValueToControl( aLock
);
2517 void OBoundControlModel::transferDbValueToControl( )
2521 setControlValue( translateDbColumnToControlValue(), eDbColumnBinding
);
2524 catch( const Exception
& )
2526 DBG_UNHANDLED_EXCEPTION("forms.component");
2530 void OBoundControlModel::transferExternalValueToControl( ControlModelLock
& _rInstanceLock
)
2532 Reference
< XValueBinding
> xExternalBinding( m_xExternalBinding
);
2533 Type
aValueExchangeType( getExternalValueType() );
2534 _rInstanceLock
.release();
2539 aExternalValue
= xExternalBinding
->getValue( aValueExchangeType
);
2542 catch( const Exception
& )
2544 DBG_UNHANDLED_EXCEPTION("forms.component");
2547 _rInstanceLock
.acquire();
2548 setControlValue( translateExternalValueToControlValue( aExternalValue
), eExternalBinding
);
2551 void OBoundControlModel::transferControlValueToExternal( ControlModelLock
& _rInstanceLock
)
2553 OSL_PRECOND( m_bSupportsExternalBinding
&& hasExternalValueBinding(),
2554 "OBoundControlModel::transferControlValueToExternal: precondition not met!" );
2555 if ( !m_xExternalBinding
.is() )
2558 Any
aExternalValue( translateControlValueToExternalValue() );
2559 m_bTransferringValue
= true;
2560 _rInstanceLock
.release();
2564 m_xExternalBinding
->setValue( aExternalValue
);
2567 catch( const Exception
& )
2569 DBG_UNHANDLED_EXCEPTION("forms.component");
2573 _rInstanceLock
.acquire();
2574 m_bTransferringValue
= false;
2577 Sequence
< Type
> OBoundControlModel::getSupportedBindingTypes()
2579 return Sequence
< Type
>( &m_aValuePropertyType
, 1 );
2582 void OBoundControlModel::calculateExternalValueType()
2584 m_aExternalValueType
= Type();
2585 if ( !m_xExternalBinding
.is() )
2587 const Sequence
< Type
> aTypeCandidates( getSupportedBindingTypes() );
2588 for ( auto const & typeCandidate
: aTypeCandidates
)
2590 if ( m_xExternalBinding
->supportsType( typeCandidate
) )
2592 m_aExternalValueType
= typeCandidate
;
2598 Any
OBoundControlModel::translateExternalValueToControlValue( const Any
& _rExternalValue
) const
2600 OSL_PRECOND( m_bSupportsExternalBinding
&& hasExternalValueBinding(),
2601 "OBoundControlModel::translateExternalValueToControlValue: precondition not met!" );
2602 Any
aControlValue( _rExternalValue
);
2603 // if the external value is VOID, and our value property is not allowed to be VOID,
2604 // then default-construct a value
2605 if ( !aControlValue
.hasValue() && !m_bValuePropertyMayBeVoid
)
2606 aControlValue
.setValue( nullptr, m_aValuePropertyType
);
2608 return aControlValue
;
2611 Any
OBoundControlModel::translateControlValueToExternalValue( ) const
2613 return getControlValue( );
2616 Any
OBoundControlModel::translateControlValueToValidatableValue( ) const
2618 OSL_PRECOND( m_xValidator
.is(), "OBoundControlModel::translateControlValueToValidatableValue: no validator, so why should I?" );
2619 if ( ( m_xValidator
== m_xExternalBinding
) && m_xValidator
.is() )
2620 return translateControlValueToExternalValue();
2621 return getControlValue();
2624 Any
OBoundControlModel::getControlValue( ) const
2626 OSL_PRECOND( m_xAggregateFastSet
.is() && m_xAggregateSet
.is(),
2627 "OBoundControlModel::getControlValue: invalid aggregate !" );
2628 OSL_PRECOND( !m_sValuePropertyName
.isEmpty() || ( m_nValuePropertyAggregateHandle
!= -1 ),
2629 "OBoundControlModel::getControlValue: please override if you have own value property handling!" );
2630 // determine the current control value
2632 if ( ( m_nValuePropertyAggregateHandle
!= -1 ) && m_xAggregateFastSet
.is() )
2634 aControlValue
= m_xAggregateFastSet
->getFastPropertyValue( m_nValuePropertyAggregateHandle
);
2637 else if ( !m_sValuePropertyName
.isEmpty() && m_xAggregateSet
.is() )
2639 aControlValue
= m_xAggregateSet
->getPropertyValue( m_sValuePropertyName
);
2641 return aControlValue
;
2644 void OBoundControlModel::connectValidator( const Reference
< XValidator
>& _rxValidator
)
2646 OSL_PRECOND( _rxValidator
.is(), "OBoundControlModel::connectValidator: invalid validator instance!" );
2647 OSL_PRECOND( !hasValidator( ), "OBoundControlModel::connectValidator: precond not met (have a validator currently)!" );
2648 m_xValidator
= _rxValidator
;
2650 // add as value listener so we get notified when the value changes
2651 if ( m_xValidator
.is() )
2655 m_xValidator
->addValidityConstraintListener( this );
2658 catch( const RuntimeException
& )
2662 onConnectedValidator( );
2665 void OBoundControlModel::disconnectValidator( )
2667 OSL_PRECOND( hasValidator( ), "OBoundControlModel::connectValidator: precond not met (don't have a validator currently)!" );
2669 // add as value listener so we get notified when the value changes
2670 if ( m_xValidator
.is() )
2674 m_xValidator
->removeValidityConstraintListener( this );
2677 catch( const RuntimeException
& )
2682 m_xValidator
.clear();
2684 onDisconnectedValidator( );
2687 void SAL_CALL
OBoundControlModel::setValidator( const Reference
< XValidator
>& _rxValidator
)
2689 osl::MutexGuard
aGuard( m_aMutex
);
2690 OSL_PRECOND( m_bSupportsValidation
, "OBoundControlModel::setValidator: How did you reach this method?" );
2691 // the interface for this method should not have been exposed if we do not
2692 // support validation
2694 // early out if the validator does not change
2695 if ( _rxValidator
== m_xValidator
)
2698 if ( m_xValidator
.is() && ( m_xValidator
== m_xExternalBinding
) )
2699 throw VetoException(
2700 FRM_RES_STRING( RID_STR_INVALID_VALIDATOR
),
2704 // disconnect from the old validator
2705 if ( hasValidator() )
2706 disconnectValidator( );
2708 // connect to the new validator
2709 if ( _rxValidator
.is() )
2710 connectValidator( _rxValidator
);
2713 Reference
< XValidator
> SAL_CALL
OBoundControlModel::getValidator( )
2715 ::osl::MutexGuard
aGuard( m_aMutex
);
2716 OSL_PRECOND( m_bSupportsValidation
, "OBoundControlModel::getValidator: How did you reach this method?" );
2717 // the interface for this method should not have been exposed if we do not
2718 // support validation
2720 return m_xValidator
;
2723 void SAL_CALL
OBoundControlModel::validityConstraintChanged( const EventObject
& /*Source*/ )
2725 osl::MutexGuard
aGuard( m_aMutex
);
2726 OSL_PRECOND( m_bSupportsValidation
, "OBoundControlModel::validityConstraintChanged: 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 recheckValidity( false );
2733 sal_Bool SAL_CALL
OBoundControlModel::isValid( )
2735 return m_bIsCurrentValueValid
;
2738 css::uno::Any
OBoundControlModel::getCurrentFormComponentValue() const
2740 if ( hasValidator() )
2741 return translateControlValueToValidatableValue();
2742 return getControlValue();
2745 Any SAL_CALL
OBoundControlModel::getCurrentValue( )
2747 ::osl::MutexGuard
aGuard( m_aMutex
);
2748 return getCurrentFormComponentValue();
2751 void SAL_CALL
OBoundControlModel::addFormComponentValidityListener( const Reference
< validation::XFormComponentValidityListener
>& Listener
)
2753 if ( Listener
.is() )
2754 m_aFormComponentListeners
.addInterface( Listener
);
2757 void SAL_CALL
OBoundControlModel::removeFormComponentValidityListener( const Reference
< validation::XFormComponentValidityListener
>& Listener
)
2759 if ( Listener
.is() )
2760 m_aFormComponentListeners
.removeInterface( Listener
);
2763 void OBoundControlModel::recheckValidity( bool _bForceNotification
)
2767 bool bIsCurrentlyValid
= true;
2768 if ( hasValidator() )
2769 bIsCurrentlyValid
= m_xValidator
->isValid( translateControlValueToValidatableValue() );
2771 if ( ( bIsCurrentlyValid
!= m_bIsCurrentValueValid
) || _bForceNotification
)
2773 m_bIsCurrentValueValid
= bIsCurrentlyValid
;
2775 // release our mutex for the notifications
2776 MutexRelease
aRelease( m_aMutex
);
2777 m_aFormComponentListeners
.notifyEach( &validation::XFormComponentValidityListener::componentValidityChanged
, EventObject( *this ) );
2782 catch( const Exception
& )
2784 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::recheckValidity");
2788 void OBoundControlModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
2790 BEGIN_DESCRIBE_PROPERTIES( 5, OControlModel
)
2791 DECL_PROP1 ( CONTROLSOURCE
, OUString
, BOUND
);
2792 DECL_IFACE_PROP3( BOUNDFIELD
, XPropertySet
, BOUND
, READONLY
, TRANSIENT
);
2793 DECL_IFACE_PROP2( CONTROLLABEL
, XPropertySet
, BOUND
, MAYBEVOID
);
2794 DECL_PROP2 ( CONTROLSOURCEPROPERTY
, OUString
, READONLY
, TRANSIENT
);
2795 DECL_BOOL_PROP1 ( INPUT_REQUIRED
, BOUND
);
2796 END_DESCRIBE_PROPERTIES()
2800 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */