| /************************************************************** | |
| * | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| * | |
| *************************************************************/ | |
| // MARKER(update_precomp.py): autogen include statement, do not remove | |
| #include "precompiled_forms.hxx" | |
| #include "componenttools.hxx" | |
| #include "FormComponent.hxx" | |
| #include "frm_resource.hrc" | |
| #include "frm_resource.hxx" | |
| #include "property.hrc" | |
| #include "services.hxx" | |
| /** === begin UNO includes === **/ | |
| #include <com/sun/star/awt/XTextComponent.hpp> | |
| #include <com/sun/star/awt/XVclWindowPeer.hpp> | |
| #include <com/sun/star/awt/XWindow.hpp> | |
| #include <com/sun/star/form/XForm.hpp> | |
| #include <com/sun/star/form/XLoadable.hpp> | |
| #include <com/sun/star/io/XMarkableStream.hpp> | |
| #include <com/sun/star/lang/DisposedException.hpp> | |
| #include <com/sun/star/sdb/XRowSetChangeBroadcaster.hpp> | |
| #include <com/sun/star/sdb/XRowSetSupplier.hpp> | |
| #include <com/sun/star/sdbc/ColumnValue.hpp> | |
| #include <com/sun/star/sdbc/DataType.hpp> | |
| #include <com/sun/star/util/XModifyBroadcaster.hpp> | |
| /** === end UNO includes === **/ | |
| #include <comphelper/basicio.hxx> | |
| #include <comphelper/guarding.hxx> | |
| #include <comphelper/listenernotification.hxx> | |
| #include <comphelper/property.hxx> | |
| #include <connectivity/dbtools.hxx> | |
| #include <cppuhelper/queryinterface.hxx> | |
| #include <rtl/logfile.hxx> | |
| #include <toolkit/helper/emptyfontdescriptor.hxx> | |
| #include <tools/debug.hxx> | |
| #include <tools/diagnose_ex.h> | |
| #include <functional> | |
| #include <algorithm> | |
| #include <functional> | |
| #include <algorithm> | |
| //... namespace frm ....................................................... | |
| namespace frm | |
| { | |
| //......................................................................... | |
| using namespace ::com::sun::star::uno; | |
| using namespace ::com::sun::star::sdb; | |
| using namespace ::com::sun::star::sdbc; | |
| using namespace ::com::sun::star::sdbcx; | |
| using namespace ::com::sun::star::beans; | |
| using namespace ::com::sun::star::container; | |
| using namespace ::com::sun::star::form; | |
| using namespace ::com::sun::star::awt; | |
| using namespace ::com::sun::star::io; | |
| using namespace ::com::sun::star::lang; | |
| using namespace ::com::sun::star::util; | |
| using namespace ::com::sun::star::form::binding; | |
| using namespace ::com::sun::star::form::validation; | |
| using namespace ::dbtools; | |
| using namespace ::comphelper; | |
| //========================================================================= | |
| //= FieldChangeNotifier | |
| //========================================================================= | |
| //------------------------------------------------------------------------- | |
| void ControlModelLock::impl_notifyAll_nothrow() | |
| { | |
| m_rModel.firePropertyChanges( m_aHandles, m_aOldValues, m_aNewValues, OControlModel::LockAccess() ); | |
| } | |
| //------------------------------------------------------------------------- | |
| void ControlModelLock::addPropertyNotification( const sal_Int32 _nHandle, const Any& _rOldValue, const Any& _rNewValue ) | |
| { | |
| sal_Int32 nOldLength = m_aHandles.getLength(); | |
| if ( ( nOldLength != m_aOldValues.getLength() ) | |
| || ( nOldLength != m_aNewValues.getLength() ) | |
| ) | |
| throw RuntimeException( ::rtl::OUString(), m_rModel ); | |
| m_aHandles.realloc( nOldLength + 1 ); | |
| m_aHandles[ nOldLength ] = _nHandle; | |
| m_aOldValues.realloc( nOldLength + 1 ); | |
| m_aOldValues[ nOldLength ] = _rOldValue; | |
| m_aNewValues.realloc( nOldLength + 1 ); | |
| m_aNewValues[ nOldLength ] = _rNewValue; | |
| } | |
| //========================================================================= | |
| //= FieldChangeNotifier | |
| //========================================================================= | |
| //------------------------------------------------------------------------- | |
| class FieldChangeNotifier | |
| { | |
| public: | |
| FieldChangeNotifier( ControlModelLock& _rLock ) | |
| :m_rLock( _rLock ) | |
| ,m_rModel( dynamic_cast< OBoundControlModel& >( _rLock.getModel() ) ) | |
| { | |
| m_xOldField = m_rModel.getField(); | |
| } | |
| ~FieldChangeNotifier() | |
| { | |
| Reference< XPropertySet > xNewField( m_rModel.getField() ); | |
| if ( m_xOldField != xNewField ) | |
| m_rLock.addPropertyNotification( PROPERTY_ID_BOUNDFIELD, makeAny( m_xOldField ), makeAny( xNewField ) ); | |
| } | |
| private: | |
| ControlModelLock& m_rLock; | |
| OBoundControlModel& m_rModel; | |
| Reference< XPropertySet > m_xOldField; | |
| }; | |
| //============================================================================= | |
| //= base class for form layer controls | |
| //============================================================================= | |
| DBG_NAME(frm_OControl) | |
| //------------------------------------------------------------------------------ | |
| OControl::OControl( const Reference< XMultiServiceFactory >& _rxFactory, const rtl::OUString& _rAggregateService, const sal_Bool _bSetDelegator ) | |
| :OComponentHelper(m_aMutex) | |
| ,m_aContext( _rxFactory ) | |
| { | |
| DBG_CTOR(frm_OControl, NULL); | |
| // VCL-Control aggregieren | |
| // bei Aggregation den Refcount um eins erhoehen da im setDelegator | |
| // das Aggregat selbst den Refcount erhoeht | |
| increment( m_refCount ); | |
| { | |
| m_xAggregate = m_xAggregate.query( _rxFactory->createInstance( _rAggregateService ) ); | |
| m_xControl = m_xControl.query( m_xAggregate ); | |
| } | |
| decrement( m_refCount ); | |
| if ( _bSetDelegator ) | |
| doSetDelegator(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| OControl::~OControl() | |
| { | |
| DBG_DTOR(frm_OControl, NULL); | |
| doResetDelegator(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControl::doResetDelegator() | |
| { | |
| if ( m_xAggregate.is() ) | |
| m_xAggregate->setDelegator( NULL ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControl::doSetDelegator() | |
| { | |
| increment( m_refCount ); | |
| if ( m_xAggregate.is() ) | |
| { // those brackets are important for some compilers, don't remove! | |
| // (they ensure that the temporary object created in the line below | |
| // is destroyed *before* the refcount-decrement) | |
| m_xAggregate->setDelegator( static_cast< XWeak* >( this ) ); | |
| } | |
| decrement( m_refCount ); | |
| } | |
| // UNO Anbindung | |
| //------------------------------------------------------------------------------ | |
| Any SAL_CALL OControl::queryAggregation( const Type& _rType ) throw(RuntimeException) | |
| { | |
| // ask the base class | |
| Any aReturn( OComponentHelper::queryAggregation(_rType) ); | |
| // ask our own interfaces | |
| if (!aReturn.hasValue()) | |
| { | |
| aReturn = OControl_BASE::queryInterface(_rType); | |
| // ask our aggregate | |
| if (!aReturn.hasValue() && m_xAggregate.is()) | |
| aReturn = m_xAggregate->queryAggregation(_rType); | |
| } | |
| return aReturn; | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence<sal_Int8> SAL_CALL OControl::getImplementationId() throw(RuntimeException) | |
| { | |
| return OImplementationIds::getImplementationId(getTypes()); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence<Type> SAL_CALL OControl::getTypes() throw(RuntimeException) | |
| { | |
| TypeBag aTypes( _getTypes() ); | |
| Reference< XTypeProvider > xProv; | |
| if ( query_aggregation( m_xAggregate, xProv ) ) | |
| aTypes.addTypes( xProv->getTypes() ); | |
| return aTypes.getTypes(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence<Type> OControl::_getTypes() | |
| { | |
| return TypeBag( OComponentHelper::getTypes(), OControl_BASE::getTypes() ).getTypes(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControl::initFormControlPeer( const Reference< XWindowPeer >& /*_rxPeer*/ ) | |
| { | |
| // nothing to do here | |
| } | |
| // OComponentHelper | |
| //------------------------------------------------------------------------------ | |
| void OControl::disposing() | |
| { | |
| OComponentHelper::disposing(); | |
| m_aWindowStateGuard.attach( NULL, NULL ); | |
| Reference< XComponent > xComp; | |
| if (query_aggregation(m_xAggregate, xComp)) | |
| xComp->dispose(); | |
| } | |
| // XServiceInfo | |
| //------------------------------------------------------------------------------ | |
| sal_Bool SAL_CALL OControl::supportsService(const rtl::OUString& _rsServiceName) throw ( RuntimeException) | |
| { | |
| Sequence<rtl::OUString> aSupported = getSupportedServiceNames(); | |
| const rtl::OUString* pSupported = aSupported.getConstArray(); | |
| for (sal_Int32 i=0; i<aSupported.getLength(); ++i, ++pSupported) | |
| if (pSupported->equals(_rsServiceName)) | |
| return sal_True; | |
| return sal_False; | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence< ::rtl::OUString > OControl::getAggregateServiceNames() | |
| { | |
| Sequence< ::rtl::OUString > aAggServices; | |
| Reference< XServiceInfo > xInfo; | |
| if ( query_aggregation( m_xAggregate, xInfo ) ) | |
| aAggServices = xInfo->getSupportedServiceNames(); | |
| return aAggServices; | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence<rtl::OUString> SAL_CALL OControl::getSupportedServiceNames() throw(RuntimeException) | |
| { | |
| return ::comphelper::concatSequences( | |
| getAggregateServiceNames(), | |
| getSupportedServiceNames_Static() | |
| ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence< ::rtl::OUString > SAL_CALL OControl::getSupportedServiceNames_Static() throw( RuntimeException ) | |
| { | |
| // no own supported service names | |
| return Sequence< ::rtl::OUString >(); | |
| } | |
| // XEventListener | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OControl::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException) | |
| { | |
| Reference< XInterface > xAggAsIface; | |
| query_aggregation(m_xAggregate, xAggAsIface); | |
| // does the disposing come from the aggregate ? | |
| if (xAggAsIface != Reference< XInterface >(_rEvent.Source, UNO_QUERY)) | |
| { // no -> forward it | |
| Reference<com::sun::star::lang::XEventListener> xListener; | |
| if (query_aggregation(m_xAggregate, xListener)) | |
| xListener->disposing(_rEvent); | |
| } | |
| } | |
| // XControl | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OControl::setContext(const Reference< XInterface >& Context) throw (RuntimeException) | |
| { | |
| if (m_xControl.is()) | |
| m_xControl->setContext(Context); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Reference< XInterface > SAL_CALL OControl::getContext() throw (RuntimeException) | |
| { | |
| return m_xControl.is() ? m_xControl->getContext() : Reference< XInterface >(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControl::impl_resetStateGuard_nothrow() | |
| { | |
| Reference< XWindow2 > xWindow; | |
| Reference< XControlModel > xModel; | |
| try | |
| { | |
| xWindow.set( getPeer(), UNO_QUERY ); | |
| xModel.set( getModel(), UNO_QUERY ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| } | |
| m_aWindowStateGuard.attach( xWindow, xModel ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OControl::createPeer(const Reference<XToolkit>& _rxToolkit, const Reference<XWindowPeer>& _rxParent) throw (RuntimeException) | |
| { | |
| if ( m_xControl.is() ) | |
| { | |
| m_xControl->createPeer( _rxToolkit, _rxParent ); | |
| initFormControlPeer( getPeer() ); | |
| impl_resetStateGuard_nothrow(); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| Reference<XWindowPeer> SAL_CALL OControl::getPeer() throw ( RuntimeException) | |
| { | |
| return m_xControl.is() ? m_xControl->getPeer() : Reference<XWindowPeer>(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| sal_Bool SAL_CALL OControl::setModel(const Reference<XControlModel>& Model) throw ( RuntimeException) | |
| { | |
| if ( !m_xControl.is() ) | |
| return sal_False; | |
| sal_Bool bSuccess = m_xControl->setModel( Model ); | |
| impl_resetStateGuard_nothrow(); | |
| return bSuccess; | |
| } | |
| //------------------------------------------------------------------------------ | |
| Reference<XControlModel> SAL_CALL OControl::getModel() throw ( RuntimeException) | |
| { | |
| return m_xControl.is() ? m_xControl->getModel() : Reference<XControlModel>(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Reference<XView> SAL_CALL OControl::getView() throw ( RuntimeException) | |
| { | |
| return m_xControl.is() ? m_xControl->getView() : Reference<XView>(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OControl::setDesignMode(sal_Bool bOn) throw ( RuntimeException) | |
| { | |
| if (m_xControl.is()) | |
| m_xControl->setDesignMode(bOn); | |
| } | |
| //------------------------------------------------------------------------------ | |
| sal_Bool SAL_CALL OControl::isDesignMode() throw ( RuntimeException) | |
| { | |
| return m_xControl.is() ? m_xControl->isDesignMode() : sal_True; | |
| } | |
| //------------------------------------------------------------------------------ | |
| sal_Bool SAL_CALL OControl::isTransparent() throw ( RuntimeException) | |
| { | |
| return m_xControl.is() ? m_xControl->isTransparent() : sal_True; | |
| } | |
| //================================================================== | |
| //= OBoundControl | |
| //================================================================== | |
| DBG_NAME(frm_OBoundControl); | |
| //------------------------------------------------------------------ | |
| OBoundControl::OBoundControl( const Reference< XMultiServiceFactory >& _rxFactory, | |
| const ::rtl::OUString& _rAggregateService, const sal_Bool _bSetDelegator ) | |
| :OControl( _rxFactory, _rAggregateService, _bSetDelegator ) | |
| ,m_bLocked(sal_False) | |
| ,m_aOriginalFont( EmptyFontDescriptor() ) | |
| ,m_nOriginalTextLineColor( 0 ) | |
| { | |
| DBG_CTOR(frm_OBoundControl, NULL); | |
| } | |
| //------------------------------------------------------------------ | |
| OBoundControl::~OBoundControl() | |
| { | |
| DBG_DTOR(frm_OBoundControl, NULL); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| Sequence< Type> OBoundControl::_getTypes() | |
| { | |
| return TypeBag( OControl::_getTypes(), OBoundControl_BASE::getTypes() ).getTypes(); | |
| } | |
| //------------------------------------------------------------------ | |
| Any SAL_CALL OBoundControl::queryAggregation(const Type& _rType) throw(RuntimeException) | |
| { | |
| Any aReturn; | |
| // XTypeProvider first - don't ask the OBoundControl_BASE, it would deliver incomplete types | |
| if ( _rType.equals( ::getCppuType( static_cast< Reference< XTypeProvider >* >( NULL ) ) ) ) | |
| aReturn = OControl::queryAggregation( _rType ); | |
| // ask our own interfaces | |
| // (do this first (except XTypeProvider ) - we want to "overwrite" XPropertiesChangeListener) | |
| if ( !aReturn.hasValue() ) | |
| aReturn = OBoundControl_BASE::queryInterface( _rType ); | |
| // ask the base class | |
| if ( !aReturn.hasValue() ) | |
| aReturn = OControl::queryAggregation( _rType ); | |
| return aReturn; | |
| } | |
| //------------------------------------------------------------------ | |
| sal_Bool SAL_CALL OBoundControl::getLock() throw(RuntimeException) | |
| { | |
| return m_bLocked; | |
| } | |
| //------------------------------------------------------------------ | |
| void SAL_CALL OBoundControl::setLock(sal_Bool _bLock) throw(RuntimeException) | |
| { | |
| if (m_bLocked == _bLock) | |
| return; | |
| osl::MutexGuard aGuard(m_aMutex); | |
| _setLock(_bLock); | |
| m_bLocked = _bLock; | |
| } | |
| //------------------------------------------------------------------ | |
| void OBoundControl::_setLock(sal_Bool _bLock) | |
| { | |
| // try to set the text component to readonly | |
| Reference< XWindowPeer > xPeer = getPeer(); | |
| Reference< XTextComponent > xText( xPeer, UNO_QUERY ); | |
| if ( xText.is() ) | |
| xText->setEditable( !_bLock ); | |
| else | |
| { | |
| // disable the window | |
| Reference< XWindow > xComp( xPeer, UNO_QUERY ); | |
| if ( xComp.is() ) | |
| xComp->setEnable( !_bLock ); | |
| } | |
| } | |
| //-------------------------------------------------------------------- | |
| sal_Bool SAL_CALL OBoundControl::setModel( const Reference< XControlModel >& _rxModel ) throw (RuntimeException) | |
| { | |
| return OControl::setModel( _rxModel ); | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OBoundControl::disposing(const EventObject& Source) throw (RuntimeException) | |
| { | |
| // just disambiguate | |
| OControl::disposing(Source); | |
| } | |
| //-------------------------------------------------------------------- | |
| void OBoundControl::disposing() | |
| { | |
| OControl::disposing(); | |
| } | |
| //================================================================== | |
| //= OControlModel | |
| //================================================================== | |
| DBG_NAME(OControlModel) | |
| //------------------------------------------------------------------ | |
| Sequence<sal_Int8> SAL_CALL OControlModel::getImplementationId() throw(RuntimeException) | |
| { | |
| return OImplementationIds::getImplementationId(getTypes()); | |
| } | |
| //------------------------------------------------------------------ | |
| Sequence<Type> SAL_CALL OControlModel::getTypes() throw(RuntimeException) | |
| { | |
| TypeBag aTypes( _getTypes() ); | |
| Reference< XTypeProvider > xProv; | |
| if ( query_aggregation( m_xAggregate, xProv ) ) | |
| aTypes.addTypes( xProv->getTypes() ); | |
| return aTypes.getTypes(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence<Type> OControlModel::_getTypes() | |
| { | |
| return TypeBag( OComponentHelper::getTypes(), | |
| OPropertySetAggregationHelper::getTypes(), | |
| OControlModel_BASE::getTypes() | |
| ).getTypes(); | |
| } | |
| //------------------------------------------------------------------ | |
| Any SAL_CALL OControlModel::queryAggregation(const Type& _rType) throw (RuntimeException) | |
| { | |
| // base class 1 | |
| Any aReturn(OComponentHelper::queryAggregation(_rType)); | |
| // base class 2 | |
| if (!aReturn.hasValue()) | |
| { | |
| aReturn = OControlModel_BASE::queryInterface(_rType); | |
| // our own interfaces | |
| if (!aReturn.hasValue()) | |
| { | |
| aReturn = OPropertySetAggregationHelper::queryInterface(_rType); | |
| // our aggregate | |
| if (!aReturn.hasValue() && m_xAggregate.is() && !_rType.equals(::getCppuType(static_cast< Reference< XCloneable>* >(NULL)))) | |
| aReturn = m_xAggregate->queryAggregation(_rType); | |
| } | |
| } | |
| return aReturn; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::readHelpTextCompatibly(const staruno::Reference< stario::XObjectInputStream >& _rxInStream) | |
| { | |
| ::rtl::OUString sHelpText; | |
| ::comphelper::operator>>( _rxInStream, sHelpText); | |
| try | |
| { | |
| if (m_xAggregateSet.is()) | |
| m_xAggregateSet->setPropertyValue(PROPERTY_HELPTEXT, makeAny(sHelpText)); | |
| } | |
| catch(const Exception&) | |
| { | |
| OSL_ENSURE(sal_False, "OControlModel::readHelpTextCompatibly: could not forward the property value to the aggregate!"); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::writeHelpTextCompatibly(const staruno::Reference< stario::XObjectOutputStream >& _rxOutStream) | |
| { | |
| ::rtl::OUString sHelpText; | |
| try | |
| { | |
| if (m_xAggregateSet.is()) | |
| m_xAggregateSet->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText; | |
| } | |
| catch(const Exception&) | |
| { | |
| OSL_ENSURE(sal_False, "OControlModel::writeHelpTextCompatibly: could not retrieve the property value from the aggregate!"); | |
| } | |
| ::comphelper::operator<<( _rxOutStream, sHelpText); | |
| } | |
| //------------------------------------------------------------------ | |
| OControlModel::OControlModel( | |
| const Reference<com::sun::star::lang::XMultiServiceFactory>& _rxFactory, | |
| const ::rtl::OUString& _rUnoControlModelTypeName, | |
| const ::rtl::OUString& rDefault, const sal_Bool _bSetDelegator) | |
| :OComponentHelper(m_aMutex) | |
| ,OPropertySetAggregationHelper(OComponentHelper::rBHelper) | |
| ,m_aContext( _rxFactory ) | |
| ,m_lockCount( 0 ) | |
| ,m_aPropertyBagHelper( *this ) | |
| ,m_nTabIndex(FRM_DEFAULT_TABINDEX) | |
| ,m_nClassId(FormComponentType::CONTROL) | |
| ,m_bNativeLook( sal_False ) | |
| ,m_nControlTypeinMSO(0) // 0 : default value is create from AOO | |
| ,m_nObjIDinMSO(INVALID_OBJ_ID_IN_MSO) | |
| // form controls are usually embedded into documents, not dialogs, and in documents | |
| // the native look is ugly .... | |
| // #i37342# / 2004-11-19 / frank.schoenheit@sun.com | |
| { | |
| DBG_CTOR(OControlModel, NULL); | |
| if (_rUnoControlModelTypeName.getLength()) // the is a model we have to aggregate | |
| { | |
| increment(m_refCount); | |
| { | |
| m_xAggregate = Reference<XAggregation>(_rxFactory->createInstance(_rUnoControlModelTypeName), UNO_QUERY); | |
| setAggregation(m_xAggregate); | |
| if ( m_xAggregateSet.is() ) | |
| { | |
| try | |
| { | |
| if ( rDefault.getLength() ) | |
| m_xAggregateSet->setPropertyValue( PROPERTY_DEFAULTCONTROL, makeAny( rDefault ) ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| OSL_ENSURE( sal_False, "OControlModel::OControlModel: caught an exception!" ); | |
| } | |
| } | |
| } | |
| if (_bSetDelegator) | |
| doSetDelegator(); | |
| // Refcount wieder bei NULL | |
| decrement(m_refCount); | |
| } | |
| } | |
| //------------------------------------------------------------------ | |
| OControlModel::OControlModel( const OControlModel* _pOriginal, const Reference< XMultiServiceFactory>& _rxFactory, const sal_Bool _bCloneAggregate, const sal_Bool _bSetDelegator ) | |
| :OComponentHelper( m_aMutex ) | |
| ,OPropertySetAggregationHelper( OComponentHelper::rBHelper ) | |
| ,m_aContext( _rxFactory ) | |
| ,m_lockCount( 0 ) | |
| ,m_aPropertyBagHelper( *this ) | |
| ,m_nTabIndex( FRM_DEFAULT_TABINDEX ) | |
| ,m_nClassId( FormComponentType::CONTROL ) | |
| { | |
| DBG_CTOR( OControlModel, NULL ); | |
| DBG_ASSERT( _pOriginal, "OControlModel::OControlModel: invalid original!" ); | |
| // copy members | |
| m_aName = _pOriginal->m_aName; | |
| m_aTag = _pOriginal->m_aTag; | |
| m_nTabIndex = _pOriginal->m_nTabIndex; | |
| m_nClassId = _pOriginal->m_nClassId; | |
| m_bNativeLook = _pOriginal->m_bNativeLook; | |
| m_nControlTypeinMSO = _pOriginal->m_nControlTypeinMSO; | |
| m_nObjIDinMSO = _pOriginal->m_nObjIDinMSO; | |
| if ( _bCloneAggregate ) | |
| { | |
| // temporarily increment refcount because of temporary references to ourself in the following | |
| increment( m_refCount ); | |
| { | |
| // transfer the (only, at the very moment!) ref count | |
| m_xAggregate = createAggregateClone( _pOriginal ); | |
| // set aggregation (retrieve other direct interfaces of the aggregate) | |
| setAggregation( m_xAggregate ); | |
| } | |
| // set the delegator, if allowed by our derived class | |
| if ( _bSetDelegator ) | |
| doSetDelegator(); | |
| // decrement ref count | |
| decrement( m_refCount ); | |
| } | |
| } | |
| //------------------------------------------------------------------ | |
| OControlModel::~OControlModel() | |
| { | |
| // release the aggregate | |
| doResetDelegator( ); | |
| DBG_DTOR(OControlModel, NULL); | |
| } | |
| //------------------------------------------------------------------ | |
| void OControlModel::clonedFrom( const OControlModel* /*_pOriginal*/ ) | |
| { | |
| // nothing to do in this base class | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::doResetDelegator() | |
| { | |
| if (m_xAggregate.is()) | |
| m_xAggregate->setDelegator(NULL); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::doSetDelegator() | |
| { | |
| increment(m_refCount); | |
| if (m_xAggregate.is()) | |
| { | |
| m_xAggregate->setDelegator(static_cast<XWeak*>(this)); | |
| } | |
| decrement(m_refCount); | |
| } | |
| // XChild | |
| //------------------------------------------------------------------------------ | |
| Reference< XInterface > SAL_CALL OControlModel::getParent() throw(RuntimeException) | |
| { | |
| return m_xParent; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OControlModel::setParent(const Reference< XInterface >& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException) | |
| { | |
| osl::MutexGuard aGuard(m_aMutex); | |
| Reference<XComponent> xComp(m_xParent, UNO_QUERY); | |
| if (xComp.is()) | |
| xComp->removeEventListener(static_cast<XPropertiesChangeListener*>(this)); | |
| m_xParent = _rxParent; | |
| xComp = xComp.query( m_xParent ); | |
| if ( xComp.is() ) | |
| xComp->addEventListener(static_cast<XPropertiesChangeListener*>(this)); | |
| } | |
| // XNamed | |
| //------------------------------------------------------------------------------ | |
| ::rtl::OUString SAL_CALL OControlModel::getName() throw(RuntimeException) | |
| { | |
| ::rtl::OUString aReturn; | |
| OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME) >>= aReturn; | |
| return aReturn; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OControlModel::setName(const ::rtl::OUString& _rName) throw(RuntimeException) | |
| { | |
| setFastPropertyValue(PROPERTY_ID_NAME, makeAny(_rName)); | |
| } | |
| // XServiceInfo | |
| //------------------------------------------------------------------------------ | |
| sal_Bool SAL_CALL OControlModel::supportsService(const rtl::OUString& _rServiceName) throw ( RuntimeException) | |
| { | |
| Sequence<rtl::OUString> aSupported = getSupportedServiceNames(); | |
| const rtl::OUString* pSupported = aSupported.getConstArray(); | |
| for (sal_Int32 i=0; i<aSupported.getLength(); ++i, ++pSupported) | |
| if (pSupported->equals(_rServiceName)) | |
| return sal_True; | |
| return sal_False; | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence< ::rtl::OUString > OControlModel::getAggregateServiceNames() | |
| { | |
| Sequence< ::rtl::OUString > aAggServices; | |
| Reference< XServiceInfo > xInfo; | |
| if ( query_aggregation( m_xAggregate, xInfo ) ) | |
| aAggServices = xInfo->getSupportedServiceNames(); | |
| return aAggServices; | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence<rtl::OUString> SAL_CALL OControlModel::getSupportedServiceNames() throw(RuntimeException) | |
| { | |
| return ::comphelper::concatSequences( | |
| getAggregateServiceNames(), | |
| getSupportedServiceNames_Static() | |
| ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence< ::rtl::OUString > SAL_CALL OControlModel::getSupportedServiceNames_Static() throw( RuntimeException ) | |
| { | |
| Sequence< ::rtl::OUString > aServiceNames( 2 ); | |
| aServiceNames[ 0 ] = FRM_SUN_FORMCOMPONENT; | |
| aServiceNames[ 1 ] = ::rtl::OUString::createFromAscii( "com.sun.star.form.FormControlModel" ); | |
| return aServiceNames; | |
| } | |
| // XEventListener | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OControlModel::disposing(const com::sun::star::lang::EventObject& _rSource) throw (RuntimeException) | |
| { | |
| // release the parent | |
| if (_rSource.Source == m_xParent) | |
| { | |
| osl::MutexGuard aGuard(m_aMutex); | |
| m_xParent = NULL; | |
| } | |
| else | |
| { | |
| Reference<com::sun::star::lang::XEventListener> xEvtLst; | |
| if (query_aggregation(m_xAggregate, xEvtLst)) | |
| { | |
| osl::MutexGuard aGuard(m_aMutex); | |
| xEvtLst->disposing(_rSource); | |
| } | |
| } | |
| } | |
| // OComponentHelper | |
| //----------------------------------------------------------------------------- | |
| void OControlModel::disposing() | |
| { | |
| OPropertySetAggregationHelper::disposing(); | |
| Reference<com::sun::star::lang::XComponent> xComp; | |
| if (query_aggregation(m_xAggregate, xComp)) | |
| xComp->dispose(); | |
| setParent(Reference<XFormComponent>()); | |
| m_aPropertyBagHelper.dispose(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::writeAggregate( const Reference< XObjectOutputStream >& _rxOutStream ) const | |
| { | |
| Reference< XPersistObject > xPersist; | |
| if ( query_aggregation( m_xAggregate, xPersist ) ) | |
| xPersist->write( _rxOutStream ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::readAggregate( const Reference< XObjectInputStream >& _rxInStream ) | |
| { | |
| Reference< XPersistObject > xPersist; | |
| if ( query_aggregation( m_xAggregate, xPersist ) ) | |
| xPersist->read( _rxInStream ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OControlModel::write(const Reference<stario::XObjectOutputStream>& _rxOutStream) | |
| throw(stario::IOException, RuntimeException) | |
| { | |
| osl::MutexGuard aGuard(m_aMutex); | |
| // 1. Schreiben des UnoControls | |
| Reference<stario::XMarkableStream> xMark(_rxOutStream, UNO_QUERY); | |
| if ( !xMark.is() ) | |
| { | |
| throw IOException( | |
| FRM_RES_STRING( RID_STR_INVALIDSTREAM ), | |
| static_cast< ::cppu::OWeakObject* >( this ) | |
| ); | |
| } | |
| sal_Int32 nMark = xMark->createMark(); | |
| sal_Int32 nLen = 0; | |
| _rxOutStream->writeLong(nLen); | |
| writeAggregate( _rxOutStream ); | |
| // feststellen der Laenge | |
| nLen = xMark->offsetToMark(nMark) - 4; | |
| xMark->jumpToMark(nMark); | |
| _rxOutStream->writeLong(nLen); | |
| xMark->jumpToFurthest(); | |
| xMark->deleteMark(nMark); | |
| // 2. Schreiben einer VersionsNummer | |
| _rxOutStream->writeShort(0x0003); | |
| // 3. Schreiben der allgemeinen Properties | |
| ::comphelper::operator<<( _rxOutStream, m_aName); | |
| _rxOutStream->writeShort(m_nTabIndex); | |
| ::comphelper::operator<<( _rxOutStream, m_aTag); // 3. version | |
| // !!! IMPORTANT NOTE !!! | |
| // don't write any new members here : this wouldn't be compatible with older versions, as OControlModel | |
| // is a base class which is called in derived classes "read" method. So if you increment the version | |
| // and write new stuff, older office versions will read this in the _derived_ classes, which may result | |
| // in anything from data loss to crash. | |
| // !!! EOIN !!! | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::read(const Reference<stario::XObjectInputStream>& InStream) throw (::com::sun::star::io::IOException, RuntimeException) | |
| { | |
| osl::MutexGuard aGuard(m_aMutex); | |
| Reference<stario::XMarkableStream> xMark(InStream, UNO_QUERY); | |
| if ( !xMark.is() ) | |
| { | |
| throw IOException( | |
| FRM_RES_STRING( RID_STR_INVALIDSTREAM ), | |
| static_cast< ::cppu::OWeakObject* >( this ) | |
| ); | |
| } | |
| // 1. Lesen des UnoControls | |
| sal_Int32 nLen = InStream->readLong(); | |
| if (nLen) | |
| { | |
| sal_Int32 nMark = xMark->createMark(); | |
| try | |
| { | |
| readAggregate( InStream ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| } | |
| xMark->jumpToMark(nMark); | |
| InStream->skipBytes(nLen); | |
| xMark->deleteMark(nMark); | |
| } | |
| // 2. Lesen des Versionsnummer | |
| sal_uInt16 nVersion = InStream->readShort(); | |
| // 3. Lesen der allgemeinen Properties | |
| ::comphelper::operator>>( InStream, m_aName); | |
| m_nTabIndex = InStream->readShort(); | |
| if (nVersion > 0x0002) | |
| ::comphelper::operator>>( InStream, m_aTag); | |
| // we had a version where we wrote the help text | |
| if (nVersion == 0x0004) | |
| readHelpTextCompatibly(InStream); | |
| DBG_ASSERT(nVersion < 5, "OControlModel::read : suspicious version number !"); | |
| // 4 was the version where we wrote the help text | |
| // later versions shouldn't exist (see write for a detailed comment) | |
| } | |
| //------------------------------------------------------------------------------ | |
| PropertyState OControlModel::getPropertyStateByHandle( sal_Int32 _nHandle ) | |
| { | |
| // simply compare the current and the default value | |
| Any aCurrentValue = getPropertyDefaultByHandle( _nHandle ); | |
| Any aDefaultValue; getFastPropertyValue( aDefaultValue, _nHandle ); | |
| sal_Bool bEqual = uno_type_equalData( | |
| const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(), | |
| const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(), | |
| reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface), | |
| reinterpret_cast< uno_ReleaseFunc >(cpp_release) | |
| ); | |
| return bEqual ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::setPropertyToDefaultByHandle( sal_Int32 _nHandle) | |
| { | |
| Any aDefault = getPropertyDefaultByHandle( _nHandle ); | |
| Any aConvertedValue, aOldValue; | |
| if ( convertFastPropertyValue( aConvertedValue, aOldValue, _nHandle, aDefault ) ) | |
| { | |
| setFastPropertyValue_NoBroadcast( _nHandle, aConvertedValue ); | |
| // TODO: fire the property change | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| Any OControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const | |
| { | |
| Any aReturn; | |
| switch ( _nHandle ) | |
| { | |
| case PROPERTY_ID_NAME: | |
| case PROPERTY_ID_TAG: | |
| aReturn <<= ::rtl::OUString(); | |
| break; | |
| case PROPERTY_ID_CLASSID: | |
| aReturn <<= (sal_Int16)FormComponentType::CONTROL; | |
| break; | |
| case PROPERTY_ID_TABINDEX: | |
| aReturn <<= (sal_Int16)FRM_DEFAULT_TABINDEX; | |
| break; | |
| case PROPERTY_ID_NATIVE_LOOK: | |
| aReturn <<= (sal_Bool)sal_True; | |
| break; | |
| //added for exporting OCX control | |
| case PROPERTY_ID_CONTROL_TYPE_IN_MSO: | |
| aReturn <<= (sal_Int16)0; | |
| break; | |
| case PROPERTY_ID_OBJ_ID_IN_MSO: | |
| aReturn <<= (sal_uInt16)INVALID_OBJ_ID_IN_MSO; | |
| break; | |
| default: | |
| if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) ) | |
| m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( _nHandle, aReturn ); | |
| else | |
| OSL_ENSURE( false, "OControlModel::convertFastPropertyValue: unknown handle!" ); | |
| } | |
| return aReturn; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const | |
| { | |
| switch ( _nHandle ) | |
| { | |
| case PROPERTY_ID_NAME: | |
| _rValue <<= m_aName; | |
| break; | |
| case PROPERTY_ID_TAG: | |
| _rValue <<= m_aTag; | |
| break; | |
| case PROPERTY_ID_CLASSID: | |
| _rValue <<= m_nClassId; | |
| break; | |
| case PROPERTY_ID_TABINDEX: | |
| _rValue <<= m_nTabIndex; | |
| break; | |
| case PROPERTY_ID_NATIVE_LOOK: | |
| _rValue <<= (sal_Bool)m_bNativeLook; | |
| break; | |
| //added for exporting OCX control | |
| case PROPERTY_ID_CONTROL_TYPE_IN_MSO: | |
| _rValue <<= (sal_Int16)m_nControlTypeinMSO; | |
| break; | |
| case PROPERTY_ID_OBJ_ID_IN_MSO: | |
| _rValue <<= (sal_uInt16)m_nObjIDinMSO; | |
| break; | |
| default: | |
| if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) ) | |
| m_aPropertyBagHelper.getDynamicFastPropertyValue( _nHandle, _rValue ); | |
| else | |
| OPropertySetAggregationHelper::getFastPropertyValue( _rValue, _nHandle ); | |
| break; | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| sal_Bool OControlModel::convertFastPropertyValue( | |
| Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue) | |
| throw (com::sun::star::lang::IllegalArgumentException) | |
| { | |
| sal_Bool bModified(sal_False); | |
| switch (_nHandle) | |
| { | |
| case PROPERTY_ID_NAME: | |
| bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aName); | |
| break; | |
| case PROPERTY_ID_TAG: | |
| bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aTag); | |
| break; | |
| case PROPERTY_ID_TABINDEX: | |
| bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nTabIndex); | |
| break; | |
| case PROPERTY_ID_NATIVE_LOOK: | |
| bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bNativeLook); | |
| break; | |
| //added for exporting OCX control | |
| case PROPERTY_ID_CONTROL_TYPE_IN_MSO: | |
| bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nControlTypeinMSO); | |
| break; | |
| case PROPERTY_ID_OBJ_ID_IN_MSO: | |
| bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nObjIDinMSO); | |
| break; | |
| default: | |
| if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) ) | |
| bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( _nHandle, _rValue, _rConvertedValue, _rOldValue ); | |
| else | |
| OSL_ENSURE( false, "OControlModel::convertFastPropertyValue: unknown handle!" ); | |
| break; | |
| } | |
| return bModified; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) | |
| throw (Exception) | |
| { | |
| switch (_nHandle) | |
| { | |
| case PROPERTY_ID_NAME: | |
| DBG_ASSERT(_rValue.getValueType() == getCppuType((const ::rtl::OUString*)NULL), | |
| "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" ); | |
| _rValue >>= m_aName; | |
| break; | |
| case PROPERTY_ID_TAG: | |
| DBG_ASSERT(_rValue.getValueType() == getCppuType((const ::rtl::OUString*)NULL), | |
| "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" ); | |
| _rValue >>= m_aTag; | |
| break; | |
| case PROPERTY_ID_TABINDEX: | |
| DBG_ASSERT(_rValue.getValueType() == getCppuType((const sal_Int16*)NULL), | |
| "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" ); | |
| _rValue >>= m_nTabIndex; | |
| break; | |
| case PROPERTY_ID_NATIVE_LOOK: | |
| OSL_VERIFY( _rValue >>= m_bNativeLook ); | |
| break; | |
| //added for exporting OCX control | |
| case PROPERTY_ID_CONTROL_TYPE_IN_MSO: | |
| OSL_VERIFY( _rValue >>= m_nControlTypeinMSO ); | |
| break; | |
| case PROPERTY_ID_OBJ_ID_IN_MSO: | |
| OSL_VERIFY( _rValue >>= m_nObjIDinMSO ); | |
| break; | |
| default: | |
| if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) ) | |
| m_aPropertyBagHelper.setDynamicFastPropertyValue( _nHandle, _rValue ); | |
| else | |
| OSL_ENSURE( false, "OControlModel::setFastPropertyValue_NoBroadcast: unknown handle!" ); | |
| break; | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const | |
| { | |
| //BEGIN_DESCRIBE_BASE_PROPERTIES( 4 ) | |
| BEGIN_DESCRIBE_BASE_PROPERTIES( 6 ) | |
| DECL_PROP2 (CLASSID, sal_Int16, READONLY, TRANSIENT); | |
| DECL_PROP1 (NAME, ::rtl::OUString, BOUND); | |
| DECL_BOOL_PROP2 (NATIVE_LOOK, BOUND, TRANSIENT); | |
| DECL_PROP1 (TAG, ::rtl::OUString, BOUND); | |
| DECL_PROP1 (CONTROL_TYPE_IN_MSO,sal_Int16, BOUND); | |
| DECL_PROP1 (OBJ_ID_IN_MSO,sal_uInt16, BOUND); | |
| END_DESCRIBE_PROPERTIES() | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ _rAggregateProps ) const | |
| { | |
| if ( m_xAggregateSet.is() ) | |
| { | |
| Reference< XPropertySetInfo > xPSI( m_xAggregateSet->getPropertySetInfo() ); | |
| if ( xPSI.is() ) | |
| _rAggregateProps = xPSI->getProperties(); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| ::osl::Mutex& OControlModel::getMutex() | |
| { | |
| return m_aMutex; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OControlModel::describeFixedAndAggregateProperties( Sequence< Property >& _out_rFixedProperties, Sequence< Property >& _out_rAggregateProperties ) const | |
| { | |
| describeFixedProperties( _out_rFixedProperties ); | |
| describeAggregateProperties( _out_rAggregateProperties ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Reference< XMultiPropertySet > OControlModel::getPropertiesInterface() | |
| { | |
| return Reference< XMultiPropertySet >( *this, UNO_QUERY ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Reference< XPropertySetInfo> SAL_CALL OControlModel::getPropertySetInfo() throw( RuntimeException) | |
| { | |
| return createPropertySetInfo( getInfoHelper() ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| ::cppu::IPropertyArrayHelper& OControlModel::getInfoHelper() | |
| { | |
| return m_aPropertyBagHelper.getInfoHelper(); | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OControlModel::addProperty( const ::rtl::OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException) | |
| { | |
| m_aPropertyBagHelper.addProperty( _rName, _nAttributes, _rInitialValue ); | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OControlModel::removeProperty( const ::rtl::OUString& _rName ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException) | |
| { | |
| m_aPropertyBagHelper.removeProperty( _rName ); | |
| } | |
| //-------------------------------------------------------------------- | |
| Sequence< PropertyValue > SAL_CALL OControlModel::getPropertyValues() throw (RuntimeException) | |
| { | |
| return m_aPropertyBagHelper.getPropertyValues(); | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OControlModel::setPropertyValues( const Sequence< PropertyValue >& _rProps ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) | |
| { | |
| m_aPropertyBagHelper.setPropertyValues( _rProps ); | |
| } | |
| //-------------------------------------------------------------------- | |
| void OControlModel::lockInstance( LockAccess ) | |
| { | |
| m_aMutex.acquire(); | |
| osl_incrementInterlockedCount( &m_lockCount ); | |
| } | |
| //-------------------------------------------------------------------- | |
| oslInterlockedCount OControlModel::unlockInstance( LockAccess ) | |
| { | |
| OSL_ENSURE( m_lockCount > 0, "OControlModel::unlockInstance: not locked!" ); | |
| oslInterlockedCount lockCount = osl_decrementInterlockedCount( &m_lockCount ); | |
| m_aMutex.release(); | |
| return lockCount; | |
| } | |
| //-------------------------------------------------------------------- | |
| void OControlModel::firePropertyChanges( const Sequence< sal_Int32 >& _rHandles, const Sequence< Any >& _rOldValues, | |
| const Sequence< Any >& _rNewValues, LockAccess ) | |
| { | |
| OPropertySetHelper::fire( | |
| const_cast< Sequence< sal_Int32 >& >( _rHandles ).getArray(), | |
| _rNewValues.getConstArray(), | |
| _rOldValues.getConstArray(), | |
| _rHandles.getLength(), | |
| sal_False | |
| ); | |
| } | |
| //================================================================== | |
| //= OBoundControlModel | |
| //================================================================== | |
| DBG_NAME(frm_OBoundControlModel); | |
| //------------------------------------------------------------------ | |
| Any SAL_CALL OBoundControlModel::queryAggregation( const Type& _rType ) throw (RuntimeException) | |
| { | |
| Any aReturn( OControlModel::queryAggregation(_rType) ); | |
| if (!aReturn.hasValue()) | |
| { | |
| aReturn = OBoundControlModel_BASE1::queryInterface(_rType); | |
| if ( !aReturn.hasValue() && m_bCommitable ) | |
| aReturn = OBoundControlModel_COMMITTING::queryInterface( _rType ); | |
| if ( !aReturn.hasValue() && m_bSupportsExternalBinding ) | |
| aReturn = OBoundControlModel_BINDING::queryInterface( _rType ); | |
| if ( !aReturn.hasValue() && m_bSupportsValidation ) | |
| aReturn = OBoundControlModel_VALIDATION::queryInterface( _rType ); | |
| } | |
| return aReturn; | |
| } | |
| //------------------------------------------------------------------ | |
| OBoundControlModel::OBoundControlModel( | |
| const Reference< XMultiServiceFactory>& _rxFactory, | |
| const ::rtl::OUString& _rUnoControlModelTypeName, const ::rtl::OUString& _rDefault, | |
| const sal_Bool _bCommitable, const sal_Bool _bSupportExternalBinding, const sal_Bool _bSupportsValidation ) | |
| :OControlModel( _rxFactory, _rUnoControlModelTypeName, _rDefault, sal_False ) | |
| ,OPropertyChangeListener( m_aMutex ) | |
| ,m_xField() | |
| ,m_xAmbientForm() | |
| ,m_nValuePropertyAggregateHandle( -1 ) | |
| ,m_nFieldType( DataType::OTHER ) | |
| ,m_bValuePropertyMayBeVoid( false ) | |
| ,m_aResetHelper( *this, m_aMutex ) | |
| ,m_aUpdateListeners(m_aMutex) | |
| ,m_aFormComponentListeners( m_aMutex ) | |
| ,m_bInputRequired( sal_True ) | |
| ,m_pAggPropMultiplexer( NULL ) | |
| ,m_bFormListening( false ) | |
| ,m_bLoaded(sal_False) | |
| ,m_bRequired(sal_False) | |
| ,m_bCommitable(_bCommitable) | |
| ,m_bSupportsExternalBinding( _bSupportExternalBinding ) | |
| ,m_bSupportsValidation( _bSupportsValidation ) | |
| ,m_bForwardValueChanges(sal_True) | |
| ,m_bTransferingValue( sal_False ) | |
| ,m_bIsCurrentValueValid( sal_True ) | |
| ,m_bBindingControlsRO( sal_False ) | |
| ,m_bBindingControlsEnable( sal_False ) | |
| ,m_eControlValueChangeInstigator( eOther ) | |
| ,m_aLabelServiceName(FRM_SUN_COMPONENT_FIXEDTEXT) | |
| { | |
| DBG_CTOR(frm_OBoundControlModel, NULL); | |
| // start property listening at the aggregate | |
| implInitAggMultiplexer( ); | |
| } | |
| //------------------------------------------------------------------ | |
| OBoundControlModel::OBoundControlModel( | |
| const OBoundControlModel* _pOriginal, const Reference< XMultiServiceFactory>& _rxFactory ) | |
| :OControlModel( _pOriginal, _rxFactory, sal_True, sal_False ) | |
| ,OPropertyChangeListener( m_aMutex ) | |
| ,m_xField() | |
| ,m_xAmbientForm() | |
| ,m_nValuePropertyAggregateHandle( _pOriginal->m_nValuePropertyAggregateHandle ) | |
| ,m_nFieldType( DataType::OTHER ) | |
| ,m_bValuePropertyMayBeVoid( _pOriginal->m_bValuePropertyMayBeVoid ) | |
| ,m_aResetHelper( *this, m_aMutex ) | |
| ,m_aUpdateListeners( m_aMutex ) | |
| ,m_aFormComponentListeners( m_aMutex ) | |
| ,m_xValidator( _pOriginal->m_xValidator ) | |
| ,m_bInputRequired( sal_True ) | |
| ,m_pAggPropMultiplexer( NULL ) | |
| ,m_bFormListening( false ) | |
| ,m_bLoaded( sal_False ) | |
| ,m_bRequired( sal_False ) | |
| ,m_bCommitable( _pOriginal->m_bCommitable ) | |
| ,m_bSupportsExternalBinding( _pOriginal->m_bSupportsExternalBinding ) | |
| ,m_bSupportsValidation( _pOriginal->m_bSupportsValidation ) | |
| ,m_bForwardValueChanges( sal_True ) | |
| ,m_bTransferingValue( sal_False ) | |
| ,m_bIsCurrentValueValid( _pOriginal->m_bIsCurrentValueValid ) | |
| ,m_bBindingControlsRO( sal_False ) | |
| ,m_bBindingControlsEnable( sal_False ) | |
| ,m_eControlValueChangeInstigator( eOther ) | |
| { | |
| DBG_CTOR(frm_OBoundControlModel, NULL); | |
| // start property listening at the aggregate | |
| implInitAggMultiplexer( ); | |
| m_aLabelServiceName = _pOriginal->m_aLabelServiceName; | |
| m_sValuePropertyName = _pOriginal->m_sValuePropertyName; | |
| m_nValuePropertyAggregateHandle = _pOriginal->m_nValuePropertyAggregateHandle; | |
| m_bValuePropertyMayBeVoid = _pOriginal->m_bValuePropertyMayBeVoid; | |
| m_aValuePropertyType = _pOriginal->m_aValuePropertyType; | |
| m_aControlSource = _pOriginal->m_aControlSource; | |
| m_bInputRequired = _pOriginal->m_bInputRequired; | |
| // m_xLabelControl, though being a property, is not to be cloned, not even the reference will be transfered. | |
| // (the former should be clear - a clone of the object we're only referencing does not make sense) | |
| // (the second would violate the restriction for label controls that they're part of the | |
| // same form component hierarchy - we ourself are no part, yet, so we can't have a label control) | |
| // start listening for changes at the value property | |
| implInitValuePropertyListening( ); | |
| } | |
| //------------------------------------------------------------------ | |
| OBoundControlModel::~OBoundControlModel() | |
| { | |
| if ( !OComponentHelper::rBHelper.bDisposed ) | |
| { | |
| acquire(); | |
| dispose(); | |
| } | |
| doResetDelegator( ); | |
| OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::~OBoundControlModel: what about my property multiplexer?" ); | |
| if ( m_pAggPropMultiplexer ) | |
| { | |
| m_pAggPropMultiplexer->dispose(); | |
| m_pAggPropMultiplexer->release(); | |
| m_pAggPropMultiplexer = NULL; | |
| } | |
| DBG_DTOR(frm_OBoundControlModel, NULL); | |
| } | |
| //------------------------------------------------------------------ | |
| void OBoundControlModel::clonedFrom( const OControlModel* _pOriginal ) | |
| { | |
| const OBoundControlModel* pBoundOriginal = static_cast< const OBoundControlModel* >( _pOriginal ); | |
| // the value binding can be handled as if somebody called setValueBinding here | |
| // By definition, bindings can be share between bindables | |
| if ( pBoundOriginal && pBoundOriginal->m_xExternalBinding.is() ) | |
| { | |
| try | |
| { | |
| setValueBinding( pBoundOriginal->m_xExternalBinding ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| } | |
| } | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::implInitAggMultiplexer( ) | |
| { | |
| increment( m_refCount ); | |
| if ( m_xAggregateSet.is() ) | |
| { | |
| m_pAggPropMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet, sal_False ); | |
| m_pAggPropMultiplexer->acquire(); | |
| } | |
| decrement( m_refCount ); | |
| doSetDelegator(); | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::implInitValuePropertyListening( ) const | |
| { | |
| // start listening for changes at the value property | |
| // There are three pre-requisites for this to be done: | |
| // 1. We support external value bindings. In this case, the changes in the control value need to | |
| // be propagated to the external binding immediately when they happen | |
| // 2. We support external validation. In this case, we need to listen for changes in the value | |
| // property, since we need to revalidate then. | |
| // 3. We are not committable. In this case, changes in the control value need to be propagated | |
| // to the database column immediately when they happen. | |
| if ( m_bSupportsExternalBinding || m_bSupportsValidation || !m_bCommitable ) | |
| { | |
| OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::implInitValuePropertyListening: no multiplexer!" ); | |
| if ( m_pAggPropMultiplexer && m_sValuePropertyName.getLength() ) | |
| m_pAggPropMultiplexer->addProperty( m_sValuePropertyName ); | |
| } | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::initOwnValueProperty( const ::rtl::OUString& i_rValuePropertyName ) | |
| { | |
| OSL_PRECOND( !m_sValuePropertyName.getLength() && -1 == m_nValuePropertyAggregateHandle, | |
| "OBoundControlModel::initOwnValueProperty: value property is already initialized!" ); | |
| OSL_ENSURE( i_rValuePropertyName.getLength(), "OBoundControlModel::initOwnValueProperty: invalid property name!" ); | |
| m_sValuePropertyName = i_rValuePropertyName; | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::initValueProperty( const ::rtl::OUString& _rValuePropertyName, sal_Int32 _nValuePropertyExternalHandle ) | |
| { | |
| OSL_PRECOND( !m_sValuePropertyName.getLength() && -1 == m_nValuePropertyAggregateHandle, | |
| "OBoundControlModel::initValueProperty: value property is already initialized!" ); | |
| OSL_ENSURE( _rValuePropertyName.getLength(), "OBoundControlModel::initValueProperty: invalid property name!" ); | |
| OSL_ENSURE( _nValuePropertyExternalHandle != -1, "OBoundControlModel::initValueProperty: invalid property handle!" ); | |
| m_sValuePropertyName = _rValuePropertyName; | |
| m_nValuePropertyAggregateHandle = getOriginalHandle( _nValuePropertyExternalHandle ); | |
| OSL_ENSURE( m_nValuePropertyAggregateHandle != -1, "OBoundControlModel::initValueProperty: unable to find the original handle!" ); | |
| if ( m_nValuePropertyAggregateHandle != -1 ) | |
| { | |
| Reference< XPropertySetInfo > xPropInfo( m_xAggregateSet->getPropertySetInfo(), UNO_SET_THROW ); | |
| Property aValuePropDesc = xPropInfo->getPropertyByName( m_sValuePropertyName ); | |
| m_aValuePropertyType = aValuePropDesc.Type; | |
| m_bValuePropertyMayBeVoid = ( aValuePropDesc.Attributes & PropertyAttribute::MAYBEVOID ) != 0; | |
| } | |
| // start listening for changes at the value property | |
| implInitValuePropertyListening( ); | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::suspendValueListening( ) | |
| { | |
| OSL_PRECOND( m_sValuePropertyName.getLength(), "OBoundControlModel::suspendValueListening: don't have a value property!" ); | |
| OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::suspendValueListening: I *am* not listening!" ); | |
| if ( m_pAggPropMultiplexer ) | |
| m_pAggPropMultiplexer->lock(); | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::resumeValueListening( ) | |
| { | |
| OSL_PRECOND( m_sValuePropertyName.getLength(), "OBoundControlModel::resumeValueListening: don't have a value property!" ); | |
| OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::resumeValueListening: I *am* not listening at all!" ); | |
| OSL_PRECOND( !m_pAggPropMultiplexer || m_pAggPropMultiplexer->locked(), "OBoundControlModel::resumeValueListening: listening not suspended currently!" ); | |
| if ( m_pAggPropMultiplexer ) | |
| m_pAggPropMultiplexer->unlock(); | |
| } | |
| //----------------------------------------------------------------------------- | |
| Sequence< Type > OBoundControlModel::_getTypes() | |
| { | |
| TypeBag aTypes( | |
| OControlModel::_getTypes(), | |
| OBoundControlModel_BASE1::getTypes() | |
| ); | |
| if ( m_bCommitable ) | |
| aTypes.addTypes( OBoundControlModel_COMMITTING::getTypes() ); | |
| if ( m_bSupportsExternalBinding ) | |
| aTypes.addTypes( OBoundControlModel_BINDING::getTypes() ); | |
| if ( m_bSupportsValidation ) | |
| aTypes.addTypes( OBoundControlModel_VALIDATION::getTypes() ); | |
| return aTypes.getTypes(); | |
| } | |
| // OComponentHelper | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::disposing() | |
| { | |
| OControlModel::disposing(); | |
| ::osl::ClearableMutexGuard aGuard(m_aMutex); | |
| if ( m_pAggPropMultiplexer ) | |
| m_pAggPropMultiplexer->dispose(); | |
| // notify all our listeners | |
| com::sun::star::lang::EventObject aEvt( static_cast< XWeak* >( this ) ); | |
| m_aUpdateListeners.disposeAndClear( aEvt ); | |
| m_aResetHelper.disposing(); | |
| // disconnect from our database column | |
| // TODO: could we replace the following 5 lines with a call to impl_disconnectDatabaseColumn_noNotify? | |
| // The only more thing which it does is calling onDisconnectedDbColumn - could this | |
| // cause trouble? At least when we continue to call OControlModel::disposing before, it *may*. | |
| if ( hasField() ) | |
| { | |
| getField()->removePropertyChangeListener( PROPERTY_VALUE, this ); | |
| resetField(); | |
| } | |
| m_xCursor = NULL; | |
| Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY ); | |
| if ( xComp.is() ) | |
| xComp->removeEventListener(static_cast< XEventListener* >( static_cast< XPropertyChangeListener* >( this ) ) ); | |
| // disconnect from our external value binding | |
| if ( hasExternalValueBinding() ) | |
| disconnectExternalValueBinding(); | |
| // dito for the validator | |
| if ( hasValidator() ) | |
| disconnectValidator( ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::onValuePropertyChange( ControlModelLock& i_rControLock ) | |
| { | |
| if ( hasExternalValueBinding() ) | |
| { // the control value changed, while we have an external value binding | |
| // -> forward the value to it | |
| if ( m_eControlValueChangeInstigator != eExternalBinding ) | |
| transferControlValueToExternal( i_rControLock ); | |
| } | |
| else if ( !m_bCommitable && m_xColumnUpdate.is() ) | |
| { // the control value changed, while we are bound to a database column, | |
| // but not committable (which means changes in the control have to be reflected to | |
| // the underlying database column immediately) | |
| // -> forward the value to the database column | |
| if ( m_eControlValueChangeInstigator != eDbColumnBinding ) | |
| commitControlValueToDbColumn( false ); | |
| } | |
| // validate the new value | |
| if ( m_bSupportsValidation ) | |
| recheckValidity( true ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::_propertyChanged( const PropertyChangeEvent& _rEvt ) throw ( RuntimeException ) | |
| { | |
| ControlModelLock aLock( *this ); | |
| OSL_ENSURE( _rEvt.PropertyName == m_sValuePropertyName, | |
| "OBoundControlModel::_propertyChanged: where did this come from (1)?" ); | |
| OSL_ENSURE( m_pAggPropMultiplexer && !m_pAggPropMultiplexer->locked(), | |
| "OBoundControlModel::_propertyChanged: where did this come from (2)?" ); | |
| if ( _rEvt.PropertyName == m_sValuePropertyName ) | |
| { | |
| onValuePropertyChange( aLock ); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::startAggregatePropertyListening( const ::rtl::OUString& _rPropertyName ) | |
| { | |
| OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::startAggregatePropertyListening: no multiplexer!" ); | |
| OSL_ENSURE( _rPropertyName.getLength(), "OBoundControlModel::startAggregatePropertyListening: invalid property name!" ); | |
| if ( m_pAggPropMultiplexer && _rPropertyName.getLength() ) | |
| { | |
| m_pAggPropMultiplexer->addProperty( _rPropertyName ); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::doFormListening( const bool _bStart ) | |
| { | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::doFormListening: external value binding should overrule the database binding!" ); | |
| if ( isFormListening() == _bStart ) | |
| return; | |
| if ( m_xAmbientForm.is() ) | |
| _bStart ? m_xAmbientForm->addLoadListener( this ) : m_xAmbientForm->removeLoadListener( this ); | |
| Reference< XLoadable > xParentLoadable( getParent(), UNO_QUERY ); | |
| if ( getParent().is() && !xParentLoadable.is() ) | |
| { | |
| // if our parent does not directly support the XLoadable interface, then it might support the | |
| // XRowSetSupplier/XRowSetChangeBroadcaster interfaces. In this case we have to listen for changes | |
| // broadcasted by the latter. | |
| Reference< XRowSetChangeBroadcaster > xRowSetBroadcaster( getParent(), UNO_QUERY ); | |
| if ( xRowSetBroadcaster.is() ) | |
| _bStart ? xRowSetBroadcaster->addRowSetChangeListener( this ) : xRowSetBroadcaster->removeRowSetChangeListener( this ); | |
| } | |
| m_bFormListening = _bStart && m_xAmbientForm.is(); | |
| } | |
| // XChild | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::setParent(const Reference<XInterface>& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException) | |
| { | |
| ControlModelLock aLock( *this ); | |
| FieldChangeNotifier aBoundFieldNotifier( aLock ); | |
| if ( getParent() == _rxParent ) | |
| return; | |
| // disconnect from database column (which is controlled by parent, directly or indirectly) | |
| if ( hasField() ) | |
| impl_disconnectDatabaseColumn_noNotify(); | |
| // log off old listeners | |
| if ( isFormListening() ) | |
| doFormListening( false ); | |
| // actually set the new parent | |
| OControlModel::setParent( _rxParent ); | |
| // a new parent means a new ambient form | |
| impl_determineAmbientForm_nothrow(); | |
| if ( !hasExternalValueBinding() ) | |
| { | |
| // log on new listeners | |
| doFormListening( true ); | |
| // re-connect to database column of the new parent | |
| if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() ) | |
| impl_connectDatabaseColumn_noNotify( false ); | |
| } | |
| } | |
| // XEventListener | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException) | |
| { | |
| ControlModelLock aLock( *this ); | |
| if ( _rEvent.Source == getField() ) | |
| { | |
| resetField(); | |
| } | |
| else if ( _rEvent.Source == m_xLabelControl ) | |
| { | |
| Reference<XPropertySet> xOldValue = m_xLabelControl; | |
| m_xLabelControl = NULL; | |
| // fire a propertyChanged (when we leave aLock's scope) | |
| aLock.addPropertyNotification( PROPERTY_ID_CONTROLLABEL, makeAny( xOldValue ), makeAny( m_xLabelControl ) ); | |
| } | |
| else if ( _rEvent.Source == m_xExternalBinding ) | |
| { // *first* check for the external binding | |
| disconnectExternalValueBinding( ); | |
| } | |
| else if ( _rEvent.Source == m_xValidator ) | |
| { // *then* check for the validator. Reason is that bindings may also act as validator at the same | |
| // time, in this case, the validator is automatically revoked when the binding is revoked | |
| disconnectValidator( ); | |
| } | |
| else | |
| OControlModel::disposing(_rEvent); | |
| } | |
| // XServiceInfo | |
| //------------------------------------------------------------------------------ | |
| StringSequence SAL_CALL OBoundControlModel::getSupportedServiceNames() throw(RuntimeException) | |
| { | |
| return ::comphelper::concatSequences( | |
| getAggregateServiceNames(), | |
| getSupportedServiceNames_Static() | |
| ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Sequence< ::rtl::OUString > SAL_CALL OBoundControlModel::getSupportedServiceNames_Static() throw( RuntimeException ) | |
| { | |
| Sequence< ::rtl::OUString > aOwnServiceNames( 1 ); | |
| aOwnServiceNames[ 0 ] = ::rtl::OUString::createFromAscii( "com.sun.star.form.DataAwareControlModel" ); | |
| return ::comphelper::concatSequences( | |
| OControlModel::getSupportedServiceNames_Static(), | |
| aOwnServiceNames | |
| ); | |
| } | |
| // XPersist | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::write( const Reference<stario::XObjectOutputStream>& _rxOutStream ) throw(stario::IOException, RuntimeException) | |
| { | |
| OControlModel::write(_rxOutStream); | |
| osl::MutexGuard aGuard(m_aMutex); | |
| // Version | |
| _rxOutStream->writeShort(0x0002); | |
| // Controlsource | |
| ::comphelper::operator<<( _rxOutStream, m_aControlSource); | |
| // !!! IMPORTANT NOTE !!! | |
| // don't write any new members here : this wouldn't be compatible with older versions, as OBoundControlModel | |
| // is a base class which is called in derived classes "read" method. So if you increment the version | |
| // and write new stuff, older office versions will read this in the _derived_ classes, which may result | |
| // in anything from data loss to crash. | |
| // (use writeCommonProperties instead, this is called in derived classes write-method) | |
| // !!! EOIN !!! | |
| // FS - 68876 - 28.09.1999 | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::defaultCommonProperties() | |
| { | |
| Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY); | |
| if (xComp.is()) | |
| xComp->removeEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this))); | |
| m_xLabelControl = NULL; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::readCommonProperties(const Reference<stario::XObjectInputStream>& _rxInStream) | |
| { | |
| sal_Int32 nLen = _rxInStream->readLong(); | |
| Reference<stario::XMarkableStream> xMark(_rxInStream, UNO_QUERY); | |
| DBG_ASSERT(xMark.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !"); | |
| sal_Int32 nMark = xMark->createMark(); | |
| // read the reference to the label control | |
| Reference<stario::XPersistObject> xPersist; | |
| sal_Int32 nUsedFlag; | |
| nUsedFlag = _rxInStream->readLong(); | |
| if (nUsedFlag) | |
| xPersist = _rxInStream->readObject(); | |
| m_xLabelControl = m_xLabelControl.query( xPersist ); | |
| Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY ); | |
| if (xComp.is()) | |
| xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this))); | |
| // read any other new common properties here | |
| // skip the remaining bytes | |
| xMark->jumpToMark(nMark); | |
| _rxInStream->skipBytes(nLen); | |
| xMark->deleteMark(nMark); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::writeCommonProperties(const Reference<stario::XObjectOutputStream>& _rxOutStream) | |
| { | |
| Reference<stario::XMarkableStream> xMark(_rxOutStream, UNO_QUERY); | |
| DBG_ASSERT(xMark.is(), "OBoundControlModel::writeCommonProperties : can only work with markable streams !"); | |
| sal_Int32 nMark = xMark->createMark(); | |
| // a placeholder where we will write the overall length (later in this method) | |
| sal_Int32 nLen = 0; | |
| _rxOutStream->writeLong(nLen); | |
| // write the reference to the label control | |
| Reference<stario::XPersistObject> xPersist(m_xLabelControl, UNO_QUERY); | |
| sal_Int32 nUsedFlag = 0; | |
| if (xPersist.is()) | |
| nUsedFlag = 1; | |
| _rxOutStream->writeLong(nUsedFlag); | |
| if (xPersist.is()) | |
| _rxOutStream->writeObject(xPersist); | |
| // write any other new common properties here | |
| // write the correct length at the beginning of the block | |
| nLen = xMark->offsetToMark(nMark) - sizeof(nLen); | |
| xMark->jumpToMark(nMark); | |
| _rxOutStream->writeLong(nLen); | |
| xMark->jumpToFurthest(); | |
| xMark->deleteMark(nMark); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::read( const Reference< stario::XObjectInputStream >& _rxInStream ) throw(stario::IOException, RuntimeException) | |
| { | |
| OControlModel::read(_rxInStream); | |
| osl::MutexGuard aGuard(m_aMutex); | |
| sal_uInt16 nVersion = _rxInStream->readShort(); (void)nVersion; | |
| ::comphelper::operator>>( _rxInStream, m_aControlSource); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const | |
| { | |
| switch (nHandle) | |
| { | |
| case PROPERTY_ID_INPUT_REQUIRED: | |
| rValue <<= m_bInputRequired; | |
| break; | |
| case PROPERTY_ID_CONTROLSOURCEPROPERTY: | |
| rValue <<= m_sValuePropertyName; | |
| break; | |
| case PROPERTY_ID_CONTROLSOURCE: | |
| rValue <<= m_aControlSource; | |
| break; | |
| case PROPERTY_ID_BOUNDFIELD: | |
| rValue <<= getField(); | |
| break; | |
| case PROPERTY_ID_CONTROLLABEL: | |
| if (!m_xLabelControl.is()) | |
| rValue.clear(); | |
| else | |
| rValue <<= m_xLabelControl; | |
| break; | |
| default: | |
| OControlModel::getFastPropertyValue(rValue, nHandle); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| sal_Bool OBoundControlModel::convertFastPropertyValue( | |
| Any& _rConvertedValue, Any& _rOldValue, | |
| sal_Int32 _nHandle, | |
| const Any& _rValue) | |
| throw (com::sun::star::lang::IllegalArgumentException) | |
| { | |
| sal_Bool bModified(sal_False); | |
| switch (_nHandle) | |
| { | |
| case PROPERTY_ID_INPUT_REQUIRED: | |
| bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, m_bInputRequired ); | |
| break; | |
| case PROPERTY_ID_CONTROLSOURCE: | |
| bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aControlSource); | |
| break; | |
| case PROPERTY_ID_BOUNDFIELD: | |
| DBG_ERROR( "OBoundControlModel::convertFastPropertyValue: BoundField should be a read-only property !" ); | |
| throw com::sun::star::lang::IllegalArgumentException(); | |
| case PROPERTY_ID_CONTROLLABEL: | |
| if (!_rValue.hasValue()) | |
| { // property set to void | |
| _rConvertedValue = Any(); | |
| getFastPropertyValue(_rOldValue, _nHandle); | |
| bModified = m_xLabelControl.is(); | |
| } | |
| else | |
| { | |
| bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_xLabelControl); | |
| if (!m_xLabelControl.is()) | |
| // an empty interface is interpreted as VOID | |
| _rOldValue.clear(); | |
| } | |
| break; | |
| default: | |
| bModified = OControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue); | |
| } | |
| return bModified; | |
| } | |
| //------------------------------------------------------------------------------ | |
| Any OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const | |
| { | |
| Any aDefault; | |
| switch ( _nHandle ) | |
| { | |
| case PROPERTY_ID_INPUT_REQUIRED: | |
| aDefault <<= sal_Bool( sal_True ); | |
| break; | |
| case PROPERTY_ID_CONTROLSOURCE: | |
| aDefault <<= ::rtl::OUString(); | |
| break; | |
| case PROPERTY_ID_CONTROLLABEL: | |
| aDefault <<= Reference< XPropertySet >(); | |
| break; | |
| } | |
| return aDefault; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception) | |
| { | |
| switch (nHandle) | |
| { | |
| case PROPERTY_ID_INPUT_REQUIRED: | |
| OSL_VERIFY( rValue >>= m_bInputRequired ); | |
| break; | |
| case PROPERTY_ID_CONTROLSOURCE: | |
| OSL_VERIFY( rValue >>= m_aControlSource ); | |
| break; | |
| case PROPERTY_ID_BOUNDFIELD: | |
| DBG_ERROR("OBoundControlModel::setFastPropertyValue_NoBroadcast : BoundField should be a read-only property !"); | |
| throw com::sun::star::lang::IllegalArgumentException(); | |
| case PROPERTY_ID_CONTROLLABEL: | |
| { | |
| if ( rValue.hasValue() && ( rValue.getValueTypeClass() != TypeClass_INTERFACE ) ) | |
| throw com::sun::star::lang::IllegalArgumentException(); | |
| Reference< XInterface > xNewValue( rValue, UNO_QUERY ); | |
| if ( !xNewValue.is() ) | |
| { // set property to "void" | |
| Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY ); | |
| if ( xComp.is() ) | |
| xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) ); | |
| m_xLabelControl = NULL; | |
| break; | |
| } | |
| Reference< XControlModel > xAsModel ( xNewValue, UNO_QUERY ); | |
| Reference< XServiceInfo > xAsServiceInfo ( xAsModel, UNO_QUERY ); | |
| Reference< XPropertySet > xAsPropSet ( xAsServiceInfo, UNO_QUERY ); | |
| Reference< XChild > xAsChild ( xAsPropSet, UNO_QUERY ); | |
| if ( !xAsChild.is() || !xAsServiceInfo->supportsService( m_aLabelServiceName ) ) | |
| { | |
| throw com::sun::star::lang::IllegalArgumentException(); | |
| } | |
| // check if weself and the given model have a common anchestor (up to the forms collection) | |
| Reference<XChild> xCont; | |
| query_interface(static_cast<XWeak*>(this), xCont); | |
| Reference< XInterface > xMyTopLevel = xCont->getParent(); | |
| while (xMyTopLevel.is()) | |
| { | |
| Reference<XForm> xAsForm(xMyTopLevel, UNO_QUERY); | |
| if (!xAsForm.is()) | |
| // found my root | |
| break; | |
| Reference<XChild> xLoopAsChild(xMyTopLevel, UNO_QUERY); | |
| xMyTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >(); | |
| } | |
| Reference< XInterface > xNewTopLevel = xAsChild->getParent(); | |
| while (xNewTopLevel.is()) | |
| { | |
| Reference<XForm> xAsForm(xNewTopLevel, UNO_QUERY); | |
| if (!xAsForm.is()) | |
| break; | |
| Reference<XChild> xLoopAsChild(xNewTopLevel, UNO_QUERY); | |
| xNewTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >(); | |
| } | |
| if (xNewTopLevel != xMyTopLevel) | |
| { | |
| // the both objects don't belong to the same forms collection -> not acceptable | |
| throw com::sun::star::lang::IllegalArgumentException(); | |
| } | |
| m_xLabelControl = xAsPropSet; | |
| Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY); | |
| if (xComp.is()) | |
| xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this))); | |
| } | |
| break; | |
| default: | |
| OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue ); | |
| } | |
| } | |
| // XPropertyChangeListener | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::propertyChange( const PropertyChangeEvent& evt ) throw(RuntimeException) | |
| { | |
| // if the DBColumn value changed, transfer it to the control | |
| if ( evt.PropertyName.equals( PROPERTY_VALUE ) ) | |
| { | |
| OSL_ENSURE( evt.Source == getField(), "OBoundControlModel::propertyChange: value changes from components other than our database colum?" ); | |
| osl::MutexGuard aGuard(m_aMutex); | |
| if ( m_bForwardValueChanges && m_xColumn.is() ) | |
| transferDbValueToControl(); | |
| } | |
| else | |
| { | |
| OSL_ENSURE( evt.Source == m_xExternalBinding, "OBoundControlModel::propertyChange: where did this come from?" ); | |
| // our binding has properties which can control properties of ourself | |
| ::rtl::OUString sBindingControlledProperty; | |
| bool bForwardToLabelControl = false; | |
| if ( evt.PropertyName.equals( PROPERTY_READONLY ) ) | |
| { | |
| sBindingControlledProperty = PROPERTY_READONLY; | |
| } | |
| else if ( evt.PropertyName.equals( PROPERTY_RELEVANT ) ) | |
| { | |
| sBindingControlledProperty = PROPERTY_ENABLED; | |
| bForwardToLabelControl = true; | |
| } | |
| else | |
| return; | |
| try | |
| { | |
| setPropertyValue( sBindingControlledProperty, evt.NewValue ); | |
| if ( bForwardToLabelControl && m_xLabelControl.is() ) | |
| m_xLabelControl->setPropertyValue( sBindingControlledProperty, evt.NewValue ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| OSL_ENSURE( sal_False, "OBoundControlModel::propertyChange: could not adjust my binding-controlled property!" ); | |
| } | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::onRowSetChanged( const EventObject& /*i_Event*/ ) throw (RuntimeException) | |
| { | |
| ControlModelLock aLock( *this ); | |
| FieldChangeNotifier aBoundFieldNotifier( aLock ); | |
| // disconnect from database column (which is controlled by parent, directly or indirectly) | |
| if ( hasField() ) | |
| impl_disconnectDatabaseColumn_noNotify(); | |
| // log off old listeners | |
| if ( isFormListening() ) | |
| doFormListening( false ); | |
| // determine the new ambient form | |
| impl_determineAmbientForm_nothrow(); | |
| // log on new listeners | |
| doFormListening( true ); | |
| // re-connect to database column if needed and possible | |
| if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() ) | |
| impl_connectDatabaseColumn_noNotify( false ); | |
| } | |
| // XBoundComponent | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::addUpdateListener(const Reference<XUpdateListener>& _rxListener) throw(RuntimeException) | |
| { | |
| m_aUpdateListeners.addInterface(_rxListener); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::removeUpdateListener(const Reference< XUpdateListener>& _rxListener) throw(RuntimeException) | |
| { | |
| m_aUpdateListeners.removeInterface(_rxListener); | |
| } | |
| //------------------------------------------------------------------------------ | |
| sal_Bool SAL_CALL OBoundControlModel::commit() throw(RuntimeException) | |
| { | |
| ControlModelLock aLock( *this ); | |
| OSL_PRECOND( m_bCommitable, "OBoundControlModel::commit: invalid call (I'm not commitable !) " ); | |
| if ( hasExternalValueBinding() ) | |
| { | |
| // in most cases, no action is required: For most derivees, we know the value property of | |
| // our control (see initValueProperty), and when an external binding is active, we | |
| // instantly forward all changes in this property to the external binding. | |
| if ( !m_sValuePropertyName.getLength() ) | |
| // but for those derivees which did not use this feature, we need an | |
| // explicit transfer | |
| transferControlValueToExternal( aLock ); | |
| return sal_True; | |
| } | |
| OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" ); | |
| // we reach this only if we're not working with an external binding | |
| if ( !hasField() ) | |
| return sal_True; | |
| ::cppu::OInterfaceIteratorHelper aIter( m_aUpdateListeners ); | |
| EventObject aEvent; | |
| aEvent.Source = static_cast< XWeak* >( this ); | |
| sal_Bool bSuccess = sal_True; | |
| aLock.release(); | |
| // >>>>>>>> ----- UNSAFE ----- >>>>>>>> | |
| while (aIter.hasMoreElements() && bSuccess) | |
| bSuccess = static_cast< XUpdateListener* >( aIter.next() )->approveUpdate( aEvent ); | |
| // <<<<<<<< ----- UNSAFE ----- <<<<<<<< | |
| aLock.acquire(); | |
| if ( bSuccess ) | |
| { | |
| try | |
| { | |
| if ( m_xColumnUpdate.is() ) | |
| bSuccess = commitControlValueToDbColumn( sal_False ); | |
| } | |
| catch(Exception&) | |
| { | |
| bSuccess = sal_False; | |
| } | |
| } | |
| if ( bSuccess ) | |
| { | |
| aLock.release(); | |
| m_aUpdateListeners.notifyEach( &XUpdateListener::updated, aEvent ); | |
| } | |
| return bSuccess; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::resetField() | |
| { | |
| m_xColumnUpdate.clear(); | |
| m_xColumn.clear(); | |
| m_xField.clear(); | |
| m_nFieldType = DataType::OTHER; | |
| } | |
| //------------------------------------------------------------------------------ | |
| sal_Bool OBoundControlModel::connectToField(const Reference<XRowSet>& rForm) | |
| { | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::connectToField: invalid call (have an external binding)!" ); | |
| // wenn eine Verbindung zur Datenbank existiert | |
| if (rForm.is() && getConnection(rForm).is()) | |
| { | |
| // Feld bestimmen und PropertyChangeListener | |
| m_xCursor = rForm; | |
| Reference<XPropertySet> xFieldCandidate; | |
| if (m_xCursor.is()) | |
| { | |
| Reference<XColumnsSupplier> xColumnsSupplier(m_xCursor, UNO_QUERY); | |
| DBG_ASSERT(xColumnsSupplier.is(), "OBoundControlModel::connectToField : the row set should support the com::sun::star::sdb::ResultSet service !"); | |
| if (xColumnsSupplier.is()) | |
| { | |
| Reference<XNameAccess> xColumns(xColumnsSupplier->getColumns(), UNO_QUERY); | |
| if (xColumns.is() && xColumns->hasByName(m_aControlSource)) | |
| { | |
| OSL_VERIFY( xColumns->getByName(m_aControlSource) >>= xFieldCandidate ); | |
| } | |
| } | |
| } | |
| try | |
| { | |
| sal_Int32 nFieldType = DataType::OTHER; | |
| if ( xFieldCandidate.is() ) | |
| { | |
| xFieldCandidate->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType; | |
| if ( approveDbColumnType( nFieldType ) ) | |
| impl_setField_noNotify( xFieldCandidate ); | |
| } | |
| else | |
| impl_setField_noNotify( NULL ); | |
| if ( m_xField.is() ) | |
| { | |
| if( m_xField->getPropertySetInfo()->hasPropertyByName( PROPERTY_VALUE ) ) | |
| { | |
| m_nFieldType = nFieldType; | |
| // an wertaenderungen horchen | |
| m_xField->addPropertyChangeListener( PROPERTY_VALUE, this ); | |
| m_xColumnUpdate = Reference< XColumnUpdate >( m_xField, UNO_QUERY ); | |
| m_xColumn = Reference< XColumn >( m_xField, UNO_QUERY ); | |
| sal_Int32 nNullableFlag = ColumnValue::NO_NULLS; | |
| m_xField->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullableFlag; | |
| m_bRequired = (ColumnValue::NO_NULLS == nNullableFlag); | |
| // we're optimistic : in case of ColumnValue_NULLABLE_UNKNOWN we assume nullability .... | |
| } | |
| else | |
| { | |
| OSL_ENSURE(sal_False, "OBoundControlModel::connectToField: property NAME not supported!"); | |
| impl_setField_noNotify( NULL ); | |
| } | |
| } | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| resetField(); | |
| } | |
| } | |
| return hasField(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::initFromField( const Reference< XRowSet >& _rxRowSet ) | |
| { | |
| // but only if the rowset if posisitioned on a valid record | |
| if ( hasField() && _rxRowSet.is() ) | |
| { | |
| if ( !_rxRowSet->isBeforeFirst() && !_rxRowSet->isAfterLast() ) | |
| transferDbValueToControl(); | |
| else | |
| // reset the field if the row set is empty | |
| // #i30661# / 2004-12-16 / frank.schoenheit@sun.com | |
| resetNoBroadcast(); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| sal_Bool OBoundControlModel::approveDbColumnType(sal_Int32 _nColumnType) | |
| { | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::approveDbColumnType: invalid call (have an external binding)!" ); | |
| if ((_nColumnType == DataType::BINARY) || (_nColumnType == DataType::VARBINARY) | |
| || (_nColumnType == DataType::LONGVARBINARY) || (_nColumnType == DataType::OTHER) | |
| || (_nColumnType == DataType::OBJECT) || (_nColumnType == DataType::DISTINCT) | |
| || (_nColumnType == DataType::STRUCT) || (_nColumnType == DataType::ARRAY) | |
| || (_nColumnType == DataType::BLOB) /*|| (_nColumnType == DataType::CLOB)*/ | |
| || (_nColumnType == DataType::REF) || (_nColumnType == DataType::SQLNULL)) | |
| return sal_False; | |
| return sal_True; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::impl_determineAmbientForm_nothrow() | |
| { | |
| Reference< XInterface > xParent( const_cast< OBoundControlModel* >( this )->getParent() ); | |
| m_xAmbientForm.set( xParent, UNO_QUERY ); | |
| if ( !m_xAmbientForm.is() ) | |
| { | |
| Reference< XRowSetSupplier > xSupRowSet( xParent, UNO_QUERY ); | |
| if ( xSupRowSet.is() ) | |
| m_xAmbientForm.set( xSupRowSet->getRowSet(), UNO_QUERY ); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::impl_connectDatabaseColumn_noNotify( bool _bFromReload ) | |
| { | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: not to be called with an external value binding!" ); | |
| // consistency checks | |
| DBG_ASSERT( !( hasField() && !_bFromReload ), | |
| "OBoundControlModel::impl_connectDatabaseColumn_noNotify: the form is just *loaded*, but we already have a field!" ); | |
| (void)_bFromReload; | |
| Reference< XRowSet > xRowSet( m_xAmbientForm, UNO_QUERY ); | |
| OSL_ENSURE( xRowSet.is(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: no row set!" ); | |
| if ( !xRowSet.is() ) | |
| return; | |
| if ( !hasField() ) | |
| { | |
| // connect to the column | |
| connectToField( xRowSet ); | |
| } | |
| // now that we're connected (more or less, even if we did not find a column), | |
| // we definately want to forward any potentially occuring value changes | |
| m_bForwardValueChanges = sal_True; | |
| // let derived classes react on this new connection | |
| m_bLoaded = sal_True; | |
| onConnectedDbColumn( xRowSet ); | |
| // initially transfer the db column value to the control, if we successfully connected to a database column | |
| if ( hasField() ) | |
| initFromField( xRowSet ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::impl_disconnectDatabaseColumn_noNotify() | |
| { | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_disconnectDatabaseColumn_noNotify: not to be called with an external value binding!" ); | |
| // let derived classes react on this | |
| onDisconnectedDbColumn(); | |
| if ( hasField() ) | |
| { | |
| getField()->removePropertyChangeListener( PROPERTY_VALUE, this ); | |
| resetField(); | |
| } | |
| m_xCursor = NULL; | |
| m_bLoaded = sal_False; | |
| } | |
| //============================================================================== | |
| // XLoadListener | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::loaded( const EventObject& _rEvent ) throw(RuntimeException) | |
| { | |
| ControlModelLock aLock( *this ); | |
| FieldChangeNotifier aBoundFieldNotifier( aLock ); | |
| OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::loaded: where does this come from?" ); | |
| (void)_rEvent; | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::loaded: we should never reach this with an external value binding!" ); | |
| if ( hasExternalValueBinding() ) | |
| return; | |
| impl_connectDatabaseColumn_noNotify( false ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::unloaded( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException) | |
| { | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloaded: we should never reach this with an external value binding!" ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::reloading( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException) | |
| { | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloading: we should never reach this with an external value binding!" ); | |
| if ( hasExternalValueBinding() ) | |
| return; | |
| osl::MutexGuard aGuard(m_aMutex); | |
| m_bForwardValueChanges = sal_False; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::unloading(const com::sun::star::lang::EventObject& /*aEvent*/) throw(RuntimeException) | |
| { | |
| ControlModelLock aLock( *this ); | |
| FieldChangeNotifier aBoundFieldNotifier( aLock ); | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloading: we should never reach this with an external value binding!" ); | |
| if ( hasExternalValueBinding() ) | |
| return; | |
| impl_disconnectDatabaseColumn_noNotify(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void SAL_CALL OBoundControlModel::reloaded( const EventObject& _rEvent ) throw(RuntimeException) | |
| { | |
| ControlModelLock aLock( *this ); | |
| FieldChangeNotifier aBoundFieldNotifier( aLock ); | |
| OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::reloaded: where does this come from?" ); | |
| (void)_rEvent; | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloaded: we should never reach this with an external value binding!" ); | |
| if ( hasExternalValueBinding() ) | |
| return; | |
| impl_connectDatabaseColumn_noNotify( true ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::setControlValue( const Any& _rValue, ValueChangeInstigator _eInstigator ) | |
| { | |
| m_eControlValueChangeInstigator = _eInstigator; | |
| doSetControlValue( _rValue ); | |
| m_eControlValueChangeInstigator = eOther; | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::doSetControlValue( const Any& _rValue ) | |
| { | |
| OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(), | |
| "OBoundControlModel::doSetControlValue: invalid aggregate !" ); | |
| OSL_PRECOND( m_sValuePropertyName.getLength() || ( m_nValuePropertyAggregateHandle != -1 ), | |
| "OBoundControlModel::doSetControlValue: please override if you have own value property handling!" ); | |
| try | |
| { | |
| // release our mutex once (it's acquired in one of the the calling methods), as setting aggregate properties | |
| // may cause any uno controls belonging to us to lock the solar mutex, which is potentially dangerous with | |
| // our own mutex locked | |
| // #72451# / 2000-01-31 / frank.schoenheit@sun.com | |
| MutexRelease aRelease( m_aMutex ); | |
| if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() ) | |
| { | |
| m_xAggregateFastSet->setFastPropertyValue( m_nValuePropertyAggregateHandle, _rValue ); | |
| } | |
| else if ( m_sValuePropertyName.getLength() && m_xAggregateSet.is() ) | |
| { | |
| m_xAggregateSet->setPropertyValue( m_sValuePropertyName, _rValue ); | |
| } | |
| } | |
| catch( const Exception& ) | |
| { | |
| OSL_ENSURE( sal_False, "OBoundControlModel::doSetControlValue: caught an exception!" ); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::onConnectedValidator( ) | |
| { | |
| try | |
| { | |
| // if we have an external validator, we do not want the control to force invalid | |
| // inputs to the default value. Instead, invalid inputs should be translated | |
| // to NaN (not a number) | |
| Reference< XPropertySetInfo > xAggregatePropertyInfo; | |
| if ( m_xAggregateSet.is() ) | |
| xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo(); | |
| if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) ) | |
| m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( (sal_Bool)sal_False ) ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| OSL_ENSURE( sal_False, "OBoundControlModel::onConnectedValidator: caught an exception!" ); | |
| } | |
| recheckValidity( false ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::onDisconnectedValidator( ) | |
| { | |
| try | |
| { | |
| Reference< XPropertySetInfo > xAggregatePropertyInfo; | |
| if ( m_xAggregateSet.is() ) | |
| xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo(); | |
| if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) ) | |
| m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( (sal_Bool)sal_True ) ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| OSL_ENSURE( sal_False, "OBoundControlModel::onDisconnectedValidator: caught an exception!" ); | |
| } | |
| recheckValidity( false ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::onConnectedExternalValue( ) | |
| { | |
| calculateExternalValueType(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::onDisconnectedExternalValue( ) | |
| { | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::onConnectedDbColumn( const Reference< XInterface >& /*_rxForm*/ ) | |
| { | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onConnectedDbColumn: how this? There's an external value binding!" ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::onDisconnectedDbColumn() | |
| { | |
| OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onDisconnectedDbColumn: how this? There's an external value binding!" ); | |
| } | |
| // XReset | |
| //----------------------------------------------------------------------------- | |
| Any OBoundControlModel::getDefaultForReset() const | |
| { | |
| return Any(); | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::resetNoBroadcast() | |
| { | |
| setControlValue( getDefaultForReset(), eOther ); | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::addResetListener(const Reference<XResetListener>& l) throw (RuntimeException) | |
| { | |
| m_aResetHelper.addResetListener( l ); | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::removeResetListener(const Reference<XResetListener>& l) throw (RuntimeException) | |
| { | |
| m_aResetHelper.removeResetListener( l ); | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::reset() throw (RuntimeException) | |
| { | |
| if ( !m_aResetHelper.approveReset() ) | |
| return; | |
| ControlModelLock aLock( *this ); | |
| // on a new record? | |
| sal_Bool bIsNewRecord = sal_False; | |
| Reference<XPropertySet> xSet( m_xCursor, UNO_QUERY ); | |
| if ( xSet.is() ) | |
| { | |
| try | |
| { | |
| xSet->getPropertyValue( PROPERTY_ISNEW ) >>= bIsNewRecord; | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| } | |
| } | |
| // cursor on an invalid row? | |
| sal_Bool bInvalidCursorPosition = sal_True; | |
| try | |
| { | |
| bInvalidCursorPosition = m_xCursor.is() | |
| && ( m_xCursor->isAfterLast() | |
| || m_xCursor->isBeforeFirst() | |
| ) | |
| && !bIsNewRecord; | |
| } | |
| catch( const SQLException& ) | |
| { | |
| OSL_ENSURE( sal_False, "OBoundControlModel::reset: caught an SQL exception!" ); | |
| } | |
| // don't count the insert row as "invalid" | |
| // @since #i24495# | |
| // @date 2004-05-14 | |
| // @author fs@openoffice.org | |
| sal_Bool bSimpleReset = | |
| ( !m_xColumn.is() // no connection to a database column | |
| || ( m_xCursor.is() // OR we have an improperly positioned cursor | |
| && bInvalidCursorPosition | |
| ) | |
| || hasExternalValueBinding() // OR we have an external value binding | |
| ); | |
| if ( !bSimpleReset ) | |
| { | |
| // The default values will be set if and only if the current value of the field which we're bound | |
| // to is NULL. | |
| // Else, the current field value should be refreshed | |
| // This behaviour is not completely ... "matured": What should happen if the field as well as the | |
| // control have a default value? | |
| sal_Bool bIsNull = sal_True; | |
| // we have to access the field content at least once to get a reliable result by XColumn::wasNull | |
| try | |
| { | |
| // normally, we'd do a getString here. However, this is extremely expensive in the case | |
| // of binary fields. Unfortunately, getString is the only method which is guaranteed | |
| // to *always* succeed, all other getXXX methods may fail if the column is asked for a | |
| // non-convertible type | |
| sal_Int32 nFieldType = DataType::OBJECT; | |
| getField()->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType; | |
| if ( ( nFieldType == DataType::BINARY ) | |
| || ( nFieldType == DataType::VARBINARY ) | |
| || ( nFieldType == DataType::LONGVARBINARY ) | |
| || ( nFieldType == DataType::OBJECT ) | |
| /*|| ( nFieldType == DataType::CLOB )*/ | |
| ) | |
| m_xColumn->getBinaryStream(); | |
| else if ( nFieldType == DataType::BLOB ) | |
| m_xColumn->getBlob(); | |
| else | |
| m_xColumn->getString(); | |
| bIsNull = m_xColumn->wasNull(); | |
| } | |
| catch(Exception&) | |
| { | |
| DBG_ERROR("OBoundControlModel::reset: this should have succeeded in all cases!"); | |
| } | |
| sal_Bool bNeedValueTransfer = sal_True; | |
| if ( bIsNull ) | |
| { | |
| if ( bIsNewRecord ) | |
| { | |
| // reset the control to it's default | |
| resetNoBroadcast(); | |
| // and immediately commit the changes to the DB column, to keep consistency | |
| commitControlValueToDbColumn( sal_True ); | |
| bNeedValueTransfer = sal_False; | |
| } | |
| } | |
| if ( bNeedValueTransfer ) | |
| transferDbValueToControl(); | |
| } | |
| else | |
| { | |
| resetNoBroadcast(); | |
| // transfer to the external binding, if necessary | |
| if ( hasExternalValueBinding() ) | |
| transferControlValueToExternal( aLock ); | |
| } | |
| // revalidate, if necessary | |
| if ( hasValidator() ) | |
| recheckValidity( true ); | |
| aLock.release(); | |
| m_aResetHelper.notifyResetted(); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| void OBoundControlModel::impl_setField_noNotify( const Reference< XPropertySet>& _rxField ) | |
| { | |
| DBG_ASSERT( !hasExternalValueBinding(), "OBoundControlModel::impl_setField_noNotify: We have an external value binding!" ); | |
| m_xField = _rxField; | |
| } | |
| //-------------------------------------------------------------------- | |
| sal_Bool OBoundControlModel::impl_approveValueBinding_nolock( const Reference< XValueBinding >& _rxBinding ) | |
| { | |
| if ( !_rxBinding.is() ) | |
| return sal_False; | |
| Sequence< Type > aTypeCandidates; | |
| { | |
| // SYNCHRONIZED --> | |
| ::osl::MutexGuard aGuard( m_aMutex ); | |
| aTypeCandidates = getSupportedBindingTypes(); | |
| // <-- SYNCHRONIZED | |
| } | |
| for ( const Type* pType = aTypeCandidates.getConstArray(); | |
| pType != aTypeCandidates.getConstArray() + aTypeCandidates.getLength(); | |
| ++pType | |
| ) | |
| { | |
| if ( _rxBinding->supportsType( *pType ) ) | |
| return sal_True; | |
| } | |
| return sal_False; | |
| } | |
| //-------------------------------------------------------------------- | |
| void OBoundControlModel::connectExternalValueBinding( | |
| const Reference< XValueBinding >& _rxBinding, ControlModelLock& _rInstanceLock ) | |
| { | |
| OSL_PRECOND( _rxBinding.is(), "OBoundControlModel::connectExternalValueBinding: invalid binding instance!" ); | |
| OSL_PRECOND( !hasExternalValueBinding( ), "OBoundControlModel::connectExternalValueBinding: precond not met (currently have a binding)!" ); | |
| // if we're connected to a database column, suspend this | |
| if ( hasField() ) | |
| impl_disconnectDatabaseColumn_noNotify(); | |
| // suspend listening for load-related events at out ambient form. | |
| // This is because an external value binding overrules a possible database binding. | |
| if ( isFormListening() ) | |
| doFormListening( false ); | |
| // remember this new binding | |
| m_xExternalBinding = _rxBinding; | |
| // tell the derivee | |
| onConnectedExternalValue(); | |
| try | |
| { | |
| // add as value listener so we get notified when the value changes | |
| Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY ); | |
| if ( xModifiable.is() ) | |
| xModifiable->addModifyListener( this ); | |
| // add as property change listener for some (possibly present) properties we're | |
| // interested in | |
| Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY ); | |
| Reference< XPropertySetInfo > xBindingPropsInfo( xBindingProps.is() ? xBindingProps->getPropertySetInfo() : Reference< XPropertySetInfo >() ); | |
| if ( xBindingPropsInfo.is() ) | |
| { | |
| if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_READONLY ) ) | |
| { | |
| xBindingProps->addPropertyChangeListener( PROPERTY_READONLY, this ); | |
| m_bBindingControlsRO = sal_True; | |
| } | |
| if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_RELEVANT ) ) | |
| { | |
| xBindingProps->addPropertyChangeListener( PROPERTY_RELEVANT, this ); | |
| m_bBindingControlsEnable = sal_True; | |
| } | |
| } | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| } | |
| // propagate our new value | |
| transferExternalValueToControl( _rInstanceLock ); | |
| // if the binding is also a validator, use it, too. This is a constraint of the | |
| // com.sun.star.form.binding.ValidatableBindableFormComponent service | |
| if ( m_bSupportsValidation ) | |
| { | |
| try | |
| { | |
| Reference< XValidator > xAsValidator( _rxBinding, UNO_QUERY ); | |
| if ( xAsValidator.is() ) | |
| setValidator( xAsValidator ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| } | |
| } | |
| } | |
| //-------------------------------------------------------------------- | |
| void OBoundControlModel::disconnectExternalValueBinding( ) | |
| { | |
| try | |
| { | |
| // not listening at the binding anymore | |
| Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY ); | |
| if ( xModifiable.is() ) | |
| xModifiable->removeModifyListener( this ); | |
| // remove as property change listener | |
| Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY ); | |
| if ( m_bBindingControlsRO ) | |
| xBindingProps->removePropertyChangeListener( PROPERTY_READONLY, this ); | |
| if ( m_bBindingControlsEnable ) | |
| xBindingProps->removePropertyChangeListener( PROPERTY_RELEVANT, this ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| OSL_ENSURE( sal_False, "OBoundControlModel::disconnectExternalValueBinding: caught an exception!" ); | |
| } | |
| // if the binding also acts as our validator, disconnect the validator, too | |
| if ( ( m_xExternalBinding == m_xValidator ) && m_xValidator.is() ) | |
| disconnectValidator( ); | |
| // no binding anymore | |
| m_xExternalBinding.clear(); | |
| // be a load listener at our form, again. This was suspended while we had | |
| // an external value binding in place. | |
| doFormListening( true ); | |
| // re-connect to database column of the new parent | |
| if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() ) | |
| impl_connectDatabaseColumn_noNotify( false ); | |
| // tell the derivee | |
| onDisconnectedExternalValue(); | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OBoundControlModel::setValueBinding( const Reference< XValueBinding >& _rxBinding ) throw (IncompatibleTypesException, RuntimeException) | |
| { | |
| OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::setValueBinding: How did you reach this method?" ); | |
| // the interface for this method should not have been exposed if we do not | |
| // support binding to external data | |
| if ( !impl_approveValueBinding_nolock( _rxBinding ) ) | |
| { | |
| throw IncompatibleTypesException( | |
| FRM_RES_STRING( RID_STR_INCOMPATIBLE_TYPES ), | |
| *this | |
| ); | |
| } | |
| ControlModelLock aLock( *this ); | |
| // since a ValueBinding overrules any potentially active database binding, the change in a ValueBinding | |
| // might trigger a change in our BoundField. | |
| FieldChangeNotifier aBoundFieldNotifier( aLock ); | |
| // disconnect from the old binding | |
| if ( hasExternalValueBinding() ) | |
| disconnectExternalValueBinding( ); | |
| // connect to the new binding | |
| if ( _rxBinding.is() ) | |
| connectExternalValueBinding( _rxBinding, aLock ); | |
| } | |
| //-------------------------------------------------------------------- | |
| Reference< XValueBinding > SAL_CALL OBoundControlModel::getValueBinding( ) throw (RuntimeException) | |
| { | |
| ::osl::MutexGuard aGuard( m_aMutex ); | |
| OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::getValueBinding: How did you reach this method?" ); | |
| // the interface for this method should not have been exposed if we do not | |
| // support binding to external data | |
| return m_xExternalBinding; | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OBoundControlModel::modified( const EventObject& _rEvent ) throw ( RuntimeException ) | |
| { | |
| ControlModelLock aLock( *this ); | |
| OSL_PRECOND( hasExternalValueBinding(), "OBoundControlModel::modified: Where did this come from?" ); | |
| if ( !m_bTransferingValue && ( m_xExternalBinding == _rEvent.Source ) && m_xExternalBinding.is() ) | |
| { | |
| transferExternalValueToControl( aLock ); | |
| } | |
| } | |
| //-------------------------------------------------------------------- | |
| void OBoundControlModel::transferDbValueToControl( ) | |
| { | |
| try | |
| { | |
| setControlValue( translateDbColumnToControlValue(), eDbColumnBinding ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::transferExternalValueToControl( ControlModelLock& _rInstanceLock ) | |
| { | |
| Reference< XValueBinding > xExternalBinding( m_xExternalBinding ); | |
| Type aValueExchangeType( getExternalValueType() ); | |
| _rInstanceLock.release(); | |
| // >>>>>>>> ----- UNSAFE ----- >>>>>>>> | |
| Any aExternalValue; | |
| try | |
| { | |
| aExternalValue = xExternalBinding->getValue( aValueExchangeType ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| } | |
| // <<<<<<<< ----- UNSAFE ----- <<<<<<<< | |
| _rInstanceLock.acquire(); | |
| setControlValue( translateExternalValueToControlValue( aExternalValue ), eExternalBinding ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::transferControlValueToExternal( ControlModelLock& _rInstanceLock ) | |
| { | |
| OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(), | |
| "OBoundControlModel::transferControlValueToExternal: precondition not met!" ); | |
| if ( m_xExternalBinding.is() ) | |
| { | |
| Any aExternalValue( translateControlValueToExternalValue() ); | |
| m_bTransferingValue = sal_True; | |
| _rInstanceLock.release(); | |
| // >>>>>>>> ----- UNSAFE ----- >>>>>>>> | |
| try | |
| { | |
| m_xExternalBinding->setValue( aExternalValue ); | |
| } | |
| catch( const Exception& ) | |
| { | |
| DBG_UNHANDLED_EXCEPTION(); | |
| } | |
| // <<<<<<<< ----- UNSAFE ----- <<<<<<<< | |
| _rInstanceLock.acquire(); | |
| m_bTransferingValue = sal_False; | |
| } | |
| } | |
| // ----------------------------------------------------------------------------- | |
| Sequence< Type > OBoundControlModel::getSupportedBindingTypes() | |
| { | |
| return Sequence< Type >( &m_aValuePropertyType, 1 ); | |
| } | |
| //----------------------------------------------------------------------------- | |
| void OBoundControlModel::calculateExternalValueType() | |
| { | |
| m_aExternalValueType = Type(); | |
| if ( !m_xExternalBinding.is() ) | |
| return; | |
| Sequence< Type > aTypeCandidates( getSupportedBindingTypes() ); | |
| for ( const Type* pTypeCandidate = aTypeCandidates.getConstArray(); | |
| pTypeCandidate != aTypeCandidates.getConstArray() + aTypeCandidates.getLength(); | |
| ++pTypeCandidate | |
| ) | |
| { | |
| if ( m_xExternalBinding->supportsType( *pTypeCandidate ) ) | |
| { | |
| m_aExternalValueType = *pTypeCandidate; | |
| break; | |
| } | |
| } | |
| } | |
| //----------------------------------------------------------------------------- | |
| Any OBoundControlModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const | |
| { | |
| OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(), | |
| "OBoundControlModel::translateExternalValueToControlValue: precondition not met!" ); | |
| Any aControlValue( _rExternalValue ); | |
| // if the external value is VOID, and our value property is not allowed to be VOID, | |
| // then default-construct a value | |
| if ( !aControlValue.hasValue() && !m_bValuePropertyMayBeVoid ) | |
| aControlValue.setValue( NULL, m_aValuePropertyType ); | |
| // outta here | |
| return aControlValue; | |
| } | |
| //------------------------------------------------------------------------------ | |
| Any OBoundControlModel::translateControlValueToExternalValue( ) const | |
| { | |
| return getControlValue( ); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Any OBoundControlModel::translateControlValueToValidatableValue( ) const | |
| { | |
| OSL_PRECOND( m_xValidator.is(), "OBoundControlModel::translateControlValueToValidatableValue: no validator, so why should I?" ); | |
| if ( ( m_xValidator == m_xExternalBinding ) && m_xValidator.is() ) | |
| return translateControlValueToExternalValue(); | |
| return getControlValue(); | |
| } | |
| //------------------------------------------------------------------------------ | |
| Any OBoundControlModel::getControlValue( ) const | |
| { | |
| OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(), | |
| "OBoundControlModel::getControlValue: invalid aggregate !" ); | |
| OSL_PRECOND( m_sValuePropertyName.getLength() || ( m_nValuePropertyAggregateHandle != -1 ), | |
| "OBoundControlModel::getControlValue: please override if you have own value property handling!" ); | |
| // determine the current control value | |
| Any aControlValue; | |
| if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() ) | |
| { | |
| aControlValue = m_xAggregateFastSet->getFastPropertyValue( m_nValuePropertyAggregateHandle ); | |
| } | |
| else if ( m_sValuePropertyName.getLength() && m_xAggregateSet.is() ) | |
| { | |
| aControlValue = m_xAggregateSet->getPropertyValue( m_sValuePropertyName ); | |
| } | |
| return aControlValue; | |
| } | |
| //-------------------------------------------------------------------- | |
| void OBoundControlModel::connectValidator( const Reference< XValidator >& _rxValidator ) | |
| { | |
| OSL_PRECOND( _rxValidator.is(), "OBoundControlModel::connectValidator: invalid validator instance!" ); | |
| OSL_PRECOND( !hasValidator( ), "OBoundControlModel::connectValidator: precond not met (have a validator currently)!" ); | |
| m_xValidator = _rxValidator; | |
| // add as value listener so we get notified when the value changes | |
| if ( m_xValidator.is() ) | |
| { | |
| try | |
| { | |
| m_xValidator->addValidityConstraintListener( this ); | |
| } | |
| catch( const RuntimeException& ) | |
| { | |
| } | |
| } | |
| onConnectedValidator( ); | |
| } | |
| //-------------------------------------------------------------------- | |
| void OBoundControlModel::disconnectValidator( ) | |
| { | |
| OSL_PRECOND( hasValidator( ), "OBoundControlModel::connectValidator: precond not met (don't have a validator currently)!" ); | |
| // add as value listener so we get notified when the value changes | |
| if ( m_xValidator.is() ) | |
| { | |
| try | |
| { | |
| m_xValidator->removeValidityConstraintListener( this ); | |
| } | |
| catch( const RuntimeException& ) | |
| { | |
| } | |
| } | |
| m_xValidator.clear(); | |
| onDisconnectedValidator( ); | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OBoundControlModel::setValidator( const Reference< XValidator >& _rxValidator ) throw (VetoException,RuntimeException) | |
| { | |
| ::osl::ClearableMutexGuard aGuard( m_aMutex ); | |
| OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::setValidator: How did you reach this method?" ); | |
| // the interface for this method should not have been exposed if we do not | |
| // support validation | |
| // early out if the validator does not change | |
| if( _rxValidator == m_xValidator ) | |
| return; | |
| if ( m_xValidator.is() && ( m_xValidator == m_xExternalBinding ) ) | |
| throw VetoException( | |
| FRM_RES_STRING( RID_STR_INVALID_VALIDATOR ), | |
| *this | |
| ); | |
| // disconnect from the old validator | |
| if ( hasValidator() ) | |
| disconnectValidator( ); | |
| // connect to the new validator | |
| if ( _rxValidator.is() ) | |
| connectValidator( _rxValidator ); | |
| } | |
| //-------------------------------------------------------------------- | |
| Reference< XValidator > SAL_CALL OBoundControlModel::getValidator( ) throw (RuntimeException) | |
| { | |
| ::osl::MutexGuard aGuard( m_aMutex ); | |
| OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::getValidator: How did you reach this method?" ); | |
| // the interface for this method should not have been exposed if we do not | |
| // support validation | |
| return m_xValidator; | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OBoundControlModel::validityConstraintChanged( const EventObject& /*Source*/ ) throw (RuntimeException) | |
| { | |
| ::osl::ClearableMutexGuard aGuard( m_aMutex ); | |
| OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::validityConstraintChanged: How did you reach this method?" ); | |
| // the interface for this method should not have been exposed if we do not | |
| // support validation | |
| recheckValidity( false ); | |
| } | |
| //-------------------------------------------------------------------- | |
| sal_Bool SAL_CALL OBoundControlModel::isValid( ) throw (RuntimeException) | |
| { | |
| return m_bIsCurrentValueValid; | |
| } | |
| //-------------------------------------------------------------------- | |
| ::com::sun::star::uno::Any OBoundControlModel::getCurrentFormComponentValue() const | |
| { | |
| if ( hasValidator() ) | |
| return translateControlValueToValidatableValue(); | |
| return getControlValue(); | |
| } | |
| //-------------------------------------------------------------------- | |
| Any SAL_CALL OBoundControlModel::getCurrentValue( ) throw (RuntimeException) | |
| { | |
| ::osl::MutexGuard aGuard( m_aMutex ); | |
| return getCurrentFormComponentValue(); | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OBoundControlModel::addFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException) | |
| { | |
| if ( Listener.is() ) | |
| m_aFormComponentListeners.addInterface( Listener ); | |
| } | |
| //-------------------------------------------------------------------- | |
| void SAL_CALL OBoundControlModel::removeFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException) | |
| { | |
| if ( Listener.is() ) | |
| m_aFormComponentListeners.removeInterface( Listener ); | |
| } | |
| //-------------------------------------------------------------------- | |
| void OBoundControlModel::recheckValidity( bool _bForceNotification ) | |
| { | |
| try | |
| { | |
| sal_Bool bIsCurrentlyValid = sal_True; | |
| if ( hasValidator() ) | |
| bIsCurrentlyValid = m_xValidator->isValid( translateControlValueToValidatableValue() ); | |
| if ( ( bIsCurrentlyValid != m_bIsCurrentValueValid ) || _bForceNotification ) | |
| { | |
| m_bIsCurrentValueValid = bIsCurrentlyValid; | |
| // release our mutex for the notifications | |
| MutexRelease aRelease( m_aMutex ); | |
| m_aFormComponentListeners.notifyEach( &validation::XFormComponentValidityListener::componentValidityChanged, EventObject( *this ) ); | |
| } | |
| } | |
| catch( const Exception& ) | |
| { | |
| OSL_ENSURE( sal_False, "OBoundControlModel::recheckValidity: caught an exception!" ); | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| void OBoundControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const | |
| { | |
| BEGIN_DESCRIBE_PROPERTIES( 5, OControlModel ) | |
| DECL_PROP1 ( CONTROLSOURCE, ::rtl::OUString, BOUND ); | |
| DECL_IFACE_PROP3( BOUNDFIELD, XPropertySet, BOUND, READONLY, TRANSIENT ); | |
| DECL_IFACE_PROP2( CONTROLLABEL, XPropertySet, BOUND, MAYBEVOID ); | |
| DECL_PROP2 ( CONTROLSOURCEPROPERTY, ::rtl::OUString, READONLY, TRANSIENT ); | |
| DECL_BOOL_PROP1 ( INPUT_REQUIRED, BOUND ); | |
| END_DESCRIBE_PROPERTIES() | |
| } | |
| // ----------------------------------------------------------------------------- | |
| //......................................................................... | |
| } | |
| //... namespace frm ....................................................... | |