nss: upgrade to release 3.73
[LibreOffice.git] / forms / source / component / FormComponent.cxx
blob8b3047cc176b4c1fe0f50c963d34d8fd1a82cd20
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <componenttools.hxx>
20 #include <FormComponent.hxx>
21 #include <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>
55 #include <algorithm>
57 namespace frm
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 );
90 namespace {
92 class FieldChangeNotifier
94 public:
95 explicit FieldChangeNotifier(ControlModelLock& _rLock)
96 : m_rLock( _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 ) );
109 private:
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 )
132 doSetDelegator();
135 OControl::~OControl()
137 doResetDelegator();
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 );
158 // UNO Binding
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);
167 // ask our aggregate
168 if (!aReturn.hasValue() && m_xAggregate.is())
169 aReturn = m_xAggregate->queryAggregation(_rType);
172 return aReturn;
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();
196 // OComponentHelper
197 void OControl::disposing()
199 OComponentHelper::disposing();
201 m_aWindowStateGuard.attach( nullptr, nullptr );
203 Reference< XComponent > xComp;
204 if (query_aggregation(m_xAggregate, xComp))
205 xComp->dispose();
208 // XServiceInfo
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();
221 return aAggServices;
224 Sequence<OUString> SAL_CALL OControl::getSupportedServiceNames()
226 // no own supported service names
227 return getAggregateServiceNames();
230 // XEventListener
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);
245 // XControl
246 void SAL_CALL OControl::setContext(const Reference< XInterface >& Context)
248 if (m_xControl.is())
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 );
264 xModel = getModel();
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() )
290 return false;
292 bool bSuccess = m_xControl->setModel( Model );
293 impl_resetStateGuard_nothrow();
294 return bSuccess;
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)
309 if (m_xControl.is())
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 )
326 ,m_bLocked(false)
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)
341 Any aReturn;
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 );
356 return aReturn;
359 sal_Bool SAL_CALL OBoundControl::getLock()
361 return m_bLocked;
364 void SAL_CALL OBoundControl::setLock(sal_Bool _bLock)
366 if (m_bLocked == bool(_bLock))
367 return;
369 osl::MutexGuard aGuard(m_aMutex);
370 _setLock(_bLock);
371 m_bLocked = _bLock;
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 );
380 if ( xText.is() )
381 xText->setEditable( !_bLock );
382 else
384 // disable the window
385 Reference< XWindow > xComp( xPeer, UNO_QUERY );
386 if ( xComp.is() )
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)
398 // just disambiguate
399 OControl::disposing(Source);
402 void OBoundControl::disposing()
404 OControl::disposing();
407 // OControlModel
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()
430 ).getTypes();
433 Any SAL_CALL OControlModel::queryAggregation(const Type& _rType)
435 // base class 1
436 Any aReturn(OComponentHelper::queryAggregation(_rType));
438 // base class 2
439 if (!aReturn.hasValue())
441 aReturn = OControlModel_BASE::queryInterface(_rType);
443 // our own interfaces
444 if (!aReturn.hasValue())
446 aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
447 // our aggregate
448 if (!aReturn.hasValue() && m_xAggregate.is() && !_rType.equals(cppu::UnoType<XCloneable>::get()))
449 aReturn = m_xAggregate->queryAggregation(_rType);
452 return aReturn;
455 void OControlModel::readHelpTextCompatibly(const css::uno::Reference< css::io::XObjectInputStream >& _rxInStream)
457 OUString sHelpText;
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)
473 OUString sHelpText;
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 )
494 ,m_lockCount( 0 )
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...
504 // #i37342#
506 if (_rUnoControlModelTypeName.isEmpty()) // the is a model we have to aggregate
507 return;
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");
527 if (_bSetDelegator)
528 doSetDelegator();
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 )
538 ,m_lockCount( 0 )
539 ,m_aPropertyBagHelper( *this )
540 ,m_nTabIndex( FRM_DEFAULT_TABINDEX )
541 ,m_nClassId( FormComponentType::CONTROL )
543 DBG_ASSERT( _pOriginal, "OControlModel::OControlModel: invalid original!" );
545 // copy members
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 )
556 return;
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 )
570 doSetDelegator();
572 // decrement ref count
573 osl_atomic_decrement( &m_refCount );
576 OControlModel::~OControlModel()
578 // release the aggregate
579 doResetDelegator( );
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);
603 // XChild
604 Reference< XInterface > SAL_CALL OControlModel::getParent()
606 return m_xParent;
609 void SAL_CALL OControlModel::setParent(const Reference< XInterface >& _rxParent)
611 osl::MutexGuard aGuard(m_aMutex);
613 Reference<XComponent> xComp(m_xParent, UNO_QUERY);
614 if (xComp.is())
615 xComp->removeEventListener(static_cast<XPropertiesChangeListener*>(this));
617 m_xParent = _rxParent;
618 xComp.set(m_xParent, css::uno::UNO_QUERY);
620 if ( xComp.is() )
621 xComp->addEventListener(static_cast<XPropertiesChangeListener*>(this));
624 // XNamed
625 OUString SAL_CALL OControlModel::getName()
627 OUString aReturn;
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",
637 *this,
641 return aReturn;
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",
655 *this,
661 // XServiceInfo
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();
673 return aAggServices;
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" };
689 // XEventListener
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);
696 m_xParent = nullptr;
698 else
700 Reference<css::lang::XEventListener> xEvtLst;
701 if (query_aggregation(m_xAggregate, xEvtLst))
703 osl::MutexGuard aGuard(m_aMutex);
704 xEvtLst->disposing(_rSource);
709 // OComponentHelper
710 void OControlModel::disposing()
712 OPropertySetAggregationHelper::disposing();
714 Reference<css::lang::XComponent> xComp;
715 if (query_aggregation(m_xAggregate, xComp))
716 xComp->dispose();
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);
743 if ( !xMark.is() )
745 throw IOException(
746 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
747 static_cast< ::cppu::OWeakObject* >( this )
751 sal_Int32 nMark = xMark->createMark();
752 sal_Int32 nLen = 0;
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
773 // IMPORTANT NOTE!
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.
778 // EOIN!
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);
786 if ( !xMark.is() )
788 throw IOException(
789 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
790 static_cast< ::cppu::OWeakObject* >( this )
794 // 1. reading the UnoControls
795 sal_Int32 nLen = InStream->readLong();
796 if (nLen)
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
858 Any aReturn;
859 switch ( _nHandle )
861 case PROPERTY_ID_NAME:
862 case PROPERTY_ID_TAG:
863 aReturn <<= OUString();
864 break;
865 case PROPERTY_ID_CLASSID:
866 aReturn <<= sal_Int16(FormComponentType::CONTROL);
867 break;
868 case PROPERTY_ID_TABINDEX:
869 aReturn <<= sal_Int16(FRM_DEFAULT_TABINDEX);
870 break;
871 case PROPERTY_ID_NATIVE_LOOK:
872 aReturn <<= true;
873 break;
874 case PROPERTY_ID_GENERATEVBAEVENTS:
875 aReturn <<= false;
876 break;
877 // added for exporting OCX control
878 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
879 aReturn <<= sal_Int16(0);
880 break;
881 case PROPERTY_ID_OBJ_ID_IN_MSO:
882 aReturn <<= sal_uInt16(INVALID_OBJ_ID_IN_MSO);
883 break;
884 default:
885 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
886 m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( _nHandle, aReturn );
887 else
888 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle);
890 return aReturn;
893 void OControlModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
895 switch ( _nHandle )
897 case PROPERTY_ID_NAME:
898 _rValue <<= m_aName;
899 break;
900 case PROPERTY_ID_TAG:
901 _rValue <<= m_aTag;
902 break;
903 case PROPERTY_ID_CLASSID:
904 _rValue <<= m_nClassId;
905 break;
906 case PROPERTY_ID_TABINDEX:
907 _rValue <<= m_nTabIndex;
908 break;
909 case PROPERTY_ID_NATIVE_LOOK:
910 _rValue <<= m_bNativeLook;
911 break;
912 case PROPERTY_ID_GENERATEVBAEVENTS:
913 _rValue <<= m_bGenerateVbEvents;
914 break;
915 // added for exporting OCX control
916 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
917 _rValue <<= m_nControlTypeinMSO;
918 break;
919 case PROPERTY_ID_OBJ_ID_IN_MSO:
920 _rValue <<= m_nObjIDinMSO;
921 break;
922 default:
923 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
924 m_aPropertyBagHelper.getDynamicFastPropertyValue( _nHandle, _rValue );
925 else
926 OPropertySetAggregationHelper::getFastPropertyValue( _rValue, _nHandle );
927 break;
931 sal_Bool OControlModel::convertFastPropertyValue(
932 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
934 bool bModified(false);
935 switch (_nHandle)
937 case PROPERTY_ID_NAME:
938 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aName);
939 break;
940 case PROPERTY_ID_TAG:
941 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aTag);
942 break;
943 case PROPERTY_ID_TABINDEX:
944 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nTabIndex);
945 break;
946 case PROPERTY_ID_NATIVE_LOOK:
947 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bNativeLook);
948 break;
949 case PROPERTY_ID_GENERATEVBAEVENTS:
950 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bGenerateVbEvents);
951 break;
952 // added for exporting OCX control
953 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
954 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nControlTypeinMSO);
955 break;
956 case PROPERTY_ID_OBJ_ID_IN_MSO:
957 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nObjIDinMSO);
958 break;
959 default:
960 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
961 bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( _nHandle, _rValue, _rConvertedValue, _rOldValue );
962 else
963 SAL_WARN("forms.component", "OControlModel::convertFastPropertyValue: unknown handle " << _nHandle);
964 break;
966 return bModified;
969 void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
971 switch (_nHandle)
973 case PROPERTY_ID_NAME:
974 DBG_ASSERT(_rValue.getValueType() == cppu::UnoType<OUString>::get(),
975 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
976 _rValue >>= m_aName;
977 break;
978 case PROPERTY_ID_TAG:
979 DBG_ASSERT(_rValue.getValueType() == cppu::UnoType<OUString>::get(),
980 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
981 _rValue >>= m_aTag;
982 break;
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;
987 break;
988 case PROPERTY_ID_NATIVE_LOOK:
989 OSL_VERIFY( _rValue >>= m_bNativeLook );
990 break;
991 case PROPERTY_ID_GENERATEVBAEVENTS:
992 OSL_VERIFY( _rValue >>= m_bGenerateVbEvents );
993 break;
994 // added for exporting OCX control
995 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
996 OSL_VERIFY( _rValue >>= m_nControlTypeinMSO );
997 break;
998 case PROPERTY_ID_OBJ_ID_IN_MSO:
999 OSL_VERIFY( _rValue >>= m_nObjIDinMSO );
1000 break;
1001 default:
1002 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1003 m_aPropertyBagHelper.setDynamicFastPropertyValue( _nHandle, _rValue );
1004 else
1005 SAL_WARN("forms.component", "OControlModel::setFastPropertyValue_NoBroadcast: unknown handle " << _nHandle );
1006 break;
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() );
1028 if ( xPSI.is() )
1029 _rAggregateProps = xPSI->getProperties();
1033 ::osl::Mutex& OControlModel::getMutex()
1035 return m_aMutex;
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 )
1081 m_aMutex.acquire();
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 );
1089 m_aMutex.release();
1090 return 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(),
1098 _rNewValues.data(),
1099 _rOldValues.data(),
1100 _rHandles.size(),
1101 false
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 );
1122 return aReturn;
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 )
1131 ,m_xField()
1132 ,m_xAmbientForm()
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 )
1142 ,m_bLoaded(false)
1143 ,m_bRequired(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 )
1163 ,m_xField()
1164 ,m_xAmbientForm()
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 )
1175 ,m_bLoaded( 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 )
1208 acquire();
1209 dispose();
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()) )
1228 return;
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 );
1251 doSetDelegator();
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()
1323 TypeBag aTypes(
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();
1339 // OComponentHelper
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*.
1358 if ( hasField() )
1360 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
1361 resetField();
1364 m_xCursor = nullptr;
1365 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1366 if ( xComp.is() )
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 )
1428 return;
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();
1445 // XChild
1446 void SAL_CALL OBoundControlModel::setParent(const Reference<XInterface>& _rxParent)
1448 ControlModelLock aLock( *this );
1449 FieldChangeNotifier aBoundFieldNotifier( aLock );
1450 if ( getParent() == _rxParent )
1451 return;
1452 // disconnect from database column (which is controlled by parent, directly or indirectly)
1453 if ( hasField() )
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 );
1472 // XEventListener
1473 void SAL_CALL OBoundControlModel::disposing(const css::lang::EventObject& _rEvent)
1475 ControlModelLock aLock( *this );
1476 if ( _rEvent.Source == getField() )
1478 resetField();
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( );
1500 else
1501 OControlModel::disposing(_rEvent);
1504 // XServiceInfo
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(),
1518 aOwnServiceNames
1522 // XPersist
1523 void SAL_CALL OBoundControlModel::write( const Reference<css::io::XObjectOutputStream>& _rxOutStream )
1525 OControlModel::write(_rxOutStream);
1526 osl::MutexGuard aGuard(m_aMutex);
1527 // Version
1528 _rxOutStream->writeShort(0x0002);
1529 // Controlsource
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)
1537 // !!! EOIN !!!
1540 void OBoundControlModel::defaultCommonProperties()
1542 Reference<css::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1543 if (xComp.is())
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();
1558 if (nUsedFlag)
1559 xPersist = _rxInStream->readObject();
1560 m_xLabelControl.set(xPersist, css::uno::UNO_QUERY);
1561 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1562 if (xComp.is())
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)
1577 sal_Int32 nLen = 0;
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;
1582 if (xPersist.is())
1583 nUsedFlag = 1;
1584 _rxOutStream->writeLong(nUsedFlag);
1585 if (xPersist.is())
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
1606 switch (nHandle)
1608 case PROPERTY_ID_INPUT_REQUIRED:
1609 rValue <<= m_bInputRequired;
1610 break;
1611 case PROPERTY_ID_CONTROLSOURCEPROPERTY:
1612 rValue <<= m_sValuePropertyName;
1613 break;
1614 case PROPERTY_ID_CONTROLSOURCE:
1615 rValue <<= m_aControlSource;
1616 break;
1617 case PROPERTY_ID_BOUNDFIELD:
1618 rValue <<= getField();
1619 break;
1620 case PROPERTY_ID_CONTROLLABEL:
1621 if (!m_xLabelControl.is())
1622 rValue.clear();
1623 else
1624 rValue <<= m_xLabelControl;
1625 break;
1626 default:
1627 OControlModel::getFastPropertyValue(rValue, nHandle);
1631 sal_Bool OBoundControlModel::convertFastPropertyValue(
1632 Any& _rConvertedValue, Any& _rOldValue,
1633 sal_Int32 _nHandle,
1634 const Any& _rValue)
1636 bool bModified(false);
1637 switch (_nHandle)
1639 case PROPERTY_ID_INPUT_REQUIRED:
1640 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, m_bInputRequired );
1641 break;
1642 case PROPERTY_ID_CONTROLSOURCE:
1643 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aControlSource);
1644 break;
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();
1656 else
1658 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_xLabelControl);
1659 if (!m_xLabelControl.is())
1660 // an empty interface is interpreted as VOID
1661 _rOldValue.clear();
1664 break;
1665 default:
1666 bModified = OControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
1668 return bModified;
1671 Any OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
1673 Any aDefault;
1674 switch ( _nHandle )
1676 case PROPERTY_ID_INPUT_REQUIRED:
1677 aDefault <<= false;
1678 break;
1679 case PROPERTY_ID_CONTROLSOURCE:
1680 aDefault <<= OUString();
1681 break;
1682 case PROPERTY_ID_CONTROLLABEL:
1683 aDefault <<= Reference< XPropertySet >();
1684 break;
1686 return aDefault;
1689 void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
1691 switch (nHandle)
1693 case PROPERTY_ID_INPUT_REQUIRED:
1694 OSL_VERIFY( rValue >>= m_bInputRequired );
1695 break;
1696 case PROPERTY_ID_CONTROLSOURCE:
1697 OSL_VERIFY( rValue >>= m_aControlSource );
1698 break;
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 );
1710 if ( xComp.is() )
1711 xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
1712 m_xLabelControl = nullptr;
1713 break;
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);
1732 if (!xAsForm.is())
1733 // found my root
1734 break;
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);
1743 if (!xAsForm.is())
1744 break;
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);
1757 if (xComp.is())
1758 xComp->addEventListener(static_cast<css::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1761 break;
1762 default:
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();
1779 else
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;
1796 else
1797 return;
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)
1819 if ( hasField() )
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 );
1833 // XBoundComponent
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 );
1857 return true;
1860 OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" );
1861 // we reach this only if we're not working with an external binding
1862 if ( !hasField() )
1863 return true;
1864 ::comphelper::OInterfaceIteratorHelper2 aIter( m_aUpdateListeners );
1865 EventObject aEvent;
1866 aEvent.Source = static_cast< XWeak* >( this );
1867 bool bSuccess = true;
1868 aLock.release();
1869 // UNSAFE >
1870 while (aIter.hasMoreElements() && bSuccess)
1871 bSuccess = static_cast< XUpdateListener* >( aIter.next() )->approveUpdate( aEvent );
1872 // < UNSAFE
1873 aLock.acquire();
1874 if ( bSuccess )
1878 if ( m_xColumnUpdate.is() )
1879 bSuccess = commitControlValueToDbColumn( false );
1882 catch(const Exception&)
1884 bSuccess = false;
1889 if ( bSuccess )
1891 aLock.release();
1892 m_aUpdateListeners.notifyEach( &XUpdateListener::updated, aEvent );
1894 return bSuccess;
1897 void OBoundControlModel::resetField()
1899 m_xColumnUpdate.clear();
1900 m_xColumn.clear();
1901 m_xField.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()))
1910 return;
1912 // determine field and PropertyChangeListener
1913 m_xCursor = rForm;
1914 Reference<XPropertySet> xFieldCandidate;
1915 if (m_xCursor.is())
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 );
1941 else
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...
1957 else
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");
1970 resetField();
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()) )
1978 return;
1980 bool shouldTransfer(!_rxRowSet->isBeforeFirst() && !_rxRowSet->isAfterLast());
1981 if (!shouldTransfer)
1983 const Reference< XPropertySet > xPS(_rxRowSet, UNO_QUERY);
1984 if (xPS.is())
1986 assert(!shouldTransfer);
1987 xPS->getPropertyValue("IsNew") >>= shouldTransfer;
1990 if ( shouldTransfer )
1991 transferDbValueToControl();
1992 else
1993 // reset the field if the row set is empty
1994 // #i30661#
1995 resetNoBroadcast();
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))
2007 return false;
2008 return true;
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() )
2033 return;
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
2044 m_bLoaded = true;
2045 onConnectedDbColumn( xRowSet );
2046 // initially transfer the db column value to the control, if we successfully connected to a database column
2047 if ( hasField() )
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();
2056 if ( hasField() )
2058 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
2059 resetField();
2062 m_xCursor = nullptr;
2063 m_bLoaded = false;
2066 // XLoadListener
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() )
2074 return;
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() )
2087 return;
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() )
2098 return;
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() )
2109 return;
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!" );
2206 // XReset
2207 Any OBoundControlModel::getDefaultForReset() const
2209 return Any();
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() )
2230 return;
2231 ControlModelLock aLock( *this );
2232 // on a new record?
2233 bool bIsNewRecord = false;
2234 Reference<XPropertySet> xSet( m_xCursor, UNO_QUERY );
2235 if ( xSet.is() )
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()
2257 && !bIsNewRecord;
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"
2266 bool bSimpleReset =
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
2276 // to is NULL.
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();
2299 else
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;
2311 if ( bIsNull )
2313 if ( bIsNewRecord )
2315 // reset the control to its default
2316 resetNoBroadcast();
2317 // and immediately commit the changes to the DB column, to keep consistency
2318 commitControlValueToDbColumn( true );
2319 bNeedValueTransfer = false;
2324 if ( bNeedValueTransfer )
2325 transferDbValueToControl();
2328 else
2330 resetNoBroadcast();
2331 // transfer to the external binding, if necessary
2332 if ( hasExternalValueBinding() )
2333 transferControlValueToExternal( aLock );
2336 // revalidate, if necessary
2337 if ( hasValidator() )
2338 recheckValidity( true );
2339 aLock.release();
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() )
2352 return false;
2353 Sequence< Type > aTypeCandidates;
2355 // SYNCHRONIZED >
2356 ::osl::MutexGuard aGuard( m_aMutex );
2357 aTypeCandidates = getSupportedBindingTypes();
2358 // < SYNCHRONIZED
2361 for ( auto const & type : std::as_const(aTypeCandidates) )
2363 if ( _rxBinding->supportsType( type ) )
2364 return true;
2366 return false;
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
2375 if ( hasField() )
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;
2383 // tell the derivee
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
2392 // interested in
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 )
2423 return;
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
2477 // allow reset
2478 if ( _rxBinding.is() && !impl_approveValueBinding_nolock( _rxBinding ) )
2480 throw IncompatibleTypesException(
2481 FRM_RES_STRING( RID_STR_INCOMPATIBLE_TYPES ),
2482 *this
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();
2535 // UNSAFE >
2536 Any aExternalValue;
2539 aExternalValue = xExternalBinding->getValue( aValueExchangeType );
2542 catch( const Exception& )
2544 DBG_UNHANDLED_EXCEPTION("forms.component");
2546 // < UNSAFE
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() )
2556 return;
2558 Any aExternalValue( translateControlValueToExternalValue() );
2559 m_bTransferringValue = true;
2560 _rInstanceLock.release();
2561 // UNSAFE >
2564 m_xExternalBinding->setValue( aExternalValue );
2567 catch( const Exception& )
2569 DBG_UNHANDLED_EXCEPTION("forms.component");
2572 // < UNSAFE
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() )
2586 return;
2587 const Sequence< Type > aTypeCandidates( getSupportedBindingTypes() );
2588 for ( auto const & typeCandidate : aTypeCandidates )
2590 if ( m_xExternalBinding->supportsType( typeCandidate ) )
2592 m_aExternalValueType = typeCandidate;
2593 break;
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 );
2607 // out of here
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
2631 Any aControlValue;
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 )
2696 return;
2698 if ( m_xValidator.is() && ( m_xValidator == m_xExternalBinding ) )
2699 throw VetoException(
2700 FRM_RES_STRING( RID_STR_INVALID_VALIDATOR ),
2701 *this
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: */