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 if (auto xProv
= query_aggregation
<XTypeProvider
>(m_xAggregate
))
185 aTypes
.addTypes( xProv
->getTypes() );
187 return aTypes
.getTypes();
190 Sequence
<Type
> OControl::_getTypes()
192 return TypeBag( OComponentHelper::getTypes(), OControl_BASE::getTypes() ).getTypes();
196 void OControl::disposing()
198 OComponentHelper::disposing();
200 m_aWindowStateGuard
.attach( nullptr, nullptr );
202 if (auto xComp
= query_aggregation
<XComponent
>(m_xAggregate
))
207 sal_Bool SAL_CALL
OControl::supportsService(const OUString
& _rsServiceName
)
209 return cppu::supportsService(this, _rsServiceName
);
212 Sequence
< OUString
> OControl::getAggregateServiceNames() const
214 Sequence
< OUString
> aAggServices
;
215 if (auto xInfo
= query_aggregation
<XServiceInfo
>(m_xAggregate
))
216 aAggServices
= xInfo
->getSupportedServiceNames();
221 Sequence
<OUString
> SAL_CALL
OControl::getSupportedServiceNames()
223 // no own supported service names
224 return getAggregateServiceNames();
228 void SAL_CALL
OControl::disposing(const css::lang::EventObject
& _rEvent
)
230 auto xAggAsIface
= query_aggregation
<XInterface
>(m_xAggregate
);
232 // does the disposing come from the aggregate?
233 if (xAggAsIface
!= Reference
< XInterface
>(_rEvent
.Source
, UNO_QUERY
))
234 { // no -> forward it
235 if (auto xListener
= query_aggregation
<css::lang::XEventListener
>(m_xAggregate
))
236 xListener
->disposing(_rEvent
);
241 void SAL_CALL
OControl::setContext(const Reference
< XInterface
>& Context
)
244 m_xControl
->setContext(Context
);
247 Reference
< XInterface
> SAL_CALL
OControl::getContext()
249 return m_xControl
.is() ? m_xControl
->getContext() : Reference
< XInterface
>();
252 void OControl::impl_resetStateGuard_nothrow()
254 Reference
< XWindow2
> xWindow
;
255 Reference
< XControlModel
> xModel
;
258 xWindow
.set( getPeer(), UNO_QUERY
);
261 catch( const Exception
& )
263 DBG_UNHANDLED_EXCEPTION("forms.component");
265 m_aWindowStateGuard
.attach( xWindow
, xModel
);
268 void SAL_CALL
OControl::createPeer(const Reference
<XToolkit
>& _rxToolkit
, const Reference
<XWindowPeer
>& _rxParent
)
270 if ( m_xControl
.is() )
272 m_xControl
->createPeer( _rxToolkit
, _rxParent
);
273 impl_resetStateGuard_nothrow();
277 Reference
<XWindowPeer
> SAL_CALL
OControl::getPeer()
279 return m_xControl
.is() ? m_xControl
->getPeer() : Reference
<XWindowPeer
>();
282 sal_Bool SAL_CALL
OControl::setModel(const Reference
<XControlModel
>& Model
)
284 if ( !m_xControl
.is() )
287 bool bSuccess
= m_xControl
->setModel( Model
);
288 impl_resetStateGuard_nothrow();
292 Reference
<XControlModel
> SAL_CALL
OControl::getModel()
294 return m_xControl
.is() ? m_xControl
->getModel() : Reference
<XControlModel
>();
297 Reference
<XView
> SAL_CALL
OControl::getView()
299 return m_xControl
.is() ? m_xControl
->getView() : Reference
<XView
>();
302 void SAL_CALL
OControl::setDesignMode(sal_Bool bOn
)
305 m_xControl
->setDesignMode(bOn
);
308 sal_Bool SAL_CALL
OControl::isDesignMode()
310 return !m_xControl
.is() || m_xControl
->isDesignMode();
313 sal_Bool SAL_CALL
OControl::isTransparent()
315 return !m_xControl
.is() || m_xControl
->isTransparent();
318 OBoundControl::OBoundControl( const Reference
< XComponentContext
>& _rxContext
,
319 const OUString
& _rAggregateService
, const bool _bSetDelegator
)
320 :OControl( _rxContext
, _rAggregateService
, _bSetDelegator
)
325 OBoundControl::~OBoundControl()
329 Sequence
< Type
> OBoundControl::_getTypes()
331 return TypeBag( OControl::_getTypes(), OBoundControl_BASE::getTypes() ).getTypes();
334 Any SAL_CALL
OBoundControl::queryAggregation(const Type
& _rType
)
338 // XTypeProvider first - don't ask the OBoundControl_BASE, it would deliver incomplete types
339 if ( _rType
.equals( cppu::UnoType
<XTypeProvider
>::get() ) )
340 aReturn
= OControl::queryAggregation( _rType
);
342 // ask our own interfaces
343 // (do this first (except XTypeProvider ) - we want to "overwrite" XPropertiesChangeListener)
344 if ( !aReturn
.hasValue() )
345 aReturn
= OBoundControl_BASE::queryInterface( _rType
);
347 // ask the base class
348 if ( !aReturn
.hasValue() )
349 aReturn
= OControl::queryAggregation( _rType
);
354 sal_Bool SAL_CALL
OBoundControl::getLock()
359 void SAL_CALL
OBoundControl::setLock(sal_Bool _bLock
)
361 if (m_bLocked
== bool(_bLock
))
364 osl::MutexGuard
aGuard(m_aMutex
);
369 void OBoundControl::_setLock(bool _bLock
)
371 // try to set the text component to readonly
372 Reference
< XWindowPeer
> xPeer
= getPeer();
373 Reference
< XTextComponent
> xText( xPeer
, UNO_QUERY
);
376 xText
->setEditable( !_bLock
);
379 // disable the window
380 Reference
< XWindow
> xComp( xPeer
, UNO_QUERY
);
382 xComp
->setEnable( !_bLock
);
386 sal_Bool SAL_CALL
OBoundControl::setModel( const Reference
< XControlModel
>& _rxModel
)
388 return OControl::setModel( _rxModel
);
391 void SAL_CALL
OBoundControl::disposing(const EventObject
& Source
)
394 OControl::disposing(Source
);
397 void OBoundControl::disposing()
399 OControl::disposing();
403 Sequence
<sal_Int8
> SAL_CALL
OControlModel::getImplementationId()
405 return css::uno::Sequence
<sal_Int8
>();
408 Sequence
<Type
> SAL_CALL
OControlModel::getTypes()
410 TypeBag
aTypes( _getTypes() );
412 if (auto xProv
= query_aggregation
<XTypeProvider
>(m_xAggregate
))
413 aTypes
.addTypes( xProv
->getTypes() );
415 return aTypes
.getTypes();
418 Sequence
<Type
> OControlModel::_getTypes()
420 return TypeBag( OComponentHelper::getTypes(),
421 OPropertySetAggregationHelper::getTypes(),
422 OControlModel_BASE::getTypes()
426 Any SAL_CALL
OControlModel::queryAggregation(const Type
& _rType
)
429 Any
aReturn(OComponentHelper::queryAggregation(_rType
));
432 if (!aReturn
.hasValue())
434 aReturn
= OControlModel_BASE::queryInterface(_rType
);
436 // our own interfaces
437 if (!aReturn
.hasValue())
439 aReturn
= OPropertySetAggregationHelper::queryInterface(_rType
);
441 if (!aReturn
.hasValue() && m_xAggregate
.is() && !_rType
.equals(cppu::UnoType
<XCloneable
>::get()))
442 aReturn
= m_xAggregate
->queryAggregation(_rType
);
448 void OControlModel::readHelpTextCompatibly(const css::uno::Reference
< css::io::XObjectInputStream
>& _rxInStream
)
451 ::comphelper::operator>>( _rxInStream
, sHelpText
);
454 if (m_xAggregateSet
.is())
455 m_xAggregateSet
->setPropertyValue(PROPERTY_HELPTEXT
, Any(sHelpText
));
457 catch(const Exception
&)
459 DBG_UNHANDLED_EXCEPTION("forms.component");
460 SAL_WARN("forms.component", "OControlModel::readHelpTextCompatibly: could not forward the property value to the aggregate!");
464 void OControlModel::writeHelpTextCompatibly(const css::uno::Reference
< css::io::XObjectOutputStream
>& _rxOutStream
)
469 if (m_xAggregateSet
.is())
470 m_xAggregateSet
->getPropertyValue(PROPERTY_HELPTEXT
) >>= sHelpText
;
472 catch(const Exception
&)
474 DBG_UNHANDLED_EXCEPTION("forms.component");
475 SAL_WARN("forms.component", "OControlModel::writeHelpTextCompatibly: could not retrieve the property value from the aggregate!");
477 ::comphelper::operator<<( _rxOutStream
, sHelpText
);
480 OControlModel::OControlModel(
481 const Reference
<XComponentContext
>& _rxContext
,
482 const OUString
& _rUnoControlModelTypeName
,
483 const OUString
& rDefault
, const bool _bSetDelegator
)
484 :OComponentHelper(m_aMutex
)
485 ,OPropertySetAggregationHelper(OComponentHelper::rBHelper
)
486 ,m_xContext( _rxContext
)
488 ,m_aPropertyBagHelper( *this )
489 ,m_nTabIndex(FRM_DEFAULT_TABINDEX
)
490 ,m_nClassId(FormComponentType::CONTROL
)
491 ,m_bNativeLook( false )
492 ,m_bStandardTheme( false )
493 ,m_bGenerateVbEvents( false )
494 ,m_nControlTypeinMSO(0) // 0 : default value is create from AOO
495 ,m_nObjIDinMSO(INVALID_OBJ_ID_IN_MSO
)
496 // form controls are usually embedded into documents, not dialogs, and in documents
497 // the native look is ugly...
500 if (_rUnoControlModelTypeName
.isEmpty()) // the is a model we have to aggregate
503 osl_atomic_increment(&m_refCount
);
505 m_xAggregate
.set(m_xContext
->getServiceManager()->createInstanceWithContext(_rUnoControlModelTypeName
, m_xContext
), UNO_QUERY
);
506 setAggregation(m_xAggregate
);
508 if ( m_xAggregateSet
.is() )
512 if ( !rDefault
.isEmpty() )
513 m_xAggregateSet
->setPropertyValue( PROPERTY_DEFAULTCONTROL
, Any( rDefault
) );
515 catch( const Exception
& )
517 TOOLS_WARN_EXCEPTION("forms.component", "OControlModel::OControlModel");
524 // Refcount is at NULL again
525 osl_atomic_decrement(&m_refCount
);
528 OControlModel::OControlModel( const OControlModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
, const bool _bCloneAggregate
, const bool _bSetDelegator
)
529 :OComponentHelper( m_aMutex
)
530 ,OPropertySetAggregationHelper( OComponentHelper::rBHelper
)
531 ,m_xContext( _rxFactory
)
533 ,m_aPropertyBagHelper( *this )
534 ,m_nTabIndex( FRM_DEFAULT_TABINDEX
)
535 ,m_nClassId( FormComponentType::CONTROL
)
537 assert(_pOriginal
&& "OControlModel::OControlModel: invalid original!");
540 m_aName
= _pOriginal
->m_aName
;
541 m_aTag
= _pOriginal
->m_aTag
;
542 m_nTabIndex
= _pOriginal
->m_nTabIndex
;
543 m_nClassId
= _pOriginal
->m_nClassId
;
544 m_bNativeLook
= _pOriginal
->m_bNativeLook
;
545 m_bStandardTheme
= _pOriginal
->m_bStandardTheme
;
546 m_bGenerateVbEvents
= _pOriginal
->m_bGenerateVbEvents
;
547 m_nControlTypeinMSO
= _pOriginal
->m_nControlTypeinMSO
;
548 m_nObjIDinMSO
= _pOriginal
->m_nObjIDinMSO
;
550 if ( !_bCloneAggregate
)
553 // temporarily increment refcount because of temporary references to ourself in the following
554 osl_atomic_increment( &m_refCount
);
556 // transfer the (only, at the very moment!) ref count
557 m_xAggregate
= createAggregateClone( _pOriginal
);
559 // set aggregation (retrieve other direct interfaces of the aggregate)
560 setAggregation( m_xAggregate
);
563 // set the delegator, if allowed by our derived class
564 if ( _bSetDelegator
)
567 // decrement ref count
568 osl_atomic_decrement( &m_refCount
);
571 OControlModel::~OControlModel()
573 // release the aggregate
577 void OControlModel::clonedFrom( const OControlModel
* /*_pOriginal*/ )
579 // nothing to do in this base class
582 void OControlModel::doResetDelegator()
584 if (m_xAggregate
.is())
585 m_xAggregate
->setDelegator(nullptr);
588 void OControlModel::doSetDelegator()
590 osl_atomic_increment(&m_refCount
);
591 if (m_xAggregate
.is())
593 m_xAggregate
->setDelegator(static_cast<XWeak
*>(this));
595 osl_atomic_decrement(&m_refCount
);
599 Reference
< XInterface
> SAL_CALL
OControlModel::getParent()
604 void SAL_CALL
OControlModel::setParent(const Reference
< XInterface
>& _rxParent
)
606 osl::MutexGuard
aGuard(m_aMutex
);
608 Reference
<XComponent
> xComp(m_xParent
, UNO_QUERY
);
610 xComp
->removeEventListener(static_cast<XPropertiesChangeListener
*>(this));
612 m_xParent
= _rxParent
;
613 xComp
.set(m_xParent
, css::uno::UNO_QUERY
);
616 xComp
->addEventListener(static_cast<XPropertiesChangeListener
*>(this));
620 OUString SAL_CALL
OControlModel::getName()
625 OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME
) >>= aReturn
;
627 catch (const css::beans::UnknownPropertyException
&)
629 css::uno::Any
a(cppu::getCaughtException());
630 throw WrappedTargetRuntimeException(
631 u
"OControlModel::getName"_ustr
,
639 void SAL_CALL
OControlModel::setName(const OUString
& _rName
)
643 setFastPropertyValue(PROPERTY_ID_NAME
, Any(_rName
));
645 catch (const css::beans::UnknownPropertyException
&)
647 css::uno::Any
a(cppu::getCaughtException());
648 throw WrappedTargetRuntimeException(
649 u
"OControlModel::setName"_ustr
,
657 sal_Bool SAL_CALL
OControlModel::supportsService(const OUString
& _rServiceName
)
659 return cppu::supportsService(this, _rServiceName
);
662 Sequence
< OUString
> OControlModel::getAggregateServiceNames() const
664 Sequence
< OUString
> aAggServices
;
665 if (auto xInfo
= query_aggregation
<XServiceInfo
>(m_xAggregate
))
666 aAggServices
= xInfo
->getSupportedServiceNames();
670 Sequence
<OUString
> SAL_CALL
OControlModel::getSupportedServiceNames()
672 return ::comphelper::concatSequences(
673 getAggregateServiceNames(),
674 getSupportedServiceNames_Static()
678 Sequence
< OUString
> OControlModel::getSupportedServiceNames_Static()
680 return { FRM_SUN_FORMCOMPONENT
, u
"com.sun.star.form.FormControlModel"_ustr
};
684 void SAL_CALL
OControlModel::disposing(const css::lang::EventObject
& _rSource
)
686 // release the parent
687 if (_rSource
.Source
== m_xParent
)
689 osl::MutexGuard
aGuard(m_aMutex
);
694 if (auto xEvtLst
= query_aggregation
<css::lang::XEventListener
>(m_xAggregate
))
696 osl::MutexGuard
aGuard(m_aMutex
);
697 xEvtLst
->disposing(_rSource
);
703 void OControlModel::disposing()
705 OPropertySetAggregationHelper::disposing();
707 if (auto xComp
= query_aggregation
<css::lang::XComponent
>(m_xAggregate
))
710 setParent(Reference
<XFormComponent
>());
712 m_aPropertyBagHelper
.dispose();
715 void OControlModel::writeAggregate( const Reference
< XObjectOutputStream
>& _rxOutStream
) const
717 if (auto xPersist
= query_aggregation
<XPersistObject
>(m_xAggregate
))
718 xPersist
->write( _rxOutStream
);
721 void OControlModel::readAggregate( const Reference
< XObjectInputStream
>& _rxInStream
)
723 if (auto xPersist
= query_aggregation
<XPersistObject
>(m_xAggregate
))
724 xPersist
->read( _rxInStream
);
727 void SAL_CALL
OControlModel::write(const Reference
<css::io::XObjectOutputStream
>& _rxOutStream
)
729 osl::MutexGuard
aGuard(m_aMutex
);
731 // 1. writing the UnoControls
732 Reference
<css::io::XMarkableStream
> xMark(_rxOutStream
, UNO_QUERY
);
736 ResourceManager::loadString(RID_STR_INVALIDSTREAM
),
737 static_cast< ::cppu::OWeakObject
* >( this )
741 sal_Int32 nMark
= xMark
->createMark();
744 _rxOutStream
->writeLong(nLen
);
746 writeAggregate( _rxOutStream
);
748 // determining the length
749 nLen
= xMark
->offsetToMark(nMark
) - 4;
750 xMark
->jumpToMark(nMark
);
751 _rxOutStream
->writeLong(nLen
);
752 xMark
->jumpToFurthest();
753 xMark
->deleteMark(nMark
);
755 // 2. writing a version number
756 _rxOutStream
->writeShort(0x0003);
758 // 3. writing the general properties
759 ::comphelper::operator<<( _rxOutStream
, m_aName
);
760 _rxOutStream
->writeShort(m_nTabIndex
);
761 ::comphelper::operator<<( _rxOutStream
, m_aTag
); // 3rd version
764 // don't write any new members here: this wouldn't be compatible with older versions, as OControlModel
765 // is a base class which is called in derived classes "read" method. So if you increment the version
766 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
767 // in anything from data loss to crash.
771 void OControlModel::read(const Reference
<css::io::XObjectInputStream
>& InStream
)
773 osl::MutexGuard
aGuard(m_aMutex
);
775 Reference
<css::io::XMarkableStream
> xMark(InStream
, UNO_QUERY
);
779 ResourceManager::loadString(RID_STR_INVALIDSTREAM
),
780 static_cast< ::cppu::OWeakObject
* >( this )
784 // 1. reading the UnoControls
785 sal_Int32 nLen
= InStream
->readLong();
788 sal_Int32 nMark
= xMark
->createMark();
792 readAggregate( InStream
);
795 catch( const Exception
& )
797 DBG_UNHANDLED_EXCEPTION("forms.component");
800 xMark
->jumpToMark(nMark
);
801 InStream
->skipBytes(nLen
);
802 xMark
->deleteMark(nMark
);
805 // 2. reading the version number
806 sal_uInt16 nVersion
= InStream
->readShort();
808 // 3. reading the general properties
809 ::comphelper::operator>>( InStream
, m_aName
);
810 m_nTabIndex
= InStream
->readShort();
812 if (nVersion
> 0x0002)
813 ::comphelper::operator>>( InStream
, m_aTag
);
815 // we had a version where we wrote the help text
816 if (nVersion
== 0x0004)
817 readHelpTextCompatibly(InStream
);
819 DBG_ASSERT(nVersion
< 5, "OControlModel::read : suspicious version number !");
820 // 4 was the version where we wrote the help text
821 // later versions shouldn't exist (see write for a detailed comment)
824 PropertyState
OControlModel::getPropertyStateByHandle( sal_Int32 _nHandle
)
826 // simply compare the current and the default value
827 Any aCurrentValue
= getPropertyDefaultByHandle( _nHandle
);
828 Any aDefaultValue
; getFastPropertyValue( aDefaultValue
, _nHandle
);
830 bool bEqual
= aCurrentValue
== aDefaultValue
;
831 return bEqual
? PropertyState_DEFAULT_VALUE
: PropertyState_DIRECT_VALUE
;
834 void OControlModel::setPropertyToDefaultByHandle( sal_Int32 _nHandle
)
836 Any aDefault
= getPropertyDefaultByHandle( _nHandle
);
838 Any aConvertedValue
, aOldValue
;
839 if ( convertFastPropertyValue( aConvertedValue
, aOldValue
, _nHandle
, aDefault
) )
841 setFastPropertyValue_NoBroadcast( _nHandle
, aConvertedValue
);
842 // TODO: fire the property change
846 Any
OControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle
) const
851 case PROPERTY_ID_NAME
:
852 case PROPERTY_ID_TAG
:
853 aReturn
<<= OUString();
855 case PROPERTY_ID_CLASSID
:
856 aReturn
<<= sal_Int16(FormComponentType::CONTROL
);
858 case PROPERTY_ID_TABINDEX
:
859 aReturn
<<= sal_Int16(FRM_DEFAULT_TABINDEX
);
861 case PROPERTY_ID_NATIVE_LOOK
:
864 case PROPERTY_ID_STANDARD_THEME
:
865 case PROPERTY_ID_GENERATEVBAEVENTS
:
868 // added for exporting OCX control
869 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
870 aReturn
<<= sal_Int16(0);
872 case PROPERTY_ID_OBJ_ID_IN_MSO
:
873 aReturn
<<= sal_uInt16(INVALID_OBJ_ID_IN_MSO
);
876 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
877 m_aPropertyBagHelper
.getDynamicPropertyDefaultByHandle( _nHandle
, aReturn
);
879 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle
);
884 void OControlModel::getFastPropertyValue( Any
& _rValue
, sal_Int32 _nHandle
) const
888 case PROPERTY_ID_NAME
:
891 case PROPERTY_ID_TAG
:
894 case PROPERTY_ID_CLASSID
:
895 _rValue
<<= m_nClassId
;
897 case PROPERTY_ID_TABINDEX
:
898 _rValue
<<= m_nTabIndex
;
900 case PROPERTY_ID_NATIVE_LOOK
:
901 _rValue
<<= m_bNativeLook
;
903 case PROPERTY_ID_STANDARD_THEME
:
904 _rValue
<<= m_bStandardTheme
;
906 case PROPERTY_ID_GENERATEVBAEVENTS
:
907 _rValue
<<= m_bGenerateVbEvents
;
909 // added for exporting OCX control
910 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
911 _rValue
<<= m_nControlTypeinMSO
;
913 case PROPERTY_ID_OBJ_ID_IN_MSO
:
914 _rValue
<<= m_nObjIDinMSO
;
917 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
918 m_aPropertyBagHelper
.getDynamicFastPropertyValue( _nHandle
, _rValue
);
920 OPropertySetAggregationHelper::getFastPropertyValue( _rValue
, _nHandle
);
925 sal_Bool
OControlModel::convertFastPropertyValue(
926 Any
& _rConvertedValue
, Any
& _rOldValue
, sal_Int32 _nHandle
, const Any
& _rValue
)
928 bool bModified(false);
931 case PROPERTY_ID_NAME
:
932 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aName
);
934 case PROPERTY_ID_TAG
:
935 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aTag
);
937 case PROPERTY_ID_TABINDEX
:
938 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_nTabIndex
);
940 case PROPERTY_ID_NATIVE_LOOK
:
941 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_bNativeLook
);
943 case PROPERTY_ID_STANDARD_THEME
:
944 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_bStandardTheme
);
946 case PROPERTY_ID_GENERATEVBAEVENTS
:
947 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_bGenerateVbEvents
);
949 // added for exporting OCX control
950 case PROPERTY_ID_CONTROL_TYPE_IN_MSO
:
951 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_nControlTypeinMSO
);
953 case PROPERTY_ID_OBJ_ID_IN_MSO
:
954 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_nObjIDinMSO
);
957 if ( m_aPropertyBagHelper
.hasDynamicPropertyByHandle( _nHandle
) )
958 bModified
= m_aPropertyBagHelper
.convertDynamicFastPropertyValue( _nHandle
, _rValue
, _rConvertedValue
, _rOldValue
);
960 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle
);
966 void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle
, const Any
& _rValue
)
970 case PROPERTY_ID_NAME
:
971 DBG_ASSERT(_rValue
.getValueType() == cppu::UnoType
<OUString
>::get(),
972 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
975 case PROPERTY_ID_TAG
:
976 DBG_ASSERT(_rValue
.getValueType() == cppu::UnoType
<OUString
>::get(),
977 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
980 case PROPERTY_ID_TABINDEX
:
981 DBG_ASSERT(_rValue
.getValueType() == cppu::UnoType
<sal_Int16
>::get(),
982 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
983 _rValue
>>= m_nTabIndex
;
985 case PROPERTY_ID_NATIVE_LOOK
:
986 OSL_VERIFY( _rValue
>>= m_bNativeLook
);
988 case PROPERTY_ID_STANDARD_THEME
:
989 OSL_VERIFY( _rValue
>>= m_bStandardTheme
);
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
1013 css::beans::Property
* pProperties
= _rProps
.getArray();
1014 *pProperties
++ = css::beans::Property(PROPERTY_CLASSID
, PROPERTY_ID_CLASSID
, cppu::UnoType
<sal_Int16
>::get(), css::beans::PropertyAttribute::READONLY
| css::beans::PropertyAttribute::TRANSIENT
);
1015 *pProperties
++ = css::beans::Property(PROPERTY_NAME
, PROPERTY_ID_NAME
, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::BOUND
);
1016 *pProperties
++ = css::beans::Property(PROPERTY_NATIVE_LOOK
, PROPERTY_ID_NATIVE_LOOK
, cppu::UnoType
<bool>::get(),
1017 css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::TRANSIENT
);
1018 *pProperties
++ = css::beans::Property(PROPERTY_STANDARD_THEME
, PROPERTY_ID_STANDARD_THEME
, cppu::UnoType
<bool>::get(),
1019 css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::TRANSIENT
);
1020 *pProperties
++ = css::beans::Property(PROPERTY_TAG
, PROPERTY_ID_TAG
, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::BOUND
);
1021 *pProperties
++ = css::beans::Property(PROPERTY_GENERATEVBAEVENTS
, PROPERTY_ID_GENERATEVBAEVENTS
, cppu::UnoType
<sal_Bool
>::get(), css::beans::PropertyAttribute::TRANSIENT
);
1022 *pProperties
++ = css::beans::Property(PROPERTY_CONTROL_TYPE_IN_MSO
, PROPERTY_ID_CONTROL_TYPE_IN_MSO
, cppu::UnoType
<sal_Int16
>::get(), css::beans::PropertyAttribute::BOUND
);
1023 *pProperties
++ = css::beans::Property(PROPERTY_OBJ_ID_IN_MSO
, PROPERTY_ID_OBJ_ID_IN_MSO
, cppu::UnoType
<cppu::UnoUnsignedShortType
>::get(), css::beans::PropertyAttribute::BOUND
);
1024 DBG_ASSERT( pProperties
== _rProps
.getArray() + _rProps
.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
1027 void OControlModel::describeAggregateProperties( Sequence
< Property
>& /* [out] */ _rAggregateProps
) const
1029 if ( m_xAggregateSet
.is() )
1031 Reference
< XPropertySetInfo
> xPSI( m_xAggregateSet
->getPropertySetInfo() );
1033 _rAggregateProps
= xPSI
->getProperties();
1037 ::osl::Mutex
& OControlModel::getMutex()
1042 void OControlModel::describeFixedAndAggregateProperties( Sequence
< Property
>& _out_rFixedProperties
, Sequence
< Property
>& _out_rAggregateProperties
) const
1044 describeFixedProperties( _out_rFixedProperties
);
1045 describeAggregateProperties( _out_rAggregateProperties
);
1048 Reference
< XMultiPropertySet
> OControlModel::getPropertiesInterface()
1053 Reference
< XPropertySetInfo
> SAL_CALL
OControlModel::getPropertySetInfo()
1055 return createPropertySetInfo( getInfoHelper() );
1058 ::cppu::IPropertyArrayHelper
& OControlModel::getInfoHelper()
1060 return m_aPropertyBagHelper
.getInfoHelper();
1063 void SAL_CALL
OControlModel::addProperty( const OUString
& _rName
, ::sal_Int16 _nAttributes
, const Any
& _rInitialValue
)
1065 m_aPropertyBagHelper
.addProperty( _rName
, _nAttributes
, _rInitialValue
);
1068 void SAL_CALL
OControlModel::removeProperty( const OUString
& _rName
)
1070 m_aPropertyBagHelper
.removeProperty( _rName
);
1073 Sequence
< PropertyValue
> SAL_CALL
OControlModel::getPropertyValues()
1075 return m_aPropertyBagHelper
.getPropertyValues();
1078 void SAL_CALL
OControlModel::setPropertyValues( const Sequence
< PropertyValue
>& _rProps
)
1080 m_aPropertyBagHelper
.setPropertyValues( _rProps
);
1083 void OControlModel::lockInstance( LockAccess
)
1086 osl_atomic_increment( &m_lockCount
);
1089 oslInterlockedCount
OControlModel::unlockInstance( LockAccess
)
1091 OSL_ENSURE( m_lockCount
> 0, "OControlModel::unlockInstance: not locked!" );
1092 oslInterlockedCount lockCount
= osl_atomic_decrement( &m_lockCount
);
1097 void OControlModel::firePropertyChanges( const std::vector
< sal_Int32
>& _rHandles
, const std::vector
< Any
>& _rOldValues
,
1098 const std::vector
< Any
>& _rNewValues
, LockAccess
)
1100 OPropertySetHelper::fire(
1101 const_cast< std::vector
< sal_Int32
>& >( _rHandles
).data(),
1109 // OBoundControlModel
1110 Any SAL_CALL
OBoundControlModel::queryAggregation( const Type
& _rType
)
1112 Any
aReturn( OControlModel::queryAggregation(_rType
) );
1113 if (!aReturn
.hasValue())
1115 aReturn
= OBoundControlModel_BASE1::queryInterface(_rType
);
1117 if ( !aReturn
.hasValue() && m_bCommitable
)
1118 aReturn
= OBoundControlModel_COMMITTING::queryInterface( _rType
);
1120 if ( !aReturn
.hasValue() && m_bSupportsExternalBinding
)
1121 aReturn
= OBoundControlModel_BINDING::queryInterface( _rType
);
1123 if ( !aReturn
.hasValue() && m_bSupportsValidation
)
1124 aReturn
= OBoundControlModel_VALIDATION::queryInterface( _rType
);
1129 OBoundControlModel::OBoundControlModel(
1130 const Reference
< XComponentContext
>& _rxFactory
,
1131 const OUString
& _rUnoControlModelTypeName
, const OUString
& _rDefault
,
1132 const bool _bCommitable
, const bool _bSupportExternalBinding
, const bool _bSupportsValidation
)
1133 :OControlModel( _rxFactory
, _rUnoControlModelTypeName
, _rDefault
, false )
1134 ,OPropertyChangeListener()
1135 ,m_nValuePropertyAggregateHandle( -1 )
1136 ,m_nFieldType( DataType::OTHER
)
1137 ,m_bValuePropertyMayBeVoid( false )
1138 ,m_aResetHelper( *this, m_aMutex
)
1139 ,m_aUpdateListeners(m_aMutex
)
1140 ,m_aFormComponentListeners( m_aMutex
)
1141 ,m_bInputRequired( false )
1142 ,m_bFormListening( false )
1145 ,m_bCommitable(_bCommitable
)
1146 ,m_bSupportsExternalBinding( _bSupportExternalBinding
)
1147 ,m_bSupportsValidation( _bSupportsValidation
)
1148 ,m_bForwardValueChanges(true)
1149 ,m_bTransferringValue( false )
1150 ,m_bIsCurrentValueValid( true )
1151 ,m_bBindingControlsRO( false )
1152 ,m_bBindingControlsEnable( false )
1153 ,m_eControlValueChangeInstigator( eOther
)
1154 ,m_aLabelServiceName(FRM_SUN_COMPONENT_FIXEDTEXT
)
1156 // start property listening at the aggregate
1157 implInitAggMultiplexer( );
1160 OBoundControlModel::OBoundControlModel(
1161 const OBoundControlModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
)
1162 :OControlModel( _pOriginal
, _rxFactory
, true, false )
1163 ,OPropertyChangeListener()
1164 ,m_nValuePropertyAggregateHandle( _pOriginal
->m_nValuePropertyAggregateHandle
)
1165 ,m_nFieldType( DataType::OTHER
)
1166 ,m_bValuePropertyMayBeVoid( _pOriginal
->m_bValuePropertyMayBeVoid
)
1167 ,m_aResetHelper( *this, m_aMutex
)
1168 ,m_aUpdateListeners( m_aMutex
)
1169 ,m_aFormComponentListeners( m_aMutex
)
1170 ,m_xValidator( _pOriginal
->m_xValidator
)
1171 ,m_bInputRequired( false )
1172 ,m_bFormListening( false )
1174 ,m_bRequired( false )
1175 ,m_bCommitable( _pOriginal
->m_bCommitable
)
1176 ,m_bSupportsExternalBinding( _pOriginal
->m_bSupportsExternalBinding
)
1177 ,m_bSupportsValidation( _pOriginal
->m_bSupportsValidation
)
1178 ,m_bForwardValueChanges( true )
1179 ,m_bTransferringValue( false )
1180 ,m_bIsCurrentValueValid( _pOriginal
->m_bIsCurrentValueValid
)
1181 ,m_bBindingControlsRO( false )
1182 ,m_bBindingControlsEnable( false )
1183 ,m_eControlValueChangeInstigator( eOther
)
1185 // start property listening at the aggregate
1186 implInitAggMultiplexer( );
1187 m_aLabelServiceName
= _pOriginal
->m_aLabelServiceName
;
1188 m_sValuePropertyName
= _pOriginal
->m_sValuePropertyName
;
1189 m_nValuePropertyAggregateHandle
= _pOriginal
->m_nValuePropertyAggregateHandle
;
1190 m_bValuePropertyMayBeVoid
= _pOriginal
->m_bValuePropertyMayBeVoid
;
1191 m_aValuePropertyType
= _pOriginal
->m_aValuePropertyType
;
1192 m_aControlSource
= _pOriginal
->m_aControlSource
;
1193 m_bInputRequired
= _pOriginal
->m_bInputRequired
;
1194 // m_xLabelControl, though being a property, is not to be cloned, not even the reference will be transferred.
1195 // (the former should be clear - a clone of the object we're only referencing does not make sense)
1196 // (the second would violate the restriction for label controls that they're part of the
1197 // same form component hierarchy - we ourself are no part, yet, so we can't have a label control)
1198 // start listening for changes at the value property
1199 implInitValuePropertyListening( );
1202 OBoundControlModel::~OBoundControlModel()
1204 if ( !OComponentHelper::rBHelper
.bDisposed
)
1210 doResetDelegator( );
1211 OSL_ENSURE( m_pAggPropMultiplexer
, "OBoundControlModel::~OBoundControlModel: what about my property multiplexer?" );
1212 if ( m_pAggPropMultiplexer
)
1214 m_pAggPropMultiplexer
->dispose();
1215 m_pAggPropMultiplexer
= nullptr;
1219 void OBoundControlModel::clonedFrom( const OControlModel
* _pOriginal
)
1221 const OBoundControlModel
* pBoundOriginal
= static_cast< const OBoundControlModel
* >( _pOriginal
);
1222 // the value binding can be handled as if somebody called setValueBinding here
1223 // By definition, bindings can be share between bindables
1224 if ( !(pBoundOriginal
&& pBoundOriginal
->m_xExternalBinding
.is()) )
1229 setValueBinding( pBoundOriginal
->m_xExternalBinding
);
1232 catch( const Exception
& )
1234 DBG_UNHANDLED_EXCEPTION("forms.component");
1238 void OBoundControlModel::implInitAggMultiplexer( )
1240 osl_atomic_increment( &m_refCount
);
1241 if ( m_xAggregateSet
.is() )
1243 m_pAggPropMultiplexer
= new OPropertyChangeMultiplexer( this, m_xAggregateSet
, false );
1246 osl_atomic_decrement( &m_refCount
);
1250 void OBoundControlModel::implInitValuePropertyListening( ) const
1252 // start listening for changes at the value property
1253 // There are three pre-requisites for this to be done:
1254 // 1. We support external value bindings. In this case, the changes in the control value need to
1255 // be propagated to the external binding immediately when they happen
1256 // 2. We support external validation. In this case, we need to listen for changes in the value
1257 // property, since we need to revalidate then.
1258 // 3. We are not committable. In this case, changes in the control value need to be propagated
1259 // to the database column immediately when they happen.
1260 if ( m_bSupportsExternalBinding
|| m_bSupportsValidation
|| !m_bCommitable
)
1262 OSL_ENSURE( m_pAggPropMultiplexer
, "OBoundControlModel::implInitValuePropertyListening: no multiplexer!" );
1263 if ( m_pAggPropMultiplexer
&& !m_sValuePropertyName
.isEmpty() )
1264 m_pAggPropMultiplexer
->addProperty( m_sValuePropertyName
);
1268 void OBoundControlModel::initOwnValueProperty( const OUString
& i_rValuePropertyName
)
1270 OSL_PRECOND( m_sValuePropertyName
.isEmpty() && -1 == m_nValuePropertyAggregateHandle
,
1271 "OBoundControlModel::initOwnValueProperty: value property is already initialized!" );
1272 OSL_ENSURE( !i_rValuePropertyName
.isEmpty(), "OBoundControlModel::initOwnValueProperty: invalid property name!" );
1273 m_sValuePropertyName
= i_rValuePropertyName
;
1276 void OBoundControlModel::initValueProperty( const OUString
& _rValuePropertyName
, sal_Int32 _nValuePropertyExternalHandle
)
1278 OSL_PRECOND( m_sValuePropertyName
.isEmpty() && -1 == m_nValuePropertyAggregateHandle
,
1279 "OBoundControlModel::initValueProperty: value property is already initialized!" );
1280 OSL_ENSURE( !_rValuePropertyName
.isEmpty(), "OBoundControlModel::initValueProperty: invalid property name!" );
1281 OSL_ENSURE( _nValuePropertyExternalHandle
!= -1, "OBoundControlModel::initValueProperty: invalid property handle!" );
1283 m_sValuePropertyName
= _rValuePropertyName
;
1284 m_nValuePropertyAggregateHandle
= getOriginalHandle( _nValuePropertyExternalHandle
);
1285 OSL_ENSURE( m_nValuePropertyAggregateHandle
!= -1, "OBoundControlModel::initValueProperty: unable to find the original handle!" );
1287 if ( m_nValuePropertyAggregateHandle
!= -1 )
1289 Reference
< XPropertySetInfo
> xPropInfo( m_xAggregateSet
->getPropertySetInfo(), UNO_SET_THROW
);
1290 Property aValuePropDesc
= xPropInfo
->getPropertyByName( m_sValuePropertyName
);
1291 m_aValuePropertyType
= aValuePropDesc
.Type
;
1292 m_bValuePropertyMayBeVoid
= ( aValuePropDesc
.Attributes
& PropertyAttribute::MAYBEVOID
) != 0;
1295 // start listening for changes at the value property
1296 implInitValuePropertyListening( );
1299 void OBoundControlModel::suspendValueListening( )
1301 OSL_PRECOND( !m_sValuePropertyName
.isEmpty(), "OBoundControlModel::suspendValueListening: don't have a value property!" );
1302 OSL_PRECOND( m_pAggPropMultiplexer
, "OBoundControlModel::suspendValueListening: I *am* not listening!" );
1304 if ( m_pAggPropMultiplexer
)
1305 m_pAggPropMultiplexer
->lock();
1308 void OBoundControlModel::resumeValueListening( )
1310 OSL_PRECOND( !m_sValuePropertyName
.isEmpty(), "OBoundControlModel::resumeValueListening: don't have a value property!" );
1311 OSL_PRECOND( m_pAggPropMultiplexer
, "OBoundControlModel::resumeValueListening: I *am* not listening at all!" );
1312 OSL_PRECOND( !m_pAggPropMultiplexer
|| m_pAggPropMultiplexer
->locked(), "OBoundControlModel::resumeValueListening: listening not suspended currently!" );
1313 if ( m_pAggPropMultiplexer
)
1314 m_pAggPropMultiplexer
->unlock();
1317 Sequence
< Type
> OBoundControlModel::_getTypes()
1320 OControlModel::_getTypes(),
1321 OBoundControlModel_BASE1::getTypes()
1324 if ( m_bCommitable
)
1325 aTypes
.addTypes( OBoundControlModel_COMMITTING::getTypes() );
1327 if ( m_bSupportsExternalBinding
)
1328 aTypes
.addTypes( OBoundControlModel_BINDING::getTypes() );
1330 if ( m_bSupportsValidation
)
1331 aTypes
.addTypes( OBoundControlModel_VALIDATION::getTypes() );
1332 return aTypes
.getTypes();
1336 void OBoundControlModel::disposing()
1338 OControlModel::disposing();
1340 osl::MutexGuard
aGuard(m_aMutex
);
1342 if ( m_pAggPropMultiplexer
)
1343 m_pAggPropMultiplexer
->dispose();
1345 // notify all our listeners
1346 css::lang::EventObject
aEvt( static_cast< XWeak
* >( this ) );
1347 m_aUpdateListeners
.disposeAndClear( aEvt
);
1348 m_aResetHelper
.disposing();
1350 // disconnect from our database column
1351 // TODO: could we replace the following 5 lines with a call to impl_disconnectDatabaseColumn_noNotify?
1352 // The only more thing which it does is calling onDisconnectedDbColumn - could this
1353 // cause trouble? At least when we continue to call OControlModel::disposing before, it *may*.
1356 getField()->removePropertyChangeListener( PROPERTY_VALUE
, this );
1360 m_xCursor
= nullptr;
1361 Reference
< XComponent
> xComp( m_xLabelControl
, UNO_QUERY
);
1363 xComp
->removeEventListener(static_cast< XEventListener
* >( static_cast< XPropertyChangeListener
* >( this ) ) );
1364 // disconnect from our external value binding
1365 if ( hasExternalValueBinding() )
1366 disconnectExternalValueBinding();
1367 // ditto for the validator
1368 if ( hasValidator() )
1369 disconnectValidator( );
1372 void OBoundControlModel::onValuePropertyChange( ControlModelLock
& i_rControLock
)
1374 if ( hasExternalValueBinding() )
1376 // the control value changed, while we have an external value binding
1377 // -> forward the value to it
1378 if ( m_eControlValueChangeInstigator
!= eExternalBinding
)
1379 transferControlValueToExternal( i_rControLock
);
1382 else if ( !m_bCommitable
&& m_xColumnUpdate
.is() )
1384 // the control value changed, while we are bound to a database column,
1385 // but not committable (which means changes in the control have to be reflected to
1386 // the underlying database column immediately)
1387 // -> forward the value to the database column
1388 if ( m_eControlValueChangeInstigator
!= eDbColumnBinding
)
1389 commitControlValueToDbColumn( false );
1392 // validate the new value
1393 if ( m_bSupportsValidation
)
1394 recheckValidity( true );
1397 void OBoundControlModel::_propertyChanged( const PropertyChangeEvent
& _rEvt
)
1399 ControlModelLock
aLock( *this );
1400 OSL_ENSURE( _rEvt
.PropertyName
== m_sValuePropertyName
,
1401 "OBoundControlModel::_propertyChanged: where did this come from (1)?" );
1402 OSL_ENSURE( m_pAggPropMultiplexer
&& !m_pAggPropMultiplexer
->locked(),
1403 "OBoundControlModel::_propertyChanged: where did this come from (2)?" );
1404 if ( _rEvt
.PropertyName
== m_sValuePropertyName
)
1406 onValuePropertyChange( aLock
);
1410 void OBoundControlModel::startAggregatePropertyListening( const OUString
& _rPropertyName
)
1412 OSL_PRECOND( m_pAggPropMultiplexer
, "OBoundControlModel::startAggregatePropertyListening: no multiplexer!" );
1413 OSL_ENSURE( !_rPropertyName
.isEmpty(), "OBoundControlModel::startAggregatePropertyListening: invalid property name!" );
1414 if ( m_pAggPropMultiplexer
&& !_rPropertyName
.isEmpty() )
1416 m_pAggPropMultiplexer
->addProperty( _rPropertyName
);
1420 void OBoundControlModel::doFormListening( const bool _bStart
)
1422 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::doFormListening: external value binding should overrule the database binding!" );
1423 if ( isFormListening() == _bStart
)
1425 if ( m_xAmbientForm
.is() )
1426 _bStart
? m_xAmbientForm
->addLoadListener( this ) : m_xAmbientForm
->removeLoadListener( this );
1427 Reference
< XLoadable
> xParentLoadable( getParent(), UNO_QUERY
);
1428 if ( getParent().is() && !xParentLoadable
.is() )
1430 // if our parent does not directly support the XLoadable interface, then it might support the
1431 // XRowSetSupplier/XRowSetChangeBroadcaster interfaces. In this case we have to listen for changes
1432 // broadcasted by the latter.
1433 Reference
< XRowSetChangeBroadcaster
> xRowSetBroadcaster( getParent(), UNO_QUERY
);
1434 if ( xRowSetBroadcaster
.is() )
1435 _bStart
? xRowSetBroadcaster
->addRowSetChangeListener( this ) : xRowSetBroadcaster
->removeRowSetChangeListener( this );
1438 m_bFormListening
= _bStart
&& m_xAmbientForm
.is();
1442 void SAL_CALL
OBoundControlModel::setParent(const Reference
<XInterface
>& _rxParent
)
1444 ControlModelLock
aLock( *this );
1445 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
1446 if ( getParent() == _rxParent
)
1448 // disconnect from database column (which is controlled by parent, directly or indirectly)
1450 impl_disconnectDatabaseColumn_noNotify();
1451 // log off old listeners
1452 if ( isFormListening() )
1453 doFormListening( false );
1454 // actually set the new parent
1455 OControlModel::setParent( _rxParent
);
1456 // a new parent means a new ambient form
1457 impl_determineAmbientForm_nothrow();
1458 if ( !hasExternalValueBinding() )
1460 // log on new listeners
1461 doFormListening( true );
1462 // re-connect to database column of the new parent
1463 if ( m_xAmbientForm
.is() && m_xAmbientForm
->isLoaded() )
1464 impl_connectDatabaseColumn_noNotify( false );
1469 void SAL_CALL
OBoundControlModel::disposing(const css::lang::EventObject
& _rEvent
)
1471 ControlModelLock
aLock( *this );
1472 if ( _rEvent
.Source
== getField() )
1477 else if ( _rEvent
.Source
== m_xLabelControl
)
1479 Reference
<XPropertySet
> xOldValue
= m_xLabelControl
;
1480 m_xLabelControl
= nullptr;
1481 // fire a propertyChanged (when we leave aLock's scope)
1482 aLock
.addPropertyNotification( PROPERTY_ID_CONTROLLABEL
, Any( xOldValue
), Any( m_xLabelControl
) );
1485 else if ( _rEvent
.Source
== m_xExternalBinding
)
1486 { // *first* check for the external binding
1487 disconnectExternalValueBinding( );
1490 else if ( _rEvent
.Source
== m_xValidator
)
1491 { // *then* check for the validator. Reason is that bindings may also act as validator at the same
1492 // time, in this case, the validator is automatically revoked when the binding is revoked
1493 disconnectValidator( );
1497 OControlModel::disposing(_rEvent
);
1501 css::uno::Sequence
<OUString
> SAL_CALL
OBoundControlModel::getSupportedServiceNames()
1503 return ::comphelper::combineSequences(
1504 getAggregateServiceNames(),
1505 getSupportedServiceNames_Static()
1509 Sequence
< OUString
> OBoundControlModel::getSupportedServiceNames_Static()
1511 static constexpr OUString aOwnServiceNames
[] { u
"com.sun.star.form.DataAwareControlModel"_ustr
};
1512 return ::comphelper::concatSequences(
1513 OControlModel::getSupportedServiceNames_Static(),
1519 void SAL_CALL
OBoundControlModel::write( const Reference
<css::io::XObjectOutputStream
>& _rxOutStream
)
1521 OControlModel::write(_rxOutStream
);
1522 osl::MutexGuard
aGuard(m_aMutex
);
1524 _rxOutStream
->writeShort(0x0002);
1526 ::comphelper::operator<<( _rxOutStream
, m_aControlSource
);
1527 // !!! IMPORTANT NOTE !!!
1528 // don't write any new members here: this wouldn't be compatible with older versions, as OBoundControlModel
1529 // is a base class which is called in derived classes "read" method. So if you increment the version
1530 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
1531 // in anything from data loss to crash.
1532 // (use writeCommonProperties instead, this is called in derived classes write-method)
1536 void OBoundControlModel::defaultCommonProperties()
1538 Reference
<css::lang::XComponent
> xComp(m_xLabelControl
, UNO_QUERY
);
1540 xComp
->removeEventListener(static_cast<css::lang::XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
1541 m_xLabelControl
= nullptr;
1544 void OBoundControlModel::readCommonProperties(const Reference
<css::io::XObjectInputStream
>& _rxInStream
)
1546 sal_Int32 nLen
= _rxInStream
->readLong();
1547 Reference
<css::io::XMarkableStream
> xMark(_rxInStream
, UNO_QUERY
);
1548 DBG_ASSERT(xMark
.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !");
1549 sal_Int32 nMark
= xMark
->createMark();
1550 // read the reference to the label control
1551 Reference
<css::io::XPersistObject
> xPersist
;
1552 sal_Int32 nUsedFlag
;
1553 nUsedFlag
= _rxInStream
->readLong();
1555 xPersist
= _rxInStream
->readObject();
1556 m_xLabelControl
.set(xPersist
, css::uno::UNO_QUERY
);
1557 Reference
< XComponent
> xComp( m_xLabelControl
, UNO_QUERY
);
1559 xComp
->addEventListener(static_cast<css::lang::XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
1560 // read any other new common properties here
1561 // skip the remaining bytes
1562 xMark
->jumpToMark(nMark
);
1563 _rxInStream
->skipBytes(nLen
);
1564 xMark
->deleteMark(nMark
);
1567 void OBoundControlModel::writeCommonProperties(const Reference
<css::io::XObjectOutputStream
>& _rxOutStream
)
1569 Reference
<css::io::XMarkableStream
> xMark(_rxOutStream
, UNO_QUERY
);
1570 DBG_ASSERT(xMark
.is(), "OBoundControlModel::writeCommonProperties : can only work with markable streams !");
1571 sal_Int32 nMark
= xMark
->createMark();
1572 // a placeholder where we will write the overall length (later in this method)
1574 _rxOutStream
->writeLong(nLen
);
1575 // write the reference to the label control
1576 Reference
<css::io::XPersistObject
> xPersist(m_xLabelControl
, UNO_QUERY
);
1577 sal_Int32 nUsedFlag
= 0;
1580 _rxOutStream
->writeLong(nUsedFlag
);
1582 _rxOutStream
->writeObject(xPersist
);
1583 // write any other new common properties here
1584 // write the correct length at the beginning of the block
1585 nLen
= xMark
->offsetToMark(nMark
) - sizeof(nLen
);
1586 xMark
->jumpToMark(nMark
);
1587 _rxOutStream
->writeLong(nLen
);
1588 xMark
->jumpToFurthest();
1589 xMark
->deleteMark(nMark
);
1592 void SAL_CALL
OBoundControlModel::read( const Reference
< css::io::XObjectInputStream
>& _rxInStream
)
1594 OControlModel::read(_rxInStream
);
1595 osl::MutexGuard
aGuard(m_aMutex
);
1596 _rxInStream
->readShort(); // version;
1597 ::comphelper::operator>>( _rxInStream
, m_aControlSource
);
1600 void OBoundControlModel::getFastPropertyValue(Any
& rValue
, sal_Int32 nHandle
) const
1604 case PROPERTY_ID_INPUT_REQUIRED
:
1605 rValue
<<= m_bInputRequired
;
1607 case PROPERTY_ID_CONTROLSOURCEPROPERTY
:
1608 rValue
<<= m_sValuePropertyName
;
1610 case PROPERTY_ID_CONTROLSOURCE
:
1611 rValue
<<= m_aControlSource
;
1613 case PROPERTY_ID_BOUNDFIELD
:
1614 rValue
<<= getField();
1616 case PROPERTY_ID_CONTROLLABEL
:
1617 if (!m_xLabelControl
.is())
1620 rValue
<<= m_xLabelControl
;
1623 OControlModel::getFastPropertyValue(rValue
, nHandle
);
1627 sal_Bool
OBoundControlModel::convertFastPropertyValue(
1628 Any
& _rConvertedValue
, Any
& _rOldValue
,
1632 bool bModified(false);
1635 case PROPERTY_ID_INPUT_REQUIRED
:
1636 bModified
= tryPropertyValue( _rConvertedValue
, _rOldValue
, _rValue
, m_bInputRequired
);
1638 case PROPERTY_ID_CONTROLSOURCE
:
1639 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aControlSource
);
1641 case PROPERTY_ID_BOUNDFIELD
:
1642 SAL_WARN("forms.component", "OBoundControlModel::convertFastPropertyValue: BoundField should be a read-only property !" );
1643 throw css::lang::IllegalArgumentException();
1644 case PROPERTY_ID_CONTROLLABEL
:
1645 if (!_rValue
.hasValue())
1646 { // property set to void
1647 _rConvertedValue
= Any();
1648 getFastPropertyValue(_rOldValue
, _nHandle
);
1649 bModified
= m_xLabelControl
.is();
1654 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_xLabelControl
);
1655 if (!m_xLabelControl
.is())
1656 // an empty interface is interpreted as VOID
1662 bModified
= OControlModel::convertFastPropertyValue(_rConvertedValue
, _rOldValue
, _nHandle
, _rValue
);
1667 Any
OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle
) const
1672 case PROPERTY_ID_INPUT_REQUIRED
:
1675 case PROPERTY_ID_CONTROLSOURCE
:
1676 aDefault
<<= OUString();
1678 case PROPERTY_ID_CONTROLLABEL
:
1679 aDefault
<<= Reference
< XPropertySet
>();
1685 void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle
, const Any
& rValue
)
1689 case PROPERTY_ID_INPUT_REQUIRED
:
1690 OSL_VERIFY( rValue
>>= m_bInputRequired
);
1692 case PROPERTY_ID_CONTROLSOURCE
:
1693 OSL_VERIFY( rValue
>>= m_aControlSource
);
1695 case PROPERTY_ID_BOUNDFIELD
:
1696 SAL_WARN("forms.component", "OBoundControlModel::setFastPropertyValue_NoBroadcast : BoundField should be a read-only property !");
1697 throw css::lang::IllegalArgumentException();
1698 case PROPERTY_ID_CONTROLLABEL
:
1700 if ( rValue
.hasValue() && ( rValue
.getValueTypeClass() != TypeClass_INTERFACE
) )
1701 throw css::lang::IllegalArgumentException();
1702 Reference
< XInterface
> xNewValue( rValue
, UNO_QUERY
);
1703 if ( !xNewValue
.is() )
1704 { // set property to "void"
1705 Reference
< XComponent
> xComp( m_xLabelControl
, UNO_QUERY
);
1707 xComp
->removeEventListener( static_cast< XPropertyChangeListener
* >( this ) );
1708 m_xLabelControl
= nullptr;
1712 Reference
< XControlModel
> xAsModel ( xNewValue
, UNO_QUERY
);
1713 Reference
< XServiceInfo
> xAsServiceInfo ( xAsModel
, UNO_QUERY
);
1714 Reference
< XPropertySet
> xAsPropSet ( xAsServiceInfo
, UNO_QUERY
);
1715 Reference
< XChild
> xAsChild ( xAsPropSet
, UNO_QUERY
);
1716 if ( !xAsChild
.is() || !xAsServiceInfo
->supportsService( m_aLabelServiceName
) )
1718 throw css::lang::IllegalArgumentException();
1721 // Check if we and the given model have a common ancestor (up to the forms collection)
1722 Reference
<XChild
> xCont(this);
1723 Reference
< XInterface
> xMyTopLevel
= xCont
->getParent();
1724 while (xMyTopLevel
.is())
1726 Reference
<XForm
> xAsForm(xMyTopLevel
, UNO_QUERY
);
1730 Reference
<XChild
> xLoopAsChild(xMyTopLevel
, UNO_QUERY
);
1731 xMyTopLevel
= xLoopAsChild
.is() ? xLoopAsChild
->getParent() : Reference
< XInterface
>();
1734 Reference
< XInterface
> xNewTopLevel
= xAsChild
->getParent();
1735 while (xNewTopLevel
.is())
1737 Reference
<XForm
> xAsForm(xNewTopLevel
, UNO_QUERY
);
1740 Reference
<XChild
> xLoopAsChild(xNewTopLevel
, UNO_QUERY
);
1741 xNewTopLevel
= xLoopAsChild
.is() ? xLoopAsChild
->getParent() : Reference
< XInterface
>();
1744 if (xNewTopLevel
!= xMyTopLevel
)
1746 // the both objects don't belong to the same forms collection -> not acceptable
1747 throw css::lang::IllegalArgumentException();
1750 m_xLabelControl
= std::move(xAsPropSet
);
1751 Reference
<css::lang::XComponent
> xComp(m_xLabelControl
, UNO_QUERY
);
1753 xComp
->addEventListener(static_cast<css::lang::XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
1758 OControlModel::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
1762 // XPropertyChangeListener
1763 void SAL_CALL
OBoundControlModel::propertyChange( const PropertyChangeEvent
& evt
)
1765 // if the DBColumn value changed, transfer it to the control
1766 if ( evt
.PropertyName
== PROPERTY_VALUE
)
1768 OSL_ENSURE( evt
.Source
== getField(), "OBoundControlModel::propertyChange: value changes from components other than our database column?" );
1769 osl::MutexGuard
aGuard(m_aMutex
);
1770 if ( m_bForwardValueChanges
&& m_xColumn
.is() )
1771 transferDbValueToControl();
1776 OSL_ENSURE( evt
.Source
== m_xExternalBinding
, "OBoundControlModel::propertyChange: where did this come from?" );
1777 // our binding has properties which can control properties of ourself
1778 OUString sBindingControlledProperty
;
1779 bool bForwardToLabelControl
= false;
1780 if ( evt
.PropertyName
== PROPERTY_READONLY
)
1782 sBindingControlledProperty
= PROPERTY_READONLY
;
1785 else if ( evt
.PropertyName
== PROPERTY_RELEVANT
)
1787 sBindingControlledProperty
= PROPERTY_ENABLED
;
1788 bForwardToLabelControl
= true;
1795 setPropertyValue( sBindingControlledProperty
, evt
.NewValue
);
1796 if ( bForwardToLabelControl
&& m_xLabelControl
.is() )
1797 m_xLabelControl
->setPropertyValue( sBindingControlledProperty
, evt
.NewValue
);
1800 catch( const Exception
& )
1802 DBG_UNHANDLED_EXCEPTION("forms.component");
1803 SAL_WARN("forms.component", "OBoundControlModel::propertyChange: could not adjust my binding-controlled property!");
1809 void SAL_CALL
OBoundControlModel::onRowSetChanged( const EventObject
& /*i_Event*/ )
1811 ControlModelLock
aLock( *this );
1812 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
1813 // disconnect from database column (which is controlled by parent, directly or indirectly)
1815 impl_disconnectDatabaseColumn_noNotify();
1816 // log off old listeners
1817 if ( isFormListening() )
1818 doFormListening( false );
1819 // determine the new ambient form
1820 impl_determineAmbientForm_nothrow();
1821 // log on new listeners
1822 doFormListening( true );
1823 // re-connect to database column if needed and possible
1824 if ( m_xAmbientForm
.is() && m_xAmbientForm
->isLoaded() )
1825 impl_connectDatabaseColumn_noNotify( false );
1829 void SAL_CALL
OBoundControlModel::addUpdateListener(const Reference
<XUpdateListener
>& _rxListener
)
1831 m_aUpdateListeners
.addInterface(_rxListener
);
1834 void SAL_CALL
OBoundControlModel::removeUpdateListener(const Reference
< XUpdateListener
>& _rxListener
)
1836 m_aUpdateListeners
.removeInterface(_rxListener
);
1839 sal_Bool SAL_CALL
OBoundControlModel::commit()
1841 ControlModelLock
aLock( *this );
1842 OSL_PRECOND( m_bCommitable
, "OBoundControlModel::commit: invalid call (I'm not committable!) " );
1843 if ( hasExternalValueBinding() )
1845 // in most cases, no action is required: For most derivees, we know the value property of
1846 // our control (see initValueProperty), and when an external binding is active, we
1847 // instantly forward all changes in this property to the external binding.
1848 if ( m_sValuePropertyName
.isEmpty() )
1849 // but for those derivees which did not use this feature, we need an
1850 // explicit transfer
1851 transferControlValueToExternal( aLock
);
1855 OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" );
1856 // we reach this only if we're not working with an external binding
1859 ::comphelper::OInterfaceIteratorHelper3
aIter( m_aUpdateListeners
);
1861 aEvent
.Source
= static_cast< XWeak
* >( this );
1862 bool bSuccess
= true;
1865 while (aIter
.hasMoreElements() && bSuccess
)
1866 bSuccess
= aIter
.next()->approveUpdate( aEvent
);
1873 if ( m_xColumnUpdate
.is() )
1874 bSuccess
= commitControlValueToDbColumn( false );
1877 catch(const Exception
&)
1887 m_aUpdateListeners
.notifyEach( &XUpdateListener::updated
, aEvent
);
1892 void OBoundControlModel::resetField()
1894 m_xColumnUpdate
.clear();
1897 m_nFieldType
= DataType::OTHER
;
1900 void OBoundControlModel::connectToField(const Reference
<XRowSet
>& rForm
)
1902 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::connectToField: invalid call (have an external binding)!" );
1903 // if there's a connection to the database
1904 if (!(rForm
.is() && getConnection(rForm
).is()))
1907 // determine field and PropertyChangeListener
1909 Reference
<XPropertySet
> xFieldCandidate
;
1912 Reference
<XColumnsSupplier
> xColumnsSupplier(m_xCursor
, UNO_QUERY
);
1913 DBG_ASSERT(xColumnsSupplier
.is(), "OBoundControlModel::connectToField : the row set should support the css::sdb::ResultSet service !");
1914 if (xColumnsSupplier
.is())
1916 Reference
<XNameAccess
> xColumns
= xColumnsSupplier
->getColumns();
1917 if (xColumns
.is() && xColumns
->hasByName(m_aControlSource
))
1919 OSL_VERIFY( xColumns
->getByName(m_aControlSource
) >>= xFieldCandidate
);
1928 sal_Int32 nFieldType
= DataType::OTHER
;
1929 if ( xFieldCandidate
.is() )
1931 xFieldCandidate
->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
;
1932 if ( approveDbColumnType( nFieldType
) )
1933 impl_setField_noNotify( xFieldCandidate
);
1937 impl_setField_noNotify( nullptr );
1938 if ( m_xField
.is() )
1940 if ( m_xField
->getPropertySetInfo()->hasPropertyByName( PROPERTY_VALUE
) )
1942 m_nFieldType
= nFieldType
;
1943 // listen to changing values
1944 m_xField
->addPropertyChangeListener( PROPERTY_VALUE
, this );
1945 m_xColumnUpdate
.set( m_xField
, UNO_QUERY
);
1946 m_xColumn
.set( m_xField
, UNO_QUERY
);
1947 sal_Int32 nNullableFlag
= ColumnValue::NO_NULLS
;
1948 m_xField
->getPropertyValue(PROPERTY_ISNULLABLE
) >>= nNullableFlag
;
1949 // tdf#122319 - don't allow nullable form components if input is required
1950 m_bRequired
= (ColumnValue::NO_NULLS
== nNullableFlag
|| m_bInputRequired
);
1951 // we're optimistic: in case of ColumnValue_NULLABLE_UNKNOWN we assume nullability...
1955 SAL_WARN("forms.component", "OBoundControlModel::connectToField: property " << PROPERTY_VALUE
<< " not supported!");
1956 impl_setField_noNotify( nullptr );
1963 catch( const Exception
& )
1965 DBG_UNHANDLED_EXCEPTION("forms.component");
1970 void OBoundControlModel::initFromField( const Reference
< XRowSet
>& _rxRowSet
)
1972 // but only if the rowset is positioned on a valid record
1973 if ( !(hasField() && _rxRowSet
.is()) )
1976 bool shouldTransfer(!_rxRowSet
->isBeforeFirst() && !_rxRowSet
->isAfterLast());
1977 if (!shouldTransfer
)
1979 const Reference
< XPropertySet
> xPS(_rxRowSet
, UNO_QUERY
);
1982 assert(!shouldTransfer
);
1983 xPS
->getPropertyValue(u
"IsNew"_ustr
) >>= shouldTransfer
;
1986 if ( shouldTransfer
)
1987 transferDbValueToControl();
1989 // reset the field if the row set is empty
1994 bool OBoundControlModel::approveDbColumnType(sal_Int32 _nColumnType
)
1996 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::approveDbColumnType: invalid call (have an external binding)!" );
1997 if ((_nColumnType
== DataType::BINARY
) || (_nColumnType
== DataType::VARBINARY
)
1998 || (_nColumnType
== DataType::LONGVARBINARY
) || (_nColumnType
== DataType::OTHER
)
1999 || (_nColumnType
== DataType::OBJECT
) || (_nColumnType
== DataType::DISTINCT
)
2000 || (_nColumnType
== DataType::STRUCT
) || (_nColumnType
== DataType::ARRAY
)
2001 || (_nColumnType
== DataType::BLOB
) /*|| (_nColumnType == DataType::CLOB)*/
2002 || (_nColumnType
== DataType::REF
) || (_nColumnType
== DataType::SQLNULL
))
2007 void OBoundControlModel::impl_determineAmbientForm_nothrow()
2009 Reference
< XInterface
> xParent( getParent() );
2010 m_xAmbientForm
.set( xParent
, UNO_QUERY
);
2011 if ( !m_xAmbientForm
.is() )
2013 Reference
< XRowSetSupplier
> xSupRowSet( xParent
, UNO_QUERY
);
2014 if ( xSupRowSet
.is() )
2015 m_xAmbientForm
.set( xSupRowSet
->getRowSet(), UNO_QUERY
);
2019 void OBoundControlModel::impl_connectDatabaseColumn_noNotify( bool _bFromReload
)
2021 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2022 // consistency checks
2023 DBG_ASSERT( !( hasField() && !_bFromReload
),
2024 "OBoundControlModel::impl_connectDatabaseColumn_noNotify: the form is just *loaded*, but we already have a field!" );
2026 Reference
< XRowSet
> xRowSet( m_xAmbientForm
, UNO_QUERY
);
2027 OSL_ENSURE( xRowSet
.is(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: no row set!" );
2028 if ( !xRowSet
.is() )
2030 if ( !hasField() || _bFromReload
)
2032 // connect to the column
2033 connectToField( xRowSet
);
2036 // now that we're connected (more or less, even if we did not find a column),
2037 // we definitely want to forward any potentially occurring value changes
2038 m_bForwardValueChanges
= true;
2039 // let derived classes react on this new connection
2041 onConnectedDbColumn( xRowSet
);
2042 // initially transfer the db column value to the control, if we successfully connected to a database column
2044 initFromField( xRowSet
);
2047 void OBoundControlModel::impl_disconnectDatabaseColumn_noNotify()
2049 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_disconnectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2050 // let derived classes react on this
2051 onDisconnectedDbColumn();
2054 getField()->removePropertyChangeListener( PROPERTY_VALUE
, this );
2058 m_xCursor
= nullptr;
2063 void SAL_CALL
OBoundControlModel::loaded( const EventObject
& _rEvent
)
2065 ControlModelLock
aLock( *this );
2066 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2067 OSL_ENSURE( _rEvent
.Source
== m_xAmbientForm
, "OBoundControlModel::loaded: where does this come from?" );
2068 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::loaded: we should never reach this with an external value binding!" );
2069 if ( hasExternalValueBinding() )
2071 impl_connectDatabaseColumn_noNotify( false );
2074 void SAL_CALL
OBoundControlModel::unloaded( const css::lang::EventObject
& /*aEvent*/ )
2076 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloaded: we should never reach this with an external value binding!" );
2079 void SAL_CALL
OBoundControlModel::reloading( const css::lang::EventObject
& /*aEvent*/ )
2081 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloading: we should never reach this with an external value binding!" );
2082 if ( hasExternalValueBinding() )
2084 osl::MutexGuard
aGuard(m_aMutex
);
2085 m_bForwardValueChanges
= false;
2088 void SAL_CALL
OBoundControlModel::unloading(const css::lang::EventObject
& /*aEvent*/)
2090 ControlModelLock
aLock( *this );
2091 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2092 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloading: we should never reach this with an external value binding!" );
2093 if ( hasExternalValueBinding() )
2095 impl_disconnectDatabaseColumn_noNotify();
2098 void SAL_CALL
OBoundControlModel::reloaded( const EventObject
& _rEvent
)
2100 ControlModelLock
aLock( *this );
2101 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2102 OSL_ENSURE( _rEvent
.Source
== m_xAmbientForm
, "OBoundControlModel::reloaded: where does this come from?" );
2103 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloaded: we should never reach this with an external value binding!" );
2104 if ( hasExternalValueBinding() )
2106 impl_connectDatabaseColumn_noNotify( true );
2109 void OBoundControlModel::setControlValue( const Any
& _rValue
, ValueChangeInstigator _eInstigator
)
2111 m_eControlValueChangeInstigator
= _eInstigator
;
2112 doSetControlValue( _rValue
);
2113 m_eControlValueChangeInstigator
= eOther
;
2116 void OBoundControlModel::doSetControlValue( const Any
& _rValue
)
2118 OSL_PRECOND( m_xAggregateFastSet
.is() && m_xAggregateSet
.is(),
2119 "OBoundControlModel::doSetControlValue: invalid aggregate !" );
2120 OSL_PRECOND( !m_sValuePropertyName
.isEmpty() || ( m_nValuePropertyAggregateHandle
!= -1 ),
2121 "OBoundControlModel::doSetControlValue: please override if you have own value property handling!" );
2124 // release our mutex once (it's acquired in one of the calling methods), as setting aggregate properties
2125 // may cause any uno controls belonging to us to lock the solar mutex, which is potentially dangerous with
2126 // our own mutex locked
2127 MutexRelease
aRelease( m_aMutex
);
2128 if ( ( m_nValuePropertyAggregateHandle
!= -1 ) && m_xAggregateFastSet
.is() )
2130 m_xAggregateFastSet
->setFastPropertyValue( m_nValuePropertyAggregateHandle
, _rValue
);
2133 else if ( !m_sValuePropertyName
.isEmpty() && m_xAggregateSet
.is() )
2135 m_xAggregateSet
->setPropertyValue( m_sValuePropertyName
, _rValue
);
2140 catch( const Exception
& )
2142 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::doSetControlValue");
2146 void OBoundControlModel::onConnectedValidator( )
2150 // if we have an external validator, we do not want the control to force invalid
2151 // inputs to the default value. Instead, invalid inputs should be translated
2152 // to NaN (not a number)
2153 Reference
< XPropertySetInfo
> xAggregatePropertyInfo
;
2154 if ( m_xAggregateSet
.is() )
2155 xAggregatePropertyInfo
= m_xAggregateSet
->getPropertySetInfo();
2156 if ( xAggregatePropertyInfo
.is() && xAggregatePropertyInfo
->hasPropertyByName( PROPERTY_ENFORCE_FORMAT
) )
2157 m_xAggregateSet
->setPropertyValue( PROPERTY_ENFORCE_FORMAT
, Any( false ) );
2160 catch( const Exception
& )
2162 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::onConnectedValidator");
2165 recheckValidity( false );
2168 void OBoundControlModel::onDisconnectedValidator( )
2172 Reference
< XPropertySetInfo
> xAggregatePropertyInfo
;
2173 if ( m_xAggregateSet
.is() )
2174 xAggregatePropertyInfo
= m_xAggregateSet
->getPropertySetInfo();
2175 if ( xAggregatePropertyInfo
.is() && xAggregatePropertyInfo
->hasPropertyByName( PROPERTY_ENFORCE_FORMAT
) )
2176 m_xAggregateSet
->setPropertyValue( PROPERTY_ENFORCE_FORMAT
, Any( true ) );
2179 catch( const Exception
& )
2181 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::onDisconnectedValidator");
2184 recheckValidity( false );
2187 void OBoundControlModel::onConnectedExternalValue( )
2189 calculateExternalValueType();
2192 void OBoundControlModel::onConnectedDbColumn( const Reference
< XInterface
>& /*_rxForm*/ )
2194 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onConnectedDbColumn: how this? There's an external value binding!" );
2197 void OBoundControlModel::onDisconnectedDbColumn()
2199 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onDisconnectedDbColumn: how this? There's an external value binding!" );
2203 Any
OBoundControlModel::getDefaultForReset() const
2208 void OBoundControlModel::resetNoBroadcast()
2210 setControlValue( getDefaultForReset(), eOther
);
2213 void OBoundControlModel::addResetListener(const Reference
<XResetListener
>& l
)
2215 m_aResetHelper
.addResetListener( l
);
2218 void OBoundControlModel::removeResetListener(const Reference
<XResetListener
>& l
)
2220 m_aResetHelper
.removeResetListener( l
);
2223 void OBoundControlModel::reset()
2225 if ( !m_aResetHelper
.approveReset() )
2227 ControlModelLock
aLock( *this );
2229 bool bIsNewRecord
= false;
2230 Reference
<XPropertySet
> xSet( m_xCursor
, UNO_QUERY
);
2235 xSet
->getPropertyValue( PROPERTY_ISNEW
) >>= bIsNewRecord
;
2238 catch( const Exception
& )
2240 DBG_UNHANDLED_EXCEPTION("forms.component");
2245 // cursor on an invalid row?
2246 bool bInvalidCursorPosition
= true;
2249 bInvalidCursorPosition
= m_xCursor
.is()
2250 && ( m_xCursor
->isAfterLast()
2251 || m_xCursor
->isBeforeFirst()
2256 catch( const SQLException
& )
2258 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::reset: caught an SQL exception!" );
2261 // #i24495# - don't count the insert row as "invalid"
2263 ( !m_xColumn
.is() // no connection to a database column
2264 || ( m_xCursor
.is() // OR we have an improperly positioned cursor
2265 && bInvalidCursorPosition
2267 || hasExternalValueBinding() // OR we have an external value binding
2269 if ( !bSimpleReset
)
2271 // The default values will be set if and only if the current value of the field which we're bound
2273 // Else, the current field value should be refreshed
2274 // This behaviour is not completely ... "matured": What should happen if the field as well as the
2275 // control have a default value?
2276 bool bIsNull
= true;
2277 // we have to access the field content at least once to get a reliable result by XColumn::wasNull
2280 // normally, we'd do a getString here. However, this is extremely expensive in the case
2281 // of binary fields. Unfortunately, getString is the only method which is guaranteed
2282 // to *always* succeed, all other getXXX methods may fail if the column is asked for a
2283 // non-convertible type
2284 sal_Int32 nFieldType
= DataType::OBJECT
;
2285 getField()->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
;
2286 if ( ( nFieldType
== DataType::BINARY
)
2287 || ( nFieldType
== DataType::VARBINARY
)
2288 || ( nFieldType
== DataType::LONGVARBINARY
)
2289 || ( nFieldType
== DataType::OBJECT
)
2290 /*|| ( nFieldType == DataType::CLOB )*/
2292 m_xColumn
->getBinaryStream();
2293 else if ( nFieldType
== DataType::BLOB
)
2294 m_xColumn
->getBlob();
2296 m_xColumn
->getString();
2297 bIsNull
= m_xColumn
->wasNull();
2300 catch(const Exception
&)
2302 DBG_UNHANDLED_EXCEPTION("forms.component");
2303 SAL_WARN("forms.component", "OBoundControlModel::reset: this should have succeeded in all cases!");
2306 bool bNeedValueTransfer
= true;
2311 // reset the control to its default
2313 // and immediately commit the changes to the DB column, to keep consistency
2314 commitControlValueToDbColumn( true );
2315 bNeedValueTransfer
= false;
2320 if ( bNeedValueTransfer
)
2321 transferDbValueToControl();
2327 // transfer to the external binding, if necessary
2328 if ( hasExternalValueBinding() )
2329 transferControlValueToExternal( aLock
);
2332 // revalidate, if necessary
2333 if ( hasValidator() )
2334 recheckValidity( true );
2336 m_aResetHelper
.notifyResetted();
2339 void OBoundControlModel::impl_setField_noNotify( const Reference
< XPropertySet
>& _rxField
)
2341 DBG_ASSERT( !hasExternalValueBinding(), "OBoundControlModel::impl_setField_noNotify: We have an external value binding!" );
2342 m_xField
= _rxField
;
2345 bool OBoundControlModel::impl_approveValueBinding_nolock( const Reference
< XValueBinding
>& _rxBinding
)
2347 if ( !_rxBinding
.is() )
2349 Sequence
< Type
> aTypeCandidates
;
2352 ::osl::MutexGuard
aGuard( m_aMutex
);
2353 aTypeCandidates
= getSupportedBindingTypes();
2357 for (auto const& type
: aTypeCandidates
)
2359 if ( _rxBinding
->supportsType( type
) )
2365 void OBoundControlModel::connectExternalValueBinding(
2366 const Reference
< XValueBinding
>& _rxBinding
, ControlModelLock
& _rInstanceLock
)
2368 OSL_PRECOND( _rxBinding
.is(), "OBoundControlModel::connectExternalValueBinding: invalid binding instance!" );
2369 OSL_PRECOND( !hasExternalValueBinding( ), "OBoundControlModel::connectExternalValueBinding: precond not met (currently have a binding)!" );
2370 // if we're connected to a database column, suspend this
2372 impl_disconnectDatabaseColumn_noNotify();
2373 // suspend listening for load-related events at out ambient form.
2374 // This is because an external value binding overrules a possible database binding.
2375 if ( isFormListening() )
2376 doFormListening( false );
2377 // remember this new binding
2378 m_xExternalBinding
= _rxBinding
;
2380 onConnectedExternalValue();
2383 // add as value listener so we get notified when the value changes
2384 Reference
< XModifyBroadcaster
> xModifiable( m_xExternalBinding
, UNO_QUERY
);
2385 if ( xModifiable
.is() )
2386 xModifiable
->addModifyListener( this );
2387 // add as property change listener for some (possibly present) properties we're
2389 Reference
< XPropertySet
> xBindingProps( m_xExternalBinding
, UNO_QUERY
);
2390 Reference
< XPropertySetInfo
> xBindingPropsInfo( xBindingProps
.is() ? xBindingProps
->getPropertySetInfo() : Reference
< XPropertySetInfo
>() );
2391 if ( xBindingPropsInfo
.is() )
2393 if ( xBindingPropsInfo
->hasPropertyByName( PROPERTY_READONLY
) )
2395 xBindingProps
->addPropertyChangeListener( PROPERTY_READONLY
, this );
2396 m_bBindingControlsRO
= true;
2399 if ( xBindingPropsInfo
->hasPropertyByName( PROPERTY_RELEVANT
) )
2401 xBindingProps
->addPropertyChangeListener( PROPERTY_RELEVANT
, this );
2402 m_bBindingControlsEnable
= true;
2409 catch( const Exception
& )
2411 DBG_UNHANDLED_EXCEPTION("forms.component");
2414 // propagate our new value
2415 transferExternalValueToControl( _rInstanceLock
);
2416 // if the binding is also a validator, use it, too. This is a constraint of the
2417 // com.sun.star.form.binding.ValidatableBindableFormComponent service
2418 if ( !m_bSupportsValidation
)
2423 Reference
< XValidator
> xAsValidator( _rxBinding
, UNO_QUERY
);
2424 if ( xAsValidator
.is() )
2425 setValidator( xAsValidator
);
2428 catch( const Exception
& )
2430 DBG_UNHANDLED_EXCEPTION("forms.component");
2434 void OBoundControlModel::disconnectExternalValueBinding( )
2438 // not listening at the binding anymore
2439 Reference
< XModifyBroadcaster
> xModifiable( m_xExternalBinding
, UNO_QUERY
);
2440 if ( xModifiable
.is() )
2441 xModifiable
->removeModifyListener( this );
2442 // remove as property change listener
2443 Reference
< XPropertySet
> xBindingProps( m_xExternalBinding
, UNO_QUERY
);
2444 if ( m_bBindingControlsRO
)
2445 xBindingProps
->removePropertyChangeListener( PROPERTY_READONLY
, this );
2446 if ( m_bBindingControlsEnable
)
2447 xBindingProps
->removePropertyChangeListener( PROPERTY_RELEVANT
, this );
2450 catch( const Exception
& )
2452 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::disconnectExternalValueBinding");
2455 // if the binding also acts as our validator, disconnect the validator, too
2456 if ( ( m_xExternalBinding
== m_xValidator
) && m_xValidator
.is() )
2457 disconnectValidator( );
2458 // no binding anymore
2459 m_xExternalBinding
.clear();
2460 // be a load listener at our form, again. This was suspended while we had
2461 // an external value binding in place.
2462 doFormListening( true );
2463 // re-connect to database column of the new parent
2464 if ( m_xAmbientForm
.is() && m_xAmbientForm
->isLoaded() )
2465 impl_connectDatabaseColumn_noNotify( false );
2468 void SAL_CALL
OBoundControlModel::setValueBinding( const Reference
< XValueBinding
>& _rxBinding
)
2470 OSL_PRECOND( m_bSupportsExternalBinding
, "OBoundControlModel::setValueBinding: How did you reach this method?" );
2471 // the interface for this method should not have been exposed if we do not
2472 // support binding to external data
2474 if ( _rxBinding
.is() && !impl_approveValueBinding_nolock( _rxBinding
) )
2476 throw IncompatibleTypesException(
2477 ResourceManager::loadString(RID_STR_INCOMPATIBLE_TYPES
),
2482 ControlModelLock
aLock( *this );
2483 // since a ValueBinding overrules any potentially active database binding, the change in a ValueBinding
2484 // might trigger a change in our BoundField.
2485 FieldChangeNotifier
aBoundFieldNotifier( aLock
);
2486 // disconnect from the old binding
2487 if ( hasExternalValueBinding() )
2488 disconnectExternalValueBinding( );
2489 // connect to the new binding
2490 if ( _rxBinding
.is() )
2491 connectExternalValueBinding( _rxBinding
, aLock
);
2494 Reference
< XValueBinding
> SAL_CALL
OBoundControlModel::getValueBinding( )
2496 ::osl::MutexGuard
aGuard( m_aMutex
);
2497 OSL_PRECOND( m_bSupportsExternalBinding
, "OBoundControlModel::getValueBinding: How did you reach this method?" );
2498 // the interface for this method should not have been exposed if we do not
2499 // support binding to external data
2500 return m_xExternalBinding
;
2503 void SAL_CALL
OBoundControlModel::modified( const EventObject
& _rEvent
)
2505 ControlModelLock
aLock( *this );
2506 OSL_PRECOND( hasExternalValueBinding(), "OBoundControlModel::modified: Where did this come from?" );
2507 if ( !m_bTransferringValue
&& ( m_xExternalBinding
== _rEvent
.Source
) && m_xExternalBinding
.is() )
2509 transferExternalValueToControl( aLock
);
2513 void OBoundControlModel::transferDbValueToControl( )
2517 setControlValue( translateDbColumnToControlValue(), eDbColumnBinding
);
2520 catch( const Exception
& )
2522 DBG_UNHANDLED_EXCEPTION("forms.component");
2526 void OBoundControlModel::transferExternalValueToControl( ControlModelLock
& _rInstanceLock
)
2528 Reference
< XValueBinding
> xExternalBinding( m_xExternalBinding
);
2529 Type
aValueExchangeType( getExternalValueType() );
2530 _rInstanceLock
.release();
2535 aExternalValue
= xExternalBinding
->getValue( aValueExchangeType
);
2538 catch( const Exception
& )
2540 DBG_UNHANDLED_EXCEPTION("forms.component");
2543 _rInstanceLock
.acquire();
2544 setControlValue( translateExternalValueToControlValue( aExternalValue
), eExternalBinding
);
2547 void OBoundControlModel::transferControlValueToExternal( ControlModelLock
& _rInstanceLock
)
2549 OSL_PRECOND( m_bSupportsExternalBinding
&& hasExternalValueBinding(),
2550 "OBoundControlModel::transferControlValueToExternal: precondition not met!" );
2551 if ( !m_xExternalBinding
.is() )
2554 Any
aExternalValue( translateControlValueToExternalValue() );
2555 m_bTransferringValue
= true;
2556 _rInstanceLock
.release();
2560 m_xExternalBinding
->setValue( aExternalValue
);
2563 catch( const Exception
& )
2565 DBG_UNHANDLED_EXCEPTION("forms.component");
2569 _rInstanceLock
.acquire();
2570 m_bTransferringValue
= false;
2573 Sequence
< Type
> OBoundControlModel::getSupportedBindingTypes()
2575 return Sequence
< Type
>( &m_aValuePropertyType
, 1 );
2578 void OBoundControlModel::calculateExternalValueType()
2580 m_aExternalValueType
= Type();
2581 if ( !m_xExternalBinding
.is() )
2583 const Sequence
< Type
> aTypeCandidates( getSupportedBindingTypes() );
2584 for ( auto const & typeCandidate
: aTypeCandidates
)
2586 if ( m_xExternalBinding
->supportsType( typeCandidate
) )
2588 m_aExternalValueType
= typeCandidate
;
2594 Any
OBoundControlModel::translateExternalValueToControlValue( const Any
& _rExternalValue
) const
2596 OSL_PRECOND( m_bSupportsExternalBinding
&& hasExternalValueBinding(),
2597 "OBoundControlModel::translateExternalValueToControlValue: precondition not met!" );
2598 Any
aControlValue( _rExternalValue
);
2599 // if the external value is VOID, and our value property is not allowed to be VOID,
2600 // then default-construct a value
2601 if ( !aControlValue
.hasValue() && !m_bValuePropertyMayBeVoid
)
2602 aControlValue
.setValue( nullptr, m_aValuePropertyType
);
2604 return aControlValue
;
2607 Any
OBoundControlModel::translateControlValueToExternalValue( ) const
2609 return getControlValue( );
2612 Any
OBoundControlModel::translateControlValueToValidatableValue( ) const
2614 OSL_PRECOND( m_xValidator
.is(), "OBoundControlModel::translateControlValueToValidatableValue: no validator, so why should I?" );
2615 if ( ( m_xValidator
== m_xExternalBinding
) && m_xValidator
.is() )
2616 return translateControlValueToExternalValue();
2617 return getControlValue();
2620 Any
OBoundControlModel::getControlValue( ) const
2622 OSL_PRECOND( m_xAggregateFastSet
.is() && m_xAggregateSet
.is(),
2623 "OBoundControlModel::getControlValue: invalid aggregate !" );
2624 OSL_PRECOND( !m_sValuePropertyName
.isEmpty() || ( m_nValuePropertyAggregateHandle
!= -1 ),
2625 "OBoundControlModel::getControlValue: please override if you have own value property handling!" );
2626 // determine the current control value
2628 if ( ( m_nValuePropertyAggregateHandle
!= -1 ) && m_xAggregateFastSet
.is() )
2630 aControlValue
= m_xAggregateFastSet
->getFastPropertyValue( m_nValuePropertyAggregateHandle
);
2633 else if ( !m_sValuePropertyName
.isEmpty() && m_xAggregateSet
.is() )
2635 aControlValue
= m_xAggregateSet
->getPropertyValue( m_sValuePropertyName
);
2637 return aControlValue
;
2640 void OBoundControlModel::connectValidator( const Reference
< XValidator
>& _rxValidator
)
2642 OSL_PRECOND( _rxValidator
.is(), "OBoundControlModel::connectValidator: invalid validator instance!" );
2643 OSL_PRECOND( !hasValidator( ), "OBoundControlModel::connectValidator: precond not met (have a validator currently)!" );
2644 m_xValidator
= _rxValidator
;
2646 // add as value listener so we get notified when the value changes
2647 if ( m_xValidator
.is() )
2651 m_xValidator
->addValidityConstraintListener( this );
2654 catch( const RuntimeException
& )
2658 onConnectedValidator( );
2661 void OBoundControlModel::disconnectValidator( )
2663 OSL_PRECOND( hasValidator( ), "OBoundControlModel::connectValidator: precond not met (don't have a validator currently)!" );
2665 // add as value listener so we get notified when the value changes
2666 if ( m_xValidator
.is() )
2670 m_xValidator
->removeValidityConstraintListener( this );
2673 catch( const RuntimeException
& )
2678 m_xValidator
.clear();
2680 onDisconnectedValidator( );
2683 void SAL_CALL
OBoundControlModel::setValidator( const Reference
< XValidator
>& _rxValidator
)
2685 osl::MutexGuard
aGuard( m_aMutex
);
2686 OSL_PRECOND( m_bSupportsValidation
, "OBoundControlModel::setValidator: How did you reach this method?" );
2687 // the interface for this method should not have been exposed if we do not
2688 // support validation
2690 // early out if the validator does not change
2691 if ( _rxValidator
== m_xValidator
)
2694 if ( m_xValidator
.is() && ( m_xValidator
== m_xExternalBinding
) )
2695 throw VetoException(
2696 ResourceManager::loadString(RID_STR_INVALID_VALIDATOR
),
2700 // disconnect from the old validator
2701 if ( hasValidator() )
2702 disconnectValidator( );
2704 // connect to the new validator
2705 if ( _rxValidator
.is() )
2706 connectValidator( _rxValidator
);
2709 Reference
< XValidator
> SAL_CALL
OBoundControlModel::getValidator( )
2711 ::osl::MutexGuard
aGuard( m_aMutex
);
2712 OSL_PRECOND( m_bSupportsValidation
, "OBoundControlModel::getValidator: How did you reach this method?" );
2713 // the interface for this method should not have been exposed if we do not
2714 // support validation
2716 return m_xValidator
;
2719 void SAL_CALL
OBoundControlModel::validityConstraintChanged( const EventObject
& /*Source*/ )
2721 osl::MutexGuard
aGuard( m_aMutex
);
2722 OSL_PRECOND( m_bSupportsValidation
, "OBoundControlModel::validityConstraintChanged: How did you reach this method?" );
2723 // the interface for this method should not have been exposed if we do not
2724 // support validation
2726 recheckValidity( false );
2729 sal_Bool SAL_CALL
OBoundControlModel::isValid( )
2731 return m_bIsCurrentValueValid
;
2734 css::uno::Any
OBoundControlModel::getCurrentFormComponentValue() const
2736 if ( hasValidator() )
2737 return translateControlValueToValidatableValue();
2738 return getControlValue();
2741 Any SAL_CALL
OBoundControlModel::getCurrentValue( )
2743 ::osl::MutexGuard
aGuard( m_aMutex
);
2744 return getCurrentFormComponentValue();
2747 void SAL_CALL
OBoundControlModel::addFormComponentValidityListener( const Reference
< validation::XFormComponentValidityListener
>& Listener
)
2749 if ( Listener
.is() )
2750 m_aFormComponentListeners
.addInterface( Listener
);
2753 void SAL_CALL
OBoundControlModel::removeFormComponentValidityListener( const Reference
< validation::XFormComponentValidityListener
>& Listener
)
2755 if ( Listener
.is() )
2756 m_aFormComponentListeners
.removeInterface( Listener
);
2759 void OBoundControlModel::recheckValidity( bool _bForceNotification
)
2763 bool bIsCurrentlyValid
= true;
2764 if ( hasValidator() )
2765 bIsCurrentlyValid
= m_xValidator
->isValid( translateControlValueToValidatableValue() );
2767 if ( ( bIsCurrentlyValid
!= m_bIsCurrentValueValid
) || _bForceNotification
)
2769 m_bIsCurrentValueValid
= bIsCurrentlyValid
;
2771 // release our mutex for the notifications
2772 MutexRelease
aRelease( m_aMutex
);
2773 m_aFormComponentListeners
.notifyEach( &validation::XFormComponentValidityListener::componentValidityChanged
, EventObject( *this ) );
2778 catch( const Exception
& )
2780 TOOLS_WARN_EXCEPTION("forms.component", "OBoundControlModel::recheckValidity");
2784 void OBoundControlModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
2786 OControlModel::describeFixedProperties( _rProps
);
2787 sal_Int32 nOldCount
= _rProps
.getLength();
2788 _rProps
.realloc( nOldCount
+ 5);
2789 css::beans::Property
* pProperties
= _rProps
.getArray() + nOldCount
;
2790 *pProperties
++ = css::beans::Property(PROPERTY_CONTROLSOURCE
, PROPERTY_ID_CONTROLSOURCE
, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::BOUND
);
2791 *pProperties
++ = css::beans::Property(PROPERTY_BOUNDFIELD
, PROPERTY_ID_BOUNDFIELD
, cppu::UnoType
<XPropertySet
>::get(),
2792 css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::READONLY
| css::beans::PropertyAttribute::TRANSIENT
);
2793 *pProperties
++ = css::beans::Property(PROPERTY_CONTROLLABEL
, PROPERTY_ID_CONTROLLABEL
, cppu::UnoType
<XPropertySet
>::get(),
2794 css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::MAYBEVOID
);
2795 *pProperties
++ = css::beans::Property(PROPERTY_CONTROLSOURCEPROPERTY
, PROPERTY_ID_CONTROLSOURCEPROPERTY
, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::READONLY
| css::beans::PropertyAttribute::TRANSIENT
);
2796 *pProperties
++ = css::beans::Property(PROPERTY_INPUT_REQUIRED
, PROPERTY_ID_INPUT_REQUIRED
, cppu::UnoType
<bool>::get(),
2797 css::beans::PropertyAttribute::BOUND
);
2798 DBG_ASSERT( pProperties
== _rProps
.getArray() + _rProps
.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
2802 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */