bump product version to 4.1.6.2
[LibreOffice.git] / forms / source / component / FormComponent.cxx
blob12f0f6a563ec8aed1a910f60d16dd50ed5c96721
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "componenttools.hxx"
22 #include "FormComponent.hxx"
23 #include "frm_resource.hrc"
24 #include "frm_resource.hxx"
25 #include "property.hrc"
26 #include "services.hxx"
28 #include <com/sun/star/awt/XTextComponent.hpp>
29 #include <com/sun/star/awt/XVclWindowPeer.hpp>
30 #include <com/sun/star/awt/XWindow.hpp>
31 #include <com/sun/star/form/XForm.hpp>
32 #include <com/sun/star/form/XLoadable.hpp>
33 #include <com/sun/star/io/XMarkableStream.hpp>
34 #include <com/sun/star/lang/DisposedException.hpp>
35 #include <com/sun/star/sdb/XRowSetChangeBroadcaster.hpp>
36 #include <com/sun/star/sdb/XRowSetSupplier.hpp>
37 #include <com/sun/star/sdbc/ColumnValue.hpp>
38 #include <com/sun/star/sdbc/DataType.hpp>
39 #include <com/sun/star/util/XModifyBroadcaster.hpp>
41 #include <comphelper/basicio.hxx>
42 #include <comphelper/guarding.hxx>
43 #include <comphelper/listenernotification.hxx>
44 #include <comphelper/property.hxx>
45 #include <connectivity/dbtools.hxx>
46 #include <cppuhelper/queryinterface.hxx>
47 #include <rtl/logfile.hxx>
48 #include <toolkit/helper/emptyfontdescriptor.hxx>
49 #include <tools/debug.hxx>
50 #include <tools/diagnose_ex.h>
52 #include <functional>
53 #include <algorithm>
56 //... namespace frm .......................................................
57 namespace frm
59 //.........................................................................
61 using namespace ::com::sun::star::uno;
62 using namespace ::com::sun::star::sdb;
63 using namespace ::com::sun::star::sdbc;
64 using namespace ::com::sun::star::sdbcx;
65 using namespace ::com::sun::star::beans;
66 using namespace ::com::sun::star::container;
67 using namespace ::com::sun::star::form;
68 using namespace ::com::sun::star::awt;
69 using namespace ::com::sun::star::io;
70 using namespace ::com::sun::star::lang;
71 using namespace ::com::sun::star::util;
72 using namespace ::com::sun::star::form::binding;
73 using namespace ::com::sun::star::form::validation;
74 using namespace ::dbtools;
75 using namespace ::comphelper;
77 //=========================================================================
78 //= FieldChangeNotifier
79 //=========================================================================
80 //-------------------------------------------------------------------------
81 void ControlModelLock::impl_notifyAll_nothrow()
83 m_rModel.firePropertyChanges( m_aHandles, m_aOldValues, m_aNewValues, OControlModel::LockAccess() );
86 //-------------------------------------------------------------------------
87 void ControlModelLock::addPropertyNotification( const sal_Int32 _nHandle, const Any& _rOldValue, const Any& _rNewValue )
89 sal_Int32 nOldLength = m_aHandles.getLength();
90 if ( ( nOldLength != m_aOldValues.getLength() )
91 || ( nOldLength != m_aNewValues.getLength() )
93 throw RuntimeException( OUString(), m_rModel );
95 m_aHandles.realloc( nOldLength + 1 );
96 m_aHandles[ nOldLength ] = _nHandle;
97 m_aOldValues.realloc( nOldLength + 1 );
98 m_aOldValues[ nOldLength ] = _rOldValue;
99 m_aNewValues.realloc( nOldLength + 1 );
100 m_aNewValues[ nOldLength ] = _rNewValue;
103 //=========================================================================
104 //= FieldChangeNotifier
105 //=========================================================================
106 //-------------------------------------------------------------------------
107 class FieldChangeNotifier
109 public:
110 FieldChangeNotifier( ControlModelLock& _rLock )
111 :m_rLock( _rLock )
112 ,m_rModel( dynamic_cast< OBoundControlModel& >( _rLock.getModel() ) )
114 m_xOldField = m_rModel.getField();
117 ~FieldChangeNotifier()
119 Reference< XPropertySet > xNewField( m_rModel.getField() );
120 if ( m_xOldField != xNewField )
121 m_rLock.addPropertyNotification( PROPERTY_ID_BOUNDFIELD, makeAny( m_xOldField ), makeAny( xNewField ) );
124 private:
125 ControlModelLock& m_rLock;
126 OBoundControlModel& m_rModel;
127 Reference< XPropertySet > m_xOldField;
130 //=============================================================================
131 //= base class for form layer controls
132 //=============================================================================
133 DBG_NAME(frm_OControl)
134 //------------------------------------------------------------------------------
135 OControl::OControl( const Reference< XMultiServiceFactory >& _rxFactory, const OUString& _rAggregateService, const sal_Bool _bSetDelegator )
136 :OComponentHelper(m_aMutex)
137 ,m_aContext( _rxFactory )
139 DBG_CTOR(frm_OControl, NULL);
140 // VCL-Control aggregieren
141 // bei Aggregation den Refcount um eins erhoehen da im setDelegator
142 // das Aggregat selbst den Refcount erhoeht
143 increment( m_refCount );
145 m_xAggregate = m_xAggregate.query( _rxFactory->createInstance( _rAggregateService ) );
146 m_xControl = m_xControl.query( m_xAggregate );
148 decrement( m_refCount );
150 if ( _bSetDelegator )
151 doSetDelegator();
154 //------------------------------------------------------------------------------
155 OControl::~OControl()
157 DBG_DTOR(frm_OControl, NULL);
158 doResetDelegator();
161 //------------------------------------------------------------------------------
162 void OControl::doResetDelegator()
164 if ( m_xAggregate.is() )
165 m_xAggregate->setDelegator( NULL );
168 //------------------------------------------------------------------------------
169 void OControl::doSetDelegator()
171 increment( m_refCount );
172 if ( m_xAggregate.is() )
173 { // those brackets are important for some compilers, don't remove!
174 // (they ensure that the temporary object created in the line below
175 // is destroyed *before* the refcount-decrement)
176 m_xAggregate->setDelegator( static_cast< XWeak* >( this ) );
178 decrement( m_refCount );
181 // UNO Anbindung
182 //------------------------------------------------------------------------------
183 Any SAL_CALL OControl::queryAggregation( const Type& _rType ) throw(RuntimeException)
185 // ask the base class
186 Any aReturn( OComponentHelper::queryAggregation(_rType) );
187 // ask our own interfaces
188 if (!aReturn.hasValue())
190 aReturn = OControl_BASE::queryInterface(_rType);
191 // ask our aggregate
192 if (!aReturn.hasValue() && m_xAggregate.is())
193 aReturn = m_xAggregate->queryAggregation(_rType);
196 return aReturn;
199 //------------------------------------------------------------------------------
200 Sequence<sal_Int8> SAL_CALL OControl::getImplementationId() throw(RuntimeException)
202 return OImplementationIds::getImplementationId(getTypes());
205 //------------------------------------------------------------------------------
206 Sequence<Type> SAL_CALL OControl::getTypes() throw(RuntimeException)
208 TypeBag aTypes( _getTypes() );
210 Reference< XTypeProvider > xProv;
211 if ( query_aggregation( m_xAggregate, xProv ) )
212 aTypes.addTypes( xProv->getTypes() );
214 return aTypes.getTypes();
217 //------------------------------------------------------------------------------
218 Sequence<Type> OControl::_getTypes()
220 return TypeBag( OComponentHelper::getTypes(), OControl_BASE::getTypes() ).getTypes();
223 //------------------------------------------------------------------------------
224 void OControl::initFormControlPeer( const Reference< XWindowPeer >& /*_rxPeer*/ )
226 // nothing to do here
229 // OComponentHelper
230 //------------------------------------------------------------------------------
231 void OControl::disposing()
233 OComponentHelper::disposing();
235 m_aWindowStateGuard.attach( NULL, NULL );
237 Reference< XComponent > xComp;
238 if (query_aggregation(m_xAggregate, xComp))
239 xComp->dispose();
242 // XServiceInfo
243 //------------------------------------------------------------------------------
244 sal_Bool SAL_CALL OControl::supportsService(const OUString& _rsServiceName) throw ( RuntimeException)
246 Sequence<OUString> aSupported = getSupportedServiceNames();
247 const OUString* pSupported = aSupported.getConstArray();
248 for (sal_Int32 i=0; i<aSupported.getLength(); ++i, ++pSupported)
249 if (pSupported->equals(_rsServiceName))
250 return sal_True;
251 return sal_False;
254 //------------------------------------------------------------------------------
255 Sequence< OUString > OControl::getAggregateServiceNames()
257 Sequence< OUString > aAggServices;
258 Reference< XServiceInfo > xInfo;
259 if ( query_aggregation( m_xAggregate, xInfo ) )
260 aAggServices = xInfo->getSupportedServiceNames();
261 return aAggServices;
264 //------------------------------------------------------------------------------
265 Sequence<OUString> SAL_CALL OControl::getSupportedServiceNames() throw(RuntimeException)
267 return ::comphelper::concatSequences(
268 getAggregateServiceNames(),
269 getSupportedServiceNames_Static()
273 //------------------------------------------------------------------------------
274 Sequence< OUString > SAL_CALL OControl::getSupportedServiceNames_Static() throw( RuntimeException )
276 // no own supported service names
277 return Sequence< OUString >();
280 // XEventListener
281 //------------------------------------------------------------------------------
282 void SAL_CALL OControl::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException)
284 Reference< XInterface > xAggAsIface;
285 query_aggregation(m_xAggregate, xAggAsIface);
287 // does the disposing come from the aggregate ?
288 if (xAggAsIface != Reference< XInterface >(_rEvent.Source, UNO_QUERY))
289 { // no -> forward it
290 Reference<com::sun::star::lang::XEventListener> xListener;
291 if (query_aggregation(m_xAggregate, xListener))
292 xListener->disposing(_rEvent);
296 // XControl
297 //------------------------------------------------------------------------------
298 void SAL_CALL OControl::setContext(const Reference< XInterface >& Context) throw (RuntimeException)
300 if (m_xControl.is())
301 m_xControl->setContext(Context);
304 //------------------------------------------------------------------------------
305 Reference< XInterface > SAL_CALL OControl::getContext() throw (RuntimeException)
307 return m_xControl.is() ? m_xControl->getContext() : Reference< XInterface >();
310 //------------------------------------------------------------------------------
311 void OControl::impl_resetStateGuard_nothrow()
313 Reference< XWindow2 > xWindow;
314 Reference< XControlModel > xModel;
317 xWindow.set( getPeer(), UNO_QUERY );
318 xModel.set( getModel(), UNO_QUERY );
320 catch( const Exception& )
322 DBG_UNHANDLED_EXCEPTION();
324 m_aWindowStateGuard.attach( xWindow, xModel );
327 //------------------------------------------------------------------------------
328 void SAL_CALL OControl::createPeer(const Reference<XToolkit>& _rxToolkit, const Reference<XWindowPeer>& _rxParent) throw (RuntimeException)
330 if ( m_xControl.is() )
332 m_xControl->createPeer( _rxToolkit, _rxParent );
334 initFormControlPeer( getPeer() );
336 impl_resetStateGuard_nothrow();
340 //------------------------------------------------------------------------------
341 Reference<XWindowPeer> SAL_CALL OControl::getPeer() throw ( RuntimeException)
343 return m_xControl.is() ? m_xControl->getPeer() : Reference<XWindowPeer>();
346 //------------------------------------------------------------------------------
347 sal_Bool SAL_CALL OControl::setModel(const Reference<XControlModel>& Model) throw ( RuntimeException)
349 if ( !m_xControl.is() )
350 return sal_False;
352 sal_Bool bSuccess = m_xControl->setModel( Model );
353 impl_resetStateGuard_nothrow();
354 return bSuccess;
357 //------------------------------------------------------------------------------
358 Reference<XControlModel> SAL_CALL OControl::getModel() throw ( RuntimeException)
360 return m_xControl.is() ? m_xControl->getModel() : Reference<XControlModel>();
363 //------------------------------------------------------------------------------
364 Reference<XView> SAL_CALL OControl::getView() throw ( RuntimeException)
366 return m_xControl.is() ? m_xControl->getView() : Reference<XView>();
369 //------------------------------------------------------------------------------
370 void SAL_CALL OControl::setDesignMode(sal_Bool bOn) throw ( RuntimeException)
372 if (m_xControl.is())
373 m_xControl->setDesignMode(bOn);
376 //------------------------------------------------------------------------------
377 sal_Bool SAL_CALL OControl::isDesignMode() throw ( RuntimeException)
379 return m_xControl.is() ? m_xControl->isDesignMode() : sal_True;
382 //------------------------------------------------------------------------------
383 sal_Bool SAL_CALL OControl::isTransparent() throw ( RuntimeException)
385 return m_xControl.is() ? m_xControl->isTransparent() : sal_True;
388 //==================================================================
389 //= OBoundControl
390 //==================================================================
391 DBG_NAME(frm_OBoundControl);
392 //------------------------------------------------------------------
393 OBoundControl::OBoundControl( const Reference< XMultiServiceFactory >& _rxFactory,
394 const OUString& _rAggregateService, const sal_Bool _bSetDelegator )
395 :OControl( _rxFactory, _rAggregateService, _bSetDelegator )
396 ,m_bLocked(sal_False)
397 ,m_aOriginalFont( EmptyFontDescriptor() )
398 ,m_nOriginalTextLineColor( 0 )
400 DBG_CTOR(frm_OBoundControl, NULL);
403 //------------------------------------------------------------------
404 OBoundControl::~OBoundControl()
406 DBG_DTOR(frm_OBoundControl, NULL);
408 // -----------------------------------------------------------------------------
409 Sequence< Type> OBoundControl::_getTypes()
411 return TypeBag( OControl::_getTypes(), OBoundControl_BASE::getTypes() ).getTypes();
413 //------------------------------------------------------------------
414 Any SAL_CALL OBoundControl::queryAggregation(const Type& _rType) throw(RuntimeException)
416 Any aReturn;
418 // XTypeProvider first - don't ask the OBoundControl_BASE, it would deliver incomplete types
419 if ( _rType.equals( ::getCppuType( static_cast< Reference< XTypeProvider >* >( NULL ) ) ) )
420 aReturn = OControl::queryAggregation( _rType );
422 // ask our own interfaces
423 // (do this first (except XTypeProvider ) - we want to "overwrite" XPropertiesChangeListener)
424 if ( !aReturn.hasValue() )
425 aReturn = OBoundControl_BASE::queryInterface( _rType );
427 // ask the base class
428 if ( !aReturn.hasValue() )
429 aReturn = OControl::queryAggregation( _rType );
431 return aReturn;
434 //------------------------------------------------------------------
435 sal_Bool SAL_CALL OBoundControl::getLock() throw(RuntimeException)
437 return m_bLocked;
440 //------------------------------------------------------------------
441 void SAL_CALL OBoundControl::setLock(sal_Bool _bLock) throw(RuntimeException)
443 if (m_bLocked == _bLock)
444 return;
446 osl::MutexGuard aGuard(m_aMutex);
447 _setLock(_bLock);
448 m_bLocked = _bLock;
451 //------------------------------------------------------------------
452 void OBoundControl::_setLock(sal_Bool _bLock)
454 // try to set the text component to readonly
455 Reference< XWindowPeer > xPeer = getPeer();
456 Reference< XTextComponent > xText( xPeer, UNO_QUERY );
458 if ( xText.is() )
459 xText->setEditable( !_bLock );
460 else
462 // disable the window
463 Reference< XWindow > xComp( xPeer, UNO_QUERY );
464 if ( xComp.is() )
465 xComp->setEnable( !_bLock );
469 //--------------------------------------------------------------------
470 sal_Bool SAL_CALL OBoundControl::setModel( const Reference< XControlModel >& _rxModel ) throw (RuntimeException)
472 return OControl::setModel( _rxModel );
475 //--------------------------------------------------------------------
476 void SAL_CALL OBoundControl::disposing(const EventObject& Source) throw (RuntimeException)
478 // just disambiguate
479 OControl::disposing(Source);
482 //--------------------------------------------------------------------
483 void OBoundControl::disposing()
485 OControl::disposing();
488 //==================================================================
489 //= OControlModel
490 //==================================================================
491 DBG_NAME(OControlModel)
492 //------------------------------------------------------------------
493 Sequence<sal_Int8> SAL_CALL OControlModel::getImplementationId() throw(RuntimeException)
495 return OImplementationIds::getImplementationId(getTypes());
498 //------------------------------------------------------------------
499 Sequence<Type> SAL_CALL OControlModel::getTypes() throw(RuntimeException)
501 TypeBag aTypes( _getTypes() );
503 Reference< XTypeProvider > xProv;
504 if ( query_aggregation( m_xAggregate, xProv ) )
505 aTypes.addTypes( xProv->getTypes() );
507 return aTypes.getTypes();
510 //------------------------------------------------------------------------------
511 Sequence<Type> OControlModel::_getTypes()
513 return TypeBag( OComponentHelper::getTypes(),
514 OPropertySetAggregationHelper::getTypes(),
515 OControlModel_BASE::getTypes()
516 ).getTypes();
519 //------------------------------------------------------------------
520 Any SAL_CALL OControlModel::queryAggregation(const Type& _rType) throw (RuntimeException)
522 // base class 1
523 Any aReturn(OComponentHelper::queryAggregation(_rType));
525 // base class 2
526 if (!aReturn.hasValue())
528 aReturn = OControlModel_BASE::queryInterface(_rType);
530 // our own interfaces
531 if (!aReturn.hasValue())
533 aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
534 // our aggregate
535 if (!aReturn.hasValue() && m_xAggregate.is() && !_rType.equals(::getCppuType(static_cast< Reference< XCloneable>* >(NULL))))
536 aReturn = m_xAggregate->queryAggregation(_rType);
539 return aReturn;
542 //------------------------------------------------------------------------------
543 void OControlModel::readHelpTextCompatibly(const staruno::Reference< stario::XObjectInputStream >& _rxInStream)
545 OUString sHelpText;
546 ::comphelper::operator>>( _rxInStream, sHelpText);
549 if (m_xAggregateSet.is())
550 m_xAggregateSet->setPropertyValue(PROPERTY_HELPTEXT, makeAny(sHelpText));
552 catch(const Exception&)
554 OSL_FAIL("OControlModel::readHelpTextCompatibly: could not forward the property value to the aggregate!");
558 //------------------------------------------------------------------------------
559 void OControlModel::writeHelpTextCompatibly(const staruno::Reference< stario::XObjectOutputStream >& _rxOutStream)
561 OUString sHelpText;
564 if (m_xAggregateSet.is())
565 m_xAggregateSet->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText;
567 catch(const Exception&)
569 OSL_FAIL("OControlModel::writeHelpTextCompatibly: could not retrieve the property value from the aggregate!");
571 ::comphelper::operator<<( _rxOutStream, sHelpText);
574 //------------------------------------------------------------------
575 OControlModel::OControlModel(
576 const Reference<com::sun::star::lang::XMultiServiceFactory>& _rxFactory,
577 const OUString& _rUnoControlModelTypeName,
578 const OUString& rDefault, const sal_Bool _bSetDelegator)
579 :OComponentHelper(m_aMutex)
580 ,OPropertySetAggregationHelper(OComponentHelper::rBHelper)
581 ,m_aContext( _rxFactory )
582 ,m_lockCount( 0 )
583 ,m_aPropertyBagHelper( *this )
584 ,m_nTabIndex(FRM_DEFAULT_TABINDEX)
585 ,m_nClassId(FormComponentType::CONTROL)
586 ,m_bNativeLook( sal_False )
587 ,m_bGenerateVbEvents( sal_False )
588 // form controls are usually embedded into documents, not dialogs, and in documents
589 // the native look is ugly ....
590 // #i37342#
592 DBG_CTOR(OControlModel, NULL);
593 if (!_rUnoControlModelTypeName.isEmpty()) // the is a model we have to aggregate
595 increment(m_refCount);
598 m_xAggregate = Reference<XAggregation>(_rxFactory->createInstance(_rUnoControlModelTypeName), UNO_QUERY);
599 setAggregation(m_xAggregate);
601 if ( m_xAggregateSet.is() )
605 if ( !rDefault.isEmpty() )
606 m_xAggregateSet->setPropertyValue( PROPERTY_DEFAULTCONTROL, makeAny( rDefault ) );
608 catch( const Exception& )
610 OSL_FAIL( "OControlModel::OControlModel: caught an exception!" );
615 if (_bSetDelegator)
616 doSetDelegator();
618 // Refcount wieder bei NULL
619 decrement(m_refCount);
624 //------------------------------------------------------------------
625 OControlModel::OControlModel( const OControlModel* _pOriginal, const Reference< XMultiServiceFactory>& _rxFactory, const sal_Bool _bCloneAggregate, const sal_Bool _bSetDelegator )
626 :OComponentHelper( m_aMutex )
627 ,OPropertySetAggregationHelper( OComponentHelper::rBHelper )
628 ,m_aContext( _rxFactory )
629 ,m_lockCount( 0 )
630 ,m_aPropertyBagHelper( *this )
631 ,m_nTabIndex( FRM_DEFAULT_TABINDEX )
632 ,m_nClassId( FormComponentType::CONTROL )
634 DBG_CTOR( OControlModel, NULL );
635 DBG_ASSERT( _pOriginal, "OControlModel::OControlModel: invalid original!" );
637 // copy members
638 m_aName = _pOriginal->m_aName;
639 m_aTag = _pOriginal->m_aTag;
640 m_nTabIndex = _pOriginal->m_nTabIndex;
641 m_nClassId = _pOriginal->m_nClassId;
642 m_bNativeLook = _pOriginal->m_bNativeLook;
643 m_bGenerateVbEvents = _pOriginal->m_bGenerateVbEvents;
645 if ( _bCloneAggregate )
647 // temporarily increment refcount because of temporary references to ourself in the following
648 increment( m_refCount );
651 // transfer the (only, at the very moment!) ref count
652 m_xAggregate = createAggregateClone( _pOriginal );
654 // set aggregation (retrieve other direct interfaces of the aggregate)
655 setAggregation( m_xAggregate );
658 // set the delegator, if allowed by our derived class
659 if ( _bSetDelegator )
660 doSetDelegator();
662 // decrement ref count
663 decrement( m_refCount );
668 //------------------------------------------------------------------
669 OControlModel::~OControlModel()
671 // release the aggregate
672 doResetDelegator( );
674 DBG_DTOR(OControlModel, NULL);
677 //------------------------------------------------------------------
678 void OControlModel::clonedFrom( const OControlModel* /*_pOriginal*/ )
680 // nothing to do in this base class
683 //------------------------------------------------------------------------------
684 void OControlModel::doResetDelegator()
686 if (m_xAggregate.is())
687 m_xAggregate->setDelegator(NULL);
690 //------------------------------------------------------------------------------
691 void OControlModel::doSetDelegator()
693 increment(m_refCount);
694 if (m_xAggregate.is())
696 m_xAggregate->setDelegator(static_cast<XWeak*>(this));
698 decrement(m_refCount);
701 // XChild
702 //------------------------------------------------------------------------------
703 Reference< XInterface > SAL_CALL OControlModel::getParent() throw(RuntimeException)
705 return m_xParent;
708 //------------------------------------------------------------------------------
709 void SAL_CALL OControlModel::setParent(const Reference< XInterface >& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException)
711 osl::MutexGuard aGuard(m_aMutex);
713 Reference<XComponent> xComp(m_xParent, UNO_QUERY);
714 if (xComp.is())
715 xComp->removeEventListener(static_cast<XPropertiesChangeListener*>(this));
717 m_xParent = _rxParent;
718 xComp = xComp.query( m_xParent );
720 if ( xComp.is() )
721 xComp->addEventListener(static_cast<XPropertiesChangeListener*>(this));
724 // XNamed
725 //------------------------------------------------------------------------------
726 OUString SAL_CALL OControlModel::getName() throw(RuntimeException)
728 OUString aReturn;
729 OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME) >>= aReturn;
730 return aReturn;
733 //------------------------------------------------------------------------------
734 void SAL_CALL OControlModel::setName(const OUString& _rName) throw(RuntimeException)
736 setFastPropertyValue(PROPERTY_ID_NAME, makeAny(_rName));
739 // XServiceInfo
740 //------------------------------------------------------------------------------
741 sal_Bool SAL_CALL OControlModel::supportsService(const OUString& _rServiceName) throw ( RuntimeException)
743 Sequence<OUString> aSupported = getSupportedServiceNames();
744 const OUString* pSupported = aSupported.getConstArray();
745 for (sal_Int32 i=0; i<aSupported.getLength(); ++i, ++pSupported)
746 if (pSupported->equals(_rServiceName))
747 return sal_True;
748 return sal_False;
751 //------------------------------------------------------------------------------
752 Sequence< OUString > OControlModel::getAggregateServiceNames()
754 Sequence< OUString > aAggServices;
755 Reference< XServiceInfo > xInfo;
756 if ( query_aggregation( m_xAggregate, xInfo ) )
757 aAggServices = xInfo->getSupportedServiceNames();
758 return aAggServices;
761 //------------------------------------------------------------------------------
762 Sequence<OUString> SAL_CALL OControlModel::getSupportedServiceNames() throw(RuntimeException)
764 return ::comphelper::concatSequences(
765 getAggregateServiceNames(),
766 getSupportedServiceNames_Static()
770 //------------------------------------------------------------------------------
771 Sequence< OUString > SAL_CALL OControlModel::getSupportedServiceNames_Static() throw( RuntimeException )
773 Sequence< OUString > aServiceNames( 2 );
774 aServiceNames[ 0 ] = FRM_SUN_FORMCOMPONENT;
775 aServiceNames[ 1 ] = OUString("com.sun.star.form.FormControlModel");
776 return aServiceNames;
779 // XEventListener
780 //------------------------------------------------------------------------------
781 void SAL_CALL OControlModel::disposing(const com::sun::star::lang::EventObject& _rSource) throw (RuntimeException)
783 // release the parent
784 if (_rSource.Source == m_xParent)
786 osl::MutexGuard aGuard(m_aMutex);
787 m_xParent = NULL;
789 else
791 Reference<com::sun::star::lang::XEventListener> xEvtLst;
792 if (query_aggregation(m_xAggregate, xEvtLst))
794 osl::MutexGuard aGuard(m_aMutex);
795 xEvtLst->disposing(_rSource);
800 // OComponentHelper
801 //-----------------------------------------------------------------------------
802 void OControlModel::disposing()
804 OPropertySetAggregationHelper::disposing();
806 Reference<com::sun::star::lang::XComponent> xComp;
807 if (query_aggregation(m_xAggregate, xComp))
808 xComp->dispose();
810 setParent(Reference<XFormComponent>());
812 m_aPropertyBagHelper.dispose();
815 //------------------------------------------------------------------------------
816 void OControlModel::writeAggregate( const Reference< XObjectOutputStream >& _rxOutStream ) const
818 Reference< XPersistObject > xPersist;
819 if ( query_aggregation( m_xAggregate, xPersist ) )
820 xPersist->write( _rxOutStream );
823 //------------------------------------------------------------------------------
824 void OControlModel::readAggregate( const Reference< XObjectInputStream >& _rxInStream )
826 Reference< XPersistObject > xPersist;
827 if ( query_aggregation( m_xAggregate, xPersist ) )
828 xPersist->read( _rxInStream );
831 //------------------------------------------------------------------------------
832 void SAL_CALL OControlModel::write(const Reference<stario::XObjectOutputStream>& _rxOutStream)
833 throw(stario::IOException, RuntimeException)
835 osl::MutexGuard aGuard(m_aMutex);
837 // 1. Schreiben des UnoControls
838 Reference<stario::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
839 if ( !xMark.is() )
841 throw IOException(
842 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
843 static_cast< ::cppu::OWeakObject* >( this )
847 sal_Int32 nMark = xMark->createMark();
848 sal_Int32 nLen = 0;
850 _rxOutStream->writeLong(nLen);
852 writeAggregate( _rxOutStream );
854 // feststellen der Laenge
855 nLen = xMark->offsetToMark(nMark) - 4;
856 xMark->jumpToMark(nMark);
857 _rxOutStream->writeLong(nLen);
858 xMark->jumpToFurthest();
859 xMark->deleteMark(nMark);
861 // 2. Schreiben einer VersionsNummer
862 _rxOutStream->writeShort(0x0003);
864 // 3. Schreiben der allgemeinen Properties
865 ::comphelper::operator<<( _rxOutStream, m_aName);
866 _rxOutStream->writeShort(m_nTabIndex);
867 ::comphelper::operator<<( _rxOutStream, m_aTag); // 3. version
869 // !!! IMPORTANT NOTE !!!
870 // don't write any new members here : this wouldn't be compatible with older versions, as OControlModel
871 // is a base class which is called in derived classes "read" method. So if you increment the version
872 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
873 // in anything from data loss to crash.
874 // !!! EOIN !!!
877 //------------------------------------------------------------------------------
878 void OControlModel::read(const Reference<stario::XObjectInputStream>& InStream) throw (::com::sun::star::io::IOException, RuntimeException)
880 osl::MutexGuard aGuard(m_aMutex);
882 Reference<stario::XMarkableStream> xMark(InStream, UNO_QUERY);
883 if ( !xMark.is() )
885 throw IOException(
886 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
887 static_cast< ::cppu::OWeakObject* >( this )
891 // 1. Lesen des UnoControls
892 sal_Int32 nLen = InStream->readLong();
893 if (nLen)
895 sal_Int32 nMark = xMark->createMark();
899 readAggregate( InStream );
901 catch( const Exception& )
903 DBG_UNHANDLED_EXCEPTION();
906 xMark->jumpToMark(nMark);
907 InStream->skipBytes(nLen);
908 xMark->deleteMark(nMark);
911 // 2. Lesen des Versionsnummer
912 sal_uInt16 nVersion = InStream->readShort();
914 // 3. Lesen der allgemeinen Properties
915 ::comphelper::operator>>( InStream, m_aName);
916 m_nTabIndex = InStream->readShort();
918 if (nVersion > 0x0002)
919 ::comphelper::operator>>( InStream, m_aTag);
921 // we had a version where we wrote the help text
922 if (nVersion == 0x0004)
923 readHelpTextCompatibly(InStream);
925 DBG_ASSERT(nVersion < 5, "OControlModel::read : suspicious version number !");
926 // 4 was the version where we wrote the help text
927 // later versions shouldn't exist (see write for a detailed comment)
930 //------------------------------------------------------------------------------
931 PropertyState OControlModel::getPropertyStateByHandle( sal_Int32 _nHandle )
933 // simply compare the current and the default value
934 Any aCurrentValue = getPropertyDefaultByHandle( _nHandle );
935 Any aDefaultValue; getFastPropertyValue( aDefaultValue, _nHandle );
937 sal_Bool bEqual = uno_type_equalData(
938 const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(),
939 const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(),
940 reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
941 reinterpret_cast< uno_ReleaseFunc >(cpp_release)
943 return bEqual ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
946 //------------------------------------------------------------------------------
947 void OControlModel::setPropertyToDefaultByHandle( sal_Int32 _nHandle)
949 Any aDefault = getPropertyDefaultByHandle( _nHandle );
951 Any aConvertedValue, aOldValue;
952 if ( convertFastPropertyValue( aConvertedValue, aOldValue, _nHandle, aDefault ) )
954 setFastPropertyValue_NoBroadcast( _nHandle, aConvertedValue );
955 // TODO: fire the property change
959 //------------------------------------------------------------------------------
960 Any OControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
962 Any aReturn;
963 switch ( _nHandle )
965 case PROPERTY_ID_NAME:
966 case PROPERTY_ID_TAG:
967 aReturn <<= OUString();
968 break;
970 case PROPERTY_ID_CLASSID:
971 aReturn <<= (sal_Int16)FormComponentType::CONTROL;
972 break;
974 case PROPERTY_ID_TABINDEX:
975 aReturn <<= (sal_Int16)FRM_DEFAULT_TABINDEX;
976 break;
978 case PROPERTY_ID_NATIVE_LOOK:
979 aReturn <<= (sal_Bool)sal_True;
980 break;
982 case PROPERTY_ID_GENERATEVBAEVENTS:
983 aReturn <<= (sal_Bool)sal_False;
984 break;
987 default:
988 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
989 m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( _nHandle, aReturn );
990 else
991 OSL_FAIL( "OControlModel::convertFastPropertyValue: unknown handle!" );
993 return aReturn;
996 //------------------------------------------------------------------------------
997 void OControlModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
999 switch ( _nHandle )
1001 case PROPERTY_ID_NAME:
1002 _rValue <<= m_aName;
1003 break;
1004 case PROPERTY_ID_TAG:
1005 _rValue <<= m_aTag;
1006 break;
1007 case PROPERTY_ID_CLASSID:
1008 _rValue <<= m_nClassId;
1009 break;
1010 case PROPERTY_ID_TABINDEX:
1011 _rValue <<= m_nTabIndex;
1012 break;
1013 case PROPERTY_ID_NATIVE_LOOK:
1014 _rValue <<= (sal_Bool)m_bNativeLook;
1015 break;
1016 case PROPERTY_ID_GENERATEVBAEVENTS:
1017 _rValue <<= (sal_Bool)m_bGenerateVbEvents;
1018 default:
1019 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1020 m_aPropertyBagHelper.getDynamicFastPropertyValue( _nHandle, _rValue );
1021 else
1022 OPropertySetAggregationHelper::getFastPropertyValue( _rValue, _nHandle );
1023 break;
1027 //------------------------------------------------------------------------------
1028 sal_Bool OControlModel::convertFastPropertyValue(
1029 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
1030 throw (com::sun::star::lang::IllegalArgumentException)
1032 sal_Bool bModified(sal_False);
1033 switch (_nHandle)
1035 case PROPERTY_ID_NAME:
1036 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aName);
1037 break;
1038 case PROPERTY_ID_TAG:
1039 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aTag);
1040 break;
1041 case PROPERTY_ID_TABINDEX:
1042 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nTabIndex);
1043 break;
1044 case PROPERTY_ID_NATIVE_LOOK:
1045 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bNativeLook);
1046 break;
1047 case PROPERTY_ID_GENERATEVBAEVENTS:
1048 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bGenerateVbEvents);
1049 break;
1050 default:
1051 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1052 bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( _nHandle, _rValue, _rConvertedValue, _rOldValue );
1053 else
1054 OSL_FAIL( "OControlModel::convertFastPropertyValue: unknown handle!" );
1055 break;
1057 return bModified;
1060 //------------------------------------------------------------------------------
1061 void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
1062 throw (Exception)
1064 switch (_nHandle)
1066 case PROPERTY_ID_NAME:
1067 DBG_ASSERT(_rValue.getValueType() == getCppuType((const OUString*)NULL),
1068 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1069 _rValue >>= m_aName;
1070 break;
1071 case PROPERTY_ID_TAG:
1072 DBG_ASSERT(_rValue.getValueType() == getCppuType((const OUString*)NULL),
1073 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1074 _rValue >>= m_aTag;
1075 break;
1076 case PROPERTY_ID_TABINDEX:
1077 DBG_ASSERT(_rValue.getValueType() == getCppuType((const sal_Int16*)NULL),
1078 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1079 _rValue >>= m_nTabIndex;
1080 break;
1081 case PROPERTY_ID_NATIVE_LOOK:
1082 OSL_VERIFY( _rValue >>= m_bNativeLook );
1083 break;
1084 case PROPERTY_ID_GENERATEVBAEVENTS:
1085 OSL_VERIFY( _rValue >>= m_bGenerateVbEvents );
1086 break;
1087 default:
1088 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1089 m_aPropertyBagHelper.setDynamicFastPropertyValue( _nHandle, _rValue );
1090 else
1091 OSL_FAIL( "OControlModel::setFastPropertyValue_NoBroadcast: unknown handle!" );
1092 break;
1096 //------------------------------------------------------------------------------
1097 void OControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
1099 BEGIN_DESCRIBE_BASE_PROPERTIES( 5 )
1100 DECL_PROP2 (CLASSID, sal_Int16, READONLY, TRANSIENT);
1101 DECL_PROP1 (NAME, OUString, BOUND);
1102 DECL_BOOL_PROP2 (NATIVE_LOOK, BOUND, TRANSIENT);
1103 DECL_PROP1 (TAG, OUString, BOUND);
1104 DECL_PROP1 (GENERATEVBAEVENTS, sal_Bool, TRANSIENT);
1105 END_DESCRIBE_PROPERTIES()
1108 //------------------------------------------------------------------------------
1109 void OControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ _rAggregateProps ) const
1111 if ( m_xAggregateSet.is() )
1113 Reference< XPropertySetInfo > xPSI( m_xAggregateSet->getPropertySetInfo() );
1114 if ( xPSI.is() )
1115 _rAggregateProps = xPSI->getProperties();
1119 //------------------------------------------------------------------------------
1120 ::osl::Mutex& OControlModel::getMutex()
1122 return m_aMutex;
1125 //------------------------------------------------------------------------------
1126 void OControlModel::describeFixedAndAggregateProperties( Sequence< Property >& _out_rFixedProperties, Sequence< Property >& _out_rAggregateProperties ) const
1128 describeFixedProperties( _out_rFixedProperties );
1129 describeAggregateProperties( _out_rAggregateProperties );
1132 //------------------------------------------------------------------------------
1133 Reference< XMultiPropertySet > OControlModel::getPropertiesInterface()
1135 return Reference< XMultiPropertySet >( *this, UNO_QUERY );
1138 //------------------------------------------------------------------------------
1139 Reference< XPropertySetInfo> SAL_CALL OControlModel::getPropertySetInfo() throw( RuntimeException)
1141 return createPropertySetInfo( getInfoHelper() );
1144 //------------------------------------------------------------------------------
1145 ::cppu::IPropertyArrayHelper& OControlModel::getInfoHelper()
1147 return m_aPropertyBagHelper.getInfoHelper();
1150 //--------------------------------------------------------------------
1151 void SAL_CALL OControlModel::addProperty( const OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException)
1153 m_aPropertyBagHelper.addProperty( _rName, _nAttributes, _rInitialValue );
1156 //--------------------------------------------------------------------
1157 void SAL_CALL OControlModel::removeProperty( const OUString& _rName ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException)
1159 m_aPropertyBagHelper.removeProperty( _rName );
1162 //--------------------------------------------------------------------
1163 Sequence< PropertyValue > SAL_CALL OControlModel::getPropertyValues() throw (RuntimeException)
1165 return m_aPropertyBagHelper.getPropertyValues();
1168 //--------------------------------------------------------------------
1169 void SAL_CALL OControlModel::setPropertyValues( const Sequence< PropertyValue >& _rProps ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
1171 m_aPropertyBagHelper.setPropertyValues( _rProps );
1174 //--------------------------------------------------------------------
1175 void OControlModel::lockInstance( LockAccess )
1177 m_aMutex.acquire();
1178 osl_atomic_increment( &m_lockCount );
1181 //--------------------------------------------------------------------
1182 oslInterlockedCount OControlModel::unlockInstance( LockAccess )
1184 OSL_ENSURE( m_lockCount > 0, "OControlModel::unlockInstance: not locked!" );
1185 oslInterlockedCount lockCount = osl_atomic_decrement( &m_lockCount );
1186 m_aMutex.release();
1187 return lockCount;
1190 //--------------------------------------------------------------------
1191 void OControlModel::firePropertyChanges( const Sequence< sal_Int32 >& _rHandles, const Sequence< Any >& _rOldValues,
1192 const Sequence< Any >& _rNewValues, LockAccess )
1194 OPropertySetHelper::fire(
1195 const_cast< Sequence< sal_Int32 >& >( _rHandles ).getArray(),
1196 _rNewValues.getConstArray(),
1197 _rOldValues.getConstArray(),
1198 _rHandles.getLength(),
1199 sal_False
1203 //==================================================================
1204 //= OBoundControlModel
1205 //==================================================================
1206 DBG_NAME(frm_OBoundControlModel);
1207 //------------------------------------------------------------------
1208 Any SAL_CALL OBoundControlModel::queryAggregation( const Type& _rType ) throw (RuntimeException)
1210 Any aReturn( OControlModel::queryAggregation(_rType) );
1211 if (!aReturn.hasValue())
1213 aReturn = OBoundControlModel_BASE1::queryInterface(_rType);
1215 if ( !aReturn.hasValue() && m_bCommitable )
1216 aReturn = OBoundControlModel_COMMITTING::queryInterface( _rType );
1218 if ( !aReturn.hasValue() && m_bSupportsExternalBinding )
1219 aReturn = OBoundControlModel_BINDING::queryInterface( _rType );
1221 if ( !aReturn.hasValue() && m_bSupportsValidation )
1222 aReturn = OBoundControlModel_VALIDATION::queryInterface( _rType );
1225 return aReturn;
1228 //------------------------------------------------------------------
1229 OBoundControlModel::OBoundControlModel(
1230 const Reference< XMultiServiceFactory>& _rxFactory,
1231 const OUString& _rUnoControlModelTypeName, const OUString& _rDefault,
1232 const sal_Bool _bCommitable, const sal_Bool _bSupportExternalBinding, const sal_Bool _bSupportsValidation )
1233 :OControlModel( _rxFactory, _rUnoControlModelTypeName, _rDefault, sal_False )
1234 ,OPropertyChangeListener( m_aMutex )
1235 ,m_xField()
1236 ,m_xAmbientForm()
1237 ,m_nValuePropertyAggregateHandle( -1 )
1238 ,m_nFieldType( DataType::OTHER )
1239 ,m_bValuePropertyMayBeVoid( false )
1240 ,m_aResetHelper( *this, m_aMutex )
1241 ,m_aUpdateListeners(m_aMutex)
1242 ,m_aFormComponentListeners( m_aMutex )
1243 ,m_bInputRequired( sal_True )
1244 ,m_pAggPropMultiplexer( NULL )
1245 ,m_bFormListening( false )
1246 ,m_bLoaded(sal_False)
1247 ,m_bRequired(sal_False)
1248 ,m_bCommitable(_bCommitable)
1249 ,m_bSupportsExternalBinding( _bSupportExternalBinding )
1250 ,m_bSupportsValidation( _bSupportsValidation )
1251 ,m_bForwardValueChanges(sal_True)
1252 ,m_bTransferingValue( sal_False )
1253 ,m_bIsCurrentValueValid( sal_True )
1254 ,m_bBindingControlsRO( sal_False )
1255 ,m_bBindingControlsEnable( sal_False )
1256 ,m_eControlValueChangeInstigator( eOther )
1257 ,m_aLabelServiceName(FRM_SUN_COMPONENT_FIXEDTEXT)
1259 DBG_CTOR(frm_OBoundControlModel, NULL);
1261 // start property listening at the aggregate
1262 implInitAggMultiplexer( );
1265 //------------------------------------------------------------------
1266 OBoundControlModel::OBoundControlModel(
1267 const OBoundControlModel* _pOriginal, const Reference< XMultiServiceFactory>& _rxFactory )
1268 :OControlModel( _pOriginal, _rxFactory, sal_True, sal_False )
1269 ,OPropertyChangeListener( m_aMutex )
1270 ,m_xField()
1271 ,m_xAmbientForm()
1272 ,m_nValuePropertyAggregateHandle( _pOriginal->m_nValuePropertyAggregateHandle )
1273 ,m_nFieldType( DataType::OTHER )
1274 ,m_bValuePropertyMayBeVoid( _pOriginal->m_bValuePropertyMayBeVoid )
1275 ,m_aResetHelper( *this, m_aMutex )
1276 ,m_aUpdateListeners( m_aMutex )
1277 ,m_aFormComponentListeners( m_aMutex )
1278 ,m_xValidator( _pOriginal->m_xValidator )
1279 ,m_bInputRequired( sal_True )
1280 ,m_pAggPropMultiplexer( NULL )
1281 ,m_bFormListening( false )
1282 ,m_bLoaded( sal_False )
1283 ,m_bRequired( sal_False )
1284 ,m_bCommitable( _pOriginal->m_bCommitable )
1285 ,m_bSupportsExternalBinding( _pOriginal->m_bSupportsExternalBinding )
1286 ,m_bSupportsValidation( _pOriginal->m_bSupportsValidation )
1287 ,m_bForwardValueChanges( sal_True )
1288 ,m_bTransferingValue( sal_False )
1289 ,m_bIsCurrentValueValid( _pOriginal->m_bIsCurrentValueValid )
1290 ,m_bBindingControlsRO( sal_False )
1291 ,m_bBindingControlsEnable( sal_False )
1292 ,m_eControlValueChangeInstigator( eOther )
1294 DBG_CTOR(frm_OBoundControlModel, NULL);
1296 // start property listening at the aggregate
1297 implInitAggMultiplexer( );
1299 m_aLabelServiceName = _pOriginal->m_aLabelServiceName;
1300 m_sValuePropertyName = _pOriginal->m_sValuePropertyName;
1301 m_nValuePropertyAggregateHandle = _pOriginal->m_nValuePropertyAggregateHandle;
1302 m_bValuePropertyMayBeVoid = _pOriginal->m_bValuePropertyMayBeVoid;
1303 m_aValuePropertyType = _pOriginal->m_aValuePropertyType;
1304 m_aControlSource = _pOriginal->m_aControlSource;
1305 m_bInputRequired = _pOriginal->m_bInputRequired;
1306 // m_xLabelControl, though being a property, is not to be cloned, not even the reference will be transferred.
1307 // (the former should be clear - a clone of the object we're only referencing does not make sense)
1308 // (the second would violate the restriction for label controls that they're part of the
1309 // same form component hierarchy - we ourself are no part, yet, so we can't have a label control)
1311 // start listening for changes at the value property
1312 implInitValuePropertyListening( );
1315 //------------------------------------------------------------------
1316 OBoundControlModel::~OBoundControlModel()
1318 if ( !OComponentHelper::rBHelper.bDisposed )
1320 acquire();
1321 dispose();
1324 doResetDelegator( );
1326 OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::~OBoundControlModel: what about my property multiplexer?" );
1327 if ( m_pAggPropMultiplexer )
1329 m_pAggPropMultiplexer->dispose();
1330 m_pAggPropMultiplexer->release();
1331 m_pAggPropMultiplexer = NULL;
1334 DBG_DTOR(frm_OBoundControlModel, NULL);
1337 //------------------------------------------------------------------
1338 void OBoundControlModel::clonedFrom( const OControlModel* _pOriginal )
1340 const OBoundControlModel* pBoundOriginal = static_cast< const OBoundControlModel* >( _pOriginal );
1341 // the value binding can be handled as if somebody called setValueBinding here
1342 // By definition, bindings can be share between bindables
1343 if ( pBoundOriginal && pBoundOriginal->m_xExternalBinding.is() )
1347 setValueBinding( pBoundOriginal->m_xExternalBinding );
1349 catch( const Exception& )
1351 DBG_UNHANDLED_EXCEPTION();
1356 //-----------------------------------------------------------------------------
1357 void OBoundControlModel::implInitAggMultiplexer( )
1359 increment( m_refCount );
1360 if ( m_xAggregateSet.is() )
1362 m_pAggPropMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet, sal_False );
1363 m_pAggPropMultiplexer->acquire();
1365 decrement( m_refCount );
1367 doSetDelegator();
1370 //-----------------------------------------------------------------------------
1371 void OBoundControlModel::implInitValuePropertyListening( ) const
1373 // start listening for changes at the value property
1374 // There are three pre-requisites for this to be done:
1375 // 1. We support external value bindings. In this case, the changes in the control value need to
1376 // be propagated to the external binding immediately when they happen
1377 // 2. We support external validation. In this case, we need to listen for changes in the value
1378 // property, since we need to revalidate then.
1379 // 3. We are not committable. In this case, changes in the control value need to be propagated
1380 // to the database column immediately when they happen.
1381 if ( m_bSupportsExternalBinding || m_bSupportsValidation || !m_bCommitable )
1383 OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::implInitValuePropertyListening: no multiplexer!" );
1384 if ( m_pAggPropMultiplexer && !m_sValuePropertyName.isEmpty() )
1385 m_pAggPropMultiplexer->addProperty( m_sValuePropertyName );
1389 //-----------------------------------------------------------------------------
1390 void OBoundControlModel::initOwnValueProperty( const OUString& i_rValuePropertyName )
1392 OSL_PRECOND( m_sValuePropertyName.isEmpty() && -1 == m_nValuePropertyAggregateHandle,
1393 "OBoundControlModel::initOwnValueProperty: value property is already initialized!" );
1394 OSL_ENSURE( !i_rValuePropertyName.isEmpty(), "OBoundControlModel::initOwnValueProperty: invalid property name!" );
1395 m_sValuePropertyName = i_rValuePropertyName;
1398 //-----------------------------------------------------------------------------
1399 void OBoundControlModel::initValueProperty( const OUString& _rValuePropertyName, sal_Int32 _nValuePropertyExternalHandle )
1401 OSL_PRECOND( m_sValuePropertyName.isEmpty() && -1 == m_nValuePropertyAggregateHandle,
1402 "OBoundControlModel::initValueProperty: value property is already initialized!" );
1403 OSL_ENSURE( !_rValuePropertyName.isEmpty(), "OBoundControlModel::initValueProperty: invalid property name!" );
1404 OSL_ENSURE( _nValuePropertyExternalHandle != -1, "OBoundControlModel::initValueProperty: invalid property handle!" );
1406 m_sValuePropertyName = _rValuePropertyName;
1407 m_nValuePropertyAggregateHandle = getOriginalHandle( _nValuePropertyExternalHandle );
1408 OSL_ENSURE( m_nValuePropertyAggregateHandle != -1, "OBoundControlModel::initValueProperty: unable to find the original handle!" );
1410 if ( m_nValuePropertyAggregateHandle != -1 )
1412 Reference< XPropertySetInfo > xPropInfo( m_xAggregateSet->getPropertySetInfo(), UNO_SET_THROW );
1413 Property aValuePropDesc = xPropInfo->getPropertyByName( m_sValuePropertyName );
1414 m_aValuePropertyType = aValuePropDesc.Type;
1415 m_bValuePropertyMayBeVoid = ( aValuePropDesc.Attributes & PropertyAttribute::MAYBEVOID ) != 0;
1418 // start listening for changes at the value property
1419 implInitValuePropertyListening( );
1422 //-----------------------------------------------------------------------------
1423 void OBoundControlModel::suspendValueListening( )
1425 OSL_PRECOND( !m_sValuePropertyName.isEmpty(), "OBoundControlModel::suspendValueListening: don't have a value property!" );
1426 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::suspendValueListening: I *am* not listening!" );
1428 if ( m_pAggPropMultiplexer )
1429 m_pAggPropMultiplexer->lock();
1432 //-----------------------------------------------------------------------------
1433 void OBoundControlModel::resumeValueListening( )
1435 OSL_PRECOND( !m_sValuePropertyName.isEmpty(), "OBoundControlModel::resumeValueListening: don't have a value property!" );
1436 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::resumeValueListening: I *am* not listening at all!" );
1437 OSL_PRECOND( !m_pAggPropMultiplexer || m_pAggPropMultiplexer->locked(), "OBoundControlModel::resumeValueListening: listening not suspended currently!" );
1439 if ( m_pAggPropMultiplexer )
1440 m_pAggPropMultiplexer->unlock();
1443 //-----------------------------------------------------------------------------
1444 Sequence< Type > OBoundControlModel::_getTypes()
1446 TypeBag aTypes(
1447 OControlModel::_getTypes(),
1448 OBoundControlModel_BASE1::getTypes()
1451 if ( m_bCommitable )
1452 aTypes.addTypes( OBoundControlModel_COMMITTING::getTypes() );
1454 if ( m_bSupportsExternalBinding )
1455 aTypes.addTypes( OBoundControlModel_BINDING::getTypes() );
1457 if ( m_bSupportsValidation )
1458 aTypes.addTypes( OBoundControlModel_VALIDATION::getTypes() );
1460 return aTypes.getTypes();
1463 // OComponentHelper
1464 //-----------------------------------------------------------------------------
1465 void OBoundControlModel::disposing()
1467 OControlModel::disposing();
1469 ::osl::ClearableMutexGuard aGuard(m_aMutex);
1471 if ( m_pAggPropMultiplexer )
1472 m_pAggPropMultiplexer->dispose();
1474 // notify all our listeners
1475 com::sun::star::lang::EventObject aEvt( static_cast< XWeak* >( this ) );
1476 m_aUpdateListeners.disposeAndClear( aEvt );
1477 m_aResetHelper.disposing();
1479 // disconnect from our database column
1480 // TODO: could we replace the following 5 lines with a call to impl_disconnectDatabaseColumn_noNotify?
1481 // The only more thing which it does is calling onDisconnectedDbColumn - could this
1482 // cause trouble? At least when we continue to call OControlModel::disposing before, it *may*.
1483 if ( hasField() )
1485 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
1486 resetField();
1488 m_xCursor = NULL;
1490 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1491 if ( xComp.is() )
1492 xComp->removeEventListener(static_cast< XEventListener* >( static_cast< XPropertyChangeListener* >( this ) ) );
1494 // disconnect from our external value binding
1495 if ( hasExternalValueBinding() )
1496 disconnectExternalValueBinding();
1498 // dito for the validator
1499 if ( hasValidator() )
1500 disconnectValidator( );
1503 //------------------------------------------------------------------------------
1504 void OBoundControlModel::onValuePropertyChange( ControlModelLock& i_rControLock )
1506 if ( hasExternalValueBinding() )
1507 { // the control value changed, while we have an external value binding
1508 // -> forward the value to it
1509 if ( m_eControlValueChangeInstigator != eExternalBinding )
1510 transferControlValueToExternal( i_rControLock );
1512 else if ( !m_bCommitable && m_xColumnUpdate.is() )
1513 { // the control value changed, while we are bound to a database column,
1514 // but not committable (which means changes in the control have to be reflected to
1515 // the underlying database column immediately)
1516 // -> forward the value to the database column
1517 if ( m_eControlValueChangeInstigator != eDbColumnBinding )
1518 commitControlValueToDbColumn( false );
1521 // validate the new value
1522 if ( m_bSupportsValidation )
1523 recheckValidity( true );
1526 //------------------------------------------------------------------------------
1527 void OBoundControlModel::_propertyChanged( const PropertyChangeEvent& _rEvt ) throw ( RuntimeException )
1529 ControlModelLock aLock( *this );
1531 OSL_ENSURE( _rEvt.PropertyName == m_sValuePropertyName,
1532 "OBoundControlModel::_propertyChanged: where did this come from (1)?" );
1533 OSL_ENSURE( m_pAggPropMultiplexer && !m_pAggPropMultiplexer->locked(),
1534 "OBoundControlModel::_propertyChanged: where did this come from (2)?" );
1536 if ( _rEvt.PropertyName == m_sValuePropertyName )
1538 onValuePropertyChange( aLock );
1542 //------------------------------------------------------------------------------
1543 void OBoundControlModel::startAggregatePropertyListening( const OUString& _rPropertyName )
1545 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::startAggregatePropertyListening: no multiplexer!" );
1546 OSL_ENSURE( !_rPropertyName.isEmpty(), "OBoundControlModel::startAggregatePropertyListening: invalid property name!" );
1548 if ( m_pAggPropMultiplexer && !_rPropertyName.isEmpty() )
1550 m_pAggPropMultiplexer->addProperty( _rPropertyName );
1554 //------------------------------------------------------------------------------
1555 void OBoundControlModel::doFormListening( const bool _bStart )
1557 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::doFormListening: external value binding should overrule the database binding!" );
1559 if ( isFormListening() == _bStart )
1560 return;
1562 if ( m_xAmbientForm.is() )
1563 _bStart ? m_xAmbientForm->addLoadListener( this ) : m_xAmbientForm->removeLoadListener( this );
1565 Reference< XLoadable > xParentLoadable( getParent(), UNO_QUERY );
1566 if ( getParent().is() && !xParentLoadable.is() )
1568 // if our parent does not directly support the XLoadable interface, then it might support the
1569 // XRowSetSupplier/XRowSetChangeBroadcaster interfaces. In this case we have to listen for changes
1570 // broadcasted by the latter.
1571 Reference< XRowSetChangeBroadcaster > xRowSetBroadcaster( getParent(), UNO_QUERY );
1572 if ( xRowSetBroadcaster.is() )
1573 _bStart ? xRowSetBroadcaster->addRowSetChangeListener( this ) : xRowSetBroadcaster->removeRowSetChangeListener( this );
1576 m_bFormListening = _bStart && m_xAmbientForm.is();
1579 // XChild
1580 //------------------------------------------------------------------------------
1581 void SAL_CALL OBoundControlModel::setParent(const Reference<XInterface>& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException)
1583 ControlModelLock aLock( *this );
1584 FieldChangeNotifier aBoundFieldNotifier( aLock );
1586 if ( getParent() == _rxParent )
1587 return;
1589 // disconnect from database column (which is controlled by parent, directly or indirectly)
1590 if ( hasField() )
1591 impl_disconnectDatabaseColumn_noNotify();
1593 // log off old listeners
1594 if ( isFormListening() )
1595 doFormListening( false );
1597 // actually set the new parent
1598 OControlModel::setParent( _rxParent );
1600 // a new parent means a new ambient form
1601 impl_determineAmbientForm_nothrow();
1603 if ( !hasExternalValueBinding() )
1605 // log on new listeners
1606 doFormListening( true );
1608 // re-connect to database column of the new parent
1609 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
1610 impl_connectDatabaseColumn_noNotify( false );
1614 // XEventListener
1615 //------------------------------------------------------------------------------
1616 void SAL_CALL OBoundControlModel::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException)
1618 ControlModelLock aLock( *this );
1620 if ( _rEvent.Source == getField() )
1622 resetField();
1624 else if ( _rEvent.Source == m_xLabelControl )
1626 Reference<XPropertySet> xOldValue = m_xLabelControl;
1627 m_xLabelControl = NULL;
1629 // fire a propertyChanged (when we leave aLock's scope)
1630 aLock.addPropertyNotification( PROPERTY_ID_CONTROLLABEL, makeAny( xOldValue ), makeAny( m_xLabelControl ) );
1632 else if ( _rEvent.Source == m_xExternalBinding )
1633 { // *first* check for the external binding
1634 disconnectExternalValueBinding( );
1636 else if ( _rEvent.Source == m_xValidator )
1637 { // *then* check for the validator. Reason is that bindings may also act as validator at the same
1638 // time, in this case, the validator is automatically revoked when the binding is revoked
1639 disconnectValidator( );
1641 else
1642 OControlModel::disposing(_rEvent);
1645 // XServiceInfo
1646 //------------------------------------------------------------------------------
1647 StringSequence SAL_CALL OBoundControlModel::getSupportedServiceNames() throw(RuntimeException)
1649 return ::comphelper::concatSequences(
1650 getAggregateServiceNames(),
1651 getSupportedServiceNames_Static()
1655 //------------------------------------------------------------------------------
1656 Sequence< OUString > SAL_CALL OBoundControlModel::getSupportedServiceNames_Static() throw( RuntimeException )
1658 Sequence< OUString > aOwnServiceNames( 1 );
1659 aOwnServiceNames[ 0 ] = OUString("com.sun.star.form.DataAwareControlModel");
1661 return ::comphelper::concatSequences(
1662 OControlModel::getSupportedServiceNames_Static(),
1663 aOwnServiceNames
1667 // XPersist
1668 //------------------------------------------------------------------------------
1669 void SAL_CALL OBoundControlModel::write( const Reference<stario::XObjectOutputStream>& _rxOutStream ) throw(stario::IOException, RuntimeException)
1671 OControlModel::write(_rxOutStream);
1673 osl::MutexGuard aGuard(m_aMutex);
1675 // Version
1676 _rxOutStream->writeShort(0x0002);
1678 // Controlsource
1679 ::comphelper::operator<<( _rxOutStream, m_aControlSource);
1681 // !!! IMPORTANT NOTE !!!
1682 // don't write any new members here : this wouldn't be compatible with older versions, as OBoundControlModel
1683 // is a base class which is called in derived classes "read" method. So if you increment the version
1684 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
1685 // in anything from data loss to crash.
1686 // (use writeCommonProperties instead, this is called in derived classes write-method)
1687 // !!! EOIN !!!
1690 //------------------------------------------------------------------------------
1691 void OBoundControlModel::defaultCommonProperties()
1693 Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1694 if (xComp.is())
1695 xComp->removeEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1696 m_xLabelControl = NULL;
1699 //------------------------------------------------------------------------------
1700 void OBoundControlModel::readCommonProperties(const Reference<stario::XObjectInputStream>& _rxInStream)
1702 sal_Int32 nLen = _rxInStream->readLong();
1704 Reference<stario::XMarkableStream> xMark(_rxInStream, UNO_QUERY);
1705 DBG_ASSERT(xMark.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !");
1706 sal_Int32 nMark = xMark->createMark();
1708 // read the reference to the label control
1709 Reference<stario::XPersistObject> xPersist;
1710 sal_Int32 nUsedFlag;
1711 nUsedFlag = _rxInStream->readLong();
1712 if (nUsedFlag)
1713 xPersist = _rxInStream->readObject();
1714 m_xLabelControl = m_xLabelControl.query( xPersist );
1715 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1716 if (xComp.is())
1717 xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1719 // read any other new common properties here
1721 // skip the remaining bytes
1722 xMark->jumpToMark(nMark);
1723 _rxInStream->skipBytes(nLen);
1724 xMark->deleteMark(nMark);
1727 //------------------------------------------------------------------------------
1728 void OBoundControlModel::writeCommonProperties(const Reference<stario::XObjectOutputStream>& _rxOutStream)
1730 Reference<stario::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
1731 DBG_ASSERT(xMark.is(), "OBoundControlModel::writeCommonProperties : can only work with markable streams !");
1732 sal_Int32 nMark = xMark->createMark();
1734 // a placeholder where we will write the overall length (later in this method)
1735 sal_Int32 nLen = 0;
1736 _rxOutStream->writeLong(nLen);
1738 // write the reference to the label control
1739 Reference<stario::XPersistObject> xPersist(m_xLabelControl, UNO_QUERY);
1740 sal_Int32 nUsedFlag = 0;
1741 if (xPersist.is())
1742 nUsedFlag = 1;
1743 _rxOutStream->writeLong(nUsedFlag);
1744 if (xPersist.is())
1745 _rxOutStream->writeObject(xPersist);
1747 // write any other new common properties here
1749 // write the correct length at the beginning of the block
1750 nLen = xMark->offsetToMark(nMark) - sizeof(nLen);
1751 xMark->jumpToMark(nMark);
1752 _rxOutStream->writeLong(nLen);
1753 xMark->jumpToFurthest();
1754 xMark->deleteMark(nMark);
1757 //------------------------------------------------------------------------------
1758 void SAL_CALL OBoundControlModel::read( const Reference< stario::XObjectInputStream >& _rxInStream ) throw(stario::IOException, RuntimeException)
1760 OControlModel::read(_rxInStream);
1762 osl::MutexGuard aGuard(m_aMutex);
1763 sal_uInt16 nVersion = _rxInStream->readShort(); (void)nVersion;
1764 ::comphelper::operator>>( _rxInStream, m_aControlSource);
1767 //------------------------------------------------------------------------------
1768 void OBoundControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
1770 switch (nHandle)
1772 case PROPERTY_ID_INPUT_REQUIRED:
1773 rValue <<= m_bInputRequired;
1774 break;
1775 case PROPERTY_ID_CONTROLSOURCEPROPERTY:
1776 rValue <<= m_sValuePropertyName;
1777 break;
1778 case PROPERTY_ID_CONTROLSOURCE:
1779 rValue <<= m_aControlSource;
1780 break;
1781 case PROPERTY_ID_BOUNDFIELD:
1782 rValue <<= getField();
1783 break;
1784 case PROPERTY_ID_CONTROLLABEL:
1785 if (!m_xLabelControl.is())
1786 rValue.clear();
1787 else
1788 rValue <<= m_xLabelControl;
1789 break;
1790 default:
1791 OControlModel::getFastPropertyValue(rValue, nHandle);
1795 //------------------------------------------------------------------------------
1796 sal_Bool OBoundControlModel::convertFastPropertyValue(
1797 Any& _rConvertedValue, Any& _rOldValue,
1798 sal_Int32 _nHandle,
1799 const Any& _rValue)
1800 throw (com::sun::star::lang::IllegalArgumentException)
1802 sal_Bool bModified(sal_False);
1803 switch (_nHandle)
1805 case PROPERTY_ID_INPUT_REQUIRED:
1806 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, m_bInputRequired );
1807 break;
1808 case PROPERTY_ID_CONTROLSOURCE:
1809 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aControlSource);
1810 break;
1811 case PROPERTY_ID_BOUNDFIELD:
1812 OSL_FAIL( "OBoundControlModel::convertFastPropertyValue: BoundField should be a read-only property !" );
1813 throw com::sun::star::lang::IllegalArgumentException();
1814 case PROPERTY_ID_CONTROLLABEL:
1815 if (!_rValue.hasValue())
1816 { // property set to void
1817 _rConvertedValue = Any();
1818 getFastPropertyValue(_rOldValue, _nHandle);
1819 bModified = m_xLabelControl.is();
1821 else
1823 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_xLabelControl);
1824 if (!m_xLabelControl.is())
1825 // an empty interface is interpreted as VOID
1826 _rOldValue.clear();
1828 break;
1829 default:
1830 bModified = OControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
1832 return bModified;
1835 //------------------------------------------------------------------------------
1836 Any OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
1838 Any aDefault;
1839 switch ( _nHandle )
1841 case PROPERTY_ID_INPUT_REQUIRED:
1842 aDefault <<= sal_Bool( sal_True );
1843 break;
1845 case PROPERTY_ID_CONTROLSOURCE:
1846 aDefault <<= OUString();
1847 break;
1849 case PROPERTY_ID_CONTROLLABEL:
1850 aDefault <<= Reference< XPropertySet >();
1851 break;
1853 return aDefault;
1856 //------------------------------------------------------------------------------
1857 void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception)
1859 switch (nHandle)
1861 case PROPERTY_ID_INPUT_REQUIRED:
1862 OSL_VERIFY( rValue >>= m_bInputRequired );
1863 break;
1864 case PROPERTY_ID_CONTROLSOURCE:
1865 OSL_VERIFY( rValue >>= m_aControlSource );
1866 break;
1867 case PROPERTY_ID_BOUNDFIELD:
1868 OSL_FAIL("OBoundControlModel::setFastPropertyValue_NoBroadcast : BoundField should be a read-only property !");
1869 throw com::sun::star::lang::IllegalArgumentException();
1870 case PROPERTY_ID_CONTROLLABEL:
1872 if ( rValue.hasValue() && ( rValue.getValueTypeClass() != TypeClass_INTERFACE ) )
1873 throw com::sun::star::lang::IllegalArgumentException();
1875 Reference< XInterface > xNewValue( rValue, UNO_QUERY );
1876 if ( !xNewValue.is() )
1877 { // set property to "void"
1878 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1879 if ( xComp.is() )
1880 xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
1881 m_xLabelControl = NULL;
1882 break;
1885 Reference< XControlModel > xAsModel ( xNewValue, UNO_QUERY );
1886 Reference< XServiceInfo > xAsServiceInfo ( xAsModel, UNO_QUERY );
1887 Reference< XPropertySet > xAsPropSet ( xAsServiceInfo, UNO_QUERY );
1888 Reference< XChild > xAsChild ( xAsPropSet, UNO_QUERY );
1889 if ( !xAsChild.is() || !xAsServiceInfo->supportsService( m_aLabelServiceName ) )
1891 throw com::sun::star::lang::IllegalArgumentException();
1894 // check if weself and the given model have a common anchestor (up to the forms collection)
1895 Reference<XChild> xCont;
1896 query_interface(static_cast<XWeak*>(this), xCont);
1897 Reference< XInterface > xMyTopLevel = xCont->getParent();
1898 while (xMyTopLevel.is())
1900 Reference<XForm> xAsForm(xMyTopLevel, UNO_QUERY);
1901 if (!xAsForm.is())
1902 // found my root
1903 break;
1905 Reference<XChild> xLoopAsChild(xMyTopLevel, UNO_QUERY);
1906 xMyTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1908 Reference< XInterface > xNewTopLevel = xAsChild->getParent();
1909 while (xNewTopLevel.is())
1911 Reference<XForm> xAsForm(xNewTopLevel, UNO_QUERY);
1912 if (!xAsForm.is())
1913 break;
1915 Reference<XChild> xLoopAsChild(xNewTopLevel, UNO_QUERY);
1916 xNewTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1918 if (xNewTopLevel != xMyTopLevel)
1920 // the both objects don't belong to the same forms collection -> not acceptable
1921 throw com::sun::star::lang::IllegalArgumentException();
1924 m_xLabelControl = xAsPropSet;
1925 Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1926 if (xComp.is())
1927 xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1929 break;
1930 default:
1931 OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue );
1935 // XPropertyChangeListener
1936 //------------------------------------------------------------------------------
1937 void SAL_CALL OBoundControlModel::propertyChange( const PropertyChangeEvent& evt ) throw(RuntimeException)
1939 // if the DBColumn value changed, transfer it to the control
1940 if ( evt.PropertyName.equals( PROPERTY_VALUE ) )
1942 OSL_ENSURE( evt.Source == getField(), "OBoundControlModel::propertyChange: value changes from components other than our database colum?" );
1943 osl::MutexGuard aGuard(m_aMutex);
1944 if ( m_bForwardValueChanges && m_xColumn.is() )
1945 transferDbValueToControl();
1947 else
1949 OSL_ENSURE( evt.Source == m_xExternalBinding, "OBoundControlModel::propertyChange: where did this come from?" );
1951 // our binding has properties which can control properties of ourself
1952 OUString sBindingControlledProperty;
1953 bool bForwardToLabelControl = false;
1954 if ( evt.PropertyName.equals( PROPERTY_READONLY ) )
1956 sBindingControlledProperty = PROPERTY_READONLY;
1958 else if ( evt.PropertyName.equals( PROPERTY_RELEVANT ) )
1960 sBindingControlledProperty = PROPERTY_ENABLED;
1961 bForwardToLabelControl = true;
1963 else
1964 return;
1968 setPropertyValue( sBindingControlledProperty, evt.NewValue );
1969 if ( bForwardToLabelControl && m_xLabelControl.is() )
1970 m_xLabelControl->setPropertyValue( sBindingControlledProperty, evt.NewValue );
1972 catch( const Exception& )
1974 OSL_FAIL( "OBoundControlModel::propertyChange: could not adjust my binding-controlled property!" );
1979 //------------------------------------------------------------------------------
1980 void SAL_CALL OBoundControlModel::onRowSetChanged( const EventObject& /*i_Event*/ ) throw (RuntimeException)
1982 ControlModelLock aLock( *this );
1983 FieldChangeNotifier aBoundFieldNotifier( aLock );
1985 // disconnect from database column (which is controlled by parent, directly or indirectly)
1986 if ( hasField() )
1987 impl_disconnectDatabaseColumn_noNotify();
1989 // log off old listeners
1990 if ( isFormListening() )
1991 doFormListening( false );
1993 // determine the new ambient form
1994 impl_determineAmbientForm_nothrow();
1996 // log on new listeners
1997 doFormListening( true );
1999 // re-connect to database column if needed and possible
2000 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
2001 impl_connectDatabaseColumn_noNotify( false );
2004 // XBoundComponent
2005 //------------------------------------------------------------------------------
2006 void SAL_CALL OBoundControlModel::addUpdateListener(const Reference<XUpdateListener>& _rxListener) throw(RuntimeException)
2008 m_aUpdateListeners.addInterface(_rxListener);
2011 //------------------------------------------------------------------------------
2012 void SAL_CALL OBoundControlModel::removeUpdateListener(const Reference< XUpdateListener>& _rxListener) throw(RuntimeException)
2014 m_aUpdateListeners.removeInterface(_rxListener);
2017 //------------------------------------------------------------------------------
2018 sal_Bool SAL_CALL OBoundControlModel::commit() throw(RuntimeException)
2020 ControlModelLock aLock( *this );
2022 OSL_PRECOND( m_bCommitable, "OBoundControlModel::commit: invalid call (I'm not commitable !) " );
2023 if ( hasExternalValueBinding() )
2025 // in most cases, no action is required: For most derivees, we know the value property of
2026 // our control (see initValueProperty), and when an external binding is active, we
2027 // instantly forward all changes in this property to the external binding.
2028 if ( m_sValuePropertyName.isEmpty() )
2029 // but for those derivees which did not use this feature, we need an
2030 // explicit transfer
2031 transferControlValueToExternal( aLock );
2032 return sal_True;
2035 OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" );
2036 // we reach this only if we're not working with an external binding
2038 if ( !hasField() )
2039 return sal_True;
2041 ::cppu::OInterfaceIteratorHelper aIter( m_aUpdateListeners );
2042 EventObject aEvent;
2043 aEvent.Source = static_cast< XWeak* >( this );
2044 sal_Bool bSuccess = sal_True;
2046 aLock.release();
2047 // >>>>>>>> ----- UNSAFE ----- >>>>>>>>
2048 while (aIter.hasMoreElements() && bSuccess)
2049 bSuccess = static_cast< XUpdateListener* >( aIter.next() )->approveUpdate( aEvent );
2050 // <<<<<<<< ----- UNSAFE ----- <<<<<<<<
2051 aLock.acquire();
2053 if ( bSuccess )
2057 if ( m_xColumnUpdate.is() )
2058 bSuccess = commitControlValueToDbColumn( sal_False );
2060 catch(const Exception&)
2062 bSuccess = sal_False;
2066 if ( bSuccess )
2068 aLock.release();
2069 m_aUpdateListeners.notifyEach( &XUpdateListener::updated, aEvent );
2072 return bSuccess;
2075 //------------------------------------------------------------------------------
2076 void OBoundControlModel::resetField()
2078 m_xColumnUpdate.clear();
2079 m_xColumn.clear();
2080 m_xField.clear();
2081 m_nFieldType = DataType::OTHER;
2084 //------------------------------------------------------------------------------
2085 sal_Bool OBoundControlModel::connectToField(const Reference<XRowSet>& rForm)
2087 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::connectToField: invalid call (have an external binding)!" );
2089 // wenn eine Verbindung zur Datenbank existiert
2090 if (rForm.is() && getConnection(rForm).is())
2092 // Feld bestimmen und PropertyChangeListener
2093 m_xCursor = rForm;
2094 Reference<XPropertySet> xFieldCandidate;
2096 if (m_xCursor.is())
2098 Reference<XColumnsSupplier> xColumnsSupplier(m_xCursor, UNO_QUERY);
2099 DBG_ASSERT(xColumnsSupplier.is(), "OBoundControlModel::connectToField : the row set should support the com::sun::star::sdb::ResultSet service !");
2100 if (xColumnsSupplier.is())
2102 Reference<XNameAccess> xColumns(xColumnsSupplier->getColumns(), UNO_QUERY);
2103 if (xColumns.is() && xColumns->hasByName(m_aControlSource))
2105 OSL_VERIFY( xColumns->getByName(m_aControlSource) >>= xFieldCandidate );
2112 sal_Int32 nFieldType = DataType::OTHER;
2113 if ( xFieldCandidate.is() )
2115 xFieldCandidate->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
2116 if ( approveDbColumnType( nFieldType ) )
2117 impl_setField_noNotify( xFieldCandidate );
2119 else
2120 impl_setField_noNotify( NULL );
2122 if ( m_xField.is() )
2124 if( m_xField->getPropertySetInfo()->hasPropertyByName( PROPERTY_VALUE ) )
2126 m_nFieldType = nFieldType;
2128 // an wertaenderungen horchen
2129 m_xField->addPropertyChangeListener( PROPERTY_VALUE, this );
2130 m_xColumnUpdate = Reference< XColumnUpdate >( m_xField, UNO_QUERY );
2131 m_xColumn = Reference< XColumn >( m_xField, UNO_QUERY );
2133 sal_Int32 nNullableFlag = ColumnValue::NO_NULLS;
2134 m_xField->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullableFlag;
2135 m_bRequired = (ColumnValue::NO_NULLS == nNullableFlag);
2136 // we're optimistic : in case of ColumnValue_NULLABLE_UNKNOWN we assume nullability ....
2138 else
2140 OSL_FAIL("OBoundControlModel::connectToField: property NAME not supported!");
2141 impl_setField_noNotify( NULL );
2145 catch( const Exception& )
2147 DBG_UNHANDLED_EXCEPTION();
2148 resetField();
2151 return hasField();
2154 //------------------------------------------------------------------------------
2155 void OBoundControlModel::initFromField( const Reference< XRowSet >& _rxRowSet )
2157 // but only if the rowset if posisitioned on a valid record
2158 if ( hasField() && _rxRowSet.is() )
2160 if ( !_rxRowSet->isBeforeFirst() && !_rxRowSet->isAfterLast() )
2161 transferDbValueToControl();
2162 else
2163 // reset the field if the row set is empty
2164 // #i30661#
2165 resetNoBroadcast();
2169 //------------------------------------------------------------------------------
2170 sal_Bool OBoundControlModel::approveDbColumnType(sal_Int32 _nColumnType)
2172 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::approveDbColumnType: invalid call (have an external binding)!" );
2174 if ((_nColumnType == DataType::BINARY) || (_nColumnType == DataType::VARBINARY)
2175 || (_nColumnType == DataType::LONGVARBINARY) || (_nColumnType == DataType::OTHER)
2176 || (_nColumnType == DataType::OBJECT) || (_nColumnType == DataType::DISTINCT)
2177 || (_nColumnType == DataType::STRUCT) || (_nColumnType == DataType::ARRAY)
2178 || (_nColumnType == DataType::BLOB) /*|| (_nColumnType == DataType::CLOB)*/
2179 || (_nColumnType == DataType::REF) || (_nColumnType == DataType::SQLNULL))
2180 return sal_False;
2182 return sal_True;
2185 //------------------------------------------------------------------------------
2186 void OBoundControlModel::impl_determineAmbientForm_nothrow()
2188 Reference< XInterface > xParent( const_cast< OBoundControlModel* >( this )->getParent() );
2190 m_xAmbientForm.set( xParent, UNO_QUERY );
2191 if ( !m_xAmbientForm.is() )
2193 Reference< XRowSetSupplier > xSupRowSet( xParent, UNO_QUERY );
2194 if ( xSupRowSet.is() )
2195 m_xAmbientForm.set( xSupRowSet->getRowSet(), UNO_QUERY );
2199 //------------------------------------------------------------------------------
2200 void OBoundControlModel::impl_connectDatabaseColumn_noNotify( bool _bFromReload )
2202 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2204 // consistency checks
2205 DBG_ASSERT( !( hasField() && !_bFromReload ),
2206 "OBoundControlModel::impl_connectDatabaseColumn_noNotify: the form is just *loaded*, but we already have a field!" );
2207 (void)_bFromReload;
2209 Reference< XRowSet > xRowSet( m_xAmbientForm, UNO_QUERY );
2210 OSL_ENSURE( xRowSet.is(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: no row set!" );
2211 if ( !xRowSet.is() )
2212 return;
2214 if ( !hasField() )
2216 // connect to the column
2217 connectToField( xRowSet );
2220 // now that we're connected (more or less, even if we did not find a column),
2221 // we definitely want to forward any potentially occuring value changes
2222 m_bForwardValueChanges = sal_True;
2224 // let derived classes react on this new connection
2225 m_bLoaded = sal_True;
2226 onConnectedDbColumn( xRowSet );
2228 // initially transfer the db column value to the control, if we successfully connected to a database column
2229 if ( hasField() )
2230 initFromField( xRowSet );
2233 //------------------------------------------------------------------------------
2234 void OBoundControlModel::impl_disconnectDatabaseColumn_noNotify()
2236 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_disconnectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2238 // let derived classes react on this
2239 onDisconnectedDbColumn();
2241 if ( hasField() )
2243 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
2244 resetField();
2247 m_xCursor = NULL;
2248 m_bLoaded = sal_False;
2251 //==============================================================================
2252 // XLoadListener
2253 //------------------------------------------------------------------------------
2254 void SAL_CALL OBoundControlModel::loaded( const EventObject& _rEvent ) throw(RuntimeException)
2256 ControlModelLock aLock( *this );
2257 FieldChangeNotifier aBoundFieldNotifier( aLock );
2259 OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::loaded: where does this come from?" );
2260 (void)_rEvent;
2262 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::loaded: we should never reach this with an external value binding!" );
2263 if ( hasExternalValueBinding() )
2264 return;
2266 impl_connectDatabaseColumn_noNotify( false );
2270 //------------------------------------------------------------------------------
2271 void SAL_CALL OBoundControlModel::unloaded( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException)
2273 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloaded: we should never reach this with an external value binding!" );
2276 //------------------------------------------------------------------------------
2277 void SAL_CALL OBoundControlModel::reloading( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException)
2279 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloading: we should never reach this with an external value binding!" );
2280 if ( hasExternalValueBinding() )
2281 return;
2283 osl::MutexGuard aGuard(m_aMutex);
2284 m_bForwardValueChanges = sal_False;
2287 //------------------------------------------------------------------------------
2288 void SAL_CALL OBoundControlModel::unloading(const com::sun::star::lang::EventObject& /*aEvent*/) throw(RuntimeException)
2290 ControlModelLock aLock( *this );
2291 FieldChangeNotifier aBoundFieldNotifier( aLock );
2293 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloading: we should never reach this with an external value binding!" );
2294 if ( hasExternalValueBinding() )
2295 return;
2297 impl_disconnectDatabaseColumn_noNotify();
2300 //------------------------------------------------------------------------------
2301 void SAL_CALL OBoundControlModel::reloaded( const EventObject& _rEvent ) throw(RuntimeException)
2303 ControlModelLock aLock( *this );
2304 FieldChangeNotifier aBoundFieldNotifier( aLock );
2306 OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::reloaded: where does this come from?" );
2307 (void)_rEvent;
2309 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloaded: we should never reach this with an external value binding!" );
2310 if ( hasExternalValueBinding() )
2311 return;
2313 impl_connectDatabaseColumn_noNotify( true );
2316 //------------------------------------------------------------------------------
2317 void OBoundControlModel::setControlValue( const Any& _rValue, ValueChangeInstigator _eInstigator )
2319 m_eControlValueChangeInstigator = _eInstigator;
2320 doSetControlValue( _rValue );
2321 m_eControlValueChangeInstigator = eOther;
2324 //------------------------------------------------------------------------------
2325 void OBoundControlModel::doSetControlValue( const Any& _rValue )
2327 OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2328 "OBoundControlModel::doSetControlValue: invalid aggregate !" );
2329 OSL_PRECOND( !m_sValuePropertyName.isEmpty() || ( m_nValuePropertyAggregateHandle != -1 ),
2330 "OBoundControlModel::doSetControlValue: please override if you have own value property handling!" );
2334 // release our mutex once (it's acquired in one of the calling methods), as setting aggregate properties
2335 // may cause any uno controls belonging to us to lock the solar mutex, which is potentially dangerous with
2336 // our own mutex locked
2337 MutexRelease aRelease( m_aMutex );
2338 if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2340 m_xAggregateFastSet->setFastPropertyValue( m_nValuePropertyAggregateHandle, _rValue );
2342 else if ( !m_sValuePropertyName.isEmpty() && m_xAggregateSet.is() )
2344 m_xAggregateSet->setPropertyValue( m_sValuePropertyName, _rValue );
2347 catch( const Exception& )
2349 OSL_FAIL( "OBoundControlModel::doSetControlValue: caught an exception!" );
2350 DBG_UNHANDLED_EXCEPTION();
2354 //------------------------------------------------------------------------------
2355 void OBoundControlModel::onConnectedValidator( )
2359 // if we have an external validator, we do not want the control to force invalid
2360 // inputs to the default value. Instead, invalid inputs should be translated
2361 // to NaN (not a number)
2362 Reference< XPropertySetInfo > xAggregatePropertyInfo;
2363 if ( m_xAggregateSet.is() )
2364 xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2365 if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2366 m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( (sal_Bool)sal_False ) );
2368 catch( const Exception& )
2370 OSL_FAIL( "OBoundControlModel::onConnectedValidator: caught an exception!" );
2371 DBG_UNHANDLED_EXCEPTION();
2373 recheckValidity( false );
2376 //------------------------------------------------------------------------------
2377 void OBoundControlModel::onDisconnectedValidator( )
2381 Reference< XPropertySetInfo > xAggregatePropertyInfo;
2382 if ( m_xAggregateSet.is() )
2383 xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2384 if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2385 m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( (sal_Bool)sal_True ) );
2387 catch( const Exception& )
2389 OSL_FAIL( "OBoundControlModel::onDisconnectedValidator: caught an exception!" );
2390 DBG_UNHANDLED_EXCEPTION();
2392 recheckValidity( false );
2395 //------------------------------------------------------------------------------
2396 void OBoundControlModel::onConnectedExternalValue( )
2398 calculateExternalValueType();
2401 //------------------------------------------------------------------------------
2402 void OBoundControlModel::onDisconnectedExternalValue( )
2406 //------------------------------------------------------------------------------
2407 void OBoundControlModel::onConnectedDbColumn( const Reference< XInterface >& /*_rxForm*/ )
2409 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onConnectedDbColumn: how this? There's an external value binding!" );
2412 //------------------------------------------------------------------------------
2413 void OBoundControlModel::onDisconnectedDbColumn()
2415 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onDisconnectedDbColumn: how this? There's an external value binding!" );
2418 // XReset
2419 //-----------------------------------------------------------------------------
2420 Any OBoundControlModel::getDefaultForReset() const
2422 return Any();
2425 //-----------------------------------------------------------------------------
2426 void OBoundControlModel::resetNoBroadcast()
2428 setControlValue( getDefaultForReset(), eOther );
2431 //-----------------------------------------------------------------------------
2432 void OBoundControlModel::addResetListener(const Reference<XResetListener>& l) throw (RuntimeException)
2434 m_aResetHelper.addResetListener( l );
2437 //-----------------------------------------------------------------------------
2438 void OBoundControlModel::removeResetListener(const Reference<XResetListener>& l) throw (RuntimeException)
2440 m_aResetHelper.removeResetListener( l );
2443 //-----------------------------------------------------------------------------
2444 void OBoundControlModel::reset() throw (RuntimeException)
2446 if ( !m_aResetHelper.approveReset() )
2447 return;
2449 ControlModelLock aLock( *this );
2451 // on a new record?
2452 sal_Bool bIsNewRecord = sal_False;
2453 Reference<XPropertySet> xSet( m_xCursor, UNO_QUERY );
2454 if ( xSet.is() )
2458 xSet->getPropertyValue( PROPERTY_ISNEW ) >>= bIsNewRecord;
2460 catch( const Exception& )
2462 DBG_UNHANDLED_EXCEPTION();
2466 // cursor on an invalid row?
2467 sal_Bool bInvalidCursorPosition = sal_True;
2470 bInvalidCursorPosition = m_xCursor.is()
2471 && ( m_xCursor->isAfterLast()
2472 || m_xCursor->isBeforeFirst()
2474 && !bIsNewRecord;
2476 catch( const SQLException& )
2478 OSL_FAIL( "OBoundControlModel::reset: caught an SQL exception!" );
2480 // #i24495# - don't count the insert row as "invalid"
2482 sal_Bool bSimpleReset =
2483 ( !m_xColumn.is() // no connection to a database column
2484 || ( m_xCursor.is() // OR we have an improperly positioned cursor
2485 && bInvalidCursorPosition
2487 || hasExternalValueBinding() // OR we have an external value binding
2490 if ( !bSimpleReset )
2492 // The default values will be set if and only if the current value of the field which we're bound
2493 // to is NULL.
2494 // Else, the current field value should be refreshed
2495 // This behaviour is not completely ... "matured": What should happen if the field as well as the
2496 // control have a default value?
2498 sal_Bool bIsNull = sal_True;
2499 // we have to access the field content at least once to get a reliable result by XColumn::wasNull
2502 // normally, we'd do a getString here. However, this is extremely expensive in the case
2503 // of binary fields. Unfortunately, getString is the only method which is guaranteed
2504 // to *always* succeed, all other getXXX methods may fail if the column is asked for a
2505 // non-convertible type
2506 sal_Int32 nFieldType = DataType::OBJECT;
2507 getField()->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
2508 if ( ( nFieldType == DataType::BINARY )
2509 || ( nFieldType == DataType::VARBINARY )
2510 || ( nFieldType == DataType::LONGVARBINARY )
2511 || ( nFieldType == DataType::OBJECT )
2512 /*|| ( nFieldType == DataType::CLOB )*/
2514 m_xColumn->getBinaryStream();
2515 else if ( nFieldType == DataType::BLOB )
2516 m_xColumn->getBlob();
2517 else
2518 m_xColumn->getString();
2520 bIsNull = m_xColumn->wasNull();
2522 catch(const Exception&)
2524 OSL_FAIL("OBoundControlModel::reset: this should have succeeded in all cases!");
2527 sal_Bool bNeedValueTransfer = sal_True;
2529 if ( bIsNull )
2531 if ( bIsNewRecord )
2533 // reset the control to it's default
2534 resetNoBroadcast();
2535 // and immediately commit the changes to the DB column, to keep consistency
2536 commitControlValueToDbColumn( sal_True );
2538 bNeedValueTransfer = sal_False;
2542 if ( bNeedValueTransfer )
2543 transferDbValueToControl();
2545 else
2547 resetNoBroadcast();
2549 // transfer to the external binding, if necessary
2550 if ( hasExternalValueBinding() )
2551 transferControlValueToExternal( aLock );
2554 // revalidate, if necessary
2555 if ( hasValidator() )
2556 recheckValidity( true );
2558 aLock.release();
2560 m_aResetHelper.notifyResetted();
2563 // -----------------------------------------------------------------------------
2564 void OBoundControlModel::impl_setField_noNotify( const Reference< XPropertySet>& _rxField )
2566 DBG_ASSERT( !hasExternalValueBinding(), "OBoundControlModel::impl_setField_noNotify: We have an external value binding!" );
2567 m_xField = _rxField;
2570 //--------------------------------------------------------------------
2571 sal_Bool OBoundControlModel::impl_approveValueBinding_nolock( const Reference< XValueBinding >& _rxBinding )
2573 if ( !_rxBinding.is() )
2574 return sal_False;
2576 Sequence< Type > aTypeCandidates;
2578 // SYNCHRONIZED -->
2579 ::osl::MutexGuard aGuard( m_aMutex );
2580 aTypeCandidates = getSupportedBindingTypes();
2581 // <-- SYNCHRONIZED
2584 for ( const Type* pType = aTypeCandidates.getConstArray();
2585 pType != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2586 ++pType
2589 if ( _rxBinding->supportsType( *pType ) )
2590 return sal_True;
2593 return sal_False;
2596 //--------------------------------------------------------------------
2597 void OBoundControlModel::connectExternalValueBinding(
2598 const Reference< XValueBinding >& _rxBinding, ControlModelLock& _rInstanceLock )
2600 OSL_PRECOND( _rxBinding.is(), "OBoundControlModel::connectExternalValueBinding: invalid binding instance!" );
2601 OSL_PRECOND( !hasExternalValueBinding( ), "OBoundControlModel::connectExternalValueBinding: precond not met (currently have a binding)!" );
2603 // if we're connected to a database column, suspend this
2604 if ( hasField() )
2605 impl_disconnectDatabaseColumn_noNotify();
2607 // suspend listening for load-related events at out ambient form.
2608 // This is because an external value binding overrules a possible database binding.
2609 if ( isFormListening() )
2610 doFormListening( false );
2612 // remember this new binding
2613 m_xExternalBinding = _rxBinding;
2615 // tell the derivee
2616 onConnectedExternalValue();
2620 // add as value listener so we get notified when the value changes
2621 Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2622 if ( xModifiable.is() )
2623 xModifiable->addModifyListener( this );
2625 // add as property change listener for some (possibly present) properties we're
2626 // interested in
2627 Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2628 Reference< XPropertySetInfo > xBindingPropsInfo( xBindingProps.is() ? xBindingProps->getPropertySetInfo() : Reference< XPropertySetInfo >() );
2629 if ( xBindingPropsInfo.is() )
2631 if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_READONLY ) )
2633 xBindingProps->addPropertyChangeListener( PROPERTY_READONLY, this );
2634 m_bBindingControlsRO = sal_True;
2636 if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_RELEVANT ) )
2638 xBindingProps->addPropertyChangeListener( PROPERTY_RELEVANT, this );
2639 m_bBindingControlsEnable = sal_True;
2643 catch( const Exception& )
2645 DBG_UNHANDLED_EXCEPTION();
2648 // propagate our new value
2649 transferExternalValueToControl( _rInstanceLock );
2651 // if the binding is also a validator, use it, too. This is a constraint of the
2652 // com.sun.star.form.binding.ValidatableBindableFormComponent service
2653 if ( m_bSupportsValidation )
2657 Reference< XValidator > xAsValidator( _rxBinding, UNO_QUERY );
2658 if ( xAsValidator.is() )
2659 setValidator( xAsValidator );
2661 catch( const Exception& )
2663 DBG_UNHANDLED_EXCEPTION();
2668 //--------------------------------------------------------------------
2669 void OBoundControlModel::disconnectExternalValueBinding( )
2673 // not listening at the binding anymore
2674 Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2675 if ( xModifiable.is() )
2676 xModifiable->removeModifyListener( this );
2678 // remove as property change listener
2679 Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2680 if ( m_bBindingControlsRO )
2681 xBindingProps->removePropertyChangeListener( PROPERTY_READONLY, this );
2682 if ( m_bBindingControlsEnable )
2683 xBindingProps->removePropertyChangeListener( PROPERTY_RELEVANT, this );
2685 catch( const Exception& )
2687 OSL_FAIL( "OBoundControlModel::disconnectExternalValueBinding: caught an exception!" );
2690 // if the binding also acts as our validator, disconnect the validator, too
2691 if ( ( m_xExternalBinding == m_xValidator ) && m_xValidator.is() )
2692 disconnectValidator( );
2694 // no binding anymore
2695 m_xExternalBinding.clear();
2697 // be a load listener at our form, again. This was suspended while we had
2698 // an external value binding in place.
2699 doFormListening( true );
2701 // re-connect to database column of the new parent
2702 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
2703 impl_connectDatabaseColumn_noNotify( false );
2705 // tell the derivee
2706 onDisconnectedExternalValue();
2709 //--------------------------------------------------------------------
2710 void SAL_CALL OBoundControlModel::setValueBinding( const Reference< XValueBinding >& _rxBinding ) throw (IncompatibleTypesException, RuntimeException)
2712 OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::setValueBinding: How did you reach this method?" );
2713 // the interface for this method should not have been exposed if we do not
2714 // support binding to external data
2715 // allow reset
2716 if ( _rxBinding.is() && !impl_approveValueBinding_nolock( _rxBinding ) )
2718 throw IncompatibleTypesException(
2719 FRM_RES_STRING( RID_STR_INCOMPATIBLE_TYPES ),
2720 *this
2724 ControlModelLock aLock( *this );
2726 // since a ValueBinding overrules any potentially active database binding, the change in a ValueBinding
2727 // might trigger a change in our BoundField.
2728 FieldChangeNotifier aBoundFieldNotifier( aLock );
2730 // disconnect from the old binding
2731 if ( hasExternalValueBinding() )
2732 disconnectExternalValueBinding( );
2734 // connect to the new binding
2735 if ( _rxBinding.is() )
2736 connectExternalValueBinding( _rxBinding, aLock );
2739 //--------------------------------------------------------------------
2740 Reference< XValueBinding > SAL_CALL OBoundControlModel::getValueBinding( ) throw (RuntimeException)
2742 ::osl::MutexGuard aGuard( m_aMutex );
2743 OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::getValueBinding: How did you reach this method?" );
2744 // the interface for this method should not have been exposed if we do not
2745 // support binding to external data
2747 return m_xExternalBinding;
2750 //--------------------------------------------------------------------
2751 void SAL_CALL OBoundControlModel::modified( const EventObject& _rEvent ) throw ( RuntimeException )
2753 ControlModelLock aLock( *this );
2755 OSL_PRECOND( hasExternalValueBinding(), "OBoundControlModel::modified: Where did this come from?" );
2756 if ( !m_bTransferingValue && ( m_xExternalBinding == _rEvent.Source ) && m_xExternalBinding.is() )
2758 transferExternalValueToControl( aLock );
2762 //--------------------------------------------------------------------
2763 void OBoundControlModel::transferDbValueToControl( )
2767 setControlValue( translateDbColumnToControlValue(), eDbColumnBinding );
2769 catch( const Exception& )
2771 DBG_UNHANDLED_EXCEPTION();
2775 //------------------------------------------------------------------------------
2776 void OBoundControlModel::transferExternalValueToControl( ControlModelLock& _rInstanceLock )
2778 Reference< XValueBinding > xExternalBinding( m_xExternalBinding );
2779 Type aValueExchangeType( getExternalValueType() );
2781 _rInstanceLock.release();
2782 // >>>>>>>> ----- UNSAFE ----- >>>>>>>>
2783 Any aExternalValue;
2786 aExternalValue = xExternalBinding->getValue( aValueExchangeType );
2788 catch( const Exception& )
2790 DBG_UNHANDLED_EXCEPTION();
2792 // <<<<<<<< ----- UNSAFE ----- <<<<<<<<
2793 _rInstanceLock.acquire();
2795 setControlValue( translateExternalValueToControlValue( aExternalValue ), eExternalBinding );
2798 //------------------------------------------------------------------------------
2799 void OBoundControlModel::transferControlValueToExternal( ControlModelLock& _rInstanceLock )
2801 OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2802 "OBoundControlModel::transferControlValueToExternal: precondition not met!" );
2804 if ( m_xExternalBinding.is() )
2806 Any aExternalValue( translateControlValueToExternalValue() );
2807 m_bTransferingValue = sal_True;
2809 _rInstanceLock.release();
2810 // >>>>>>>> ----- UNSAFE ----- >>>>>>>>
2813 m_xExternalBinding->setValue( aExternalValue );
2815 catch( const Exception& )
2817 DBG_UNHANDLED_EXCEPTION();
2819 // <<<<<<<< ----- UNSAFE ----- <<<<<<<<
2820 _rInstanceLock.acquire();
2822 m_bTransferingValue = sal_False;
2826 // -----------------------------------------------------------------------------
2827 Sequence< Type > OBoundControlModel::getSupportedBindingTypes()
2829 return Sequence< Type >( &m_aValuePropertyType, 1 );
2832 //-----------------------------------------------------------------------------
2833 void OBoundControlModel::calculateExternalValueType()
2835 m_aExternalValueType = Type();
2836 if ( !m_xExternalBinding.is() )
2837 return;
2839 Sequence< Type > aTypeCandidates( getSupportedBindingTypes() );
2840 for ( const Type* pTypeCandidate = aTypeCandidates.getConstArray();
2841 pTypeCandidate != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2842 ++pTypeCandidate
2845 if ( m_xExternalBinding->supportsType( *pTypeCandidate ) )
2847 m_aExternalValueType = *pTypeCandidate;
2848 break;
2853 //-----------------------------------------------------------------------------
2854 Any OBoundControlModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
2856 OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2857 "OBoundControlModel::translateExternalValueToControlValue: precondition not met!" );
2859 Any aControlValue( _rExternalValue );
2861 // if the external value is VOID, and our value property is not allowed to be VOID,
2862 // then default-construct a value
2863 if ( !aControlValue.hasValue() && !m_bValuePropertyMayBeVoid )
2864 aControlValue.setValue( NULL, m_aValuePropertyType );
2866 // outta here
2867 return aControlValue;
2870 //------------------------------------------------------------------------------
2871 Any OBoundControlModel::translateControlValueToExternalValue( ) const
2873 return getControlValue( );
2876 //------------------------------------------------------------------------------
2877 Any OBoundControlModel::translateControlValueToValidatableValue( ) const
2879 OSL_PRECOND( m_xValidator.is(), "OBoundControlModel::translateControlValueToValidatableValue: no validator, so why should I?" );
2880 if ( ( m_xValidator == m_xExternalBinding ) && m_xValidator.is() )
2881 return translateControlValueToExternalValue();
2882 return getControlValue();
2885 //------------------------------------------------------------------------------
2886 Any OBoundControlModel::getControlValue( ) const
2888 OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2889 "OBoundControlModel::getControlValue: invalid aggregate !" );
2890 OSL_PRECOND( !m_sValuePropertyName.isEmpty() || ( m_nValuePropertyAggregateHandle != -1 ),
2891 "OBoundControlModel::getControlValue: please override if you have own value property handling!" );
2893 // determine the current control value
2894 Any aControlValue;
2895 if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2897 aControlValue = m_xAggregateFastSet->getFastPropertyValue( m_nValuePropertyAggregateHandle );
2899 else if ( !m_sValuePropertyName.isEmpty() && m_xAggregateSet.is() )
2901 aControlValue = m_xAggregateSet->getPropertyValue( m_sValuePropertyName );
2904 return aControlValue;
2907 //--------------------------------------------------------------------
2908 void OBoundControlModel::connectValidator( const Reference< XValidator >& _rxValidator )
2910 OSL_PRECOND( _rxValidator.is(), "OBoundControlModel::connectValidator: invalid validator instance!" );
2911 OSL_PRECOND( !hasValidator( ), "OBoundControlModel::connectValidator: precond not met (have a validator currently)!" );
2913 m_xValidator = _rxValidator;
2915 // add as value listener so we get notified when the value changes
2916 if ( m_xValidator.is() )
2920 m_xValidator->addValidityConstraintListener( this );
2922 catch( const RuntimeException& )
2927 onConnectedValidator( );
2930 //--------------------------------------------------------------------
2931 void OBoundControlModel::disconnectValidator( )
2933 OSL_PRECOND( hasValidator( ), "OBoundControlModel::connectValidator: precond not met (don't have a validator currently)!" );
2935 // add as value listener so we get notified when the value changes
2936 if ( m_xValidator.is() )
2940 m_xValidator->removeValidityConstraintListener( this );
2942 catch( const RuntimeException& )
2947 m_xValidator.clear();
2949 onDisconnectedValidator( );
2952 //--------------------------------------------------------------------
2953 void SAL_CALL OBoundControlModel::setValidator( const Reference< XValidator >& _rxValidator ) throw (VetoException,RuntimeException)
2955 ::osl::ClearableMutexGuard aGuard( m_aMutex );
2956 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::setValidator: How did you reach this method?" );
2957 // the interface for this method should not have been exposed if we do not
2958 // support validation
2960 // early out if the validator does not change
2961 if( _rxValidator == m_xValidator )
2962 return;
2964 if ( m_xValidator.is() && ( m_xValidator == m_xExternalBinding ) )
2965 throw VetoException(
2966 FRM_RES_STRING( RID_STR_INVALID_VALIDATOR ),
2967 *this
2970 // disconnect from the old validator
2971 if ( hasValidator() )
2972 disconnectValidator( );
2974 // connect to the new validator
2975 if ( _rxValidator.is() )
2976 connectValidator( _rxValidator );
2979 //--------------------------------------------------------------------
2980 Reference< XValidator > SAL_CALL OBoundControlModel::getValidator( ) throw (RuntimeException)
2982 ::osl::MutexGuard aGuard( m_aMutex );
2983 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::getValidator: How did you reach this method?" );
2984 // the interface for this method should not have been exposed if we do not
2985 // support validation
2987 return m_xValidator;
2990 //--------------------------------------------------------------------
2991 void SAL_CALL OBoundControlModel::validityConstraintChanged( const EventObject& /*Source*/ ) throw (RuntimeException)
2993 ::osl::ClearableMutexGuard aGuard( m_aMutex );
2994 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::validityConstraintChanged: How did you reach this method?" );
2995 // the interface for this method should not have been exposed if we do not
2996 // support validation
2998 recheckValidity( false );
3001 //--------------------------------------------------------------------
3002 sal_Bool SAL_CALL OBoundControlModel::isValid( ) throw (RuntimeException)
3004 return m_bIsCurrentValueValid;
3007 //--------------------------------------------------------------------
3008 ::com::sun::star::uno::Any OBoundControlModel::getCurrentFormComponentValue() const
3010 if ( hasValidator() )
3011 return translateControlValueToValidatableValue();
3012 return getControlValue();
3015 //--------------------------------------------------------------------
3016 Any SAL_CALL OBoundControlModel::getCurrentValue( ) throw (RuntimeException)
3018 ::osl::MutexGuard aGuard( m_aMutex );
3019 return getCurrentFormComponentValue();
3022 //--------------------------------------------------------------------
3023 void SAL_CALL OBoundControlModel::addFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException)
3025 if ( Listener.is() )
3026 m_aFormComponentListeners.addInterface( Listener );
3029 //--------------------------------------------------------------------
3030 void SAL_CALL OBoundControlModel::removeFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException)
3032 if ( Listener.is() )
3033 m_aFormComponentListeners.removeInterface( Listener );
3036 //--------------------------------------------------------------------
3037 void OBoundControlModel::recheckValidity( bool _bForceNotification )
3041 sal_Bool bIsCurrentlyValid = sal_True;
3042 if ( hasValidator() )
3043 bIsCurrentlyValid = m_xValidator->isValid( translateControlValueToValidatableValue() );
3045 if ( ( bIsCurrentlyValid != m_bIsCurrentValueValid ) || _bForceNotification )
3047 m_bIsCurrentValueValid = bIsCurrentlyValid;
3049 // release our mutex for the notifications
3050 MutexRelease aRelease( m_aMutex );
3051 m_aFormComponentListeners.notifyEach( &validation::XFormComponentValidityListener::componentValidityChanged, EventObject( *this ) );
3054 catch( const Exception& )
3056 OSL_FAIL( "OBoundControlModel::recheckValidity: caught an exception!" );
3060 //------------------------------------------------------------------------------
3061 void OBoundControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
3063 BEGIN_DESCRIBE_PROPERTIES( 5, OControlModel )
3064 DECL_PROP1 ( CONTROLSOURCE, OUString, BOUND );
3065 DECL_IFACE_PROP3( BOUNDFIELD, XPropertySet, BOUND, READONLY, TRANSIENT );
3066 DECL_IFACE_PROP2( CONTROLLABEL, XPropertySet, BOUND, MAYBEVOID );
3067 DECL_PROP2 ( CONTROLSOURCEPROPERTY, OUString, READONLY, TRANSIENT );
3068 DECL_BOOL_PROP1 ( INPUT_REQUIRED, BOUND );
3069 END_DESCRIBE_PROPERTIES()
3072 // -----------------------------------------------------------------------------
3074 //.........................................................................
3076 //... namespace frm .......................................................
3078 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */