1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_forms.hxx"
26
27 #include "componenttools.hxx"
28 #include "FormComponent.hxx"
29 #include "frm_resource.hrc"
30 #include "frm_resource.hxx"
31 #include "property.hrc"
32 #include "services.hxx"
33
34 /** === begin UNO includes === **/
35 #include <com/sun/star/awt/XTextComponent.hpp>
36 #include <com/sun/star/awt/XVclWindowPeer.hpp>
37 #include <com/sun/star/awt/XWindow.hpp>
38 #include <com/sun/star/form/XForm.hpp>
39 #include <com/sun/star/form/XLoadable.hpp>
40 #include <com/sun/star/io/XMarkableStream.hpp>
41 #include <com/sun/star/lang/DisposedException.hpp>
42 #include <com/sun/star/sdb/XRowSetChangeBroadcaster.hpp>
43 #include <com/sun/star/sdb/XRowSetSupplier.hpp>
44 #include <com/sun/star/sdbc/ColumnValue.hpp>
45 #include <com/sun/star/sdbc/DataType.hpp>
46 #include <com/sun/star/util/XModifyBroadcaster.hpp>
47 /** === end UNO includes === **/
48
49 #include <comphelper/basicio.hxx>
50 #include <comphelper/guarding.hxx>
51 #include <comphelper/listenernotification.hxx>
52 #include <comphelper/property.hxx>
53 #include <connectivity/dbtools.hxx>
54 #include <cppuhelper/queryinterface.hxx>
55 #include <rtl/logfile.hxx>
56 #include <toolkit/helper/emptyfontdescriptor.hxx>
57 #include <tools/debug.hxx>
58 #include <tools/diagnose_ex.h>
59
60 #include <functional>
61 #include <algorithm>
62
63 #include <functional>
64 #include <algorithm>
65
66
67 //... namespace frm .......................................................
68 namespace frm
69 {
70 //.........................................................................
71
72 using namespace ::com::sun::star::uno;
73 using namespace ::com::sun::star::sdb;
74 using namespace ::com::sun::star::sdbc;
75 using namespace ::com::sun::star::sdbcx;
76 using namespace ::com::sun::star::beans;
77 using namespace ::com::sun::star::container;
78 using namespace ::com::sun::star::form;
79 using namespace ::com::sun::star::awt;
80 using namespace ::com::sun::star::io;
81 using namespace ::com::sun::star::lang;
82 using namespace ::com::sun::star::util;
83 using namespace ::com::sun::star::form::binding;
84 using namespace ::com::sun::star::form::validation;
85 using namespace ::dbtools;
86 using namespace ::comphelper;
87
88 //=========================================================================
89 //= FieldChangeNotifier
90 //=========================================================================
91 //-------------------------------------------------------------------------
impl_notifyAll_nothrow()92 void ControlModelLock::impl_notifyAll_nothrow()
93 {
94 m_rModel.firePropertyChanges( m_aHandles, m_aOldValues, m_aNewValues, OControlModel::LockAccess() );
95 }
96
97 //-------------------------------------------------------------------------
addPropertyNotification(const sal_Int32 _nHandle,const Any & _rOldValue,const Any & _rNewValue)98 void ControlModelLock::addPropertyNotification( const sal_Int32 _nHandle, const Any& _rOldValue, const Any& _rNewValue )
99 {
100 sal_Int32 nOldLength = m_aHandles.getLength();
101 if ( ( nOldLength != m_aOldValues.getLength() )
102 || ( nOldLength != m_aNewValues.getLength() )
103 )
104 throw RuntimeException( ::rtl::OUString(), m_rModel );
105
106 m_aHandles.realloc( nOldLength + 1 );
107 m_aHandles[ nOldLength ] = _nHandle;
108 m_aOldValues.realloc( nOldLength + 1 );
109 m_aOldValues[ nOldLength ] = _rOldValue;
110 m_aNewValues.realloc( nOldLength + 1 );
111 m_aNewValues[ nOldLength ] = _rNewValue;
112 }
113
114 //=========================================================================
115 //= FieldChangeNotifier
116 //=========================================================================
117 //-------------------------------------------------------------------------
118 class FieldChangeNotifier
119 {
120 public:
FieldChangeNotifier(ControlModelLock & _rLock)121 FieldChangeNotifier( ControlModelLock& _rLock )
122 :m_rLock( _rLock )
123 ,m_rModel( dynamic_cast< OBoundControlModel& >( _rLock.getModel() ) )
124 {
125 m_xOldField = m_rModel.getField();
126 }
127
~FieldChangeNotifier()128 ~FieldChangeNotifier()
129 {
130 Reference< XPropertySet > xNewField( m_rModel.getField() );
131 if ( m_xOldField != xNewField )
132 m_rLock.addPropertyNotification( PROPERTY_ID_BOUNDFIELD, makeAny( m_xOldField ), makeAny( xNewField ) );
133 }
134
135 private:
136 ControlModelLock& m_rLock;
137 OBoundControlModel& m_rModel;
138 Reference< XPropertySet > m_xOldField;
139 };
140
141 //=============================================================================
142 //= base class for form layer controls
143 //=============================================================================
DBG_NAME(frm_OControl)144 DBG_NAME(frm_OControl)
145 //------------------------------------------------------------------------------
146 OControl::OControl( const Reference< XMultiServiceFactory >& _rxFactory, const rtl::OUString& _rAggregateService, const sal_Bool _bSetDelegator )
147 :OComponentHelper(m_aMutex)
148 ,m_aContext( _rxFactory )
149 {
150 DBG_CTOR(frm_OControl, NULL);
151 // VCL-Control aggregieren
152 // bei Aggregation den Refcount um eins erhoehen da im setDelegator
153 // das Aggregat selbst den Refcount erhoeht
154 increment( m_refCount );
155 {
156 m_xAggregate = m_xAggregate.query( _rxFactory->createInstance( _rAggregateService ) );
157 m_xControl = m_xControl.query( m_xAggregate );
158 }
159 decrement( m_refCount );
160
161 if ( _bSetDelegator )
162 doSetDelegator();
163 }
164
165 //------------------------------------------------------------------------------
~OControl()166 OControl::~OControl()
167 {
168 DBG_DTOR(frm_OControl, NULL);
169 doResetDelegator();
170 }
171
172 //------------------------------------------------------------------------------
doResetDelegator()173 void OControl::doResetDelegator()
174 {
175 if ( m_xAggregate.is() )
176 m_xAggregate->setDelegator( NULL );
177 }
178
179 //------------------------------------------------------------------------------
doSetDelegator()180 void OControl::doSetDelegator()
181 {
182 increment( m_refCount );
183 if ( m_xAggregate.is() )
184 { // those brackets are important for some compilers, don't remove!
185 // (they ensure that the temporary object created in the line below
186 // is destroyed *before* the refcount-decrement)
187 m_xAggregate->setDelegator( static_cast< XWeak* >( this ) );
188 }
189 decrement( m_refCount );
190 }
191
192 // UNO Anbindung
193 //------------------------------------------------------------------------------
queryAggregation(const Type & _rType)194 Any SAL_CALL OControl::queryAggregation( const Type& _rType ) throw(RuntimeException)
195 {
196 // ask the base class
197 Any aReturn( OComponentHelper::queryAggregation(_rType) );
198 // ask our own interfaces
199 if (!aReturn.hasValue())
200 {
201 aReturn = OControl_BASE::queryInterface(_rType);
202 // ask our aggregate
203 if (!aReturn.hasValue() && m_xAggregate.is())
204 aReturn = m_xAggregate->queryAggregation(_rType);
205 }
206
207 return aReturn;
208 }
209
210 //------------------------------------------------------------------------------
getImplementationId()211 Sequence<sal_Int8> SAL_CALL OControl::getImplementationId() throw(RuntimeException)
212 {
213 return OImplementationIds::getImplementationId(getTypes());
214 }
215
216 //------------------------------------------------------------------------------
getTypes()217 Sequence<Type> SAL_CALL OControl::getTypes() throw(RuntimeException)
218 {
219 TypeBag aTypes( _getTypes() );
220
221 Reference< XTypeProvider > xProv;
222 if ( query_aggregation( m_xAggregate, xProv ) )
223 aTypes.addTypes( xProv->getTypes() );
224
225 return aTypes.getTypes();
226 }
227
228 //------------------------------------------------------------------------------
_getTypes()229 Sequence<Type> OControl::_getTypes()
230 {
231 return TypeBag( OComponentHelper::getTypes(), OControl_BASE::getTypes() ).getTypes();
232 }
233
234 //------------------------------------------------------------------------------
initFormControlPeer(const Reference<XWindowPeer> &)235 void OControl::initFormControlPeer( const Reference< XWindowPeer >& /*_rxPeer*/ )
236 {
237 // nothing to do here
238 }
239
240 // OComponentHelper
241 //------------------------------------------------------------------------------
disposing()242 void OControl::disposing()
243 {
244 OComponentHelper::disposing();
245
246 m_aWindowStateGuard.attach( NULL, NULL );
247
248 Reference< XComponent > xComp;
249 if (query_aggregation(m_xAggregate, xComp))
250 xComp->dispose();
251 }
252
253 // XServiceInfo
254 //------------------------------------------------------------------------------
supportsService(const rtl::OUString & _rsServiceName)255 sal_Bool SAL_CALL OControl::supportsService(const rtl::OUString& _rsServiceName) throw ( RuntimeException)
256 {
257 Sequence<rtl::OUString> aSupported = getSupportedServiceNames();
258 const rtl::OUString* pSupported = aSupported.getConstArray();
259 for (sal_Int32 i=0; i<aSupported.getLength(); ++i, ++pSupported)
260 if (pSupported->equals(_rsServiceName))
261 return sal_True;
262 return sal_False;
263 }
264
265 //------------------------------------------------------------------------------
getAggregateServiceNames()266 Sequence< ::rtl::OUString > OControl::getAggregateServiceNames()
267 {
268 Sequence< ::rtl::OUString > aAggServices;
269 Reference< XServiceInfo > xInfo;
270 if ( query_aggregation( m_xAggregate, xInfo ) )
271 aAggServices = xInfo->getSupportedServiceNames();
272 return aAggServices;
273 }
274
275 //------------------------------------------------------------------------------
getSupportedServiceNames()276 Sequence<rtl::OUString> SAL_CALL OControl::getSupportedServiceNames() throw(RuntimeException)
277 {
278 return ::comphelper::concatSequences(
279 getAggregateServiceNames(),
280 getSupportedServiceNames_Static()
281 );
282 }
283
284 //------------------------------------------------------------------------------
getSupportedServiceNames_Static()285 Sequence< ::rtl::OUString > SAL_CALL OControl::getSupportedServiceNames_Static() throw( RuntimeException )
286 {
287 // no own supported service names
288 return Sequence< ::rtl::OUString >();
289 }
290
291 // XEventListener
292 //------------------------------------------------------------------------------
disposing(const com::sun::star::lang::EventObject & _rEvent)293 void SAL_CALL OControl::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException)
294 {
295 Reference< XInterface > xAggAsIface;
296 query_aggregation(m_xAggregate, xAggAsIface);
297
298 // does the disposing come from the aggregate ?
299 if (xAggAsIface != Reference< XInterface >(_rEvent.Source, UNO_QUERY))
300 { // no -> forward it
301 Reference<com::sun::star::lang::XEventListener> xListener;
302 if (query_aggregation(m_xAggregate, xListener))
303 xListener->disposing(_rEvent);
304 }
305 }
306
307 // XControl
308 //------------------------------------------------------------------------------
setContext(const Reference<XInterface> & Context)309 void SAL_CALL OControl::setContext(const Reference< XInterface >& Context) throw (RuntimeException)
310 {
311 if (m_xControl.is())
312 m_xControl->setContext(Context);
313 }
314
315 //------------------------------------------------------------------------------
getContext()316 Reference< XInterface > SAL_CALL OControl::getContext() throw (RuntimeException)
317 {
318 return m_xControl.is() ? m_xControl->getContext() : Reference< XInterface >();
319 }
320
321 //------------------------------------------------------------------------------
impl_resetStateGuard_nothrow()322 void OControl::impl_resetStateGuard_nothrow()
323 {
324 Reference< XWindow2 > xWindow;
325 Reference< XControlModel > xModel;
326 try
327 {
328 xWindow.set( getPeer(), UNO_QUERY );
329 xModel.set( getModel(), UNO_QUERY );
330 }
331 catch( const Exception& )
332 {
333 DBG_UNHANDLED_EXCEPTION();
334 }
335 m_aWindowStateGuard.attach( xWindow, xModel );
336 }
337
338 //------------------------------------------------------------------------------
createPeer(const Reference<XToolkit> & _rxToolkit,const Reference<XWindowPeer> & _rxParent)339 void SAL_CALL OControl::createPeer(const Reference<XToolkit>& _rxToolkit, const Reference<XWindowPeer>& _rxParent) throw (RuntimeException)
340 {
341 if ( m_xControl.is() )
342 {
343 m_xControl->createPeer( _rxToolkit, _rxParent );
344
345 initFormControlPeer( getPeer() );
346
347 impl_resetStateGuard_nothrow();
348 }
349 }
350
351 //------------------------------------------------------------------------------
getPeer()352 Reference<XWindowPeer> SAL_CALL OControl::getPeer() throw ( RuntimeException)
353 {
354 return m_xControl.is() ? m_xControl->getPeer() : Reference<XWindowPeer>();
355 }
356
357 //------------------------------------------------------------------------------
setModel(const Reference<XControlModel> & Model)358 sal_Bool SAL_CALL OControl::setModel(const Reference<XControlModel>& Model) throw ( RuntimeException)
359 {
360 if ( !m_xControl.is() )
361 return sal_False;
362
363 sal_Bool bSuccess = m_xControl->setModel( Model );
364 impl_resetStateGuard_nothrow();
365 return bSuccess;
366 }
367
368 //------------------------------------------------------------------------------
getModel()369 Reference<XControlModel> SAL_CALL OControl::getModel() throw ( RuntimeException)
370 {
371 return m_xControl.is() ? m_xControl->getModel() : Reference<XControlModel>();
372 }
373
374 //------------------------------------------------------------------------------
getView()375 Reference<XView> SAL_CALL OControl::getView() throw ( RuntimeException)
376 {
377 return m_xControl.is() ? m_xControl->getView() : Reference<XView>();
378 }
379
380 //------------------------------------------------------------------------------
setDesignMode(sal_Bool bOn)381 void SAL_CALL OControl::setDesignMode(sal_Bool bOn) throw ( RuntimeException)
382 {
383 if (m_xControl.is())
384 m_xControl->setDesignMode(bOn);
385 }
386
387 //------------------------------------------------------------------------------
isDesignMode()388 sal_Bool SAL_CALL OControl::isDesignMode() throw ( RuntimeException)
389 {
390 return m_xControl.is() ? m_xControl->isDesignMode() : sal_True;
391 }
392
393 //------------------------------------------------------------------------------
isTransparent()394 sal_Bool SAL_CALL OControl::isTransparent() throw ( RuntimeException)
395 {
396 return m_xControl.is() ? m_xControl->isTransparent() : sal_True;
397 }
398
399 //==================================================================
400 //= OBoundControl
401 //==================================================================
402 DBG_NAME(frm_OBoundControl);
403 //------------------------------------------------------------------
OBoundControl(const Reference<XMultiServiceFactory> & _rxFactory,const::rtl::OUString & _rAggregateService,const sal_Bool _bSetDelegator)404 OBoundControl::OBoundControl( const Reference< XMultiServiceFactory >& _rxFactory,
405 const ::rtl::OUString& _rAggregateService, const sal_Bool _bSetDelegator )
406 :OControl( _rxFactory, _rAggregateService, _bSetDelegator )
407 ,m_bLocked(sal_False)
408 ,m_aOriginalFont( EmptyFontDescriptor() )
409 ,m_nOriginalTextLineColor( 0 )
410 {
411 DBG_CTOR(frm_OBoundControl, NULL);
412 }
413
414 //------------------------------------------------------------------
~OBoundControl()415 OBoundControl::~OBoundControl()
416 {
417 DBG_DTOR(frm_OBoundControl, NULL);
418 }
419 // -----------------------------------------------------------------------------
_getTypes()420 Sequence< Type> OBoundControl::_getTypes()
421 {
422 return TypeBag( OControl::_getTypes(), OBoundControl_BASE::getTypes() ).getTypes();
423 }
424 //------------------------------------------------------------------
queryAggregation(const Type & _rType)425 Any SAL_CALL OBoundControl::queryAggregation(const Type& _rType) throw(RuntimeException)
426 {
427 Any aReturn;
428
429 // XTypeProvider first - don't ask the OBoundControl_BASE, it would deliver incomplete types
430 if ( _rType.equals( ::getCppuType( static_cast< Reference< XTypeProvider >* >( NULL ) ) ) )
431 aReturn = OControl::queryAggregation( _rType );
432
433 // ask our own interfaces
434 // (do this first (except XTypeProvider ) - we want to "overwrite" XPropertiesChangeListener)
435 if ( !aReturn.hasValue() )
436 aReturn = OBoundControl_BASE::queryInterface( _rType );
437
438 // ask the base class
439 if ( !aReturn.hasValue() )
440 aReturn = OControl::queryAggregation( _rType );
441
442 return aReturn;
443 }
444
445 //------------------------------------------------------------------
getLock()446 sal_Bool SAL_CALL OBoundControl::getLock() throw(RuntimeException)
447 {
448 return m_bLocked;
449 }
450
451 //------------------------------------------------------------------
setLock(sal_Bool _bLock)452 void SAL_CALL OBoundControl::setLock(sal_Bool _bLock) throw(RuntimeException)
453 {
454 if (m_bLocked == _bLock)
455 return;
456
457 osl::MutexGuard aGuard(m_aMutex);
458 _setLock(_bLock);
459 m_bLocked = _bLock;
460 }
461
462 //------------------------------------------------------------------
_setLock(sal_Bool _bLock)463 void OBoundControl::_setLock(sal_Bool _bLock)
464 {
465 // try to set the text component to readonly
466 Reference< XWindowPeer > xPeer = getPeer();
467 Reference< XTextComponent > xText( xPeer, UNO_QUERY );
468
469 if ( xText.is() )
470 xText->setEditable( !_bLock );
471 else
472 {
473 // disable the window
474 Reference< XWindow > xComp( xPeer, UNO_QUERY );
475 if ( xComp.is() )
476 xComp->setEnable( !_bLock );
477 }
478 }
479
480 //--------------------------------------------------------------------
setModel(const Reference<XControlModel> & _rxModel)481 sal_Bool SAL_CALL OBoundControl::setModel( const Reference< XControlModel >& _rxModel ) throw (RuntimeException)
482 {
483 return OControl::setModel( _rxModel );
484 }
485
486 //--------------------------------------------------------------------
disposing(const EventObject & Source)487 void SAL_CALL OBoundControl::disposing(const EventObject& Source) throw (RuntimeException)
488 {
489 // just disambiguate
490 OControl::disposing(Source);
491 }
492
493 //--------------------------------------------------------------------
disposing()494 void OBoundControl::disposing()
495 {
496 OControl::disposing();
497 }
498
499 //==================================================================
500 //= OControlModel
501 //==================================================================
DBG_NAME(OControlModel)502 DBG_NAME(OControlModel)
503 //------------------------------------------------------------------
504 Sequence<sal_Int8> SAL_CALL OControlModel::getImplementationId() throw(RuntimeException)
505 {
506 return OImplementationIds::getImplementationId(getTypes());
507 }
508
509 //------------------------------------------------------------------
getTypes()510 Sequence<Type> SAL_CALL OControlModel::getTypes() throw(RuntimeException)
511 {
512 TypeBag aTypes( _getTypes() );
513
514 Reference< XTypeProvider > xProv;
515 if ( query_aggregation( m_xAggregate, xProv ) )
516 aTypes.addTypes( xProv->getTypes() );
517
518 return aTypes.getTypes();
519 }
520
521 //------------------------------------------------------------------------------
_getTypes()522 Sequence<Type> OControlModel::_getTypes()
523 {
524 return TypeBag( OComponentHelper::getTypes(),
525 OPropertySetAggregationHelper::getTypes(),
526 OControlModel_BASE::getTypes()
527 ).getTypes();
528 }
529
530 //------------------------------------------------------------------
queryAggregation(const Type & _rType)531 Any SAL_CALL OControlModel::queryAggregation(const Type& _rType) throw (RuntimeException)
532 {
533 // base class 1
534 Any aReturn(OComponentHelper::queryAggregation(_rType));
535
536 // base class 2
537 if (!aReturn.hasValue())
538 {
539 aReturn = OControlModel_BASE::queryInterface(_rType);
540
541 // our own interfaces
542 if (!aReturn.hasValue())
543 {
544 aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
545 // our aggregate
546 if (!aReturn.hasValue() && m_xAggregate.is() && !_rType.equals(::getCppuType(static_cast< Reference< XCloneable>* >(NULL))))
547 aReturn = m_xAggregate->queryAggregation(_rType);
548 }
549 }
550 return aReturn;
551 }
552
553 //------------------------------------------------------------------------------
readHelpTextCompatibly(const staruno::Reference<stario::XObjectInputStream> & _rxInStream)554 void OControlModel::readHelpTextCompatibly(const staruno::Reference< stario::XObjectInputStream >& _rxInStream)
555 {
556 ::rtl::OUString sHelpText;
557 ::comphelper::operator>>( _rxInStream, sHelpText);
558 try
559 {
560 if (m_xAggregateSet.is())
561 m_xAggregateSet->setPropertyValue(PROPERTY_HELPTEXT, makeAny(sHelpText));
562 }
563 catch(const Exception&)
564 {
565 OSL_ENSURE(sal_False, "OControlModel::readHelpTextCompatibly: could not forward the property value to the aggregate!");
566 }
567 }
568
569 //------------------------------------------------------------------------------
writeHelpTextCompatibly(const staruno::Reference<stario::XObjectOutputStream> & _rxOutStream)570 void OControlModel::writeHelpTextCompatibly(const staruno::Reference< stario::XObjectOutputStream >& _rxOutStream)
571 {
572 ::rtl::OUString sHelpText;
573 try
574 {
575 if (m_xAggregateSet.is())
576 m_xAggregateSet->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText;
577 }
578 catch(const Exception&)
579 {
580 OSL_ENSURE(sal_False, "OControlModel::writeHelpTextCompatibly: could not retrieve the property value from the aggregate!");
581 }
582 ::comphelper::operator<<( _rxOutStream, sHelpText);
583 }
584
585 //------------------------------------------------------------------
OControlModel(const Reference<com::sun::star::lang::XMultiServiceFactory> & _rxFactory,const::rtl::OUString & _rUnoControlModelTypeName,const::rtl::OUString & rDefault,const sal_Bool _bSetDelegator)586 OControlModel::OControlModel(
587 const Reference<com::sun::star::lang::XMultiServiceFactory>& _rxFactory,
588 const ::rtl::OUString& _rUnoControlModelTypeName,
589 const ::rtl::OUString& rDefault, const sal_Bool _bSetDelegator)
590 :OComponentHelper(m_aMutex)
591 ,OPropertySetAggregationHelper(OComponentHelper::rBHelper)
592 ,m_aContext( _rxFactory )
593 ,m_lockCount( 0 )
594 ,m_aPropertyBagHelper( *this )
595 ,m_nTabIndex(FRM_DEFAULT_TABINDEX)
596 ,m_nClassId(FormComponentType::CONTROL)
597 ,m_bNativeLook( sal_False )
598 ,m_nControlTypeinMSO(0) // 0 : default value is create from AOO
599 ,m_nObjIDinMSO(INVALID_OBJ_ID_IN_MSO)
600 // form controls are usually embedded into documents, not dialogs, and in documents
601 // the native look is ugly ....
602 // #i37342# / 2004-11-19 / frank.schoenheit@sun.com
603 {
604 DBG_CTOR(OControlModel, NULL);
605 if (_rUnoControlModelTypeName.getLength()) // the is a model we have to aggregate
606 {
607 increment(m_refCount);
608
609 {
610 m_xAggregate = Reference<XAggregation>(_rxFactory->createInstance(_rUnoControlModelTypeName), UNO_QUERY);
611 setAggregation(m_xAggregate);
612
613 if ( m_xAggregateSet.is() )
614 {
615 try
616 {
617 if ( rDefault.getLength() )
618 m_xAggregateSet->setPropertyValue( PROPERTY_DEFAULTCONTROL, makeAny( rDefault ) );
619 }
620 catch( const Exception& )
621 {
622 OSL_ENSURE( sal_False, "OControlModel::OControlModel: caught an exception!" );
623 }
624 }
625 }
626
627 if (_bSetDelegator)
628 doSetDelegator();
629
630 // Refcount wieder bei NULL
631 decrement(m_refCount);
632 }
633 }
634
635 //------------------------------------------------------------------
OControlModel(const OControlModel * _pOriginal,const Reference<XMultiServiceFactory> & _rxFactory,const sal_Bool _bCloneAggregate,const sal_Bool _bSetDelegator)636 OControlModel::OControlModel( const OControlModel* _pOriginal, const Reference< XMultiServiceFactory>& _rxFactory, const sal_Bool _bCloneAggregate, const sal_Bool _bSetDelegator )
637 :OComponentHelper( m_aMutex )
638 ,OPropertySetAggregationHelper( OComponentHelper::rBHelper )
639 ,m_aContext( _rxFactory )
640 ,m_lockCount( 0 )
641 ,m_aPropertyBagHelper( *this )
642 ,m_nTabIndex( FRM_DEFAULT_TABINDEX )
643 ,m_nClassId( FormComponentType::CONTROL )
644 {
645 DBG_CTOR( OControlModel, NULL );
646 DBG_ASSERT( _pOriginal, "OControlModel::OControlModel: invalid original!" );
647
648 // copy members
649 m_aName = _pOriginal->m_aName;
650 m_aTag = _pOriginal->m_aTag;
651 m_nTabIndex = _pOriginal->m_nTabIndex;
652 m_nClassId = _pOriginal->m_nClassId;
653 m_bNativeLook = _pOriginal->m_bNativeLook;
654 m_nControlTypeinMSO = _pOriginal->m_nControlTypeinMSO;
655 m_nObjIDinMSO = _pOriginal->m_nObjIDinMSO;
656
657 if ( _bCloneAggregate )
658 {
659 // temporarily increment refcount because of temporary references to ourself in the following
660 increment( m_refCount );
661
662 {
663 // transfer the (only, at the very moment!) ref count
664 m_xAggregate = createAggregateClone( _pOriginal );
665
666 // set aggregation (retrieve other direct interfaces of the aggregate)
667 setAggregation( m_xAggregate );
668 }
669
670 // set the delegator, if allowed by our derived class
671 if ( _bSetDelegator )
672 doSetDelegator();
673
674 // decrement ref count
675 decrement( m_refCount );
676 }
677 }
678
679 //------------------------------------------------------------------
~OControlModel()680 OControlModel::~OControlModel()
681 {
682 // release the aggregate
683 doResetDelegator( );
684
685 DBG_DTOR(OControlModel, NULL);
686 }
687
688 //------------------------------------------------------------------
clonedFrom(const OControlModel *)689 void OControlModel::clonedFrom( const OControlModel* /*_pOriginal*/ )
690 {
691 // nothing to do in this base class
692 }
693
694 //------------------------------------------------------------------------------
doResetDelegator()695 void OControlModel::doResetDelegator()
696 {
697 if (m_xAggregate.is())
698 m_xAggregate->setDelegator(NULL);
699 }
700
701 //------------------------------------------------------------------------------
doSetDelegator()702 void OControlModel::doSetDelegator()
703 {
704 increment(m_refCount);
705 if (m_xAggregate.is())
706 {
707 m_xAggregate->setDelegator(static_cast<XWeak*>(this));
708 }
709 decrement(m_refCount);
710 }
711
712 // XChild
713 //------------------------------------------------------------------------------
getParent()714 Reference< XInterface > SAL_CALL OControlModel::getParent() throw(RuntimeException)
715 {
716 return m_xParent;
717 }
718
719 //------------------------------------------------------------------------------
setParent(const Reference<XInterface> & _rxParent)720 void SAL_CALL OControlModel::setParent(const Reference< XInterface >& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException)
721 {
722 osl::MutexGuard aGuard(m_aMutex);
723
724 Reference<XComponent> xComp(m_xParent, UNO_QUERY);
725 if (xComp.is())
726 xComp->removeEventListener(static_cast<XPropertiesChangeListener*>(this));
727
728 m_xParent = _rxParent;
729 xComp = xComp.query( m_xParent );
730
731 if ( xComp.is() )
732 xComp->addEventListener(static_cast<XPropertiesChangeListener*>(this));
733 }
734
735 // XNamed
736 //------------------------------------------------------------------------------
getName()737 ::rtl::OUString SAL_CALL OControlModel::getName() throw(RuntimeException)
738 {
739 ::rtl::OUString aReturn;
740 OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME) >>= aReturn;
741 return aReturn;
742 }
743
744 //------------------------------------------------------------------------------
setName(const::rtl::OUString & _rName)745 void SAL_CALL OControlModel::setName(const ::rtl::OUString& _rName) throw(RuntimeException)
746 {
747 setFastPropertyValue(PROPERTY_ID_NAME, makeAny(_rName));
748 }
749
750 // XServiceInfo
751 //------------------------------------------------------------------------------
supportsService(const rtl::OUString & _rServiceName)752 sal_Bool SAL_CALL OControlModel::supportsService(const rtl::OUString& _rServiceName) throw ( RuntimeException)
753 {
754 Sequence<rtl::OUString> aSupported = getSupportedServiceNames();
755 const rtl::OUString* pSupported = aSupported.getConstArray();
756 for (sal_Int32 i=0; i<aSupported.getLength(); ++i, ++pSupported)
757 if (pSupported->equals(_rServiceName))
758 return sal_True;
759 return sal_False;
760 }
761
762 //------------------------------------------------------------------------------
getAggregateServiceNames()763 Sequence< ::rtl::OUString > OControlModel::getAggregateServiceNames()
764 {
765 Sequence< ::rtl::OUString > aAggServices;
766 Reference< XServiceInfo > xInfo;
767 if ( query_aggregation( m_xAggregate, xInfo ) )
768 aAggServices = xInfo->getSupportedServiceNames();
769 return aAggServices;
770 }
771
772 //------------------------------------------------------------------------------
getSupportedServiceNames()773 Sequence<rtl::OUString> SAL_CALL OControlModel::getSupportedServiceNames() throw(RuntimeException)
774 {
775 return ::comphelper::concatSequences(
776 getAggregateServiceNames(),
777 getSupportedServiceNames_Static()
778 );
779 }
780
781 //------------------------------------------------------------------------------
getSupportedServiceNames_Static()782 Sequence< ::rtl::OUString > SAL_CALL OControlModel::getSupportedServiceNames_Static() throw( RuntimeException )
783 {
784 Sequence< ::rtl::OUString > aServiceNames( 2 );
785 aServiceNames[ 0 ] = FRM_SUN_FORMCOMPONENT;
786 aServiceNames[ 1 ] = ::rtl::OUString::createFromAscii( "com.sun.star.form.FormControlModel" );
787 return aServiceNames;
788 }
789
790 // XEventListener
791 //------------------------------------------------------------------------------
disposing(const com::sun::star::lang::EventObject & _rSource)792 void SAL_CALL OControlModel::disposing(const com::sun::star::lang::EventObject& _rSource) throw (RuntimeException)
793 {
794 // release the parent
795 if (_rSource.Source == m_xParent)
796 {
797 osl::MutexGuard aGuard(m_aMutex);
798 m_xParent = NULL;
799 }
800 else
801 {
802 Reference<com::sun::star::lang::XEventListener> xEvtLst;
803 if (query_aggregation(m_xAggregate, xEvtLst))
804 {
805 osl::MutexGuard aGuard(m_aMutex);
806 xEvtLst->disposing(_rSource);
807 }
808 }
809 }
810
811 // OComponentHelper
812 //-----------------------------------------------------------------------------
disposing()813 void OControlModel::disposing()
814 {
815 OPropertySetAggregationHelper::disposing();
816
817 Reference<com::sun::star::lang::XComponent> xComp;
818 if (query_aggregation(m_xAggregate, xComp))
819 xComp->dispose();
820
821 setParent(Reference<XFormComponent>());
822
823 m_aPropertyBagHelper.dispose();
824 }
825
826 //------------------------------------------------------------------------------
writeAggregate(const Reference<XObjectOutputStream> & _rxOutStream) const827 void OControlModel::writeAggregate( const Reference< XObjectOutputStream >& _rxOutStream ) const
828 {
829 Reference< XPersistObject > xPersist;
830 if ( query_aggregation( m_xAggregate, xPersist ) )
831 xPersist->write( _rxOutStream );
832 }
833
834 //------------------------------------------------------------------------------
readAggregate(const Reference<XObjectInputStream> & _rxInStream)835 void OControlModel::readAggregate( const Reference< XObjectInputStream >& _rxInStream )
836 {
837 Reference< XPersistObject > xPersist;
838 if ( query_aggregation( m_xAggregate, xPersist ) )
839 xPersist->read( _rxInStream );
840 }
841
842 //------------------------------------------------------------------------------
write(const Reference<stario::XObjectOutputStream> & _rxOutStream)843 void SAL_CALL OControlModel::write(const Reference<stario::XObjectOutputStream>& _rxOutStream)
844 throw(stario::IOException, RuntimeException)
845 {
846 osl::MutexGuard aGuard(m_aMutex);
847
848 // 1. Schreiben des UnoControls
849 Reference<stario::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
850 if ( !xMark.is() )
851 {
852 throw IOException(
853 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
854 static_cast< ::cppu::OWeakObject* >( this )
855 );
856 }
857
858 sal_Int32 nMark = xMark->createMark();
859 sal_Int32 nLen = 0;
860
861 _rxOutStream->writeLong(nLen);
862
863 writeAggregate( _rxOutStream );
864
865 // feststellen der Laenge
866 nLen = xMark->offsetToMark(nMark) - 4;
867 xMark->jumpToMark(nMark);
868 _rxOutStream->writeLong(nLen);
869 xMark->jumpToFurthest();
870 xMark->deleteMark(nMark);
871
872 // 2. Schreiben einer VersionsNummer
873 _rxOutStream->writeShort(0x0003);
874
875 // 3. Schreiben der allgemeinen Properties
876 ::comphelper::operator<<( _rxOutStream, m_aName);
877 _rxOutStream->writeShort(m_nTabIndex);
878 ::comphelper::operator<<( _rxOutStream, m_aTag); // 3. version
879
880 // !!! IMPORTANT NOTE !!!
881 // don't write any new members here : this wouldn't be compatible with older versions, as OControlModel
882 // is a base class which is called in derived classes "read" method. So if you increment the version
883 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
884 // in anything from data loss to crash.
885 // !!! EOIN !!!
886 }
887
888 //------------------------------------------------------------------------------
read(const Reference<stario::XObjectInputStream> & InStream)889 void OControlModel::read(const Reference<stario::XObjectInputStream>& InStream) throw (::com::sun::star::io::IOException, RuntimeException)
890 {
891 osl::MutexGuard aGuard(m_aMutex);
892
893 Reference<stario::XMarkableStream> xMark(InStream, UNO_QUERY);
894 if ( !xMark.is() )
895 {
896 throw IOException(
897 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
898 static_cast< ::cppu::OWeakObject* >( this )
899 );
900 }
901
902 // 1. Lesen des UnoControls
903 sal_Int32 nLen = InStream->readLong();
904 if (nLen)
905 {
906 sal_Int32 nMark = xMark->createMark();
907
908 try
909 {
910 readAggregate( InStream );
911 }
912 catch( const Exception& )
913 {
914 DBG_UNHANDLED_EXCEPTION();
915 }
916
917 xMark->jumpToMark(nMark);
918 InStream->skipBytes(nLen);
919 xMark->deleteMark(nMark);
920 }
921
922 // 2. Lesen des Versionsnummer
923 sal_uInt16 nVersion = InStream->readShort();
924
925 // 3. Lesen der allgemeinen Properties
926 ::comphelper::operator>>( InStream, m_aName);
927 m_nTabIndex = InStream->readShort();
928
929 if (nVersion > 0x0002)
930 ::comphelper::operator>>( InStream, m_aTag);
931
932 // we had a version where we wrote the help text
933 if (nVersion == 0x0004)
934 readHelpTextCompatibly(InStream);
935
936 DBG_ASSERT(nVersion < 5, "OControlModel::read : suspicious version number !");
937 // 4 was the version where we wrote the help text
938 // later versions shouldn't exist (see write for a detailed comment)
939 }
940
941 //------------------------------------------------------------------------------
getPropertyStateByHandle(sal_Int32 _nHandle)942 PropertyState OControlModel::getPropertyStateByHandle( sal_Int32 _nHandle )
943 {
944 // simply compare the current and the default value
945 Any aCurrentValue = getPropertyDefaultByHandle( _nHandle );
946 Any aDefaultValue; getFastPropertyValue( aDefaultValue, _nHandle );
947
948 sal_Bool bEqual = uno_type_equalData(
949 const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(),
950 const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(),
951 reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
952 reinterpret_cast< uno_ReleaseFunc >(cpp_release)
953 );
954 return bEqual ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
955 }
956
957 //------------------------------------------------------------------------------
setPropertyToDefaultByHandle(sal_Int32 _nHandle)958 void OControlModel::setPropertyToDefaultByHandle( sal_Int32 _nHandle)
959 {
960 Any aDefault = getPropertyDefaultByHandle( _nHandle );
961
962 Any aConvertedValue, aOldValue;
963 if ( convertFastPropertyValue( aConvertedValue, aOldValue, _nHandle, aDefault ) )
964 {
965 setFastPropertyValue_NoBroadcast( _nHandle, aConvertedValue );
966 // TODO: fire the property change
967 }
968 }
969
970 //------------------------------------------------------------------------------
getPropertyDefaultByHandle(sal_Int32 _nHandle) const971 Any OControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
972 {
973 Any aReturn;
974 switch ( _nHandle )
975 {
976 case PROPERTY_ID_NAME:
977 case PROPERTY_ID_TAG:
978 aReturn <<= ::rtl::OUString();
979 break;
980
981 case PROPERTY_ID_CLASSID:
982 aReturn <<= (sal_Int16)FormComponentType::CONTROL;
983 break;
984
985 case PROPERTY_ID_TABINDEX:
986 aReturn <<= (sal_Int16)FRM_DEFAULT_TABINDEX;
987 break;
988
989 case PROPERTY_ID_NATIVE_LOOK:
990 aReturn <<= (sal_Bool)sal_True;
991 break;
992 //added for exporting OCX control
993 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
994 aReturn <<= (sal_Int16)0;
995 break;
996 case PROPERTY_ID_OBJ_ID_IN_MSO:
997 aReturn <<= (sal_uInt16)INVALID_OBJ_ID_IN_MSO;
998 break;
999 default:
1000 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1001 m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( _nHandle, aReturn );
1002 else
1003 OSL_ENSURE( false, "OControlModel::convertFastPropertyValue: unknown handle!" );
1004 }
1005 return aReturn;
1006 }
1007
1008 //------------------------------------------------------------------------------
getFastPropertyValue(Any & _rValue,sal_Int32 _nHandle) const1009 void OControlModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
1010 {
1011 switch ( _nHandle )
1012 {
1013 case PROPERTY_ID_NAME:
1014 _rValue <<= m_aName;
1015 break;
1016 case PROPERTY_ID_TAG:
1017 _rValue <<= m_aTag;
1018 break;
1019 case PROPERTY_ID_CLASSID:
1020 _rValue <<= m_nClassId;
1021 break;
1022 case PROPERTY_ID_TABINDEX:
1023 _rValue <<= m_nTabIndex;
1024 break;
1025 case PROPERTY_ID_NATIVE_LOOK:
1026 _rValue <<= (sal_Bool)m_bNativeLook;
1027 break;
1028 //added for exporting OCX control
1029 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
1030 _rValue <<= (sal_Int16)m_nControlTypeinMSO;
1031 break;
1032 case PROPERTY_ID_OBJ_ID_IN_MSO:
1033 _rValue <<= (sal_uInt16)m_nObjIDinMSO;
1034 break;
1035 default:
1036 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1037 m_aPropertyBagHelper.getDynamicFastPropertyValue( _nHandle, _rValue );
1038 else
1039 OPropertySetAggregationHelper::getFastPropertyValue( _rValue, _nHandle );
1040 break;
1041 }
1042 }
1043
1044 //------------------------------------------------------------------------------
convertFastPropertyValue(Any & _rConvertedValue,Any & _rOldValue,sal_Int32 _nHandle,const Any & _rValue)1045 sal_Bool OControlModel::convertFastPropertyValue(
1046 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
1047 throw (com::sun::star::lang::IllegalArgumentException)
1048 {
1049 sal_Bool bModified(sal_False);
1050 switch (_nHandle)
1051 {
1052 case PROPERTY_ID_NAME:
1053 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aName);
1054 break;
1055 case PROPERTY_ID_TAG:
1056 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aTag);
1057 break;
1058 case PROPERTY_ID_TABINDEX:
1059 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nTabIndex);
1060 break;
1061 case PROPERTY_ID_NATIVE_LOOK:
1062 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bNativeLook);
1063 break;
1064 //added for exporting OCX control
1065 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
1066 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nControlTypeinMSO);
1067 break;
1068 case PROPERTY_ID_OBJ_ID_IN_MSO:
1069 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nObjIDinMSO);
1070 break;
1071 default:
1072 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1073 bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( _nHandle, _rValue, _rConvertedValue, _rOldValue );
1074 else
1075 OSL_ENSURE( false, "OControlModel::convertFastPropertyValue: unknown handle!" );
1076 break;
1077 }
1078 return bModified;
1079 }
1080
1081 //------------------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle,const Any & _rValue)1082 void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
1083 throw (Exception)
1084 {
1085 switch (_nHandle)
1086 {
1087 case PROPERTY_ID_NAME:
1088 DBG_ASSERT(_rValue.getValueType() == getCppuType((const ::rtl::OUString*)NULL),
1089 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1090 _rValue >>= m_aName;
1091 break;
1092 case PROPERTY_ID_TAG:
1093 DBG_ASSERT(_rValue.getValueType() == getCppuType((const ::rtl::OUString*)NULL),
1094 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1095 _rValue >>= m_aTag;
1096 break;
1097 case PROPERTY_ID_TABINDEX:
1098 DBG_ASSERT(_rValue.getValueType() == getCppuType((const sal_Int16*)NULL),
1099 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1100 _rValue >>= m_nTabIndex;
1101 break;
1102 case PROPERTY_ID_NATIVE_LOOK:
1103 OSL_VERIFY( _rValue >>= m_bNativeLook );
1104 break;
1105 //added for exporting OCX control
1106 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
1107 OSL_VERIFY( _rValue >>= m_nControlTypeinMSO );
1108 break;
1109 case PROPERTY_ID_OBJ_ID_IN_MSO:
1110 OSL_VERIFY( _rValue >>= m_nObjIDinMSO );
1111 break;
1112 default:
1113 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1114 m_aPropertyBagHelper.setDynamicFastPropertyValue( _nHandle, _rValue );
1115 else
1116 OSL_ENSURE( false, "OControlModel::setFastPropertyValue_NoBroadcast: unknown handle!" );
1117 break;
1118 }
1119 }
1120
1121 //------------------------------------------------------------------------------
describeFixedProperties(Sequence<Property> & _rProps) const1122 void OControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
1123 {
1124 //BEGIN_DESCRIBE_BASE_PROPERTIES( 4 )
1125 BEGIN_DESCRIBE_BASE_PROPERTIES( 6 )
1126 DECL_PROP2 (CLASSID, sal_Int16, READONLY, TRANSIENT);
1127 DECL_PROP1 (NAME, ::rtl::OUString, BOUND);
1128 DECL_BOOL_PROP2 (NATIVE_LOOK, BOUND, TRANSIENT);
1129 DECL_PROP1 (TAG, ::rtl::OUString, BOUND);
1130 DECL_PROP1 (CONTROL_TYPE_IN_MSO,sal_Int16, BOUND);
1131 DECL_PROP1 (OBJ_ID_IN_MSO,sal_uInt16, BOUND);
1132 END_DESCRIBE_PROPERTIES()
1133 }
1134
1135 //------------------------------------------------------------------------------
describeAggregateProperties(Sequence<Property> & _rAggregateProps) const1136 void OControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ _rAggregateProps ) const
1137 {
1138 if ( m_xAggregateSet.is() )
1139 {
1140 Reference< XPropertySetInfo > xPSI( m_xAggregateSet->getPropertySetInfo() );
1141 if ( xPSI.is() )
1142 _rAggregateProps = xPSI->getProperties();
1143 }
1144 }
1145
1146 //------------------------------------------------------------------------------
getMutex()1147 ::osl::Mutex& OControlModel::getMutex()
1148 {
1149 return m_aMutex;
1150 }
1151
1152 //------------------------------------------------------------------------------
describeFixedAndAggregateProperties(Sequence<Property> & _out_rFixedProperties,Sequence<Property> & _out_rAggregateProperties) const1153 void OControlModel::describeFixedAndAggregateProperties( Sequence< Property >& _out_rFixedProperties, Sequence< Property >& _out_rAggregateProperties ) const
1154 {
1155 describeFixedProperties( _out_rFixedProperties );
1156 describeAggregateProperties( _out_rAggregateProperties );
1157 }
1158
1159 //------------------------------------------------------------------------------
getPropertiesInterface()1160 Reference< XMultiPropertySet > OControlModel::getPropertiesInterface()
1161 {
1162 return Reference< XMultiPropertySet >( *this, UNO_QUERY );
1163 }
1164
1165 //------------------------------------------------------------------------------
getPropertySetInfo()1166 Reference< XPropertySetInfo> SAL_CALL OControlModel::getPropertySetInfo() throw( RuntimeException)
1167 {
1168 return createPropertySetInfo( getInfoHelper() );
1169 }
1170
1171 //------------------------------------------------------------------------------
getInfoHelper()1172 ::cppu::IPropertyArrayHelper& OControlModel::getInfoHelper()
1173 {
1174 return m_aPropertyBagHelper.getInfoHelper();
1175 }
1176
1177 //--------------------------------------------------------------------
addProperty(const::rtl::OUString & _rName,::sal_Int16 _nAttributes,const Any & _rInitialValue)1178 void SAL_CALL OControlModel::addProperty( const ::rtl::OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException)
1179 {
1180 m_aPropertyBagHelper.addProperty( _rName, _nAttributes, _rInitialValue );
1181 }
1182
1183 //--------------------------------------------------------------------
removeProperty(const::rtl::OUString & _rName)1184 void SAL_CALL OControlModel::removeProperty( const ::rtl::OUString& _rName ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException)
1185 {
1186 m_aPropertyBagHelper.removeProperty( _rName );
1187 }
1188
1189 //--------------------------------------------------------------------
getPropertyValues()1190 Sequence< PropertyValue > SAL_CALL OControlModel::getPropertyValues() throw (RuntimeException)
1191 {
1192 return m_aPropertyBagHelper.getPropertyValues();
1193 }
1194
1195 //--------------------------------------------------------------------
setPropertyValues(const Sequence<PropertyValue> & _rProps)1196 void SAL_CALL OControlModel::setPropertyValues( const Sequence< PropertyValue >& _rProps ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
1197 {
1198 m_aPropertyBagHelper.setPropertyValues( _rProps );
1199 }
1200
1201 //--------------------------------------------------------------------
lockInstance(LockAccess)1202 void OControlModel::lockInstance( LockAccess )
1203 {
1204 m_aMutex.acquire();
1205 osl_incrementInterlockedCount( &m_lockCount );
1206 }
1207
1208 //--------------------------------------------------------------------
unlockInstance(LockAccess)1209 oslInterlockedCount OControlModel::unlockInstance( LockAccess )
1210 {
1211 OSL_ENSURE( m_lockCount > 0, "OControlModel::unlockInstance: not locked!" );
1212 oslInterlockedCount lockCount = osl_decrementInterlockedCount( &m_lockCount );
1213 m_aMutex.release();
1214 return lockCount;
1215 }
1216
1217 //--------------------------------------------------------------------
firePropertyChanges(const Sequence<sal_Int32> & _rHandles,const Sequence<Any> & _rOldValues,const Sequence<Any> & _rNewValues,LockAccess)1218 void OControlModel::firePropertyChanges( const Sequence< sal_Int32 >& _rHandles, const Sequence< Any >& _rOldValues,
1219 const Sequence< Any >& _rNewValues, LockAccess )
1220 {
1221 OPropertySetHelper::fire(
1222 const_cast< Sequence< sal_Int32 >& >( _rHandles ).getArray(),
1223 _rNewValues.getConstArray(),
1224 _rOldValues.getConstArray(),
1225 _rHandles.getLength(),
1226 sal_False
1227 );
1228 }
1229
1230 //==================================================================
1231 //= OBoundControlModel
1232 //==================================================================
1233 DBG_NAME(frm_OBoundControlModel);
1234 //------------------------------------------------------------------
queryAggregation(const Type & _rType)1235 Any SAL_CALL OBoundControlModel::queryAggregation( const Type& _rType ) throw (RuntimeException)
1236 {
1237 Any aReturn( OControlModel::queryAggregation(_rType) );
1238 if (!aReturn.hasValue())
1239 {
1240 aReturn = OBoundControlModel_BASE1::queryInterface(_rType);
1241
1242 if ( !aReturn.hasValue() && m_bCommitable )
1243 aReturn = OBoundControlModel_COMMITTING::queryInterface( _rType );
1244
1245 if ( !aReturn.hasValue() && m_bSupportsExternalBinding )
1246 aReturn = OBoundControlModel_BINDING::queryInterface( _rType );
1247
1248 if ( !aReturn.hasValue() && m_bSupportsValidation )
1249 aReturn = OBoundControlModel_VALIDATION::queryInterface( _rType );
1250 }
1251
1252 return aReturn;
1253 }
1254
1255 //------------------------------------------------------------------
OBoundControlModel(const Reference<XMultiServiceFactory> & _rxFactory,const::rtl::OUString & _rUnoControlModelTypeName,const::rtl::OUString & _rDefault,const sal_Bool _bCommitable,const sal_Bool _bSupportExternalBinding,const sal_Bool _bSupportsValidation)1256 OBoundControlModel::OBoundControlModel(
1257 const Reference< XMultiServiceFactory>& _rxFactory,
1258 const ::rtl::OUString& _rUnoControlModelTypeName, const ::rtl::OUString& _rDefault,
1259 const sal_Bool _bCommitable, const sal_Bool _bSupportExternalBinding, const sal_Bool _bSupportsValidation )
1260 :OControlModel( _rxFactory, _rUnoControlModelTypeName, _rDefault, sal_False )
1261 ,OPropertyChangeListener( m_aMutex )
1262 ,m_xField()
1263 ,m_xAmbientForm()
1264 ,m_nValuePropertyAggregateHandle( -1 )
1265 ,m_nFieldType( DataType::OTHER )
1266 ,m_bValuePropertyMayBeVoid( false )
1267 ,m_aResetHelper( *this, m_aMutex )
1268 ,m_aUpdateListeners(m_aMutex)
1269 ,m_aFormComponentListeners( m_aMutex )
1270 ,m_bInputRequired( sal_True )
1271 ,m_pAggPropMultiplexer( NULL )
1272 ,m_bFormListening( false )
1273 ,m_bLoaded(sal_False)
1274 ,m_bRequired(sal_False)
1275 ,m_bCommitable(_bCommitable)
1276 ,m_bSupportsExternalBinding( _bSupportExternalBinding )
1277 ,m_bSupportsValidation( _bSupportsValidation )
1278 ,m_bForwardValueChanges(sal_True)
1279 ,m_bTransferingValue( sal_False )
1280 ,m_bIsCurrentValueValid( sal_True )
1281 ,m_bBindingControlsRO( sal_False )
1282 ,m_bBindingControlsEnable( sal_False )
1283 ,m_eControlValueChangeInstigator( eOther )
1284 ,m_aLabelServiceName(FRM_SUN_COMPONENT_FIXEDTEXT)
1285 {
1286 DBG_CTOR(frm_OBoundControlModel, NULL);
1287
1288 // start property listening at the aggregate
1289 implInitAggMultiplexer( );
1290 }
1291
1292 //------------------------------------------------------------------
OBoundControlModel(const OBoundControlModel * _pOriginal,const Reference<XMultiServiceFactory> & _rxFactory)1293 OBoundControlModel::OBoundControlModel(
1294 const OBoundControlModel* _pOriginal, const Reference< XMultiServiceFactory>& _rxFactory )
1295 :OControlModel( _pOriginal, _rxFactory, sal_True, sal_False )
1296 ,OPropertyChangeListener( m_aMutex )
1297 ,m_xField()
1298 ,m_xAmbientForm()
1299 ,m_nValuePropertyAggregateHandle( _pOriginal->m_nValuePropertyAggregateHandle )
1300 ,m_nFieldType( DataType::OTHER )
1301 ,m_bValuePropertyMayBeVoid( _pOriginal->m_bValuePropertyMayBeVoid )
1302 ,m_aResetHelper( *this, m_aMutex )
1303 ,m_aUpdateListeners( m_aMutex )
1304 ,m_aFormComponentListeners( m_aMutex )
1305 ,m_xValidator( _pOriginal->m_xValidator )
1306 ,m_bInputRequired( sal_True )
1307 ,m_pAggPropMultiplexer( NULL )
1308 ,m_bFormListening( false )
1309 ,m_bLoaded( sal_False )
1310 ,m_bRequired( sal_False )
1311 ,m_bCommitable( _pOriginal->m_bCommitable )
1312 ,m_bSupportsExternalBinding( _pOriginal->m_bSupportsExternalBinding )
1313 ,m_bSupportsValidation( _pOriginal->m_bSupportsValidation )
1314 ,m_bForwardValueChanges( sal_True )
1315 ,m_bTransferingValue( sal_False )
1316 ,m_bIsCurrentValueValid( _pOriginal->m_bIsCurrentValueValid )
1317 ,m_bBindingControlsRO( sal_False )
1318 ,m_bBindingControlsEnable( sal_False )
1319 ,m_eControlValueChangeInstigator( eOther )
1320 {
1321 DBG_CTOR(frm_OBoundControlModel, NULL);
1322
1323 // start property listening at the aggregate
1324 implInitAggMultiplexer( );
1325
1326 m_aLabelServiceName = _pOriginal->m_aLabelServiceName;
1327 m_sValuePropertyName = _pOriginal->m_sValuePropertyName;
1328 m_nValuePropertyAggregateHandle = _pOriginal->m_nValuePropertyAggregateHandle;
1329 m_bValuePropertyMayBeVoid = _pOriginal->m_bValuePropertyMayBeVoid;
1330 m_aValuePropertyType = _pOriginal->m_aValuePropertyType;
1331 m_aControlSource = _pOriginal->m_aControlSource;
1332 m_bInputRequired = _pOriginal->m_bInputRequired;
1333 // m_xLabelControl, though being a property, is not to be cloned, not even the reference will be transferred.
1334 // (the former should be clear - a clone of the object we're only referencing does not make sense)
1335 // (the second would violate the restriction for label controls that they're part of the
1336 // same form component hierarchy - we ourself are no part, yet, so we can't have a label control)
1337
1338 // start listening for changes at the value property
1339 implInitValuePropertyListening( );
1340 }
1341
1342 //------------------------------------------------------------------
~OBoundControlModel()1343 OBoundControlModel::~OBoundControlModel()
1344 {
1345 if ( !OComponentHelper::rBHelper.bDisposed )
1346 {
1347 acquire();
1348 dispose();
1349 }
1350
1351 doResetDelegator( );
1352
1353 OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::~OBoundControlModel: what about my property multiplexer?" );
1354 if ( m_pAggPropMultiplexer )
1355 {
1356 m_pAggPropMultiplexer->dispose();
1357 m_pAggPropMultiplexer->release();
1358 m_pAggPropMultiplexer = NULL;
1359 }
1360
1361 DBG_DTOR(frm_OBoundControlModel, NULL);
1362 }
1363
1364 //------------------------------------------------------------------
clonedFrom(const OControlModel * _pOriginal)1365 void OBoundControlModel::clonedFrom( const OControlModel* _pOriginal )
1366 {
1367 const OBoundControlModel* pBoundOriginal = static_cast< const OBoundControlModel* >( _pOriginal );
1368 // the value binding can be handled as if somebody called setValueBinding here
1369 // By definition, bindings can be share between bindables
1370 if ( pBoundOriginal && pBoundOriginal->m_xExternalBinding.is() )
1371 {
1372 try
1373 {
1374 setValueBinding( pBoundOriginal->m_xExternalBinding );
1375 }
1376 catch( const Exception& )
1377 {
1378 DBG_UNHANDLED_EXCEPTION();
1379 }
1380 }
1381 }
1382
1383 //-----------------------------------------------------------------------------
implInitAggMultiplexer()1384 void OBoundControlModel::implInitAggMultiplexer( )
1385 {
1386 increment( m_refCount );
1387 if ( m_xAggregateSet.is() )
1388 {
1389 m_pAggPropMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet, sal_False );
1390 m_pAggPropMultiplexer->acquire();
1391 }
1392 decrement( m_refCount );
1393
1394 doSetDelegator();
1395 }
1396
1397 //-----------------------------------------------------------------------------
implInitValuePropertyListening() const1398 void OBoundControlModel::implInitValuePropertyListening( ) const
1399 {
1400 // start listening for changes at the value property
1401 // There are three pre-requisites for this to be done:
1402 // 1. We support external value bindings. In this case, the changes in the control value need to
1403 // be propagated to the external binding immediately when they happen
1404 // 2. We support external validation. In this case, we need to listen for changes in the value
1405 // property, since we need to revalidate then.
1406 // 3. We are not committable. In this case, changes in the control value need to be propagated
1407 // to the database column immediately when they happen.
1408 if ( m_bSupportsExternalBinding || m_bSupportsValidation || !m_bCommitable )
1409 {
1410 OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::implInitValuePropertyListening: no multiplexer!" );
1411 if ( m_pAggPropMultiplexer && m_sValuePropertyName.getLength() )
1412 m_pAggPropMultiplexer->addProperty( m_sValuePropertyName );
1413 }
1414 }
1415
1416 //-----------------------------------------------------------------------------
initOwnValueProperty(const::rtl::OUString & i_rValuePropertyName)1417 void OBoundControlModel::initOwnValueProperty( const ::rtl::OUString& i_rValuePropertyName )
1418 {
1419 OSL_PRECOND( !m_sValuePropertyName.getLength() && -1 == m_nValuePropertyAggregateHandle,
1420 "OBoundControlModel::initOwnValueProperty: value property is already initialized!" );
1421 OSL_ENSURE( i_rValuePropertyName.getLength(), "OBoundControlModel::initOwnValueProperty: invalid property name!" );
1422 m_sValuePropertyName = i_rValuePropertyName;
1423 }
1424
1425 //-----------------------------------------------------------------------------
initValueProperty(const::rtl::OUString & _rValuePropertyName,sal_Int32 _nValuePropertyExternalHandle)1426 void OBoundControlModel::initValueProperty( const ::rtl::OUString& _rValuePropertyName, sal_Int32 _nValuePropertyExternalHandle )
1427 {
1428 OSL_PRECOND( !m_sValuePropertyName.getLength() && -1 == m_nValuePropertyAggregateHandle,
1429 "OBoundControlModel::initValueProperty: value property is already initialized!" );
1430 OSL_ENSURE( _rValuePropertyName.getLength(), "OBoundControlModel::initValueProperty: invalid property name!" );
1431 OSL_ENSURE( _nValuePropertyExternalHandle != -1, "OBoundControlModel::initValueProperty: invalid property handle!" );
1432
1433 m_sValuePropertyName = _rValuePropertyName;
1434 m_nValuePropertyAggregateHandle = getOriginalHandle( _nValuePropertyExternalHandle );
1435 OSL_ENSURE( m_nValuePropertyAggregateHandle != -1, "OBoundControlModel::initValueProperty: unable to find the original handle!" );
1436
1437 if ( m_nValuePropertyAggregateHandle != -1 )
1438 {
1439 Reference< XPropertySetInfo > xPropInfo( m_xAggregateSet->getPropertySetInfo(), UNO_SET_THROW );
1440 Property aValuePropDesc = xPropInfo->getPropertyByName( m_sValuePropertyName );
1441 m_aValuePropertyType = aValuePropDesc.Type;
1442 m_bValuePropertyMayBeVoid = ( aValuePropDesc.Attributes & PropertyAttribute::MAYBEVOID ) != 0;
1443 }
1444
1445 // start listening for changes at the value property
1446 implInitValuePropertyListening( );
1447 }
1448
1449 //-----------------------------------------------------------------------------
suspendValueListening()1450 void OBoundControlModel::suspendValueListening( )
1451 {
1452 OSL_PRECOND( m_sValuePropertyName.getLength(), "OBoundControlModel::suspendValueListening: don't have a value property!" );
1453 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::suspendValueListening: I *am* not listening!" );
1454
1455 if ( m_pAggPropMultiplexer )
1456 m_pAggPropMultiplexer->lock();
1457 }
1458
1459 //-----------------------------------------------------------------------------
resumeValueListening()1460 void OBoundControlModel::resumeValueListening( )
1461 {
1462 OSL_PRECOND( m_sValuePropertyName.getLength(), "OBoundControlModel::resumeValueListening: don't have a value property!" );
1463 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::resumeValueListening: I *am* not listening at all!" );
1464 OSL_PRECOND( !m_pAggPropMultiplexer || m_pAggPropMultiplexer->locked(), "OBoundControlModel::resumeValueListening: listening not suspended currently!" );
1465
1466 if ( m_pAggPropMultiplexer )
1467 m_pAggPropMultiplexer->unlock();
1468 }
1469
1470 //-----------------------------------------------------------------------------
_getTypes()1471 Sequence< Type > OBoundControlModel::_getTypes()
1472 {
1473 TypeBag aTypes(
1474 OControlModel::_getTypes(),
1475 OBoundControlModel_BASE1::getTypes()
1476 );
1477
1478 if ( m_bCommitable )
1479 aTypes.addTypes( OBoundControlModel_COMMITTING::getTypes() );
1480
1481 if ( m_bSupportsExternalBinding )
1482 aTypes.addTypes( OBoundControlModel_BINDING::getTypes() );
1483
1484 if ( m_bSupportsValidation )
1485 aTypes.addTypes( OBoundControlModel_VALIDATION::getTypes() );
1486
1487 return aTypes.getTypes();
1488 }
1489
1490 // OComponentHelper
1491 //-----------------------------------------------------------------------------
disposing()1492 void OBoundControlModel::disposing()
1493 {
1494 OControlModel::disposing();
1495
1496 ::osl::ClearableMutexGuard aGuard(m_aMutex);
1497
1498 if ( m_pAggPropMultiplexer )
1499 m_pAggPropMultiplexer->dispose();
1500
1501 // notify all our listeners
1502 com::sun::star::lang::EventObject aEvt( static_cast< XWeak* >( this ) );
1503 m_aUpdateListeners.disposeAndClear( aEvt );
1504 m_aResetHelper.disposing();
1505
1506 // disconnect from our database column
1507 // TODO: could we replace the following 5 lines with a call to impl_disconnectDatabaseColumn_noNotify?
1508 // The only more thing which it does is calling onDisconnectedDbColumn - could this
1509 // cause trouble? At least when we continue to call OControlModel::disposing before, it *may*.
1510 if ( hasField() )
1511 {
1512 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
1513 resetField();
1514 }
1515 m_xCursor = NULL;
1516
1517 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1518 if ( xComp.is() )
1519 xComp->removeEventListener(static_cast< XEventListener* >( static_cast< XPropertyChangeListener* >( this ) ) );
1520
1521 // disconnect from our external value binding
1522 if ( hasExternalValueBinding() )
1523 disconnectExternalValueBinding();
1524
1525 // dito for the validator
1526 if ( hasValidator() )
1527 disconnectValidator( );
1528 }
1529
1530 //------------------------------------------------------------------------------
onValuePropertyChange(ControlModelLock & i_rControLock)1531 void OBoundControlModel::onValuePropertyChange( ControlModelLock& i_rControLock )
1532 {
1533 if ( hasExternalValueBinding() )
1534 { // the control value changed, while we have an external value binding
1535 // -> forward the value to it
1536 if ( m_eControlValueChangeInstigator != eExternalBinding )
1537 transferControlValueToExternal( i_rControLock );
1538 }
1539 else if ( !m_bCommitable && m_xColumnUpdate.is() )
1540 { // the control value changed, while we are bound to a database column,
1541 // but not committable (which means changes in the control have to be reflected to
1542 // the underlying database column immediately)
1543 // -> forward the value to the database column
1544 if ( m_eControlValueChangeInstigator != eDbColumnBinding )
1545 commitControlValueToDbColumn( false );
1546 }
1547
1548 // validate the new value
1549 if ( m_bSupportsValidation )
1550 recheckValidity( true );
1551 }
1552
1553 //------------------------------------------------------------------------------
_propertyChanged(const PropertyChangeEvent & _rEvt)1554 void OBoundControlModel::_propertyChanged( const PropertyChangeEvent& _rEvt ) throw ( RuntimeException )
1555 {
1556 ControlModelLock aLock( *this );
1557
1558 OSL_ENSURE( _rEvt.PropertyName == m_sValuePropertyName,
1559 "OBoundControlModel::_propertyChanged: where did this come from (1)?" );
1560 OSL_ENSURE( m_pAggPropMultiplexer && !m_pAggPropMultiplexer->locked(),
1561 "OBoundControlModel::_propertyChanged: where did this come from (2)?" );
1562
1563 if ( _rEvt.PropertyName == m_sValuePropertyName )
1564 {
1565 onValuePropertyChange( aLock );
1566 }
1567 }
1568
1569 //------------------------------------------------------------------------------
startAggregatePropertyListening(const::rtl::OUString & _rPropertyName)1570 void OBoundControlModel::startAggregatePropertyListening( const ::rtl::OUString& _rPropertyName )
1571 {
1572 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::startAggregatePropertyListening: no multiplexer!" );
1573 OSL_ENSURE( _rPropertyName.getLength(), "OBoundControlModel::startAggregatePropertyListening: invalid property name!" );
1574
1575 if ( m_pAggPropMultiplexer && _rPropertyName.getLength() )
1576 {
1577 m_pAggPropMultiplexer->addProperty( _rPropertyName );
1578 }
1579 }
1580
1581 //------------------------------------------------------------------------------
doFormListening(const bool _bStart)1582 void OBoundControlModel::doFormListening( const bool _bStart )
1583 {
1584 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::doFormListening: external value binding should overrule the database binding!" );
1585
1586 if ( isFormListening() == _bStart )
1587 return;
1588
1589 if ( m_xAmbientForm.is() )
1590 _bStart ? m_xAmbientForm->addLoadListener( this ) : m_xAmbientForm->removeLoadListener( this );
1591
1592 Reference< XLoadable > xParentLoadable( getParent(), UNO_QUERY );
1593 if ( getParent().is() && !xParentLoadable.is() )
1594 {
1595 // if our parent does not directly support the XLoadable interface, then it might support the
1596 // XRowSetSupplier/XRowSetChangeBroadcaster interfaces. In this case we have to listen for changes
1597 // broadcasted by the latter.
1598 Reference< XRowSetChangeBroadcaster > xRowSetBroadcaster( getParent(), UNO_QUERY );
1599 if ( xRowSetBroadcaster.is() )
1600 _bStart ? xRowSetBroadcaster->addRowSetChangeListener( this ) : xRowSetBroadcaster->removeRowSetChangeListener( this );
1601 }
1602
1603 m_bFormListening = _bStart && m_xAmbientForm.is();
1604 }
1605
1606 // XChild
1607 //------------------------------------------------------------------------------
setParent(const Reference<XInterface> & _rxParent)1608 void SAL_CALL OBoundControlModel::setParent(const Reference<XInterface>& _rxParent) throw(com::sun::star::lang::NoSupportException, RuntimeException)
1609 {
1610 ControlModelLock aLock( *this );
1611 FieldChangeNotifier aBoundFieldNotifier( aLock );
1612
1613 if ( getParent() == _rxParent )
1614 return;
1615
1616 // disconnect from database column (which is controlled by parent, directly or indirectly)
1617 if ( hasField() )
1618 impl_disconnectDatabaseColumn_noNotify();
1619
1620 // log off old listeners
1621 if ( isFormListening() )
1622 doFormListening( false );
1623
1624 // actually set the new parent
1625 OControlModel::setParent( _rxParent );
1626
1627 // a new parent means a new ambient form
1628 impl_determineAmbientForm_nothrow();
1629
1630 if ( !hasExternalValueBinding() )
1631 {
1632 // log on new listeners
1633 doFormListening( true );
1634
1635 // re-connect to database column of the new parent
1636 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
1637 impl_connectDatabaseColumn_noNotify( false );
1638 }
1639 }
1640
1641 // XEventListener
1642 //------------------------------------------------------------------------------
disposing(const com::sun::star::lang::EventObject & _rEvent)1643 void SAL_CALL OBoundControlModel::disposing(const com::sun::star::lang::EventObject& _rEvent) throw (RuntimeException)
1644 {
1645 ControlModelLock aLock( *this );
1646
1647 if ( _rEvent.Source == getField() )
1648 {
1649 resetField();
1650 }
1651 else if ( _rEvent.Source == m_xLabelControl )
1652 {
1653 Reference<XPropertySet> xOldValue = m_xLabelControl;
1654 m_xLabelControl = NULL;
1655
1656 // fire a propertyChanged (when we leave aLock's scope)
1657 aLock.addPropertyNotification( PROPERTY_ID_CONTROLLABEL, makeAny( xOldValue ), makeAny( m_xLabelControl ) );
1658 }
1659 else if ( _rEvent.Source == m_xExternalBinding )
1660 { // *first* check for the external binding
1661 disconnectExternalValueBinding( );
1662 }
1663 else if ( _rEvent.Source == m_xValidator )
1664 { // *then* check for the validator. Reason is that bindings may also act as validator at the same
1665 // time, in this case, the validator is automatically revoked when the binding is revoked
1666 disconnectValidator( );
1667 }
1668 else
1669 OControlModel::disposing(_rEvent);
1670 }
1671
1672 // XServiceInfo
1673 //------------------------------------------------------------------------------
getSupportedServiceNames()1674 StringSequence SAL_CALL OBoundControlModel::getSupportedServiceNames() throw(RuntimeException)
1675 {
1676 return ::comphelper::concatSequences(
1677 getAggregateServiceNames(),
1678 getSupportedServiceNames_Static()
1679 );
1680 }
1681
1682 //------------------------------------------------------------------------------
getSupportedServiceNames_Static()1683 Sequence< ::rtl::OUString > SAL_CALL OBoundControlModel::getSupportedServiceNames_Static() throw( RuntimeException )
1684 {
1685 Sequence< ::rtl::OUString > aOwnServiceNames( 1 );
1686 aOwnServiceNames[ 0 ] = ::rtl::OUString::createFromAscii( "com.sun.star.form.DataAwareControlModel" );
1687
1688 return ::comphelper::concatSequences(
1689 OControlModel::getSupportedServiceNames_Static(),
1690 aOwnServiceNames
1691 );
1692 }
1693
1694 // XPersist
1695 //------------------------------------------------------------------------------
write(const Reference<stario::XObjectOutputStream> & _rxOutStream)1696 void SAL_CALL OBoundControlModel::write( const Reference<stario::XObjectOutputStream>& _rxOutStream ) throw(stario::IOException, RuntimeException)
1697 {
1698 OControlModel::write(_rxOutStream);
1699
1700 osl::MutexGuard aGuard(m_aMutex);
1701
1702 // Version
1703 _rxOutStream->writeShort(0x0002);
1704
1705 // Controlsource
1706 ::comphelper::operator<<( _rxOutStream, m_aControlSource);
1707
1708 // !!! IMPORTANT NOTE !!!
1709 // don't write any new members here : this wouldn't be compatible with older versions, as OBoundControlModel
1710 // is a base class which is called in derived classes "read" method. So if you increment the version
1711 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
1712 // in anything from data loss to crash.
1713 // (use writeCommonProperties instead, this is called in derived classes write-method)
1714 // !!! EOIN !!!
1715 // FS - 68876 - 28.09.1999
1716 }
1717
1718 //------------------------------------------------------------------------------
defaultCommonProperties()1719 void OBoundControlModel::defaultCommonProperties()
1720 {
1721 Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1722 if (xComp.is())
1723 xComp->removeEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1724 m_xLabelControl = NULL;
1725 }
1726
1727 //------------------------------------------------------------------------------
readCommonProperties(const Reference<stario::XObjectInputStream> & _rxInStream)1728 void OBoundControlModel::readCommonProperties(const Reference<stario::XObjectInputStream>& _rxInStream)
1729 {
1730 sal_Int32 nLen = _rxInStream->readLong();
1731
1732 Reference<stario::XMarkableStream> xMark(_rxInStream, UNO_QUERY);
1733 DBG_ASSERT(xMark.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !");
1734 sal_Int32 nMark = xMark->createMark();
1735
1736 // read the reference to the label control
1737 Reference<stario::XPersistObject> xPersist;
1738 sal_Int32 nUsedFlag;
1739 nUsedFlag = _rxInStream->readLong();
1740 if (nUsedFlag)
1741 xPersist = _rxInStream->readObject();
1742 m_xLabelControl = m_xLabelControl.query( xPersist );
1743 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1744 if (xComp.is())
1745 xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1746
1747 // read any other new common properties here
1748
1749 // skip the remaining bytes
1750 xMark->jumpToMark(nMark);
1751 _rxInStream->skipBytes(nLen);
1752 xMark->deleteMark(nMark);
1753 }
1754
1755 //------------------------------------------------------------------------------
writeCommonProperties(const Reference<stario::XObjectOutputStream> & _rxOutStream)1756 void OBoundControlModel::writeCommonProperties(const Reference<stario::XObjectOutputStream>& _rxOutStream)
1757 {
1758 Reference<stario::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
1759 DBG_ASSERT(xMark.is(), "OBoundControlModel::writeCommonProperties : can only work with markable streams !");
1760 sal_Int32 nMark = xMark->createMark();
1761
1762 // a placeholder where we will write the overall length (later in this method)
1763 sal_Int32 nLen = 0;
1764 _rxOutStream->writeLong(nLen);
1765
1766 // write the reference to the label control
1767 Reference<stario::XPersistObject> xPersist(m_xLabelControl, UNO_QUERY);
1768 sal_Int32 nUsedFlag = 0;
1769 if (xPersist.is())
1770 nUsedFlag = 1;
1771 _rxOutStream->writeLong(nUsedFlag);
1772 if (xPersist.is())
1773 _rxOutStream->writeObject(xPersist);
1774
1775 // write any other new common properties here
1776
1777 // write the correct length at the beginning of the block
1778 nLen = xMark->offsetToMark(nMark) - sizeof(nLen);
1779 xMark->jumpToMark(nMark);
1780 _rxOutStream->writeLong(nLen);
1781 xMark->jumpToFurthest();
1782 xMark->deleteMark(nMark);
1783 }
1784
1785 //------------------------------------------------------------------------------
read(const Reference<stario::XObjectInputStream> & _rxInStream)1786 void SAL_CALL OBoundControlModel::read( const Reference< stario::XObjectInputStream >& _rxInStream ) throw(stario::IOException, RuntimeException)
1787 {
1788 OControlModel::read(_rxInStream);
1789
1790 osl::MutexGuard aGuard(m_aMutex);
1791 sal_uInt16 nVersion = _rxInStream->readShort(); (void)nVersion;
1792 ::comphelper::operator>>( _rxInStream, m_aControlSource);
1793 }
1794
1795 //------------------------------------------------------------------------------
getFastPropertyValue(Any & rValue,sal_Int32 nHandle) const1796 void OBoundControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
1797 {
1798 switch (nHandle)
1799 {
1800 case PROPERTY_ID_INPUT_REQUIRED:
1801 rValue <<= m_bInputRequired;
1802 break;
1803 case PROPERTY_ID_CONTROLSOURCEPROPERTY:
1804 rValue <<= m_sValuePropertyName;
1805 break;
1806 case PROPERTY_ID_CONTROLSOURCE:
1807 rValue <<= m_aControlSource;
1808 break;
1809 case PROPERTY_ID_BOUNDFIELD:
1810 rValue <<= getField();
1811 break;
1812 case PROPERTY_ID_CONTROLLABEL:
1813 if (!m_xLabelControl.is())
1814 rValue.clear();
1815 else
1816 rValue <<= m_xLabelControl;
1817 break;
1818 default:
1819 OControlModel::getFastPropertyValue(rValue, nHandle);
1820 }
1821 }
1822
1823 //------------------------------------------------------------------------------
convertFastPropertyValue(Any & _rConvertedValue,Any & _rOldValue,sal_Int32 _nHandle,const Any & _rValue)1824 sal_Bool OBoundControlModel::convertFastPropertyValue(
1825 Any& _rConvertedValue, Any& _rOldValue,
1826 sal_Int32 _nHandle,
1827 const Any& _rValue)
1828 throw (com::sun::star::lang::IllegalArgumentException)
1829 {
1830 sal_Bool bModified(sal_False);
1831 switch (_nHandle)
1832 {
1833 case PROPERTY_ID_INPUT_REQUIRED:
1834 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, m_bInputRequired );
1835 break;
1836 case PROPERTY_ID_CONTROLSOURCE:
1837 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aControlSource);
1838 break;
1839 case PROPERTY_ID_BOUNDFIELD:
1840 DBG_ERROR( "OBoundControlModel::convertFastPropertyValue: BoundField should be a read-only property !" );
1841 throw com::sun::star::lang::IllegalArgumentException();
1842 case PROPERTY_ID_CONTROLLABEL:
1843 if (!_rValue.hasValue())
1844 { // property set to void
1845 _rConvertedValue = Any();
1846 getFastPropertyValue(_rOldValue, _nHandle);
1847 bModified = m_xLabelControl.is();
1848 }
1849 else
1850 {
1851 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_xLabelControl);
1852 if (!m_xLabelControl.is())
1853 // an empty interface is interpreted as VOID
1854 _rOldValue.clear();
1855 }
1856 break;
1857 default:
1858 bModified = OControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
1859 }
1860 return bModified;
1861 }
1862
1863 //------------------------------------------------------------------------------
getPropertyDefaultByHandle(sal_Int32 _nHandle) const1864 Any OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
1865 {
1866 Any aDefault;
1867 switch ( _nHandle )
1868 {
1869 case PROPERTY_ID_INPUT_REQUIRED:
1870 aDefault <<= sal_Bool( sal_True );
1871 break;
1872
1873 case PROPERTY_ID_CONTROLSOURCE:
1874 aDefault <<= ::rtl::OUString();
1875 break;
1876
1877 case PROPERTY_ID_CONTROLLABEL:
1878 aDefault <<= Reference< XPropertySet >();
1879 break;
1880 }
1881 return aDefault;
1882 }
1883
1884 //------------------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any & rValue)1885 void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception)
1886 {
1887 switch (nHandle)
1888 {
1889 case PROPERTY_ID_INPUT_REQUIRED:
1890 OSL_VERIFY( rValue >>= m_bInputRequired );
1891 break;
1892 case PROPERTY_ID_CONTROLSOURCE:
1893 OSL_VERIFY( rValue >>= m_aControlSource );
1894 break;
1895 case PROPERTY_ID_BOUNDFIELD:
1896 DBG_ERROR("OBoundControlModel::setFastPropertyValue_NoBroadcast : BoundField should be a read-only property !");
1897 throw com::sun::star::lang::IllegalArgumentException();
1898 case PROPERTY_ID_CONTROLLABEL:
1899 {
1900 if ( rValue.hasValue() && ( rValue.getValueTypeClass() != TypeClass_INTERFACE ) )
1901 throw com::sun::star::lang::IllegalArgumentException();
1902
1903 Reference< XInterface > xNewValue( rValue, UNO_QUERY );
1904 if ( !xNewValue.is() )
1905 { // set property to "void"
1906 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1907 if ( xComp.is() )
1908 xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
1909 m_xLabelControl = NULL;
1910 break;
1911 }
1912
1913 Reference< XControlModel > xAsModel ( xNewValue, UNO_QUERY );
1914 Reference< XServiceInfo > xAsServiceInfo ( xAsModel, UNO_QUERY );
1915 Reference< XPropertySet > xAsPropSet ( xAsServiceInfo, UNO_QUERY );
1916 Reference< XChild > xAsChild ( xAsPropSet, UNO_QUERY );
1917 if ( !xAsChild.is() || !xAsServiceInfo->supportsService( m_aLabelServiceName ) )
1918 {
1919 throw com::sun::star::lang::IllegalArgumentException();
1920 }
1921
1922 // check if weself and the given model have a common anchestor (up to the forms collection)
1923 Reference<XChild> xCont;
1924 query_interface(static_cast<XWeak*>(this), xCont);
1925 Reference< XInterface > xMyTopLevel = xCont->getParent();
1926 while (xMyTopLevel.is())
1927 {
1928 Reference<XForm> xAsForm(xMyTopLevel, UNO_QUERY);
1929 if (!xAsForm.is())
1930 // found my root
1931 break;
1932
1933 Reference<XChild> xLoopAsChild(xMyTopLevel, UNO_QUERY);
1934 xMyTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1935 }
1936 Reference< XInterface > xNewTopLevel = xAsChild->getParent();
1937 while (xNewTopLevel.is())
1938 {
1939 Reference<XForm> xAsForm(xNewTopLevel, UNO_QUERY);
1940 if (!xAsForm.is())
1941 break;
1942
1943 Reference<XChild> xLoopAsChild(xNewTopLevel, UNO_QUERY);
1944 xNewTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1945 }
1946 if (xNewTopLevel != xMyTopLevel)
1947 {
1948 // the both objects don't belong to the same forms collection -> not acceptable
1949 throw com::sun::star::lang::IllegalArgumentException();
1950 }
1951
1952 m_xLabelControl = xAsPropSet;
1953 Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1954 if (xComp.is())
1955 xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1956 }
1957 break;
1958 default:
1959 OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue );
1960 }
1961 }
1962
1963 // XPropertyChangeListener
1964 //------------------------------------------------------------------------------
propertyChange(const PropertyChangeEvent & evt)1965 void SAL_CALL OBoundControlModel::propertyChange( const PropertyChangeEvent& evt ) throw(RuntimeException)
1966 {
1967 // if the DBColumn value changed, transfer it to the control
1968 if ( evt.PropertyName.equals( PROPERTY_VALUE ) )
1969 {
1970 OSL_ENSURE( evt.Source == getField(), "OBoundControlModel::propertyChange: value changes from components other than our database column?" );
1971 osl::MutexGuard aGuard(m_aMutex);
1972 if ( m_bForwardValueChanges && m_xColumn.is() )
1973 transferDbValueToControl();
1974 }
1975 else
1976 {
1977 OSL_ENSURE( evt.Source == m_xExternalBinding, "OBoundControlModel::propertyChange: where did this come from?" );
1978
1979 // our binding has properties which can control properties of ourself
1980 ::rtl::OUString sBindingControlledProperty;
1981 bool bForwardToLabelControl = false;
1982 if ( evt.PropertyName.equals( PROPERTY_READONLY ) )
1983 {
1984 sBindingControlledProperty = PROPERTY_READONLY;
1985 }
1986 else if ( evt.PropertyName.equals( PROPERTY_RELEVANT ) )
1987 {
1988 sBindingControlledProperty = PROPERTY_ENABLED;
1989 bForwardToLabelControl = true;
1990 }
1991 else
1992 return;
1993
1994 try
1995 {
1996 setPropertyValue( sBindingControlledProperty, evt.NewValue );
1997 if ( bForwardToLabelControl && m_xLabelControl.is() )
1998 m_xLabelControl->setPropertyValue( sBindingControlledProperty, evt.NewValue );
1999 }
2000 catch( const Exception& )
2001 {
2002 OSL_ENSURE( sal_False, "OBoundControlModel::propertyChange: could not adjust my binding-controlled property!" );
2003 }
2004 }
2005 }
2006
2007 //------------------------------------------------------------------------------
onRowSetChanged(const EventObject &)2008 void SAL_CALL OBoundControlModel::onRowSetChanged( const EventObject& /*i_Event*/ ) throw (RuntimeException)
2009 {
2010 ControlModelLock aLock( *this );
2011 FieldChangeNotifier aBoundFieldNotifier( aLock );
2012
2013 // disconnect from database column (which is controlled by parent, directly or indirectly)
2014 if ( hasField() )
2015 impl_disconnectDatabaseColumn_noNotify();
2016
2017 // log off old listeners
2018 if ( isFormListening() )
2019 doFormListening( false );
2020
2021 // determine the new ambient form
2022 impl_determineAmbientForm_nothrow();
2023
2024 // log on new listeners
2025 doFormListening( true );
2026
2027 // re-connect to database column if needed and possible
2028 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
2029 impl_connectDatabaseColumn_noNotify( false );
2030 }
2031
2032 // XBoundComponent
2033 //------------------------------------------------------------------------------
addUpdateListener(const Reference<XUpdateListener> & _rxListener)2034 void SAL_CALL OBoundControlModel::addUpdateListener(const Reference<XUpdateListener>& _rxListener) throw(RuntimeException)
2035 {
2036 m_aUpdateListeners.addInterface(_rxListener);
2037 }
2038
2039 //------------------------------------------------------------------------------
removeUpdateListener(const Reference<XUpdateListener> & _rxListener)2040 void SAL_CALL OBoundControlModel::removeUpdateListener(const Reference< XUpdateListener>& _rxListener) throw(RuntimeException)
2041 {
2042 m_aUpdateListeners.removeInterface(_rxListener);
2043 }
2044
2045 //------------------------------------------------------------------------------
commit()2046 sal_Bool SAL_CALL OBoundControlModel::commit() throw(RuntimeException)
2047 {
2048 ControlModelLock aLock( *this );
2049
2050 OSL_PRECOND( m_bCommitable, "OBoundControlModel::commit: invalid call (I'm not commitable !) " );
2051 if ( hasExternalValueBinding() )
2052 {
2053 // in most cases, no action is required: For most derivees, we know the value property of
2054 // our control (see initValueProperty), and when an external binding is active, we
2055 // instantly forward all changes in this property to the external binding.
2056 if ( !m_sValuePropertyName.getLength() )
2057 // but for those derivees which did not use this feature, we need an
2058 // explicit transfer
2059 transferControlValueToExternal( aLock );
2060 return sal_True;
2061 }
2062
2063 OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" );
2064 // we reach this only if we're not working with an external binding
2065
2066 if ( !hasField() )
2067 return sal_True;
2068
2069 ::cppu::OInterfaceIteratorHelper aIter( m_aUpdateListeners );
2070 EventObject aEvent;
2071 aEvent.Source = static_cast< XWeak* >( this );
2072 sal_Bool bSuccess = sal_True;
2073
2074 aLock.release();
2075 // >>>>>>>> ----- UNSAFE ----- >>>>>>>>
2076 while (aIter.hasMoreElements() && bSuccess)
2077 bSuccess = static_cast< XUpdateListener* >( aIter.next() )->approveUpdate( aEvent );
2078 // <<<<<<<< ----- UNSAFE ----- <<<<<<<<
2079 aLock.acquire();
2080
2081 if ( bSuccess )
2082 {
2083 try
2084 {
2085 if ( m_xColumnUpdate.is() )
2086 bSuccess = commitControlValueToDbColumn( sal_False );
2087 }
2088 catch(Exception&)
2089 {
2090 bSuccess = sal_False;
2091 }
2092 }
2093
2094 if ( bSuccess )
2095 {
2096 aLock.release();
2097 m_aUpdateListeners.notifyEach( &XUpdateListener::updated, aEvent );
2098 }
2099
2100 return bSuccess;
2101 }
2102
2103 //------------------------------------------------------------------------------
resetField()2104 void OBoundControlModel::resetField()
2105 {
2106 m_xColumnUpdate.clear();
2107 m_xColumn.clear();
2108 m_xField.clear();
2109 m_nFieldType = DataType::OTHER;
2110 }
2111
2112 //------------------------------------------------------------------------------
connectToField(const Reference<XRowSet> & rForm)2113 sal_Bool OBoundControlModel::connectToField(const Reference<XRowSet>& rForm)
2114 {
2115 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::connectToField: invalid call (have an external binding)!" );
2116
2117 // wenn eine Verbindung zur Datenbank existiert
2118 if (rForm.is() && getConnection(rForm).is())
2119 {
2120 // Feld bestimmen und PropertyChangeListener
2121 m_xCursor = rForm;
2122 Reference<XPropertySet> xFieldCandidate;
2123
2124 if (m_xCursor.is())
2125 {
2126 Reference<XColumnsSupplier> xColumnsSupplier(m_xCursor, UNO_QUERY);
2127 DBG_ASSERT(xColumnsSupplier.is(), "OBoundControlModel::connectToField : the row set should support the com::sun::star::sdb::ResultSet service !");
2128 if (xColumnsSupplier.is())
2129 {
2130 Reference<XNameAccess> xColumns(xColumnsSupplier->getColumns(), UNO_QUERY);
2131 if (xColumns.is() && xColumns->hasByName(m_aControlSource))
2132 {
2133 OSL_VERIFY( xColumns->getByName(m_aControlSource) >>= xFieldCandidate );
2134 }
2135 }
2136 }
2137
2138 try
2139 {
2140 sal_Int32 nFieldType = DataType::OTHER;
2141 if ( xFieldCandidate.is() )
2142 {
2143 xFieldCandidate->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
2144 if ( approveDbColumnType( nFieldType ) )
2145 impl_setField_noNotify( xFieldCandidate );
2146 }
2147 else
2148 impl_setField_noNotify( NULL );
2149
2150 if ( m_xField.is() )
2151 {
2152 if( m_xField->getPropertySetInfo()->hasPropertyByName( PROPERTY_VALUE ) )
2153 {
2154 m_nFieldType = nFieldType;
2155
2156 // an wertaenderungen horchen
2157 m_xField->addPropertyChangeListener( PROPERTY_VALUE, this );
2158 m_xColumnUpdate = Reference< XColumnUpdate >( m_xField, UNO_QUERY );
2159 m_xColumn = Reference< XColumn >( m_xField, UNO_QUERY );
2160
2161 sal_Int32 nNullableFlag = ColumnValue::NO_NULLS;
2162 m_xField->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullableFlag;
2163 m_bRequired = (ColumnValue::NO_NULLS == nNullableFlag);
2164 // we're optimistic : in case of ColumnValue_NULLABLE_UNKNOWN we assume nullability ....
2165 }
2166 else
2167 {
2168 OSL_ENSURE(sal_False, "OBoundControlModel::connectToField: property NAME not supported!");
2169 impl_setField_noNotify( NULL );
2170 }
2171 }
2172 }
2173 catch( const Exception& )
2174 {
2175 DBG_UNHANDLED_EXCEPTION();
2176 resetField();
2177 }
2178 }
2179 return hasField();
2180 }
2181
2182 //------------------------------------------------------------------------------
initFromField(const Reference<XRowSet> & _rxRowSet)2183 void OBoundControlModel::initFromField( const Reference< XRowSet >& _rxRowSet )
2184 {
2185 // but only if the rowset if posisitioned on a valid record
2186 if ( hasField() && _rxRowSet.is() )
2187 {
2188 if ( !_rxRowSet->isBeforeFirst() && !_rxRowSet->isAfterLast() )
2189 transferDbValueToControl();
2190 else
2191 // reset the field if the row set is empty
2192 // #i30661# / 2004-12-16 / frank.schoenheit@sun.com
2193 resetNoBroadcast();
2194 }
2195 }
2196
2197 //------------------------------------------------------------------------------
approveDbColumnType(sal_Int32 _nColumnType)2198 sal_Bool OBoundControlModel::approveDbColumnType(sal_Int32 _nColumnType)
2199 {
2200 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::approveDbColumnType: invalid call (have an external binding)!" );
2201
2202 if ((_nColumnType == DataType::BINARY) || (_nColumnType == DataType::VARBINARY)
2203 || (_nColumnType == DataType::LONGVARBINARY) || (_nColumnType == DataType::OTHER)
2204 || (_nColumnType == DataType::OBJECT) || (_nColumnType == DataType::DISTINCT)
2205 || (_nColumnType == DataType::STRUCT) || (_nColumnType == DataType::ARRAY)
2206 || (_nColumnType == DataType::BLOB) /*|| (_nColumnType == DataType::CLOB)*/
2207 || (_nColumnType == DataType::REF) || (_nColumnType == DataType::SQLNULL))
2208 return sal_False;
2209
2210 return sal_True;
2211 }
2212
2213 //------------------------------------------------------------------------------
impl_determineAmbientForm_nothrow()2214 void OBoundControlModel::impl_determineAmbientForm_nothrow()
2215 {
2216 Reference< XInterface > xParent( const_cast< OBoundControlModel* >( this )->getParent() );
2217
2218 m_xAmbientForm.set( xParent, UNO_QUERY );
2219 if ( !m_xAmbientForm.is() )
2220 {
2221 Reference< XRowSetSupplier > xSupRowSet( xParent, UNO_QUERY );
2222 if ( xSupRowSet.is() )
2223 m_xAmbientForm.set( xSupRowSet->getRowSet(), UNO_QUERY );
2224 }
2225 }
2226
2227 //------------------------------------------------------------------------------
impl_connectDatabaseColumn_noNotify(bool _bFromReload)2228 void OBoundControlModel::impl_connectDatabaseColumn_noNotify( bool _bFromReload )
2229 {
2230 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2231
2232 // consistency checks
2233 DBG_ASSERT( !( hasField() && !_bFromReload ),
2234 "OBoundControlModel::impl_connectDatabaseColumn_noNotify: the form is just *loaded*, but we already have a field!" );
2235 (void)_bFromReload;
2236
2237 Reference< XRowSet > xRowSet( m_xAmbientForm, UNO_QUERY );
2238 OSL_ENSURE( xRowSet.is(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: no row set!" );
2239 if ( !xRowSet.is() )
2240 return;
2241
2242 if ( !hasField() )
2243 {
2244 // connect to the column
2245 connectToField( xRowSet );
2246 }
2247
2248 // now that we're connected (more or less, even if we did not find a column),
2249 // we definitely want to forward any potentially occurring value changes
2250 m_bForwardValueChanges = sal_True;
2251
2252 // let derived classes react on this new connection
2253 m_bLoaded = sal_True;
2254 onConnectedDbColumn( xRowSet );
2255
2256 // initially transfer the db column value to the control, if we successfully connected to a database column
2257 if ( hasField() )
2258 initFromField( xRowSet );
2259 }
2260
2261 //------------------------------------------------------------------------------
impl_disconnectDatabaseColumn_noNotify()2262 void OBoundControlModel::impl_disconnectDatabaseColumn_noNotify()
2263 {
2264 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_disconnectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2265
2266 // let derived classes react on this
2267 onDisconnectedDbColumn();
2268
2269 if ( hasField() )
2270 {
2271 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
2272 resetField();
2273 }
2274
2275 m_xCursor = NULL;
2276 m_bLoaded = sal_False;
2277 }
2278
2279 //==============================================================================
2280 // XLoadListener
2281 //------------------------------------------------------------------------------
loaded(const EventObject & _rEvent)2282 void SAL_CALL OBoundControlModel::loaded( const EventObject& _rEvent ) throw(RuntimeException)
2283 {
2284 ControlModelLock aLock( *this );
2285 FieldChangeNotifier aBoundFieldNotifier( aLock );
2286
2287 OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::loaded: where does this come from?" );
2288 (void)_rEvent;
2289
2290 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::loaded: we should never reach this with an external value binding!" );
2291 if ( hasExternalValueBinding() )
2292 return;
2293
2294 impl_connectDatabaseColumn_noNotify( false );
2295 }
2296
2297
2298 //------------------------------------------------------------------------------
unloaded(const com::sun::star::lang::EventObject &)2299 void SAL_CALL OBoundControlModel::unloaded( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException)
2300 {
2301 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloaded: we should never reach this with an external value binding!" );
2302 }
2303
2304 //------------------------------------------------------------------------------
reloading(const com::sun::star::lang::EventObject &)2305 void SAL_CALL OBoundControlModel::reloading( const com::sun::star::lang::EventObject& /*aEvent*/ ) throw(RuntimeException)
2306 {
2307 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloading: we should never reach this with an external value binding!" );
2308 if ( hasExternalValueBinding() )
2309 return;
2310
2311 osl::MutexGuard aGuard(m_aMutex);
2312 m_bForwardValueChanges = sal_False;
2313 }
2314
2315 //------------------------------------------------------------------------------
unloading(const com::sun::star::lang::EventObject &)2316 void SAL_CALL OBoundControlModel::unloading(const com::sun::star::lang::EventObject& /*aEvent*/) throw(RuntimeException)
2317 {
2318 ControlModelLock aLock( *this );
2319 FieldChangeNotifier aBoundFieldNotifier( aLock );
2320
2321 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloading: we should never reach this with an external value binding!" );
2322 if ( hasExternalValueBinding() )
2323 return;
2324
2325 impl_disconnectDatabaseColumn_noNotify();
2326 }
2327
2328 //------------------------------------------------------------------------------
reloaded(const EventObject & _rEvent)2329 void SAL_CALL OBoundControlModel::reloaded( const EventObject& _rEvent ) throw(RuntimeException)
2330 {
2331 ControlModelLock aLock( *this );
2332 FieldChangeNotifier aBoundFieldNotifier( aLock );
2333
2334 OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::reloaded: where does this come from?" );
2335 (void)_rEvent;
2336
2337 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloaded: we should never reach this with an external value binding!" );
2338 if ( hasExternalValueBinding() )
2339 return;
2340
2341 impl_connectDatabaseColumn_noNotify( true );
2342 }
2343
2344 //------------------------------------------------------------------------------
setControlValue(const Any & _rValue,ValueChangeInstigator _eInstigator)2345 void OBoundControlModel::setControlValue( const Any& _rValue, ValueChangeInstigator _eInstigator )
2346 {
2347 m_eControlValueChangeInstigator = _eInstigator;
2348 doSetControlValue( _rValue );
2349 m_eControlValueChangeInstigator = eOther;
2350 }
2351
2352 //------------------------------------------------------------------------------
doSetControlValue(const Any & _rValue)2353 void OBoundControlModel::doSetControlValue( const Any& _rValue )
2354 {
2355 OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2356 "OBoundControlModel::doSetControlValue: invalid aggregate !" );
2357 OSL_PRECOND( m_sValuePropertyName.getLength() || ( m_nValuePropertyAggregateHandle != -1 ),
2358 "OBoundControlModel::doSetControlValue: please override if you have own value property handling!" );
2359
2360 try
2361 {
2362 // release our mutex once (it's acquired in one of the calling methods), as setting aggregate properties
2363 // may cause any uno controls belonging to us to lock the solar mutex, which is potentially dangerous with
2364 // our own mutex locked
2365 // #72451# / 2000-01-31 / frank.schoenheit@sun.com
2366 MutexRelease aRelease( m_aMutex );
2367 if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2368 {
2369 m_xAggregateFastSet->setFastPropertyValue( m_nValuePropertyAggregateHandle, _rValue );
2370 }
2371 else if ( m_sValuePropertyName.getLength() && m_xAggregateSet.is() )
2372 {
2373 m_xAggregateSet->setPropertyValue( m_sValuePropertyName, _rValue );
2374 }
2375 }
2376 catch( const Exception& )
2377 {
2378 OSL_ENSURE( sal_False, "OBoundControlModel::doSetControlValue: caught an exception!" );
2379 }
2380 }
2381
2382 //------------------------------------------------------------------------------
onConnectedValidator()2383 void OBoundControlModel::onConnectedValidator( )
2384 {
2385 try
2386 {
2387 // if we have an external validator, we do not want the control to force invalid
2388 // inputs to the default value. Instead, invalid inputs should be translated
2389 // to NaN (not a number)
2390 Reference< XPropertySetInfo > xAggregatePropertyInfo;
2391 if ( m_xAggregateSet.is() )
2392 xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2393 if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2394 m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( (sal_Bool)sal_False ) );
2395 }
2396 catch( const Exception& )
2397 {
2398 OSL_ENSURE( sal_False, "OBoundControlModel::onConnectedValidator: caught an exception!" );
2399 }
2400 recheckValidity( false );
2401 }
2402
2403 //------------------------------------------------------------------------------
onDisconnectedValidator()2404 void OBoundControlModel::onDisconnectedValidator( )
2405 {
2406 try
2407 {
2408 Reference< XPropertySetInfo > xAggregatePropertyInfo;
2409 if ( m_xAggregateSet.is() )
2410 xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2411 if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2412 m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( (sal_Bool)sal_True ) );
2413 }
2414 catch( const Exception& )
2415 {
2416 OSL_ENSURE( sal_False, "OBoundControlModel::onDisconnectedValidator: caught an exception!" );
2417 }
2418 recheckValidity( false );
2419 }
2420
2421 //------------------------------------------------------------------------------
onConnectedExternalValue()2422 void OBoundControlModel::onConnectedExternalValue( )
2423 {
2424 calculateExternalValueType();
2425 }
2426
2427 //------------------------------------------------------------------------------
onDisconnectedExternalValue()2428 void OBoundControlModel::onDisconnectedExternalValue( )
2429 {
2430 }
2431
2432 //------------------------------------------------------------------------------
onConnectedDbColumn(const Reference<XInterface> &)2433 void OBoundControlModel::onConnectedDbColumn( const Reference< XInterface >& /*_rxForm*/ )
2434 {
2435 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onConnectedDbColumn: how this? There's an external value binding!" );
2436 }
2437
2438 //------------------------------------------------------------------------------
onDisconnectedDbColumn()2439 void OBoundControlModel::onDisconnectedDbColumn()
2440 {
2441 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onDisconnectedDbColumn: how this? There's an external value binding!" );
2442 }
2443
2444 // XReset
2445 //-----------------------------------------------------------------------------
getDefaultForReset() const2446 Any OBoundControlModel::getDefaultForReset() const
2447 {
2448 return Any();
2449 }
2450
2451 //-----------------------------------------------------------------------------
resetNoBroadcast()2452 void OBoundControlModel::resetNoBroadcast()
2453 {
2454 setControlValue( getDefaultForReset(), eOther );
2455 }
2456
2457 //-----------------------------------------------------------------------------
addResetListener(const Reference<XResetListener> & l)2458 void OBoundControlModel::addResetListener(const Reference<XResetListener>& l) throw (RuntimeException)
2459 {
2460 m_aResetHelper.addResetListener( l );
2461 }
2462
2463 //-----------------------------------------------------------------------------
removeResetListener(const Reference<XResetListener> & l)2464 void OBoundControlModel::removeResetListener(const Reference<XResetListener>& l) throw (RuntimeException)
2465 {
2466 m_aResetHelper.removeResetListener( l );
2467 }
2468
2469 //-----------------------------------------------------------------------------
reset()2470 void OBoundControlModel::reset() throw (RuntimeException)
2471 {
2472 if ( !m_aResetHelper.approveReset() )
2473 return;
2474
2475 ControlModelLock aLock( *this );
2476
2477 // on a new record?
2478 sal_Bool bIsNewRecord = sal_False;
2479 Reference<XPropertySet> xSet( m_xCursor, UNO_QUERY );
2480 if ( xSet.is() )
2481 {
2482 try
2483 {
2484 xSet->getPropertyValue( PROPERTY_ISNEW ) >>= bIsNewRecord;
2485 }
2486 catch( const Exception& )
2487 {
2488 DBG_UNHANDLED_EXCEPTION();
2489 }
2490 }
2491
2492 // cursor on an invalid row?
2493 sal_Bool bInvalidCursorPosition = sal_True;
2494 try
2495 {
2496 bInvalidCursorPosition = m_xCursor.is()
2497 && ( m_xCursor->isAfterLast()
2498 || m_xCursor->isBeforeFirst()
2499 )
2500 && !bIsNewRecord;
2501 }
2502 catch( const SQLException& )
2503 {
2504 OSL_ENSURE( sal_False, "OBoundControlModel::reset: caught an SQL exception!" );
2505 }
2506 // don't count the insert row as "invalid"
2507 // @since #i24495#
2508 // @date 2004-05-14
2509 // @author fs@openoffice.org
2510
2511 sal_Bool bSimpleReset =
2512 ( !m_xColumn.is() // no connection to a database column
2513 || ( m_xCursor.is() // OR we have an improperly positioned cursor
2514 && bInvalidCursorPosition
2515 )
2516 || hasExternalValueBinding() // OR we have an external value binding
2517 );
2518
2519 if ( !bSimpleReset )
2520 {
2521 // The default values will be set if and only if the current value of the field which we're bound
2522 // to is NULL.
2523 // Else, the current field value should be refreshed
2524 // This behaviour is not completely ... "matured": What should happen if the field as well as the
2525 // control have a default value?
2526
2527 sal_Bool bIsNull = sal_True;
2528 // we have to access the field content at least once to get a reliable result by XColumn::wasNull
2529 try
2530 {
2531 // normally, we'd do a getString here. However, this is extremely expensive in the case
2532 // of binary fields. Unfortunately, getString is the only method which is guaranteed
2533 // to *always* succeed, all other getXXX methods may fail if the column is asked for a
2534 // non-convertible type
2535 sal_Int32 nFieldType = DataType::OBJECT;
2536 getField()->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
2537 if ( ( nFieldType == DataType::BINARY )
2538 || ( nFieldType == DataType::VARBINARY )
2539 || ( nFieldType == DataType::LONGVARBINARY )
2540 || ( nFieldType == DataType::OBJECT )
2541 /*|| ( nFieldType == DataType::CLOB )*/
2542 )
2543 m_xColumn->getBinaryStream();
2544 else if ( nFieldType == DataType::BLOB )
2545 m_xColumn->getBlob();
2546 else
2547 m_xColumn->getString();
2548
2549 bIsNull = m_xColumn->wasNull();
2550 }
2551 catch(Exception&)
2552 {
2553 DBG_ERROR("OBoundControlModel::reset: this should have succeeded in all cases!");
2554 }
2555
2556 sal_Bool bNeedValueTransfer = sal_True;
2557
2558 if ( bIsNull )
2559 {
2560 if ( bIsNewRecord )
2561 {
2562 // reset the control to it's default
2563 resetNoBroadcast();
2564 // and immediately commit the changes to the DB column, to keep consistency
2565 commitControlValueToDbColumn( sal_True );
2566
2567 bNeedValueTransfer = sal_False;
2568 }
2569 }
2570
2571 if ( bNeedValueTransfer )
2572 transferDbValueToControl();
2573 }
2574 else
2575 {
2576 resetNoBroadcast();
2577
2578 // transfer to the external binding, if necessary
2579 if ( hasExternalValueBinding() )
2580 transferControlValueToExternal( aLock );
2581 }
2582
2583 // revalidate, if necessary
2584 if ( hasValidator() )
2585 recheckValidity( true );
2586
2587 aLock.release();
2588
2589 m_aResetHelper.notifyResetted();
2590 }
2591
2592 // -----------------------------------------------------------------------------
impl_setField_noNotify(const Reference<XPropertySet> & _rxField)2593 void OBoundControlModel::impl_setField_noNotify( const Reference< XPropertySet>& _rxField )
2594 {
2595 DBG_ASSERT( !hasExternalValueBinding(), "OBoundControlModel::impl_setField_noNotify: We have an external value binding!" );
2596 m_xField = _rxField;
2597 }
2598
2599 //--------------------------------------------------------------------
impl_approveValueBinding_nolock(const Reference<XValueBinding> & _rxBinding)2600 sal_Bool OBoundControlModel::impl_approveValueBinding_nolock( const Reference< XValueBinding >& _rxBinding )
2601 {
2602 if ( !_rxBinding.is() )
2603 return sal_False;
2604
2605 Sequence< Type > aTypeCandidates;
2606 {
2607 // SYNCHRONIZED -->
2608 ::osl::MutexGuard aGuard( m_aMutex );
2609 aTypeCandidates = getSupportedBindingTypes();
2610 // <-- SYNCHRONIZED
2611 }
2612
2613 for ( const Type* pType = aTypeCandidates.getConstArray();
2614 pType != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2615 ++pType
2616 )
2617 {
2618 if ( _rxBinding->supportsType( *pType ) )
2619 return sal_True;
2620 }
2621
2622 return sal_False;
2623 }
2624
2625 //--------------------------------------------------------------------
connectExternalValueBinding(const Reference<XValueBinding> & _rxBinding,ControlModelLock & _rInstanceLock)2626 void OBoundControlModel::connectExternalValueBinding(
2627 const Reference< XValueBinding >& _rxBinding, ControlModelLock& _rInstanceLock )
2628 {
2629 OSL_PRECOND( _rxBinding.is(), "OBoundControlModel::connectExternalValueBinding: invalid binding instance!" );
2630 OSL_PRECOND( !hasExternalValueBinding( ), "OBoundControlModel::connectExternalValueBinding: precond not met (currently have a binding)!" );
2631
2632 // if we're connected to a database column, suspend this
2633 if ( hasField() )
2634 impl_disconnectDatabaseColumn_noNotify();
2635
2636 // suspend listening for load-related events at out ambient form.
2637 // This is because an external value binding overrules a possible database binding.
2638 if ( isFormListening() )
2639 doFormListening( false );
2640
2641 // remember this new binding
2642 m_xExternalBinding = _rxBinding;
2643
2644 // tell the derivee
2645 onConnectedExternalValue();
2646
2647 try
2648 {
2649 // add as value listener so we get notified when the value changes
2650 Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2651 if ( xModifiable.is() )
2652 xModifiable->addModifyListener( this );
2653
2654 // add as property change listener for some (possibly present) properties we're
2655 // interested in
2656 Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2657 Reference< XPropertySetInfo > xBindingPropsInfo( xBindingProps.is() ? xBindingProps->getPropertySetInfo() : Reference< XPropertySetInfo >() );
2658 if ( xBindingPropsInfo.is() )
2659 {
2660 if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_READONLY ) )
2661 {
2662 xBindingProps->addPropertyChangeListener( PROPERTY_READONLY, this );
2663 m_bBindingControlsRO = sal_True;
2664 }
2665 if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_RELEVANT ) )
2666 {
2667 xBindingProps->addPropertyChangeListener( PROPERTY_RELEVANT, this );
2668 m_bBindingControlsEnable = sal_True;
2669 }
2670 }
2671 }
2672 catch( const Exception& )
2673 {
2674 DBG_UNHANDLED_EXCEPTION();
2675 }
2676
2677 // propagate our new value
2678 transferExternalValueToControl( _rInstanceLock );
2679
2680 // if the binding is also a validator, use it, too. This is a constraint of the
2681 // com.sun.star.form.binding.ValidatableBindableFormComponent service
2682 if ( m_bSupportsValidation )
2683 {
2684 try
2685 {
2686 Reference< XValidator > xAsValidator( _rxBinding, UNO_QUERY );
2687 if ( xAsValidator.is() )
2688 setValidator( xAsValidator );
2689 }
2690 catch( const Exception& )
2691 {
2692 DBG_UNHANDLED_EXCEPTION();
2693 }
2694 }
2695 }
2696
2697 //--------------------------------------------------------------------
disconnectExternalValueBinding()2698 void OBoundControlModel::disconnectExternalValueBinding( )
2699 {
2700 try
2701 {
2702 // not listening at the binding anymore
2703 Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2704 if ( xModifiable.is() )
2705 xModifiable->removeModifyListener( this );
2706
2707 // remove as property change listener
2708 Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2709 if ( m_bBindingControlsRO )
2710 xBindingProps->removePropertyChangeListener( PROPERTY_READONLY, this );
2711 if ( m_bBindingControlsEnable )
2712 xBindingProps->removePropertyChangeListener( PROPERTY_RELEVANT, this );
2713 }
2714 catch( const Exception& )
2715 {
2716 OSL_ENSURE( sal_False, "OBoundControlModel::disconnectExternalValueBinding: caught an exception!" );
2717 }
2718
2719 // if the binding also acts as our validator, disconnect the validator, too
2720 if ( ( m_xExternalBinding == m_xValidator ) && m_xValidator.is() )
2721 disconnectValidator( );
2722
2723 // no binding anymore
2724 m_xExternalBinding.clear();
2725
2726 // be a load listener at our form, again. This was suspended while we had
2727 // an external value binding in place.
2728 doFormListening( true );
2729
2730 // re-connect to database column of the new parent
2731 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
2732 impl_connectDatabaseColumn_noNotify( false );
2733
2734 // tell the derivee
2735 onDisconnectedExternalValue();
2736 }
2737
2738 //--------------------------------------------------------------------
setValueBinding(const Reference<XValueBinding> & _rxBinding)2739 void SAL_CALL OBoundControlModel::setValueBinding( const Reference< XValueBinding >& _rxBinding ) throw (IncompatibleTypesException, RuntimeException)
2740 {
2741 OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::setValueBinding: How did you reach this method?" );
2742 // the interface for this method should not have been exposed if we do not
2743 // support binding to external data
2744
2745 if ( !impl_approveValueBinding_nolock( _rxBinding ) )
2746 {
2747 throw IncompatibleTypesException(
2748 FRM_RES_STRING( RID_STR_INCOMPATIBLE_TYPES ),
2749 *this
2750 );
2751 }
2752
2753 ControlModelLock aLock( *this );
2754
2755 // since a ValueBinding overrules any potentially active database binding, the change in a ValueBinding
2756 // might trigger a change in our BoundField.
2757 FieldChangeNotifier aBoundFieldNotifier( aLock );
2758
2759 // disconnect from the old binding
2760 if ( hasExternalValueBinding() )
2761 disconnectExternalValueBinding( );
2762
2763 // connect to the new binding
2764 if ( _rxBinding.is() )
2765 connectExternalValueBinding( _rxBinding, aLock );
2766 }
2767
2768 //--------------------------------------------------------------------
getValueBinding()2769 Reference< XValueBinding > SAL_CALL OBoundControlModel::getValueBinding( ) throw (RuntimeException)
2770 {
2771 ::osl::MutexGuard aGuard( m_aMutex );
2772 OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::getValueBinding: How did you reach this method?" );
2773 // the interface for this method should not have been exposed if we do not
2774 // support binding to external data
2775
2776 return m_xExternalBinding;
2777 }
2778
2779 //--------------------------------------------------------------------
modified(const EventObject & _rEvent)2780 void SAL_CALL OBoundControlModel::modified( const EventObject& _rEvent ) throw ( RuntimeException )
2781 {
2782 ControlModelLock aLock( *this );
2783
2784 OSL_PRECOND( hasExternalValueBinding(), "OBoundControlModel::modified: Where did this come from?" );
2785 if ( !m_bTransferingValue && ( m_xExternalBinding == _rEvent.Source ) && m_xExternalBinding.is() )
2786 {
2787 transferExternalValueToControl( aLock );
2788 }
2789 }
2790
2791 //--------------------------------------------------------------------
transferDbValueToControl()2792 void OBoundControlModel::transferDbValueToControl( )
2793 {
2794 try
2795 {
2796 setControlValue( translateDbColumnToControlValue(), eDbColumnBinding );
2797 }
2798 catch( const Exception& )
2799 {
2800 DBG_UNHANDLED_EXCEPTION();
2801 }
2802 }
2803
2804 //------------------------------------------------------------------------------
transferExternalValueToControl(ControlModelLock & _rInstanceLock)2805 void OBoundControlModel::transferExternalValueToControl( ControlModelLock& _rInstanceLock )
2806 {
2807 Reference< XValueBinding > xExternalBinding( m_xExternalBinding );
2808 Type aValueExchangeType( getExternalValueType() );
2809
2810 _rInstanceLock.release();
2811 // >>>>>>>> ----- UNSAFE ----- >>>>>>>>
2812 Any aExternalValue;
2813 try
2814 {
2815 aExternalValue = xExternalBinding->getValue( aValueExchangeType );
2816 }
2817 catch( const Exception& )
2818 {
2819 DBG_UNHANDLED_EXCEPTION();
2820 }
2821 // <<<<<<<< ----- UNSAFE ----- <<<<<<<<
2822 _rInstanceLock.acquire();
2823
2824 setControlValue( translateExternalValueToControlValue( aExternalValue ), eExternalBinding );
2825 }
2826
2827 //------------------------------------------------------------------------------
transferControlValueToExternal(ControlModelLock & _rInstanceLock)2828 void OBoundControlModel::transferControlValueToExternal( ControlModelLock& _rInstanceLock )
2829 {
2830 OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2831 "OBoundControlModel::transferControlValueToExternal: precondition not met!" );
2832
2833 if ( m_xExternalBinding.is() )
2834 {
2835 Any aExternalValue( translateControlValueToExternalValue() );
2836 m_bTransferingValue = sal_True;
2837
2838 _rInstanceLock.release();
2839 // >>>>>>>> ----- UNSAFE ----- >>>>>>>>
2840 try
2841 {
2842 m_xExternalBinding->setValue( aExternalValue );
2843 }
2844 catch( const Exception& )
2845 {
2846 DBG_UNHANDLED_EXCEPTION();
2847 }
2848 // <<<<<<<< ----- UNSAFE ----- <<<<<<<<
2849 _rInstanceLock.acquire();
2850
2851 m_bTransferingValue = sal_False;
2852 }
2853 }
2854
2855 // -----------------------------------------------------------------------------
getSupportedBindingTypes()2856 Sequence< Type > OBoundControlModel::getSupportedBindingTypes()
2857 {
2858 return Sequence< Type >( &m_aValuePropertyType, 1 );
2859 }
2860
2861 //-----------------------------------------------------------------------------
calculateExternalValueType()2862 void OBoundControlModel::calculateExternalValueType()
2863 {
2864 m_aExternalValueType = Type();
2865 if ( !m_xExternalBinding.is() )
2866 return;
2867
2868 Sequence< Type > aTypeCandidates( getSupportedBindingTypes() );
2869 for ( const Type* pTypeCandidate = aTypeCandidates.getConstArray();
2870 pTypeCandidate != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2871 ++pTypeCandidate
2872 )
2873 {
2874 if ( m_xExternalBinding->supportsType( *pTypeCandidate ) )
2875 {
2876 m_aExternalValueType = *pTypeCandidate;
2877 break;
2878 }
2879 }
2880 }
2881
2882 //-----------------------------------------------------------------------------
translateExternalValueToControlValue(const Any & _rExternalValue) const2883 Any OBoundControlModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
2884 {
2885 OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2886 "OBoundControlModel::translateExternalValueToControlValue: precondition not met!" );
2887
2888 Any aControlValue( _rExternalValue );
2889
2890 // if the external value is VOID, and our value property is not allowed to be VOID,
2891 // then default-construct a value
2892 if ( !aControlValue.hasValue() && !m_bValuePropertyMayBeVoid )
2893 aControlValue.setValue( NULL, m_aValuePropertyType );
2894
2895 // outta here
2896 return aControlValue;
2897 }
2898
2899 //------------------------------------------------------------------------------
translateControlValueToExternalValue() const2900 Any OBoundControlModel::translateControlValueToExternalValue( ) const
2901 {
2902 return getControlValue( );
2903 }
2904
2905 //------------------------------------------------------------------------------
translateControlValueToValidatableValue() const2906 Any OBoundControlModel::translateControlValueToValidatableValue( ) const
2907 {
2908 OSL_PRECOND( m_xValidator.is(), "OBoundControlModel::translateControlValueToValidatableValue: no validator, so why should I?" );
2909 if ( ( m_xValidator == m_xExternalBinding ) && m_xValidator.is() )
2910 return translateControlValueToExternalValue();
2911 return getControlValue();
2912 }
2913
2914 //------------------------------------------------------------------------------
getControlValue() const2915 Any OBoundControlModel::getControlValue( ) const
2916 {
2917 OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2918 "OBoundControlModel::getControlValue: invalid aggregate !" );
2919 OSL_PRECOND( m_sValuePropertyName.getLength() || ( m_nValuePropertyAggregateHandle != -1 ),
2920 "OBoundControlModel::getControlValue: please override if you have own value property handling!" );
2921
2922 // determine the current control value
2923 Any aControlValue;
2924 if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2925 {
2926 aControlValue = m_xAggregateFastSet->getFastPropertyValue( m_nValuePropertyAggregateHandle );
2927 }
2928 else if ( m_sValuePropertyName.getLength() && m_xAggregateSet.is() )
2929 {
2930 aControlValue = m_xAggregateSet->getPropertyValue( m_sValuePropertyName );
2931 }
2932
2933 return aControlValue;
2934 }
2935
2936 //--------------------------------------------------------------------
connectValidator(const Reference<XValidator> & _rxValidator)2937 void OBoundControlModel::connectValidator( const Reference< XValidator >& _rxValidator )
2938 {
2939 OSL_PRECOND( _rxValidator.is(), "OBoundControlModel::connectValidator: invalid validator instance!" );
2940 OSL_PRECOND( !hasValidator( ), "OBoundControlModel::connectValidator: precond not met (have a validator currently)!" );
2941
2942 m_xValidator = _rxValidator;
2943
2944 // add as value listener so we get notified when the value changes
2945 if ( m_xValidator.is() )
2946 {
2947 try
2948 {
2949 m_xValidator->addValidityConstraintListener( this );
2950 }
2951 catch( const RuntimeException& )
2952 {
2953 }
2954 }
2955
2956 onConnectedValidator( );
2957 }
2958
2959 //--------------------------------------------------------------------
disconnectValidator()2960 void OBoundControlModel::disconnectValidator( )
2961 {
2962 OSL_PRECOND( hasValidator( ), "OBoundControlModel::connectValidator: precond not met (don't have a validator currently)!" );
2963
2964 // add as value listener so we get notified when the value changes
2965 if ( m_xValidator.is() )
2966 {
2967 try
2968 {
2969 m_xValidator->removeValidityConstraintListener( this );
2970 }
2971 catch( const RuntimeException& )
2972 {
2973 }
2974 }
2975
2976 m_xValidator.clear();
2977
2978 onDisconnectedValidator( );
2979 }
2980
2981 //--------------------------------------------------------------------
setValidator(const Reference<XValidator> & _rxValidator)2982 void SAL_CALL OBoundControlModel::setValidator( const Reference< XValidator >& _rxValidator ) throw (VetoException,RuntimeException)
2983 {
2984 ::osl::ClearableMutexGuard aGuard( m_aMutex );
2985 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::setValidator: How did you reach this method?" );
2986 // the interface for this method should not have been exposed if we do not
2987 // support validation
2988
2989 // early out if the validator does not change
2990 if( _rxValidator == m_xValidator )
2991 return;
2992
2993 if ( m_xValidator.is() && ( m_xValidator == m_xExternalBinding ) )
2994 throw VetoException(
2995 FRM_RES_STRING( RID_STR_INVALID_VALIDATOR ),
2996 *this
2997 );
2998
2999 // disconnect from the old validator
3000 if ( hasValidator() )
3001 disconnectValidator( );
3002
3003 // connect to the new validator
3004 if ( _rxValidator.is() )
3005 connectValidator( _rxValidator );
3006 }
3007
3008 //--------------------------------------------------------------------
getValidator()3009 Reference< XValidator > SAL_CALL OBoundControlModel::getValidator( ) throw (RuntimeException)
3010 {
3011 ::osl::MutexGuard aGuard( m_aMutex );
3012 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::getValidator: How did you reach this method?" );
3013 // the interface for this method should not have been exposed if we do not
3014 // support validation
3015
3016 return m_xValidator;
3017 }
3018
3019 //--------------------------------------------------------------------
validityConstraintChanged(const EventObject &)3020 void SAL_CALL OBoundControlModel::validityConstraintChanged( const EventObject& /*Source*/ ) throw (RuntimeException)
3021 {
3022 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3023 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::validityConstraintChanged: How did you reach this method?" );
3024 // the interface for this method should not have been exposed if we do not
3025 // support validation
3026
3027 recheckValidity( false );
3028 }
3029
3030 //--------------------------------------------------------------------
isValid()3031 sal_Bool SAL_CALL OBoundControlModel::isValid( ) throw (RuntimeException)
3032 {
3033 return m_bIsCurrentValueValid;
3034 }
3035
3036 //--------------------------------------------------------------------
getCurrentFormComponentValue() const3037 ::com::sun::star::uno::Any OBoundControlModel::getCurrentFormComponentValue() const
3038 {
3039 if ( hasValidator() )
3040 return translateControlValueToValidatableValue();
3041 return getControlValue();
3042 }
3043
3044 //--------------------------------------------------------------------
getCurrentValue()3045 Any SAL_CALL OBoundControlModel::getCurrentValue( ) throw (RuntimeException)
3046 {
3047 ::osl::MutexGuard aGuard( m_aMutex );
3048 return getCurrentFormComponentValue();
3049 }
3050
3051 //--------------------------------------------------------------------
addFormComponentValidityListener(const Reference<validation::XFormComponentValidityListener> & Listener)3052 void SAL_CALL OBoundControlModel::addFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException)
3053 {
3054 if ( Listener.is() )
3055 m_aFormComponentListeners.addInterface( Listener );
3056 }
3057
3058 //--------------------------------------------------------------------
removeFormComponentValidityListener(const Reference<validation::XFormComponentValidityListener> & Listener)3059 void SAL_CALL OBoundControlModel::removeFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener ) throw (NullPointerException, RuntimeException)
3060 {
3061 if ( Listener.is() )
3062 m_aFormComponentListeners.removeInterface( Listener );
3063 }
3064
3065 //--------------------------------------------------------------------
recheckValidity(bool _bForceNotification)3066 void OBoundControlModel::recheckValidity( bool _bForceNotification )
3067 {
3068 try
3069 {
3070 sal_Bool bIsCurrentlyValid = sal_True;
3071 if ( hasValidator() )
3072 bIsCurrentlyValid = m_xValidator->isValid( translateControlValueToValidatableValue() );
3073
3074 if ( ( bIsCurrentlyValid != m_bIsCurrentValueValid ) || _bForceNotification )
3075 {
3076 m_bIsCurrentValueValid = bIsCurrentlyValid;
3077
3078 // release our mutex for the notifications
3079 MutexRelease aRelease( m_aMutex );
3080 m_aFormComponentListeners.notifyEach( &validation::XFormComponentValidityListener::componentValidityChanged, EventObject( *this ) );
3081 }
3082 }
3083 catch( const Exception& )
3084 {
3085 OSL_ENSURE( sal_False, "OBoundControlModel::recheckValidity: caught an exception!" );
3086 }
3087 }
3088
3089 //------------------------------------------------------------------------------
describeFixedProperties(Sequence<Property> & _rProps) const3090 void OBoundControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
3091 {
3092 BEGIN_DESCRIBE_PROPERTIES( 5, OControlModel )
3093 DECL_PROP1 ( CONTROLSOURCE, ::rtl::OUString, BOUND );
3094 DECL_IFACE_PROP3( BOUNDFIELD, XPropertySet, BOUND, READONLY, TRANSIENT );
3095 DECL_IFACE_PROP2( CONTROLLABEL, XPropertySet, BOUND, MAYBEVOID );
3096 DECL_PROP2 ( CONTROLSOURCEPROPERTY, ::rtl::OUString, READONLY, TRANSIENT );
3097 DECL_BOOL_PROP1 ( INPUT_REQUIRED, BOUND );
3098 END_DESCRIBE_PROPERTIES()
3099 }
3100
3101 // -----------------------------------------------------------------------------
3102
3103 //.........................................................................
3104 }
3105 //... namespace frm .......................................................
3106
3107