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 )
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()
212 {
213 return OImplementationIds::getImplementationId(getTypes());
214 }
215
216 //------------------------------------------------------------------------------
getTypes()217 Sequence<Type> SAL_CALL OControl::getTypes()
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)
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()
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()
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)
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)
310 {
311 if (m_xControl.is())
312 m_xControl->setContext(Context);
313 }
314
315 //------------------------------------------------------------------------------
getContext()316 Reference< XInterface > SAL_CALL OControl::getContext()
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)
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()
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)
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()
370 {
371 return m_xControl.is() ? m_xControl->getModel() : Reference<XControlModel>();
372 }
373
374 //------------------------------------------------------------------------------
getView()375 Reference<XView> SAL_CALL OControl::getView()
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)
382 {
383 if (m_xControl.is())
384 m_xControl->setDesignMode(bOn);
385 }
386
387 //------------------------------------------------------------------------------
isDesignMode()388 sal_Bool SAL_CALL OControl::isDesignMode()
389 {
390 return m_xControl.is() ? m_xControl->isDesignMode() : sal_True;
391 }
392
393 //------------------------------------------------------------------------------
isTransparent()394 sal_Bool SAL_CALL OControl::isTransparent()
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)
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()
447 {
448 return m_bLocked;
449 }
450
451 //------------------------------------------------------------------
setLock(sal_Bool _bLock)452 void SAL_CALL OBoundControl::setLock(sal_Bool _bLock)
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 )
482 {
483 return OControl::setModel( _rxModel );
484 }
485
486 //--------------------------------------------------------------------
disposing(const EventObject & Source)487 void SAL_CALL OBoundControl::disposing(const EventObject& Source)
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()
505 {
506 return OImplementationIds::getImplementationId(getTypes());
507 }
508
509 //------------------------------------------------------------------
getTypes()510 Sequence<Type> SAL_CALL OControlModel::getTypes()
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)
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()
715 {
716 return m_xParent;
717 }
718
719 //------------------------------------------------------------------------------
setParent(const Reference<XInterface> & _rxParent)720 void SAL_CALL OControlModel::setParent(const Reference< XInterface >& _rxParent)
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()
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)
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)
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()
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()
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)
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 {
845 osl::MutexGuard aGuard(m_aMutex);
846
847 // 1. Schreiben des UnoControls
848 Reference<stario::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
849 if ( !xMark.is() )
850 {
851 throw IOException(
852 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
853 static_cast< ::cppu::OWeakObject* >( this )
854 );
855 }
856
857 sal_Int32 nMark = xMark->createMark();
858 sal_Int32 nLen = 0;
859
860 _rxOutStream->writeLong(nLen);
861
862 writeAggregate( _rxOutStream );
863
864 // feststellen der Laenge
865 nLen = xMark->offsetToMark(nMark) - 4;
866 xMark->jumpToMark(nMark);
867 _rxOutStream->writeLong(nLen);
868 xMark->jumpToFurthest();
869 xMark->deleteMark(nMark);
870
871 // 2. Schreiben einer VersionsNummer
872 _rxOutStream->writeShort(0x0003);
873
874 // 3. Schreiben der allgemeinen Properties
875 ::comphelper::operator<<( _rxOutStream, m_aName);
876 _rxOutStream->writeShort(m_nTabIndex);
877 ::comphelper::operator<<( _rxOutStream, m_aTag); // 3. version
878
879 // !!! IMPORTANT NOTE !!!
880 // don't write any new members here : this wouldn't be compatible with older versions, as OControlModel
881 // is a base class which is called in derived classes "read" method. So if you increment the version
882 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
883 // in anything from data loss to crash.
884 // !!! EOIN !!!
885 }
886
887 //------------------------------------------------------------------------------
read(const Reference<stario::XObjectInputStream> & InStream)888 void OControlModel::read(const Reference<stario::XObjectInputStream>& InStream)
889 {
890 osl::MutexGuard aGuard(m_aMutex);
891
892 Reference<stario::XMarkableStream> xMark(InStream, UNO_QUERY);
893 if ( !xMark.is() )
894 {
895 throw IOException(
896 FRM_RES_STRING( RID_STR_INVALIDSTREAM ),
897 static_cast< ::cppu::OWeakObject* >( this )
898 );
899 }
900
901 // 1. Lesen des UnoControls
902 sal_Int32 nLen = InStream->readLong();
903 if (nLen)
904 {
905 sal_Int32 nMark = xMark->createMark();
906
907 try
908 {
909 readAggregate( InStream );
910 }
911 catch( const Exception& )
912 {
913 DBG_UNHANDLED_EXCEPTION();
914 }
915
916 xMark->jumpToMark(nMark);
917 InStream->skipBytes(nLen);
918 xMark->deleteMark(nMark);
919 }
920
921 // 2. Lesen des Versionsnummer
922 sal_uInt16 nVersion = InStream->readShort();
923
924 // 3. Lesen der allgemeinen Properties
925 ::comphelper::operator>>( InStream, m_aName);
926 m_nTabIndex = InStream->readShort();
927
928 if (nVersion > 0x0002)
929 ::comphelper::operator>>( InStream, m_aTag);
930
931 // we had a version where we wrote the help text
932 if (nVersion == 0x0004)
933 readHelpTextCompatibly(InStream);
934
935 DBG_ASSERT(nVersion < 5, "OControlModel::read : suspicious version number !");
936 // 4 was the version where we wrote the help text
937 // later versions shouldn't exist (see write for a detailed comment)
938 }
939
940 //------------------------------------------------------------------------------
getPropertyStateByHandle(sal_Int32 _nHandle)941 PropertyState OControlModel::getPropertyStateByHandle( sal_Int32 _nHandle )
942 {
943 // simply compare the current and the default value
944 Any aCurrentValue = getPropertyDefaultByHandle( _nHandle );
945 Any aDefaultValue; getFastPropertyValue( aDefaultValue, _nHandle );
946
947 sal_Bool bEqual = uno_type_equalData(
948 const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(),
949 const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(),
950 reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
951 reinterpret_cast< uno_ReleaseFunc >(cpp_release)
952 );
953 return bEqual ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
954 }
955
956 //------------------------------------------------------------------------------
setPropertyToDefaultByHandle(sal_Int32 _nHandle)957 void OControlModel::setPropertyToDefaultByHandle( sal_Int32 _nHandle)
958 {
959 Any aDefault = getPropertyDefaultByHandle( _nHandle );
960
961 Any aConvertedValue, aOldValue;
962 if ( convertFastPropertyValue( aConvertedValue, aOldValue, _nHandle, aDefault ) )
963 {
964 setFastPropertyValue_NoBroadcast( _nHandle, aConvertedValue );
965 // TODO: fire the property change
966 }
967 }
968
969 //------------------------------------------------------------------------------
getPropertyDefaultByHandle(sal_Int32 _nHandle) const970 Any OControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
971 {
972 Any aReturn;
973 switch ( _nHandle )
974 {
975 case PROPERTY_ID_NAME:
976 case PROPERTY_ID_TAG:
977 aReturn <<= ::rtl::OUString();
978 break;
979
980 case PROPERTY_ID_CLASSID:
981 aReturn <<= (sal_Int16)FormComponentType::CONTROL;
982 break;
983
984 case PROPERTY_ID_TABINDEX:
985 aReturn <<= (sal_Int16)FRM_DEFAULT_TABINDEX;
986 break;
987
988 case PROPERTY_ID_NATIVE_LOOK:
989 aReturn <<= (sal_Bool)sal_True;
990 break;
991 //added for exporting OCX control
992 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
993 aReturn <<= (sal_Int16)0;
994 break;
995 case PROPERTY_ID_OBJ_ID_IN_MSO:
996 aReturn <<= (sal_uInt16)INVALID_OBJ_ID_IN_MSO;
997 break;
998 default:
999 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1000 m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( _nHandle, aReturn );
1001 else
1002 OSL_ENSURE( false, "OControlModel::convertFastPropertyValue: unknown handle!" );
1003 }
1004 return aReturn;
1005 }
1006
1007 //------------------------------------------------------------------------------
getFastPropertyValue(Any & _rValue,sal_Int32 _nHandle) const1008 void OControlModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
1009 {
1010 switch ( _nHandle )
1011 {
1012 case PROPERTY_ID_NAME:
1013 _rValue <<= m_aName;
1014 break;
1015 case PROPERTY_ID_TAG:
1016 _rValue <<= m_aTag;
1017 break;
1018 case PROPERTY_ID_CLASSID:
1019 _rValue <<= m_nClassId;
1020 break;
1021 case PROPERTY_ID_TABINDEX:
1022 _rValue <<= m_nTabIndex;
1023 break;
1024 case PROPERTY_ID_NATIVE_LOOK:
1025 _rValue <<= (sal_Bool)m_bNativeLook;
1026 break;
1027 //added for exporting OCX control
1028 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
1029 _rValue <<= (sal_Int16)m_nControlTypeinMSO;
1030 break;
1031 case PROPERTY_ID_OBJ_ID_IN_MSO:
1032 _rValue <<= (sal_uInt16)m_nObjIDinMSO;
1033 break;
1034 default:
1035 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1036 m_aPropertyBagHelper.getDynamicFastPropertyValue( _nHandle, _rValue );
1037 else
1038 OPropertySetAggregationHelper::getFastPropertyValue( _rValue, _nHandle );
1039 break;
1040 }
1041 }
1042
1043 //------------------------------------------------------------------------------
convertFastPropertyValue(Any & _rConvertedValue,Any & _rOldValue,sal_Int32 _nHandle,const Any & _rValue)1044 sal_Bool OControlModel::convertFastPropertyValue(
1045 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
1046 {
1047 sal_Bool bModified(sal_False);
1048 switch (_nHandle)
1049 {
1050 case PROPERTY_ID_NAME:
1051 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aName);
1052 break;
1053 case PROPERTY_ID_TAG:
1054 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aTag);
1055 break;
1056 case PROPERTY_ID_TABINDEX:
1057 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nTabIndex);
1058 break;
1059 case PROPERTY_ID_NATIVE_LOOK:
1060 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bNativeLook);
1061 break;
1062 //added for exporting OCX control
1063 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
1064 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nControlTypeinMSO);
1065 break;
1066 case PROPERTY_ID_OBJ_ID_IN_MSO:
1067 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_nObjIDinMSO);
1068 break;
1069 default:
1070 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1071 bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( _nHandle, _rValue, _rConvertedValue, _rOldValue );
1072 else
1073 OSL_ENSURE( false, "OControlModel::convertFastPropertyValue: unknown handle!" );
1074 break;
1075 }
1076 return bModified;
1077 }
1078
1079 //------------------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle,const Any & _rValue)1080 void OControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
1081 {
1082 switch (_nHandle)
1083 {
1084 case PROPERTY_ID_NAME:
1085 DBG_ASSERT(_rValue.getValueType() == getCppuType((const ::rtl::OUString*)NULL),
1086 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1087 _rValue >>= m_aName;
1088 break;
1089 case PROPERTY_ID_TAG:
1090 DBG_ASSERT(_rValue.getValueType() == getCppuType((const ::rtl::OUString*)NULL),
1091 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1092 _rValue >>= m_aTag;
1093 break;
1094 case PROPERTY_ID_TABINDEX:
1095 DBG_ASSERT(_rValue.getValueType() == getCppuType((const sal_Int16*)NULL),
1096 "OControlModel::setFastPropertyValue_NoBroadcast : invalid type" );
1097 _rValue >>= m_nTabIndex;
1098 break;
1099 case PROPERTY_ID_NATIVE_LOOK:
1100 OSL_VERIFY( _rValue >>= m_bNativeLook );
1101 break;
1102 //added for exporting OCX control
1103 case PROPERTY_ID_CONTROL_TYPE_IN_MSO:
1104 OSL_VERIFY( _rValue >>= m_nControlTypeinMSO );
1105 break;
1106 case PROPERTY_ID_OBJ_ID_IN_MSO:
1107 OSL_VERIFY( _rValue >>= m_nObjIDinMSO );
1108 break;
1109 default:
1110 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( _nHandle ) )
1111 m_aPropertyBagHelper.setDynamicFastPropertyValue( _nHandle, _rValue );
1112 else
1113 OSL_ENSURE( false, "OControlModel::setFastPropertyValue_NoBroadcast: unknown handle!" );
1114 break;
1115 }
1116 }
1117
1118 //------------------------------------------------------------------------------
describeFixedProperties(Sequence<Property> & _rProps) const1119 void OControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
1120 {
1121 //BEGIN_DESCRIBE_BASE_PROPERTIES( 4 )
1122 BEGIN_DESCRIBE_BASE_PROPERTIES( 6 )
1123 DECL_PROP2 (CLASSID, sal_Int16, READONLY, TRANSIENT);
1124 DECL_PROP1 (NAME, ::rtl::OUString, BOUND);
1125 DECL_BOOL_PROP2 (NATIVE_LOOK, BOUND, TRANSIENT);
1126 DECL_PROP1 (TAG, ::rtl::OUString, BOUND);
1127 DECL_PROP1 (CONTROL_TYPE_IN_MSO,sal_Int16, BOUND);
1128 DECL_PROP1 (OBJ_ID_IN_MSO,sal_uInt16, BOUND);
1129 END_DESCRIBE_PROPERTIES()
1130 }
1131
1132 //------------------------------------------------------------------------------
describeAggregateProperties(Sequence<Property> & _rAggregateProps) const1133 void OControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ _rAggregateProps ) const
1134 {
1135 if ( m_xAggregateSet.is() )
1136 {
1137 Reference< XPropertySetInfo > xPSI( m_xAggregateSet->getPropertySetInfo() );
1138 if ( xPSI.is() )
1139 _rAggregateProps = xPSI->getProperties();
1140 }
1141 }
1142
1143 //------------------------------------------------------------------------------
getMutex()1144 ::osl::Mutex& OControlModel::getMutex()
1145 {
1146 return m_aMutex;
1147 }
1148
1149 //------------------------------------------------------------------------------
describeFixedAndAggregateProperties(Sequence<Property> & _out_rFixedProperties,Sequence<Property> & _out_rAggregateProperties) const1150 void OControlModel::describeFixedAndAggregateProperties( Sequence< Property >& _out_rFixedProperties, Sequence< Property >& _out_rAggregateProperties ) const
1151 {
1152 describeFixedProperties( _out_rFixedProperties );
1153 describeAggregateProperties( _out_rAggregateProperties );
1154 }
1155
1156 //------------------------------------------------------------------------------
getPropertiesInterface()1157 Reference< XMultiPropertySet > OControlModel::getPropertiesInterface()
1158 {
1159 return Reference< XMultiPropertySet >( *this, UNO_QUERY );
1160 }
1161
1162 //------------------------------------------------------------------------------
getPropertySetInfo()1163 Reference< XPropertySetInfo> SAL_CALL OControlModel::getPropertySetInfo()
1164 {
1165 return createPropertySetInfo( getInfoHelper() );
1166 }
1167
1168 //------------------------------------------------------------------------------
getInfoHelper()1169 ::cppu::IPropertyArrayHelper& OControlModel::getInfoHelper()
1170 {
1171 return m_aPropertyBagHelper.getInfoHelper();
1172 }
1173
1174 //--------------------------------------------------------------------
addProperty(const::rtl::OUString & _rName,::sal_Int16 _nAttributes,const Any & _rInitialValue)1175 void SAL_CALL OControlModel::addProperty( const ::rtl::OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue )
1176 {
1177 m_aPropertyBagHelper.addProperty( _rName, _nAttributes, _rInitialValue );
1178 }
1179
1180 //--------------------------------------------------------------------
removeProperty(const::rtl::OUString & _rName)1181 void SAL_CALL OControlModel::removeProperty( const ::rtl::OUString& _rName )
1182 {
1183 m_aPropertyBagHelper.removeProperty( _rName );
1184 }
1185
1186 //--------------------------------------------------------------------
getPropertyValues()1187 Sequence< PropertyValue > SAL_CALL OControlModel::getPropertyValues()
1188 {
1189 return m_aPropertyBagHelper.getPropertyValues();
1190 }
1191
1192 //--------------------------------------------------------------------
setPropertyValues(const Sequence<PropertyValue> & _rProps)1193 void SAL_CALL OControlModel::setPropertyValues( const Sequence< PropertyValue >& _rProps )
1194 {
1195 m_aPropertyBagHelper.setPropertyValues( _rProps );
1196 }
1197
1198 //--------------------------------------------------------------------
lockInstance(LockAccess)1199 void OControlModel::lockInstance( LockAccess )
1200 {
1201 m_aMutex.acquire();
1202 osl_incrementInterlockedCount( &m_lockCount );
1203 }
1204
1205 //--------------------------------------------------------------------
unlockInstance(LockAccess)1206 oslInterlockedCount OControlModel::unlockInstance( LockAccess )
1207 {
1208 OSL_ENSURE( m_lockCount > 0, "OControlModel::unlockInstance: not locked!" );
1209 oslInterlockedCount lockCount = osl_decrementInterlockedCount( &m_lockCount );
1210 m_aMutex.release();
1211 return lockCount;
1212 }
1213
1214 //--------------------------------------------------------------------
firePropertyChanges(const Sequence<sal_Int32> & _rHandles,const Sequence<Any> & _rOldValues,const Sequence<Any> & _rNewValues,LockAccess)1215 void OControlModel::firePropertyChanges( const Sequence< sal_Int32 >& _rHandles, const Sequence< Any >& _rOldValues,
1216 const Sequence< Any >& _rNewValues, LockAccess )
1217 {
1218 OPropertySetHelper::fire(
1219 const_cast< Sequence< sal_Int32 >& >( _rHandles ).getArray(),
1220 _rNewValues.getConstArray(),
1221 _rOldValues.getConstArray(),
1222 _rHandles.getLength(),
1223 sal_False
1224 );
1225 }
1226
1227 //==================================================================
1228 //= OBoundControlModel
1229 //==================================================================
1230 DBG_NAME(frm_OBoundControlModel);
1231 //------------------------------------------------------------------
queryAggregation(const Type & _rType)1232 Any SAL_CALL OBoundControlModel::queryAggregation( const Type& _rType )
1233 {
1234 Any aReturn( OControlModel::queryAggregation(_rType) );
1235 if (!aReturn.hasValue())
1236 {
1237 aReturn = OBoundControlModel_BASE1::queryInterface(_rType);
1238
1239 if ( !aReturn.hasValue() && m_bCommitable )
1240 aReturn = OBoundControlModel_COMMITTING::queryInterface( _rType );
1241
1242 if ( !aReturn.hasValue() && m_bSupportsExternalBinding )
1243 aReturn = OBoundControlModel_BINDING::queryInterface( _rType );
1244
1245 if ( !aReturn.hasValue() && m_bSupportsValidation )
1246 aReturn = OBoundControlModel_VALIDATION::queryInterface( _rType );
1247 }
1248
1249 return aReturn;
1250 }
1251
1252 //------------------------------------------------------------------
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)1253 OBoundControlModel::OBoundControlModel(
1254 const Reference< XMultiServiceFactory>& _rxFactory,
1255 const ::rtl::OUString& _rUnoControlModelTypeName, const ::rtl::OUString& _rDefault,
1256 const sal_Bool _bCommitable, const sal_Bool _bSupportExternalBinding, const sal_Bool _bSupportsValidation )
1257 :OControlModel( _rxFactory, _rUnoControlModelTypeName, _rDefault, sal_False )
1258 ,OPropertyChangeListener( m_aMutex )
1259 ,m_xField()
1260 ,m_xAmbientForm()
1261 ,m_nValuePropertyAggregateHandle( -1 )
1262 ,m_nFieldType( DataType::OTHER )
1263 ,m_bValuePropertyMayBeVoid( false )
1264 ,m_aResetHelper( *this, m_aMutex )
1265 ,m_aUpdateListeners(m_aMutex)
1266 ,m_aFormComponentListeners( m_aMutex )
1267 ,m_bInputRequired( sal_True )
1268 ,m_pAggPropMultiplexer( NULL )
1269 ,m_bFormListening( false )
1270 ,m_bLoaded(sal_False)
1271 ,m_bRequired(sal_False)
1272 ,m_bCommitable(_bCommitable)
1273 ,m_bSupportsExternalBinding( _bSupportExternalBinding )
1274 ,m_bSupportsValidation( _bSupportsValidation )
1275 ,m_bForwardValueChanges(sal_True)
1276 ,m_bTransferingValue( sal_False )
1277 ,m_bIsCurrentValueValid( sal_True )
1278 ,m_bBindingControlsRO( sal_False )
1279 ,m_bBindingControlsEnable( sal_False )
1280 ,m_eControlValueChangeInstigator( eOther )
1281 ,m_aLabelServiceName(FRM_SUN_COMPONENT_FIXEDTEXT)
1282 {
1283 DBG_CTOR(frm_OBoundControlModel, NULL);
1284
1285 // start property listening at the aggregate
1286 implInitAggMultiplexer( );
1287 }
1288
1289 //------------------------------------------------------------------
OBoundControlModel(const OBoundControlModel * _pOriginal,const Reference<XMultiServiceFactory> & _rxFactory)1290 OBoundControlModel::OBoundControlModel(
1291 const OBoundControlModel* _pOriginal, const Reference< XMultiServiceFactory>& _rxFactory )
1292 :OControlModel( _pOriginal, _rxFactory, sal_True, sal_False )
1293 ,OPropertyChangeListener( m_aMutex )
1294 ,m_xField()
1295 ,m_xAmbientForm()
1296 ,m_nValuePropertyAggregateHandle( _pOriginal->m_nValuePropertyAggregateHandle )
1297 ,m_nFieldType( DataType::OTHER )
1298 ,m_bValuePropertyMayBeVoid( _pOriginal->m_bValuePropertyMayBeVoid )
1299 ,m_aResetHelper( *this, m_aMutex )
1300 ,m_aUpdateListeners( m_aMutex )
1301 ,m_aFormComponentListeners( m_aMutex )
1302 ,m_xValidator( _pOriginal->m_xValidator )
1303 ,m_bInputRequired( sal_True )
1304 ,m_pAggPropMultiplexer( NULL )
1305 ,m_bFormListening( false )
1306 ,m_bLoaded( sal_False )
1307 ,m_bRequired( sal_False )
1308 ,m_bCommitable( _pOriginal->m_bCommitable )
1309 ,m_bSupportsExternalBinding( _pOriginal->m_bSupportsExternalBinding )
1310 ,m_bSupportsValidation( _pOriginal->m_bSupportsValidation )
1311 ,m_bForwardValueChanges( sal_True )
1312 ,m_bTransferingValue( sal_False )
1313 ,m_bIsCurrentValueValid( _pOriginal->m_bIsCurrentValueValid )
1314 ,m_bBindingControlsRO( sal_False )
1315 ,m_bBindingControlsEnable( sal_False )
1316 ,m_eControlValueChangeInstigator( eOther )
1317 {
1318 DBG_CTOR(frm_OBoundControlModel, NULL);
1319
1320 // start property listening at the aggregate
1321 implInitAggMultiplexer( );
1322
1323 m_aLabelServiceName = _pOriginal->m_aLabelServiceName;
1324 m_sValuePropertyName = _pOriginal->m_sValuePropertyName;
1325 m_nValuePropertyAggregateHandle = _pOriginal->m_nValuePropertyAggregateHandle;
1326 m_bValuePropertyMayBeVoid = _pOriginal->m_bValuePropertyMayBeVoid;
1327 m_aValuePropertyType = _pOriginal->m_aValuePropertyType;
1328 m_aControlSource = _pOriginal->m_aControlSource;
1329 m_bInputRequired = _pOriginal->m_bInputRequired;
1330 // m_xLabelControl, though being a property, is not to be cloned, not even the reference will be transferred.
1331 // (the former should be clear - a clone of the object we're only referencing does not make sense)
1332 // (the second would violate the restriction for label controls that they're part of the
1333 // same form component hierarchy - we ourself are no part, yet, so we can't have a label control)
1334
1335 // start listening for changes at the value property
1336 implInitValuePropertyListening( );
1337 }
1338
1339 //------------------------------------------------------------------
~OBoundControlModel()1340 OBoundControlModel::~OBoundControlModel()
1341 {
1342 if ( !OComponentHelper::rBHelper.bDisposed )
1343 {
1344 acquire();
1345 dispose();
1346 }
1347
1348 doResetDelegator( );
1349
1350 OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::~OBoundControlModel: what about my property multiplexer?" );
1351 if ( m_pAggPropMultiplexer )
1352 {
1353 m_pAggPropMultiplexer->dispose();
1354 m_pAggPropMultiplexer->release();
1355 m_pAggPropMultiplexer = NULL;
1356 }
1357
1358 DBG_DTOR(frm_OBoundControlModel, NULL);
1359 }
1360
1361 //------------------------------------------------------------------
clonedFrom(const OControlModel * _pOriginal)1362 void OBoundControlModel::clonedFrom( const OControlModel* _pOriginal )
1363 {
1364 const OBoundControlModel* pBoundOriginal = static_cast< const OBoundControlModel* >( _pOriginal );
1365 // the value binding can be handled as if somebody called setValueBinding here
1366 // By definition, bindings can be share between bindables
1367 if ( pBoundOriginal && pBoundOriginal->m_xExternalBinding.is() )
1368 {
1369 try
1370 {
1371 setValueBinding( pBoundOriginal->m_xExternalBinding );
1372 }
1373 catch( const Exception& )
1374 {
1375 DBG_UNHANDLED_EXCEPTION();
1376 }
1377 }
1378 }
1379
1380 //-----------------------------------------------------------------------------
implInitAggMultiplexer()1381 void OBoundControlModel::implInitAggMultiplexer( )
1382 {
1383 increment( m_refCount );
1384 if ( m_xAggregateSet.is() )
1385 {
1386 m_pAggPropMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet, sal_False );
1387 m_pAggPropMultiplexer->acquire();
1388 }
1389 decrement( m_refCount );
1390
1391 doSetDelegator();
1392 }
1393
1394 //-----------------------------------------------------------------------------
implInitValuePropertyListening() const1395 void OBoundControlModel::implInitValuePropertyListening( ) const
1396 {
1397 // start listening for changes at the value property
1398 // There are three pre-requisites for this to be done:
1399 // 1. We support external value bindings. In this case, the changes in the control value need to
1400 // be propagated to the external binding immediately when they happen
1401 // 2. We support external validation. In this case, we need to listen for changes in the value
1402 // property, since we need to revalidate then.
1403 // 3. We are not committable. In this case, changes in the control value need to be propagated
1404 // to the database column immediately when they happen.
1405 if ( m_bSupportsExternalBinding || m_bSupportsValidation || !m_bCommitable )
1406 {
1407 OSL_ENSURE( m_pAggPropMultiplexer, "OBoundControlModel::implInitValuePropertyListening: no multiplexer!" );
1408 if ( m_pAggPropMultiplexer && m_sValuePropertyName.getLength() )
1409 m_pAggPropMultiplexer->addProperty( m_sValuePropertyName );
1410 }
1411 }
1412
1413 //-----------------------------------------------------------------------------
initOwnValueProperty(const::rtl::OUString & i_rValuePropertyName)1414 void OBoundControlModel::initOwnValueProperty( const ::rtl::OUString& i_rValuePropertyName )
1415 {
1416 OSL_PRECOND( !m_sValuePropertyName.getLength() && -1 == m_nValuePropertyAggregateHandle,
1417 "OBoundControlModel::initOwnValueProperty: value property is already initialized!" );
1418 OSL_ENSURE( i_rValuePropertyName.getLength(), "OBoundControlModel::initOwnValueProperty: invalid property name!" );
1419 m_sValuePropertyName = i_rValuePropertyName;
1420 }
1421
1422 //-----------------------------------------------------------------------------
initValueProperty(const::rtl::OUString & _rValuePropertyName,sal_Int32 _nValuePropertyExternalHandle)1423 void OBoundControlModel::initValueProperty( const ::rtl::OUString& _rValuePropertyName, sal_Int32 _nValuePropertyExternalHandle )
1424 {
1425 OSL_PRECOND( !m_sValuePropertyName.getLength() && -1 == m_nValuePropertyAggregateHandle,
1426 "OBoundControlModel::initValueProperty: value property is already initialized!" );
1427 OSL_ENSURE( _rValuePropertyName.getLength(), "OBoundControlModel::initValueProperty: invalid property name!" );
1428 OSL_ENSURE( _nValuePropertyExternalHandle != -1, "OBoundControlModel::initValueProperty: invalid property handle!" );
1429
1430 m_sValuePropertyName = _rValuePropertyName;
1431 m_nValuePropertyAggregateHandle = getOriginalHandle( _nValuePropertyExternalHandle );
1432 OSL_ENSURE( m_nValuePropertyAggregateHandle != -1, "OBoundControlModel::initValueProperty: unable to find the original handle!" );
1433
1434 if ( m_nValuePropertyAggregateHandle != -1 )
1435 {
1436 Reference< XPropertySetInfo > xPropInfo( m_xAggregateSet->getPropertySetInfo(), UNO_SET_THROW );
1437 Property aValuePropDesc = xPropInfo->getPropertyByName( m_sValuePropertyName );
1438 m_aValuePropertyType = aValuePropDesc.Type;
1439 m_bValuePropertyMayBeVoid = ( aValuePropDesc.Attributes & PropertyAttribute::MAYBEVOID ) != 0;
1440 }
1441
1442 // start listening for changes at the value property
1443 implInitValuePropertyListening( );
1444 }
1445
1446 //-----------------------------------------------------------------------------
suspendValueListening()1447 void OBoundControlModel::suspendValueListening( )
1448 {
1449 OSL_PRECOND( m_sValuePropertyName.getLength(), "OBoundControlModel::suspendValueListening: don't have a value property!" );
1450 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::suspendValueListening: I *am* not listening!" );
1451
1452 if ( m_pAggPropMultiplexer )
1453 m_pAggPropMultiplexer->lock();
1454 }
1455
1456 //-----------------------------------------------------------------------------
resumeValueListening()1457 void OBoundControlModel::resumeValueListening( )
1458 {
1459 OSL_PRECOND( m_sValuePropertyName.getLength(), "OBoundControlModel::resumeValueListening: don't have a value property!" );
1460 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::resumeValueListening: I *am* not listening at all!" );
1461 OSL_PRECOND( !m_pAggPropMultiplexer || m_pAggPropMultiplexer->locked(), "OBoundControlModel::resumeValueListening: listening not suspended currently!" );
1462
1463 if ( m_pAggPropMultiplexer )
1464 m_pAggPropMultiplexer->unlock();
1465 }
1466
1467 //-----------------------------------------------------------------------------
_getTypes()1468 Sequence< Type > OBoundControlModel::_getTypes()
1469 {
1470 TypeBag aTypes(
1471 OControlModel::_getTypes(),
1472 OBoundControlModel_BASE1::getTypes()
1473 );
1474
1475 if ( m_bCommitable )
1476 aTypes.addTypes( OBoundControlModel_COMMITTING::getTypes() );
1477
1478 if ( m_bSupportsExternalBinding )
1479 aTypes.addTypes( OBoundControlModel_BINDING::getTypes() );
1480
1481 if ( m_bSupportsValidation )
1482 aTypes.addTypes( OBoundControlModel_VALIDATION::getTypes() );
1483
1484 return aTypes.getTypes();
1485 }
1486
1487 // OComponentHelper
1488 //-----------------------------------------------------------------------------
disposing()1489 void OBoundControlModel::disposing()
1490 {
1491 OControlModel::disposing();
1492
1493 ::osl::ClearableMutexGuard aGuard(m_aMutex);
1494
1495 if ( m_pAggPropMultiplexer )
1496 m_pAggPropMultiplexer->dispose();
1497
1498 // notify all our listeners
1499 com::sun::star::lang::EventObject aEvt( static_cast< XWeak* >( this ) );
1500 m_aUpdateListeners.disposeAndClear( aEvt );
1501 m_aResetHelper.disposing();
1502
1503 // disconnect from our database column
1504 // TODO: could we replace the following 5 lines with a call to impl_disconnectDatabaseColumn_noNotify?
1505 // The only more thing which it does is calling onDisconnectedDbColumn - could this
1506 // cause trouble? At least when we continue to call OControlModel::disposing before, it *may*.
1507 if ( hasField() )
1508 {
1509 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
1510 resetField();
1511 }
1512 m_xCursor = NULL;
1513
1514 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1515 if ( xComp.is() )
1516 xComp->removeEventListener(static_cast< XEventListener* >( static_cast< XPropertyChangeListener* >( this ) ) );
1517
1518 // disconnect from our external value binding
1519 if ( hasExternalValueBinding() )
1520 disconnectExternalValueBinding();
1521
1522 // dito for the validator
1523 if ( hasValidator() )
1524 disconnectValidator( );
1525 }
1526
1527 //------------------------------------------------------------------------------
onValuePropertyChange(ControlModelLock & i_rControLock)1528 void OBoundControlModel::onValuePropertyChange( ControlModelLock& i_rControLock )
1529 {
1530 if ( hasExternalValueBinding() )
1531 { // the control value changed, while we have an external value binding
1532 // -> forward the value to it
1533 if ( m_eControlValueChangeInstigator != eExternalBinding )
1534 transferControlValueToExternal( i_rControLock );
1535 }
1536 else if ( !m_bCommitable && m_xColumnUpdate.is() )
1537 { // the control value changed, while we are bound to a database column,
1538 // but not committable (which means changes in the control have to be reflected to
1539 // the underlying database column immediately)
1540 // -> forward the value to the database column
1541 if ( m_eControlValueChangeInstigator != eDbColumnBinding )
1542 commitControlValueToDbColumn( false );
1543 }
1544
1545 // validate the new value
1546 if ( m_bSupportsValidation )
1547 recheckValidity( true );
1548 }
1549
1550 //------------------------------------------------------------------------------
_propertyChanged(const PropertyChangeEvent & _rEvt)1551 void OBoundControlModel::_propertyChanged( const PropertyChangeEvent& _rEvt )
1552 {
1553 ControlModelLock aLock( *this );
1554
1555 OSL_ENSURE( _rEvt.PropertyName == m_sValuePropertyName,
1556 "OBoundControlModel::_propertyChanged: where did this come from (1)?" );
1557 OSL_ENSURE( m_pAggPropMultiplexer && !m_pAggPropMultiplexer->locked(),
1558 "OBoundControlModel::_propertyChanged: where did this come from (2)?" );
1559
1560 if ( _rEvt.PropertyName == m_sValuePropertyName )
1561 {
1562 onValuePropertyChange( aLock );
1563 }
1564 }
1565
1566 //------------------------------------------------------------------------------
startAggregatePropertyListening(const::rtl::OUString & _rPropertyName)1567 void OBoundControlModel::startAggregatePropertyListening( const ::rtl::OUString& _rPropertyName )
1568 {
1569 OSL_PRECOND( m_pAggPropMultiplexer, "OBoundControlModel::startAggregatePropertyListening: no multiplexer!" );
1570 OSL_ENSURE( _rPropertyName.getLength(), "OBoundControlModel::startAggregatePropertyListening: invalid property name!" );
1571
1572 if ( m_pAggPropMultiplexer && _rPropertyName.getLength() )
1573 {
1574 m_pAggPropMultiplexer->addProperty( _rPropertyName );
1575 }
1576 }
1577
1578 //------------------------------------------------------------------------------
doFormListening(const bool _bStart)1579 void OBoundControlModel::doFormListening( const bool _bStart )
1580 {
1581 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::doFormListening: external value binding should overrule the database binding!" );
1582
1583 if ( isFormListening() == _bStart )
1584 return;
1585
1586 if ( m_xAmbientForm.is() )
1587 _bStart ? m_xAmbientForm->addLoadListener( this ) : m_xAmbientForm->removeLoadListener( this );
1588
1589 Reference< XLoadable > xParentLoadable( getParent(), UNO_QUERY );
1590 if ( getParent().is() && !xParentLoadable.is() )
1591 {
1592 // if our parent does not directly support the XLoadable interface, then it might support the
1593 // XRowSetSupplier/XRowSetChangeBroadcaster interfaces. In this case we have to listen for changes
1594 // broadcasted by the latter.
1595 Reference< XRowSetChangeBroadcaster > xRowSetBroadcaster( getParent(), UNO_QUERY );
1596 if ( xRowSetBroadcaster.is() )
1597 _bStart ? xRowSetBroadcaster->addRowSetChangeListener( this ) : xRowSetBroadcaster->removeRowSetChangeListener( this );
1598 }
1599
1600 m_bFormListening = _bStart && m_xAmbientForm.is();
1601 }
1602
1603 // XChild
1604 //------------------------------------------------------------------------------
setParent(const Reference<XInterface> & _rxParent)1605 void SAL_CALL OBoundControlModel::setParent(const Reference<XInterface>& _rxParent)
1606 {
1607 ControlModelLock aLock( *this );
1608 FieldChangeNotifier aBoundFieldNotifier( aLock );
1609
1610 if ( getParent() == _rxParent )
1611 return;
1612
1613 // disconnect from database column (which is controlled by parent, directly or indirectly)
1614 if ( hasField() )
1615 impl_disconnectDatabaseColumn_noNotify();
1616
1617 // log off old listeners
1618 if ( isFormListening() )
1619 doFormListening( false );
1620
1621 // actually set the new parent
1622 OControlModel::setParent( _rxParent );
1623
1624 // a new parent means a new ambient form
1625 impl_determineAmbientForm_nothrow();
1626
1627 if ( !hasExternalValueBinding() )
1628 {
1629 // log on new listeners
1630 doFormListening( true );
1631
1632 // re-connect to database column of the new parent
1633 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
1634 impl_connectDatabaseColumn_noNotify( false );
1635 }
1636 }
1637
1638 // XEventListener
1639 //------------------------------------------------------------------------------
disposing(const com::sun::star::lang::EventObject & _rEvent)1640 void SAL_CALL OBoundControlModel::disposing(const com::sun::star::lang::EventObject& _rEvent)
1641 {
1642 ControlModelLock aLock( *this );
1643
1644 if ( _rEvent.Source == getField() )
1645 {
1646 resetField();
1647 }
1648 else if ( _rEvent.Source == m_xLabelControl )
1649 {
1650 Reference<XPropertySet> xOldValue = m_xLabelControl;
1651 m_xLabelControl = NULL;
1652
1653 // fire a propertyChanged (when we leave aLock's scope)
1654 aLock.addPropertyNotification( PROPERTY_ID_CONTROLLABEL, makeAny( xOldValue ), makeAny( m_xLabelControl ) );
1655 }
1656 else if ( _rEvent.Source == m_xExternalBinding )
1657 { // *first* check for the external binding
1658 disconnectExternalValueBinding( );
1659 }
1660 else if ( _rEvent.Source == m_xValidator )
1661 { // *then* check for the validator. Reason is that bindings may also act as validator at the same
1662 // time, in this case, the validator is automatically revoked when the binding is revoked
1663 disconnectValidator( );
1664 }
1665 else
1666 OControlModel::disposing(_rEvent);
1667 }
1668
1669 // XServiceInfo
1670 //------------------------------------------------------------------------------
getSupportedServiceNames()1671 StringSequence SAL_CALL OBoundControlModel::getSupportedServiceNames()
1672 {
1673 return ::comphelper::concatSequences(
1674 getAggregateServiceNames(),
1675 getSupportedServiceNames_Static()
1676 );
1677 }
1678
1679 //------------------------------------------------------------------------------
getSupportedServiceNames_Static()1680 Sequence< ::rtl::OUString > SAL_CALL OBoundControlModel::getSupportedServiceNames_Static()
1681 {
1682 Sequence< ::rtl::OUString > aOwnServiceNames( 1 );
1683 aOwnServiceNames[ 0 ] = ::rtl::OUString::createFromAscii( "com.sun.star.form.DataAwareControlModel" );
1684
1685 return ::comphelper::concatSequences(
1686 OControlModel::getSupportedServiceNames_Static(),
1687 aOwnServiceNames
1688 );
1689 }
1690
1691 // XPersist
1692 //------------------------------------------------------------------------------
write(const Reference<stario::XObjectOutputStream> & _rxOutStream)1693 void SAL_CALL OBoundControlModel::write( const Reference<stario::XObjectOutputStream>& _rxOutStream )
1694 {
1695 OControlModel::write(_rxOutStream);
1696
1697 osl::MutexGuard aGuard(m_aMutex);
1698
1699 // Version
1700 _rxOutStream->writeShort(0x0002);
1701
1702 // Controlsource
1703 ::comphelper::operator<<( _rxOutStream, m_aControlSource);
1704
1705 // !!! IMPORTANT NOTE !!!
1706 // don't write any new members here : this wouldn't be compatible with older versions, as OBoundControlModel
1707 // is a base class which is called in derived classes "read" method. So if you increment the version
1708 // and write new stuff, older office versions will read this in the _derived_ classes, which may result
1709 // in anything from data loss to crash.
1710 // (use writeCommonProperties instead, this is called in derived classes write-method)
1711 // !!! EOIN !!!
1712 // FS - 68876 - 28.09.1999
1713 }
1714
1715 //------------------------------------------------------------------------------
defaultCommonProperties()1716 void OBoundControlModel::defaultCommonProperties()
1717 {
1718 Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1719 if (xComp.is())
1720 xComp->removeEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1721 m_xLabelControl = NULL;
1722 }
1723
1724 //------------------------------------------------------------------------------
readCommonProperties(const Reference<stario::XObjectInputStream> & _rxInStream)1725 void OBoundControlModel::readCommonProperties(const Reference<stario::XObjectInputStream>& _rxInStream)
1726 {
1727 sal_Int32 nLen = _rxInStream->readLong();
1728
1729 Reference<stario::XMarkableStream> xMark(_rxInStream, UNO_QUERY);
1730 DBG_ASSERT(xMark.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !");
1731 sal_Int32 nMark = xMark->createMark();
1732
1733 // read the reference to the label control
1734 Reference<stario::XPersistObject> xPersist;
1735 sal_Int32 nUsedFlag;
1736 nUsedFlag = _rxInStream->readLong();
1737 if (nUsedFlag)
1738 xPersist = _rxInStream->readObject();
1739 m_xLabelControl = m_xLabelControl.query( xPersist );
1740 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1741 if (xComp.is())
1742 xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1743
1744 // read any other new common properties here
1745
1746 // skip the remaining bytes
1747 xMark->jumpToMark(nMark);
1748 _rxInStream->skipBytes(nLen);
1749 xMark->deleteMark(nMark);
1750 }
1751
1752 //------------------------------------------------------------------------------
writeCommonProperties(const Reference<stario::XObjectOutputStream> & _rxOutStream)1753 void OBoundControlModel::writeCommonProperties(const Reference<stario::XObjectOutputStream>& _rxOutStream)
1754 {
1755 Reference<stario::XMarkableStream> xMark(_rxOutStream, UNO_QUERY);
1756 DBG_ASSERT(xMark.is(), "OBoundControlModel::writeCommonProperties : can only work with markable streams !");
1757 sal_Int32 nMark = xMark->createMark();
1758
1759 // a placeholder where we will write the overall length (later in this method)
1760 sal_Int32 nLen = 0;
1761 _rxOutStream->writeLong(nLen);
1762
1763 // write the reference to the label control
1764 Reference<stario::XPersistObject> xPersist(m_xLabelControl, UNO_QUERY);
1765 sal_Int32 nUsedFlag = 0;
1766 if (xPersist.is())
1767 nUsedFlag = 1;
1768 _rxOutStream->writeLong(nUsedFlag);
1769 if (xPersist.is())
1770 _rxOutStream->writeObject(xPersist);
1771
1772 // write any other new common properties here
1773
1774 // write the correct length at the beginning of the block
1775 nLen = xMark->offsetToMark(nMark) - sizeof(nLen);
1776 xMark->jumpToMark(nMark);
1777 _rxOutStream->writeLong(nLen);
1778 xMark->jumpToFurthest();
1779 xMark->deleteMark(nMark);
1780 }
1781
1782 //------------------------------------------------------------------------------
read(const Reference<stario::XObjectInputStream> & _rxInStream)1783 void SAL_CALL OBoundControlModel::read( const Reference< stario::XObjectInputStream >& _rxInStream )
1784 {
1785 OControlModel::read(_rxInStream);
1786
1787 osl::MutexGuard aGuard(m_aMutex);
1788 sal_uInt16 nVersion = _rxInStream->readShort(); (void)nVersion;
1789 ::comphelper::operator>>( _rxInStream, m_aControlSource);
1790 }
1791
1792 //------------------------------------------------------------------------------
getFastPropertyValue(Any & rValue,sal_Int32 nHandle) const1793 void OBoundControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
1794 {
1795 switch (nHandle)
1796 {
1797 case PROPERTY_ID_INPUT_REQUIRED:
1798 rValue <<= m_bInputRequired;
1799 break;
1800 case PROPERTY_ID_CONTROLSOURCEPROPERTY:
1801 rValue <<= m_sValuePropertyName;
1802 break;
1803 case PROPERTY_ID_CONTROLSOURCE:
1804 rValue <<= m_aControlSource;
1805 break;
1806 case PROPERTY_ID_BOUNDFIELD:
1807 rValue <<= getField();
1808 break;
1809 case PROPERTY_ID_CONTROLLABEL:
1810 if (!m_xLabelControl.is())
1811 rValue.clear();
1812 else
1813 rValue <<= m_xLabelControl;
1814 break;
1815 default:
1816 OControlModel::getFastPropertyValue(rValue, nHandle);
1817 }
1818 }
1819
1820 //------------------------------------------------------------------------------
convertFastPropertyValue(Any & _rConvertedValue,Any & _rOldValue,sal_Int32 _nHandle,const Any & _rValue)1821 sal_Bool OBoundControlModel::convertFastPropertyValue(
1822 Any& _rConvertedValue, Any& _rOldValue,
1823 sal_Int32 _nHandle,
1824 const Any& _rValue)
1825 {
1826 sal_Bool bModified(sal_False);
1827 switch (_nHandle)
1828 {
1829 case PROPERTY_ID_INPUT_REQUIRED:
1830 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, m_bInputRequired );
1831 break;
1832 case PROPERTY_ID_CONTROLSOURCE:
1833 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aControlSource);
1834 break;
1835 case PROPERTY_ID_BOUNDFIELD:
1836 DBG_ERROR( "OBoundControlModel::convertFastPropertyValue: BoundField should be a read-only property !" );
1837 throw com::sun::star::lang::IllegalArgumentException();
1838 case PROPERTY_ID_CONTROLLABEL:
1839 if (!_rValue.hasValue())
1840 { // property set to void
1841 _rConvertedValue = Any();
1842 getFastPropertyValue(_rOldValue, _nHandle);
1843 bModified = m_xLabelControl.is();
1844 }
1845 else
1846 {
1847 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_xLabelControl);
1848 if (!m_xLabelControl.is())
1849 // an empty interface is interpreted as VOID
1850 _rOldValue.clear();
1851 }
1852 break;
1853 default:
1854 bModified = OControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
1855 }
1856 return bModified;
1857 }
1858
1859 //------------------------------------------------------------------------------
getPropertyDefaultByHandle(sal_Int32 _nHandle) const1860 Any OBoundControlModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
1861 {
1862 Any aDefault;
1863 switch ( _nHandle )
1864 {
1865 case PROPERTY_ID_INPUT_REQUIRED:
1866 aDefault <<= sal_Bool( sal_True );
1867 break;
1868
1869 case PROPERTY_ID_CONTROLSOURCE:
1870 aDefault <<= ::rtl::OUString();
1871 break;
1872
1873 case PROPERTY_ID_CONTROLLABEL:
1874 aDefault <<= Reference< XPropertySet >();
1875 break;
1876 }
1877 return aDefault;
1878 }
1879
1880 //------------------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any & rValue)1881 void OBoundControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
1882 {
1883 switch (nHandle)
1884 {
1885 case PROPERTY_ID_INPUT_REQUIRED:
1886 OSL_VERIFY( rValue >>= m_bInputRequired );
1887 break;
1888 case PROPERTY_ID_CONTROLSOURCE:
1889 OSL_VERIFY( rValue >>= m_aControlSource );
1890 break;
1891 case PROPERTY_ID_BOUNDFIELD:
1892 DBG_ERROR("OBoundControlModel::setFastPropertyValue_NoBroadcast : BoundField should be a read-only property !");
1893 throw com::sun::star::lang::IllegalArgumentException();
1894 case PROPERTY_ID_CONTROLLABEL:
1895 {
1896 if ( rValue.hasValue() && ( rValue.getValueTypeClass() != TypeClass_INTERFACE ) )
1897 throw com::sun::star::lang::IllegalArgumentException();
1898
1899 Reference< XInterface > xNewValue( rValue, UNO_QUERY );
1900 if ( !xNewValue.is() )
1901 { // set property to "void"
1902 Reference< XComponent > xComp( m_xLabelControl, UNO_QUERY );
1903 if ( xComp.is() )
1904 xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
1905 m_xLabelControl = NULL;
1906 break;
1907 }
1908
1909 Reference< XControlModel > xAsModel ( xNewValue, UNO_QUERY );
1910 Reference< XServiceInfo > xAsServiceInfo ( xAsModel, UNO_QUERY );
1911 Reference< XPropertySet > xAsPropSet ( xAsServiceInfo, UNO_QUERY );
1912 Reference< XChild > xAsChild ( xAsPropSet, UNO_QUERY );
1913 if ( !xAsChild.is() || !xAsServiceInfo->supportsService( m_aLabelServiceName ) )
1914 {
1915 throw com::sun::star::lang::IllegalArgumentException();
1916 }
1917
1918 // check if weself and the given model have a common anchestor (up to the forms collection)
1919 Reference<XChild> xCont;
1920 query_interface(static_cast<XWeak*>(this), xCont);
1921 Reference< XInterface > xMyTopLevel = xCont->getParent();
1922 while (xMyTopLevel.is())
1923 {
1924 Reference<XForm> xAsForm(xMyTopLevel, UNO_QUERY);
1925 if (!xAsForm.is())
1926 // found my root
1927 break;
1928
1929 Reference<XChild> xLoopAsChild(xMyTopLevel, UNO_QUERY);
1930 xMyTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1931 }
1932 Reference< XInterface > xNewTopLevel = xAsChild->getParent();
1933 while (xNewTopLevel.is())
1934 {
1935 Reference<XForm> xAsForm(xNewTopLevel, UNO_QUERY);
1936 if (!xAsForm.is())
1937 break;
1938
1939 Reference<XChild> xLoopAsChild(xNewTopLevel, UNO_QUERY);
1940 xNewTopLevel = xLoopAsChild.is() ? xLoopAsChild->getParent() : Reference< XInterface >();
1941 }
1942 if (xNewTopLevel != xMyTopLevel)
1943 {
1944 // the both objects don't belong to the same forms collection -> not acceptable
1945 throw com::sun::star::lang::IllegalArgumentException();
1946 }
1947
1948 m_xLabelControl = xAsPropSet;
1949 Reference<com::sun::star::lang::XComponent> xComp(m_xLabelControl, UNO_QUERY);
1950 if (xComp.is())
1951 xComp->addEventListener(static_cast<com::sun::star::lang::XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
1952 }
1953 break;
1954 default:
1955 OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue );
1956 }
1957 }
1958
1959 // XPropertyChangeListener
1960 //------------------------------------------------------------------------------
propertyChange(const PropertyChangeEvent & evt)1961 void SAL_CALL OBoundControlModel::propertyChange( const PropertyChangeEvent& evt )
1962 {
1963 // if the DBColumn value changed, transfer it to the control
1964 if ( evt.PropertyName.equals( PROPERTY_VALUE ) )
1965 {
1966 OSL_ENSURE( evt.Source == getField(), "OBoundControlModel::propertyChange: value changes from components other than our database column?" );
1967 osl::MutexGuard aGuard(m_aMutex);
1968 if ( m_bForwardValueChanges && m_xColumn.is() )
1969 transferDbValueToControl();
1970 }
1971 else
1972 {
1973 OSL_ENSURE( evt.Source == m_xExternalBinding, "OBoundControlModel::propertyChange: where did this come from?" );
1974
1975 // our binding has properties which can control properties of ourself
1976 ::rtl::OUString sBindingControlledProperty;
1977 bool bForwardToLabelControl = false;
1978 if ( evt.PropertyName.equals( PROPERTY_READONLY ) )
1979 {
1980 sBindingControlledProperty = PROPERTY_READONLY;
1981 }
1982 else if ( evt.PropertyName.equals( PROPERTY_RELEVANT ) )
1983 {
1984 sBindingControlledProperty = PROPERTY_ENABLED;
1985 bForwardToLabelControl = true;
1986 }
1987 else
1988 return;
1989
1990 try
1991 {
1992 setPropertyValue( sBindingControlledProperty, evt.NewValue );
1993 if ( bForwardToLabelControl && m_xLabelControl.is() )
1994 m_xLabelControl->setPropertyValue( sBindingControlledProperty, evt.NewValue );
1995 }
1996 catch( const Exception& )
1997 {
1998 OSL_ENSURE( sal_False, "OBoundControlModel::propertyChange: could not adjust my binding-controlled property!" );
1999 }
2000 }
2001 }
2002
2003 //------------------------------------------------------------------------------
onRowSetChanged(const EventObject &)2004 void SAL_CALL OBoundControlModel::onRowSetChanged( const EventObject& /*i_Event*/ )
2005 {
2006 ControlModelLock aLock( *this );
2007 FieldChangeNotifier aBoundFieldNotifier( aLock );
2008
2009 // disconnect from database column (which is controlled by parent, directly or indirectly)
2010 if ( hasField() )
2011 impl_disconnectDatabaseColumn_noNotify();
2012
2013 // log off old listeners
2014 if ( isFormListening() )
2015 doFormListening( false );
2016
2017 // determine the new ambient form
2018 impl_determineAmbientForm_nothrow();
2019
2020 // log on new listeners
2021 doFormListening( true );
2022
2023 // re-connect to database column if needed and possible
2024 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
2025 impl_connectDatabaseColumn_noNotify( false );
2026 }
2027
2028 // XBoundComponent
2029 //------------------------------------------------------------------------------
addUpdateListener(const Reference<XUpdateListener> & _rxListener)2030 void SAL_CALL OBoundControlModel::addUpdateListener(const Reference<XUpdateListener>& _rxListener)
2031 {
2032 m_aUpdateListeners.addInterface(_rxListener);
2033 }
2034
2035 //------------------------------------------------------------------------------
removeUpdateListener(const Reference<XUpdateListener> & _rxListener)2036 void SAL_CALL OBoundControlModel::removeUpdateListener(const Reference< XUpdateListener>& _rxListener)
2037 {
2038 m_aUpdateListeners.removeInterface(_rxListener);
2039 }
2040
2041 //------------------------------------------------------------------------------
commit()2042 sal_Bool SAL_CALL OBoundControlModel::commit()
2043 {
2044 ControlModelLock aLock( *this );
2045
2046 OSL_PRECOND( m_bCommitable, "OBoundControlModel::commit: invalid call (I'm not commitable !) " );
2047 if ( hasExternalValueBinding() )
2048 {
2049 // in most cases, no action is required: For most derivees, we know the value property of
2050 // our control (see initValueProperty), and when an external binding is active, we
2051 // instantly forward all changes in this property to the external binding.
2052 if ( !m_sValuePropertyName.getLength() )
2053 // but for those derivees which did not use this feature, we need an
2054 // explicit transfer
2055 transferControlValueToExternal( aLock );
2056 return sal_True;
2057 }
2058
2059 OSL_ENSURE( !hasExternalValueBinding(), "OBoundControlModel::commit: control flow broken!" );
2060 // we reach this only if we're not working with an external binding
2061
2062 if ( !hasField() )
2063 return sal_True;
2064
2065 ::cppu::OInterfaceIteratorHelper aIter( m_aUpdateListeners );
2066 EventObject aEvent;
2067 aEvent.Source = static_cast< XWeak* >( this );
2068 sal_Bool bSuccess = sal_True;
2069
2070 aLock.release();
2071 // >>>>>>>> ----- UNSAFE ----- >>>>>>>>
2072 while (aIter.hasMoreElements() && bSuccess)
2073 bSuccess = static_cast< XUpdateListener* >( aIter.next() )->approveUpdate( aEvent );
2074 // <<<<<<<< ----- UNSAFE ----- <<<<<<<<
2075 aLock.acquire();
2076
2077 if ( bSuccess )
2078 {
2079 try
2080 {
2081 if ( m_xColumnUpdate.is() )
2082 bSuccess = commitControlValueToDbColumn( sal_False );
2083 }
2084 catch(Exception&)
2085 {
2086 bSuccess = sal_False;
2087 }
2088 }
2089
2090 if ( bSuccess )
2091 {
2092 aLock.release();
2093 m_aUpdateListeners.notifyEach( &XUpdateListener::updated, aEvent );
2094 }
2095
2096 return bSuccess;
2097 }
2098
2099 //------------------------------------------------------------------------------
resetField()2100 void OBoundControlModel::resetField()
2101 {
2102 m_xColumnUpdate.clear();
2103 m_xColumn.clear();
2104 m_xField.clear();
2105 m_nFieldType = DataType::OTHER;
2106 }
2107
2108 //------------------------------------------------------------------------------
connectToField(const Reference<XRowSet> & rForm)2109 sal_Bool OBoundControlModel::connectToField(const Reference<XRowSet>& rForm)
2110 {
2111 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::connectToField: invalid call (have an external binding)!" );
2112
2113 // wenn eine Verbindung zur Datenbank existiert
2114 if (rForm.is() && getConnection(rForm).is())
2115 {
2116 // Feld bestimmen und PropertyChangeListener
2117 m_xCursor = rForm;
2118 Reference<XPropertySet> xFieldCandidate;
2119
2120 if (m_xCursor.is())
2121 {
2122 Reference<XColumnsSupplier> xColumnsSupplier(m_xCursor, UNO_QUERY);
2123 DBG_ASSERT(xColumnsSupplier.is(), "OBoundControlModel::connectToField : the row set should support the com::sun::star::sdb::ResultSet service !");
2124 if (xColumnsSupplier.is())
2125 {
2126 Reference<XNameAccess> xColumns(xColumnsSupplier->getColumns(), UNO_QUERY);
2127 if (xColumns.is() && xColumns->hasByName(m_aControlSource))
2128 {
2129 OSL_VERIFY( xColumns->getByName(m_aControlSource) >>= xFieldCandidate );
2130 }
2131 }
2132 }
2133
2134 try
2135 {
2136 sal_Int32 nFieldType = DataType::OTHER;
2137 if ( xFieldCandidate.is() )
2138 {
2139 xFieldCandidate->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
2140 if ( approveDbColumnType( nFieldType ) )
2141 impl_setField_noNotify( xFieldCandidate );
2142 }
2143 else
2144 impl_setField_noNotify( NULL );
2145
2146 if ( m_xField.is() )
2147 {
2148 if( m_xField->getPropertySetInfo()->hasPropertyByName( PROPERTY_VALUE ) )
2149 {
2150 m_nFieldType = nFieldType;
2151
2152 // an wertaenderungen horchen
2153 m_xField->addPropertyChangeListener( PROPERTY_VALUE, this );
2154 m_xColumnUpdate = Reference< XColumnUpdate >( m_xField, UNO_QUERY );
2155 m_xColumn = Reference< XColumn >( m_xField, UNO_QUERY );
2156
2157 sal_Int32 nNullableFlag = ColumnValue::NO_NULLS;
2158 m_xField->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullableFlag;
2159 m_bRequired = (ColumnValue::NO_NULLS == nNullableFlag);
2160 // we're optimistic : in case of ColumnValue_NULLABLE_UNKNOWN we assume nullability ....
2161 }
2162 else
2163 {
2164 OSL_ENSURE(sal_False, "OBoundControlModel::connectToField: property NAME not supported!");
2165 impl_setField_noNotify( NULL );
2166 }
2167 }
2168 }
2169 catch( const Exception& )
2170 {
2171 DBG_UNHANDLED_EXCEPTION();
2172 resetField();
2173 }
2174 }
2175 return hasField();
2176 }
2177
2178 //------------------------------------------------------------------------------
initFromField(const Reference<XRowSet> & _rxRowSet)2179 void OBoundControlModel::initFromField( const Reference< XRowSet >& _rxRowSet )
2180 {
2181 // but only if the rowset if positioned on a valid record
2182 if ( hasField() && _rxRowSet.is() )
2183 {
2184 if ( !_rxRowSet->isBeforeFirst() && !_rxRowSet->isAfterLast() )
2185 transferDbValueToControl();
2186 else
2187 // reset the field if the row set is empty
2188 // #i30661# / 2004-12-16 / frank.schoenheit@sun.com
2189 resetNoBroadcast();
2190 }
2191 }
2192
2193 //------------------------------------------------------------------------------
approveDbColumnType(sal_Int32 _nColumnType)2194 sal_Bool OBoundControlModel::approveDbColumnType(sal_Int32 _nColumnType)
2195 {
2196 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::approveDbColumnType: invalid call (have an external binding)!" );
2197
2198 if ((_nColumnType == DataType::BINARY) || (_nColumnType == DataType::VARBINARY)
2199 || (_nColumnType == DataType::LONGVARBINARY) || (_nColumnType == DataType::OTHER)
2200 || (_nColumnType == DataType::OBJECT) || (_nColumnType == DataType::DISTINCT)
2201 || (_nColumnType == DataType::STRUCT) || (_nColumnType == DataType::ARRAY)
2202 || (_nColumnType == DataType::BLOB) /*|| (_nColumnType == DataType::CLOB)*/
2203 || (_nColumnType == DataType::REF) || (_nColumnType == DataType::SQLNULL))
2204 return sal_False;
2205
2206 return sal_True;
2207 }
2208
2209 //------------------------------------------------------------------------------
impl_determineAmbientForm_nothrow()2210 void OBoundControlModel::impl_determineAmbientForm_nothrow()
2211 {
2212 Reference< XInterface > xParent( const_cast< OBoundControlModel* >( this )->getParent() );
2213
2214 m_xAmbientForm.set( xParent, UNO_QUERY );
2215 if ( !m_xAmbientForm.is() )
2216 {
2217 Reference< XRowSetSupplier > xSupRowSet( xParent, UNO_QUERY );
2218 if ( xSupRowSet.is() )
2219 m_xAmbientForm.set( xSupRowSet->getRowSet(), UNO_QUERY );
2220 }
2221 }
2222
2223 //------------------------------------------------------------------------------
impl_connectDatabaseColumn_noNotify(bool _bFromReload)2224 void OBoundControlModel::impl_connectDatabaseColumn_noNotify( bool _bFromReload )
2225 {
2226 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2227
2228 // consistency checks
2229 DBG_ASSERT( !( hasField() && !_bFromReload ),
2230 "OBoundControlModel::impl_connectDatabaseColumn_noNotify: the form is just *loaded*, but we already have a field!" );
2231 (void)_bFromReload;
2232
2233 Reference< XRowSet > xRowSet( m_xAmbientForm, UNO_QUERY );
2234 OSL_ENSURE( xRowSet.is(), "OBoundControlModel::impl_connectDatabaseColumn_noNotify: no row set!" );
2235 if ( !xRowSet.is() )
2236 return;
2237
2238 if ( !hasField() )
2239 {
2240 // connect to the column
2241 connectToField( xRowSet );
2242 }
2243
2244 // now that we're connected (more or less, even if we did not find a column),
2245 // we definitely want to forward any potentially occurring value changes
2246 m_bForwardValueChanges = sal_True;
2247
2248 // let derived classes react on this new connection
2249 m_bLoaded = sal_True;
2250 onConnectedDbColumn( xRowSet );
2251
2252 // initially transfer the db column value to the control, if we successfully connected to a database column
2253 if ( hasField() )
2254 initFromField( xRowSet );
2255 }
2256
2257 //------------------------------------------------------------------------------
impl_disconnectDatabaseColumn_noNotify()2258 void OBoundControlModel::impl_disconnectDatabaseColumn_noNotify()
2259 {
2260 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::impl_disconnectDatabaseColumn_noNotify: not to be called with an external value binding!" );
2261
2262 // let derived classes react on this
2263 onDisconnectedDbColumn();
2264
2265 if ( hasField() )
2266 {
2267 getField()->removePropertyChangeListener( PROPERTY_VALUE, this );
2268 resetField();
2269 }
2270
2271 m_xCursor = NULL;
2272 m_bLoaded = sal_False;
2273 }
2274
2275 //==============================================================================
2276 // XLoadListener
2277 //------------------------------------------------------------------------------
loaded(const EventObject & _rEvent)2278 void SAL_CALL OBoundControlModel::loaded( const EventObject& _rEvent )
2279 {
2280 ControlModelLock aLock( *this );
2281 FieldChangeNotifier aBoundFieldNotifier( aLock );
2282
2283 OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::loaded: where does this come from?" );
2284 (void)_rEvent;
2285
2286 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::loaded: we should never reach this with an external value binding!" );
2287 if ( hasExternalValueBinding() )
2288 return;
2289
2290 impl_connectDatabaseColumn_noNotify( false );
2291 }
2292
2293
2294 //------------------------------------------------------------------------------
unloaded(const com::sun::star::lang::EventObject &)2295 void SAL_CALL OBoundControlModel::unloaded( const com::sun::star::lang::EventObject& /*aEvent*/ )
2296 {
2297 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloaded: we should never reach this with an external value binding!" );
2298 }
2299
2300 //------------------------------------------------------------------------------
reloading(const com::sun::star::lang::EventObject &)2301 void SAL_CALL OBoundControlModel::reloading( const com::sun::star::lang::EventObject& /*aEvent*/ )
2302 {
2303 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloading: we should never reach this with an external value binding!" );
2304 if ( hasExternalValueBinding() )
2305 return;
2306
2307 osl::MutexGuard aGuard(m_aMutex);
2308 m_bForwardValueChanges = sal_False;
2309 }
2310
2311 //------------------------------------------------------------------------------
unloading(const com::sun::star::lang::EventObject &)2312 void SAL_CALL OBoundControlModel::unloading(const com::sun::star::lang::EventObject& /*aEvent*/)
2313 {
2314 ControlModelLock aLock( *this );
2315 FieldChangeNotifier aBoundFieldNotifier( aLock );
2316
2317 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::unloading: we should never reach this with an external value binding!" );
2318 if ( hasExternalValueBinding() )
2319 return;
2320
2321 impl_disconnectDatabaseColumn_noNotify();
2322 }
2323
2324 //------------------------------------------------------------------------------
reloaded(const EventObject & _rEvent)2325 void SAL_CALL OBoundControlModel::reloaded( const EventObject& _rEvent )
2326 {
2327 ControlModelLock aLock( *this );
2328 FieldChangeNotifier aBoundFieldNotifier( aLock );
2329
2330 OSL_ENSURE( _rEvent.Source == m_xAmbientForm, "OBoundControlModel::reloaded: where does this come from?" );
2331 (void)_rEvent;
2332
2333 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::reloaded: we should never reach this with an external value binding!" );
2334 if ( hasExternalValueBinding() )
2335 return;
2336
2337 impl_connectDatabaseColumn_noNotify( true );
2338 }
2339
2340 //------------------------------------------------------------------------------
setControlValue(const Any & _rValue,ValueChangeInstigator _eInstigator)2341 void OBoundControlModel::setControlValue( const Any& _rValue, ValueChangeInstigator _eInstigator )
2342 {
2343 m_eControlValueChangeInstigator = _eInstigator;
2344 doSetControlValue( _rValue );
2345 m_eControlValueChangeInstigator = eOther;
2346 }
2347
2348 //------------------------------------------------------------------------------
doSetControlValue(const Any & _rValue)2349 void OBoundControlModel::doSetControlValue( const Any& _rValue )
2350 {
2351 OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2352 "OBoundControlModel::doSetControlValue: invalid aggregate !" );
2353 OSL_PRECOND( m_sValuePropertyName.getLength() || ( m_nValuePropertyAggregateHandle != -1 ),
2354 "OBoundControlModel::doSetControlValue: please override if you have own value property handling!" );
2355
2356 try
2357 {
2358 // release our mutex once (it's acquired in one of the calling methods), as setting aggregate properties
2359 // may cause any uno controls belonging to us to lock the solar mutex, which is potentially dangerous with
2360 // our own mutex locked
2361 // #72451# / 2000-01-31 / frank.schoenheit@sun.com
2362 MutexRelease aRelease( m_aMutex );
2363 if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2364 {
2365 m_xAggregateFastSet->setFastPropertyValue( m_nValuePropertyAggregateHandle, _rValue );
2366 }
2367 else if ( m_sValuePropertyName.getLength() && m_xAggregateSet.is() )
2368 {
2369 m_xAggregateSet->setPropertyValue( m_sValuePropertyName, _rValue );
2370 }
2371 }
2372 catch( const Exception& )
2373 {
2374 OSL_ENSURE( sal_False, "OBoundControlModel::doSetControlValue: caught an exception!" );
2375 }
2376 }
2377
2378 //------------------------------------------------------------------------------
onConnectedValidator()2379 void OBoundControlModel::onConnectedValidator( )
2380 {
2381 try
2382 {
2383 // if we have an external validator, we do not want the control to force invalid
2384 // inputs to the default value. Instead, invalid inputs should be translated
2385 // to NaN (not a number)
2386 Reference< XPropertySetInfo > xAggregatePropertyInfo;
2387 if ( m_xAggregateSet.is() )
2388 xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2389 if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2390 m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( (sal_Bool)sal_False ) );
2391 }
2392 catch( const Exception& )
2393 {
2394 OSL_ENSURE( sal_False, "OBoundControlModel::onConnectedValidator: caught an exception!" );
2395 }
2396 recheckValidity( false );
2397 }
2398
2399 //------------------------------------------------------------------------------
onDisconnectedValidator()2400 void OBoundControlModel::onDisconnectedValidator( )
2401 {
2402 try
2403 {
2404 Reference< XPropertySetInfo > xAggregatePropertyInfo;
2405 if ( m_xAggregateSet.is() )
2406 xAggregatePropertyInfo = m_xAggregateSet->getPropertySetInfo();
2407 if ( xAggregatePropertyInfo.is() && xAggregatePropertyInfo->hasPropertyByName( PROPERTY_ENFORCE_FORMAT ) )
2408 m_xAggregateSet->setPropertyValue( PROPERTY_ENFORCE_FORMAT, makeAny( (sal_Bool)sal_True ) );
2409 }
2410 catch( const Exception& )
2411 {
2412 OSL_ENSURE( sal_False, "OBoundControlModel::onDisconnectedValidator: caught an exception!" );
2413 }
2414 recheckValidity( false );
2415 }
2416
2417 //------------------------------------------------------------------------------
onConnectedExternalValue()2418 void OBoundControlModel::onConnectedExternalValue( )
2419 {
2420 calculateExternalValueType();
2421 }
2422
2423 //------------------------------------------------------------------------------
onDisconnectedExternalValue()2424 void OBoundControlModel::onDisconnectedExternalValue( )
2425 {
2426 }
2427
2428 //------------------------------------------------------------------------------
onConnectedDbColumn(const Reference<XInterface> &)2429 void OBoundControlModel::onConnectedDbColumn( const Reference< XInterface >& /*_rxForm*/ )
2430 {
2431 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onConnectedDbColumn: how this? There's an external value binding!" );
2432 }
2433
2434 //------------------------------------------------------------------------------
onDisconnectedDbColumn()2435 void OBoundControlModel::onDisconnectedDbColumn()
2436 {
2437 OSL_PRECOND( !hasExternalValueBinding(), "OBoundControlModel::onDisconnectedDbColumn: how this? There's an external value binding!" );
2438 }
2439
2440 // XReset
2441 //-----------------------------------------------------------------------------
getDefaultForReset() const2442 Any OBoundControlModel::getDefaultForReset() const
2443 {
2444 return Any();
2445 }
2446
2447 //-----------------------------------------------------------------------------
resetNoBroadcast()2448 void OBoundControlModel::resetNoBroadcast()
2449 {
2450 setControlValue( getDefaultForReset(), eOther );
2451 }
2452
2453 //-----------------------------------------------------------------------------
addResetListener(const Reference<XResetListener> & l)2454 void OBoundControlModel::addResetListener(const Reference<XResetListener>& l)
2455 {
2456 m_aResetHelper.addResetListener( l );
2457 }
2458
2459 //-----------------------------------------------------------------------------
removeResetListener(const Reference<XResetListener> & l)2460 void OBoundControlModel::removeResetListener(const Reference<XResetListener>& l)
2461 {
2462 m_aResetHelper.removeResetListener( l );
2463 }
2464
2465 //-----------------------------------------------------------------------------
reset()2466 void OBoundControlModel::reset()
2467 {
2468 if ( !m_aResetHelper.approveReset() )
2469 return;
2470
2471 ControlModelLock aLock( *this );
2472
2473 // on a new record?
2474 sal_Bool bIsNewRecord = sal_False;
2475 Reference<XPropertySet> xSet( m_xCursor, UNO_QUERY );
2476 if ( xSet.is() )
2477 {
2478 try
2479 {
2480 xSet->getPropertyValue( PROPERTY_ISNEW ) >>= bIsNewRecord;
2481 }
2482 catch( const Exception& )
2483 {
2484 DBG_UNHANDLED_EXCEPTION();
2485 }
2486 }
2487
2488 // cursor on an invalid row?
2489 sal_Bool bInvalidCursorPosition = sal_True;
2490 try
2491 {
2492 bInvalidCursorPosition = m_xCursor.is()
2493 && ( m_xCursor->isAfterLast()
2494 || m_xCursor->isBeforeFirst()
2495 )
2496 && !bIsNewRecord;
2497 }
2498 catch( const SQLException& )
2499 {
2500 OSL_ENSURE( sal_False, "OBoundControlModel::reset: caught an SQL exception!" );
2501 }
2502 // don't count the insert row as "invalid"
2503 // @since #i24495#
2504 // @date 2004-05-14
2505 // @author fs@openoffice.org
2506
2507 sal_Bool bSimpleReset =
2508 ( !m_xColumn.is() // no connection to a database column
2509 || ( m_xCursor.is() // OR we have an improperly positioned cursor
2510 && bInvalidCursorPosition
2511 )
2512 || hasExternalValueBinding() // OR we have an external value binding
2513 );
2514
2515 if ( !bSimpleReset )
2516 {
2517 // The default values will be set if and only if the current value of the field which we're bound
2518 // to is NULL.
2519 // Else, the current field value should be refreshed
2520 // This behaviour is not completely ... "matured": What should happen if the field as well as the
2521 // control have a default value?
2522
2523 sal_Bool bIsNull = sal_True;
2524 // we have to access the field content at least once to get a reliable result by XColumn::wasNull
2525 try
2526 {
2527 // normally, we'd do a getString here. However, this is extremely expensive in the case
2528 // of binary fields. Unfortunately, getString is the only method which is guaranteed
2529 // to *always* succeed, all other getXXX methods may fail if the column is asked for a
2530 // non-convertible type
2531 sal_Int32 nFieldType = DataType::OBJECT;
2532 getField()->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType;
2533 if ( ( nFieldType == DataType::BINARY )
2534 || ( nFieldType == DataType::VARBINARY )
2535 || ( nFieldType == DataType::LONGVARBINARY )
2536 || ( nFieldType == DataType::OBJECT )
2537 /*|| ( nFieldType == DataType::CLOB )*/
2538 )
2539 m_xColumn->getBinaryStream();
2540 else if ( nFieldType == DataType::BLOB )
2541 m_xColumn->getBlob();
2542 else
2543 m_xColumn->getString();
2544
2545 bIsNull = m_xColumn->wasNull();
2546 }
2547 catch(Exception&)
2548 {
2549 DBG_ERROR("OBoundControlModel::reset: this should have succeeded in all cases!");
2550 }
2551
2552 sal_Bool bNeedValueTransfer = sal_True;
2553
2554 if ( bIsNull )
2555 {
2556 if ( bIsNewRecord )
2557 {
2558 // reset the control to it's default
2559 resetNoBroadcast();
2560 // and immediately commit the changes to the DB column, to keep consistency
2561 commitControlValueToDbColumn( sal_True );
2562
2563 bNeedValueTransfer = sal_False;
2564 }
2565 }
2566
2567 if ( bNeedValueTransfer )
2568 transferDbValueToControl();
2569 }
2570 else
2571 {
2572 resetNoBroadcast();
2573
2574 // transfer to the external binding, if necessary
2575 if ( hasExternalValueBinding() )
2576 transferControlValueToExternal( aLock );
2577 }
2578
2579 // revalidate, if necessary
2580 if ( hasValidator() )
2581 recheckValidity( true );
2582
2583 aLock.release();
2584
2585 m_aResetHelper.notifyResetted();
2586 }
2587
2588 // -----------------------------------------------------------------------------
impl_setField_noNotify(const Reference<XPropertySet> & _rxField)2589 void OBoundControlModel::impl_setField_noNotify( const Reference< XPropertySet>& _rxField )
2590 {
2591 DBG_ASSERT( !hasExternalValueBinding(), "OBoundControlModel::impl_setField_noNotify: We have an external value binding!" );
2592 m_xField = _rxField;
2593 }
2594
2595 //--------------------------------------------------------------------
impl_approveValueBinding_nolock(const Reference<XValueBinding> & _rxBinding)2596 sal_Bool OBoundControlModel::impl_approveValueBinding_nolock( const Reference< XValueBinding >& _rxBinding )
2597 {
2598 if ( !_rxBinding.is() )
2599 return sal_False;
2600
2601 Sequence< Type > aTypeCandidates;
2602 {
2603 // SYNCHRONIZED -->
2604 ::osl::MutexGuard aGuard( m_aMutex );
2605 aTypeCandidates = getSupportedBindingTypes();
2606 // <-- SYNCHRONIZED
2607 }
2608
2609 for ( const Type* pType = aTypeCandidates.getConstArray();
2610 pType != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2611 ++pType
2612 )
2613 {
2614 if ( _rxBinding->supportsType( *pType ) )
2615 return sal_True;
2616 }
2617
2618 return sal_False;
2619 }
2620
2621 //--------------------------------------------------------------------
connectExternalValueBinding(const Reference<XValueBinding> & _rxBinding,ControlModelLock & _rInstanceLock)2622 void OBoundControlModel::connectExternalValueBinding(
2623 const Reference< XValueBinding >& _rxBinding, ControlModelLock& _rInstanceLock )
2624 {
2625 OSL_PRECOND( _rxBinding.is(), "OBoundControlModel::connectExternalValueBinding: invalid binding instance!" );
2626 OSL_PRECOND( !hasExternalValueBinding( ), "OBoundControlModel::connectExternalValueBinding: precond not met (currently have a binding)!" );
2627
2628 // if we're connected to a database column, suspend this
2629 if ( hasField() )
2630 impl_disconnectDatabaseColumn_noNotify();
2631
2632 // suspend listening for load-related events at out ambient form.
2633 // This is because an external value binding overrules a possible database binding.
2634 if ( isFormListening() )
2635 doFormListening( false );
2636
2637 // remember this new binding
2638 m_xExternalBinding = _rxBinding;
2639
2640 // tell the derivee
2641 onConnectedExternalValue();
2642
2643 try
2644 {
2645 // add as value listener so we get notified when the value changes
2646 Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2647 if ( xModifiable.is() )
2648 xModifiable->addModifyListener( this );
2649
2650 // add as property change listener for some (possibly present) properties we're
2651 // interested in
2652 Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2653 Reference< XPropertySetInfo > xBindingPropsInfo( xBindingProps.is() ? xBindingProps->getPropertySetInfo() : Reference< XPropertySetInfo >() );
2654 if ( xBindingPropsInfo.is() )
2655 {
2656 if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_READONLY ) )
2657 {
2658 xBindingProps->addPropertyChangeListener( PROPERTY_READONLY, this );
2659 m_bBindingControlsRO = sal_True;
2660 }
2661 if ( xBindingPropsInfo->hasPropertyByName( PROPERTY_RELEVANT ) )
2662 {
2663 xBindingProps->addPropertyChangeListener( PROPERTY_RELEVANT, this );
2664 m_bBindingControlsEnable = sal_True;
2665 }
2666 }
2667 }
2668 catch( const Exception& )
2669 {
2670 DBG_UNHANDLED_EXCEPTION();
2671 }
2672
2673 // propagate our new value
2674 transferExternalValueToControl( _rInstanceLock );
2675
2676 // if the binding is also a validator, use it, too. This is a constraint of the
2677 // com.sun.star.form.binding.ValidatableBindableFormComponent service
2678 if ( m_bSupportsValidation )
2679 {
2680 try
2681 {
2682 Reference< XValidator > xAsValidator( _rxBinding, UNO_QUERY );
2683 if ( xAsValidator.is() )
2684 setValidator( xAsValidator );
2685 }
2686 catch( const Exception& )
2687 {
2688 DBG_UNHANDLED_EXCEPTION();
2689 }
2690 }
2691 }
2692
2693 //--------------------------------------------------------------------
disconnectExternalValueBinding()2694 void OBoundControlModel::disconnectExternalValueBinding( )
2695 {
2696 try
2697 {
2698 // not listening at the binding anymore
2699 Reference< XModifyBroadcaster > xModifiable( m_xExternalBinding, UNO_QUERY );
2700 if ( xModifiable.is() )
2701 xModifiable->removeModifyListener( this );
2702
2703 // remove as property change listener
2704 Reference< XPropertySet > xBindingProps( m_xExternalBinding, UNO_QUERY );
2705 if ( m_bBindingControlsRO )
2706 xBindingProps->removePropertyChangeListener( PROPERTY_READONLY, this );
2707 if ( m_bBindingControlsEnable )
2708 xBindingProps->removePropertyChangeListener( PROPERTY_RELEVANT, this );
2709 }
2710 catch( const Exception& )
2711 {
2712 OSL_ENSURE( sal_False, "OBoundControlModel::disconnectExternalValueBinding: caught an exception!" );
2713 }
2714
2715 // if the binding also acts as our validator, disconnect the validator, too
2716 if ( ( m_xExternalBinding == m_xValidator ) && m_xValidator.is() )
2717 disconnectValidator( );
2718
2719 // no binding anymore
2720 m_xExternalBinding.clear();
2721
2722 // be a load listener at our form, again. This was suspended while we had
2723 // an external value binding in place.
2724 doFormListening( true );
2725
2726 // re-connect to database column of the new parent
2727 if ( m_xAmbientForm.is() && m_xAmbientForm->isLoaded() )
2728 impl_connectDatabaseColumn_noNotify( false );
2729
2730 // tell the derivee
2731 onDisconnectedExternalValue();
2732 }
2733
2734 //--------------------------------------------------------------------
setValueBinding(const Reference<XValueBinding> & _rxBinding)2735 void SAL_CALL OBoundControlModel::setValueBinding( const Reference< XValueBinding >& _rxBinding )
2736 {
2737 OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::setValueBinding: How did you reach this method?" );
2738 // the interface for this method should not have been exposed if we do not
2739 // support binding to external data
2740
2741 if ( !impl_approveValueBinding_nolock( _rxBinding ) )
2742 {
2743 throw IncompatibleTypesException(
2744 FRM_RES_STRING( RID_STR_INCOMPATIBLE_TYPES ),
2745 *this
2746 );
2747 }
2748
2749 ControlModelLock aLock( *this );
2750
2751 // since a ValueBinding overrules any potentially active database binding, the change in a ValueBinding
2752 // might trigger a change in our BoundField.
2753 FieldChangeNotifier aBoundFieldNotifier( aLock );
2754
2755 // disconnect from the old binding
2756 if ( hasExternalValueBinding() )
2757 disconnectExternalValueBinding( );
2758
2759 // connect to the new binding
2760 if ( _rxBinding.is() )
2761 connectExternalValueBinding( _rxBinding, aLock );
2762 }
2763
2764 //--------------------------------------------------------------------
getValueBinding()2765 Reference< XValueBinding > SAL_CALL OBoundControlModel::getValueBinding( )
2766 {
2767 ::osl::MutexGuard aGuard( m_aMutex );
2768 OSL_PRECOND( m_bSupportsExternalBinding, "OBoundControlModel::getValueBinding: How did you reach this method?" );
2769 // the interface for this method should not have been exposed if we do not
2770 // support binding to external data
2771
2772 return m_xExternalBinding;
2773 }
2774
2775 //--------------------------------------------------------------------
modified(const EventObject & _rEvent)2776 void SAL_CALL OBoundControlModel::modified( const EventObject& _rEvent )
2777 {
2778 ControlModelLock aLock( *this );
2779
2780 OSL_PRECOND( hasExternalValueBinding(), "OBoundControlModel::modified: Where did this come from?" );
2781 if ( !m_bTransferingValue && ( m_xExternalBinding == _rEvent.Source ) && m_xExternalBinding.is() )
2782 {
2783 transferExternalValueToControl( aLock );
2784 }
2785 }
2786
2787 //--------------------------------------------------------------------
transferDbValueToControl()2788 void OBoundControlModel::transferDbValueToControl( )
2789 {
2790 try
2791 {
2792 setControlValue( translateDbColumnToControlValue(), eDbColumnBinding );
2793 }
2794 catch( const Exception& )
2795 {
2796 DBG_UNHANDLED_EXCEPTION();
2797 }
2798 }
2799
2800 //------------------------------------------------------------------------------
transferExternalValueToControl(ControlModelLock & _rInstanceLock)2801 void OBoundControlModel::transferExternalValueToControl( ControlModelLock& _rInstanceLock )
2802 {
2803 Reference< XValueBinding > xExternalBinding( m_xExternalBinding );
2804 Type aValueExchangeType( getExternalValueType() );
2805
2806 _rInstanceLock.release();
2807 // >>>>>>>> ----- UNSAFE ----- >>>>>>>>
2808 Any aExternalValue;
2809 try
2810 {
2811 aExternalValue = xExternalBinding->getValue( aValueExchangeType );
2812 }
2813 catch( const Exception& )
2814 {
2815 DBG_UNHANDLED_EXCEPTION();
2816 }
2817 // <<<<<<<< ----- UNSAFE ----- <<<<<<<<
2818 _rInstanceLock.acquire();
2819
2820 setControlValue( translateExternalValueToControlValue( aExternalValue ), eExternalBinding );
2821 }
2822
2823 //------------------------------------------------------------------------------
transferControlValueToExternal(ControlModelLock & _rInstanceLock)2824 void OBoundControlModel::transferControlValueToExternal( ControlModelLock& _rInstanceLock )
2825 {
2826 OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2827 "OBoundControlModel::transferControlValueToExternal: precondition not met!" );
2828
2829 if ( m_xExternalBinding.is() )
2830 {
2831 Any aExternalValue( translateControlValueToExternalValue() );
2832 m_bTransferingValue = sal_True;
2833
2834 _rInstanceLock.release();
2835 // >>>>>>>> ----- UNSAFE ----- >>>>>>>>
2836 try
2837 {
2838 m_xExternalBinding->setValue( aExternalValue );
2839 }
2840 catch( const Exception& )
2841 {
2842 DBG_UNHANDLED_EXCEPTION();
2843 }
2844 // <<<<<<<< ----- UNSAFE ----- <<<<<<<<
2845 _rInstanceLock.acquire();
2846
2847 m_bTransferingValue = sal_False;
2848 }
2849 }
2850
2851 // -----------------------------------------------------------------------------
getSupportedBindingTypes()2852 Sequence< Type > OBoundControlModel::getSupportedBindingTypes()
2853 {
2854 return Sequence< Type >( &m_aValuePropertyType, 1 );
2855 }
2856
2857 //-----------------------------------------------------------------------------
calculateExternalValueType()2858 void OBoundControlModel::calculateExternalValueType()
2859 {
2860 m_aExternalValueType = Type();
2861 if ( !m_xExternalBinding.is() )
2862 return;
2863
2864 Sequence< Type > aTypeCandidates( getSupportedBindingTypes() );
2865 for ( const Type* pTypeCandidate = aTypeCandidates.getConstArray();
2866 pTypeCandidate != aTypeCandidates.getConstArray() + aTypeCandidates.getLength();
2867 ++pTypeCandidate
2868 )
2869 {
2870 if ( m_xExternalBinding->supportsType( *pTypeCandidate ) )
2871 {
2872 m_aExternalValueType = *pTypeCandidate;
2873 break;
2874 }
2875 }
2876 }
2877
2878 //-----------------------------------------------------------------------------
translateExternalValueToControlValue(const Any & _rExternalValue) const2879 Any OBoundControlModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
2880 {
2881 OSL_PRECOND( m_bSupportsExternalBinding && hasExternalValueBinding(),
2882 "OBoundControlModel::translateExternalValueToControlValue: precondition not met!" );
2883
2884 Any aControlValue( _rExternalValue );
2885
2886 // if the external value is VOID, and our value property is not allowed to be VOID,
2887 // then default-construct a value
2888 if ( !aControlValue.hasValue() && !m_bValuePropertyMayBeVoid )
2889 aControlValue.setValue( NULL, m_aValuePropertyType );
2890
2891 // outta here
2892 return aControlValue;
2893 }
2894
2895 //------------------------------------------------------------------------------
translateControlValueToExternalValue() const2896 Any OBoundControlModel::translateControlValueToExternalValue( ) const
2897 {
2898 return getControlValue( );
2899 }
2900
2901 //------------------------------------------------------------------------------
translateControlValueToValidatableValue() const2902 Any OBoundControlModel::translateControlValueToValidatableValue( ) const
2903 {
2904 OSL_PRECOND( m_xValidator.is(), "OBoundControlModel::translateControlValueToValidatableValue: no validator, so why should I?" );
2905 if ( ( m_xValidator == m_xExternalBinding ) && m_xValidator.is() )
2906 return translateControlValueToExternalValue();
2907 return getControlValue();
2908 }
2909
2910 //------------------------------------------------------------------------------
getControlValue() const2911 Any OBoundControlModel::getControlValue( ) const
2912 {
2913 OSL_PRECOND( m_xAggregateFastSet.is() && m_xAggregateSet.is(),
2914 "OBoundControlModel::getControlValue: invalid aggregate !" );
2915 OSL_PRECOND( m_sValuePropertyName.getLength() || ( m_nValuePropertyAggregateHandle != -1 ),
2916 "OBoundControlModel::getControlValue: please override if you have own value property handling!" );
2917
2918 // determine the current control value
2919 Any aControlValue;
2920 if ( ( m_nValuePropertyAggregateHandle != -1 ) && m_xAggregateFastSet.is() )
2921 {
2922 aControlValue = m_xAggregateFastSet->getFastPropertyValue( m_nValuePropertyAggregateHandle );
2923 }
2924 else if ( m_sValuePropertyName.getLength() && m_xAggregateSet.is() )
2925 {
2926 aControlValue = m_xAggregateSet->getPropertyValue( m_sValuePropertyName );
2927 }
2928
2929 return aControlValue;
2930 }
2931
2932 //--------------------------------------------------------------------
connectValidator(const Reference<XValidator> & _rxValidator)2933 void OBoundControlModel::connectValidator( const Reference< XValidator >& _rxValidator )
2934 {
2935 OSL_PRECOND( _rxValidator.is(), "OBoundControlModel::connectValidator: invalid validator instance!" );
2936 OSL_PRECOND( !hasValidator( ), "OBoundControlModel::connectValidator: precond not met (have a validator currently)!" );
2937
2938 m_xValidator = _rxValidator;
2939
2940 // add as value listener so we get notified when the value changes
2941 if ( m_xValidator.is() )
2942 {
2943 try
2944 {
2945 m_xValidator->addValidityConstraintListener( this );
2946 }
2947 catch( const RuntimeException& )
2948 {
2949 }
2950 }
2951
2952 onConnectedValidator( );
2953 }
2954
2955 //--------------------------------------------------------------------
disconnectValidator()2956 void OBoundControlModel::disconnectValidator( )
2957 {
2958 OSL_PRECOND( hasValidator( ), "OBoundControlModel::connectValidator: precond not met (don't have a validator currently)!" );
2959
2960 // add as value listener so we get notified when the value changes
2961 if ( m_xValidator.is() )
2962 {
2963 try
2964 {
2965 m_xValidator->removeValidityConstraintListener( this );
2966 }
2967 catch( const RuntimeException& )
2968 {
2969 }
2970 }
2971
2972 m_xValidator.clear();
2973
2974 onDisconnectedValidator( );
2975 }
2976
2977 //--------------------------------------------------------------------
setValidator(const Reference<XValidator> & _rxValidator)2978 void SAL_CALL OBoundControlModel::setValidator( const Reference< XValidator >& _rxValidator )
2979 {
2980 ::osl::ClearableMutexGuard aGuard( m_aMutex );
2981 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::setValidator: How did you reach this method?" );
2982 // the interface for this method should not have been exposed if we do not
2983 // support validation
2984
2985 // early out if the validator does not change
2986 if( _rxValidator == m_xValidator )
2987 return;
2988
2989 if ( m_xValidator.is() && ( m_xValidator == m_xExternalBinding ) )
2990 throw VetoException(
2991 FRM_RES_STRING( RID_STR_INVALID_VALIDATOR ),
2992 *this
2993 );
2994
2995 // disconnect from the old validator
2996 if ( hasValidator() )
2997 disconnectValidator( );
2998
2999 // connect to the new validator
3000 if ( _rxValidator.is() )
3001 connectValidator( _rxValidator );
3002 }
3003
3004 //--------------------------------------------------------------------
getValidator()3005 Reference< XValidator > SAL_CALL OBoundControlModel::getValidator( )
3006 {
3007 ::osl::MutexGuard aGuard( m_aMutex );
3008 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::getValidator: How did you reach this method?" );
3009 // the interface for this method should not have been exposed if we do not
3010 // support validation
3011
3012 return m_xValidator;
3013 }
3014
3015 //--------------------------------------------------------------------
validityConstraintChanged(const EventObject &)3016 void SAL_CALL OBoundControlModel::validityConstraintChanged( const EventObject& /*Source*/ )
3017 {
3018 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3019 OSL_PRECOND( m_bSupportsValidation, "OBoundControlModel::validityConstraintChanged: How did you reach this method?" );
3020 // the interface for this method should not have been exposed if we do not
3021 // support validation
3022
3023 recheckValidity( false );
3024 }
3025
3026 //--------------------------------------------------------------------
isValid()3027 sal_Bool SAL_CALL OBoundControlModel::isValid( )
3028 {
3029 return m_bIsCurrentValueValid;
3030 }
3031
3032 //--------------------------------------------------------------------
getCurrentFormComponentValue() const3033 ::com::sun::star::uno::Any OBoundControlModel::getCurrentFormComponentValue() const
3034 {
3035 if ( hasValidator() )
3036 return translateControlValueToValidatableValue();
3037 return getControlValue();
3038 }
3039
3040 //--------------------------------------------------------------------
getCurrentValue()3041 Any SAL_CALL OBoundControlModel::getCurrentValue( )
3042 {
3043 ::osl::MutexGuard aGuard( m_aMutex );
3044 return getCurrentFormComponentValue();
3045 }
3046
3047 //--------------------------------------------------------------------
addFormComponentValidityListener(const Reference<validation::XFormComponentValidityListener> & Listener)3048 void SAL_CALL OBoundControlModel::addFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener )
3049 {
3050 if ( Listener.is() )
3051 m_aFormComponentListeners.addInterface( Listener );
3052 }
3053
3054 //--------------------------------------------------------------------
removeFormComponentValidityListener(const Reference<validation::XFormComponentValidityListener> & Listener)3055 void SAL_CALL OBoundControlModel::removeFormComponentValidityListener( const Reference< validation::XFormComponentValidityListener >& Listener )
3056 {
3057 if ( Listener.is() )
3058 m_aFormComponentListeners.removeInterface( Listener );
3059 }
3060
3061 //--------------------------------------------------------------------
recheckValidity(bool _bForceNotification)3062 void OBoundControlModel::recheckValidity( bool _bForceNotification )
3063 {
3064 try
3065 {
3066 sal_Bool bIsCurrentlyValid = sal_True;
3067 if ( hasValidator() )
3068 bIsCurrentlyValid = m_xValidator->isValid( translateControlValueToValidatableValue() );
3069
3070 if ( ( bIsCurrentlyValid != m_bIsCurrentValueValid ) || _bForceNotification )
3071 {
3072 m_bIsCurrentValueValid = bIsCurrentlyValid;
3073
3074 // release our mutex for the notifications
3075 MutexRelease aRelease( m_aMutex );
3076 m_aFormComponentListeners.notifyEach( &validation::XFormComponentValidityListener::componentValidityChanged, EventObject( *this ) );
3077 }
3078 }
3079 catch( const Exception& )
3080 {
3081 OSL_ENSURE( sal_False, "OBoundControlModel::recheckValidity: caught an exception!" );
3082 }
3083 }
3084
3085 //------------------------------------------------------------------------------
describeFixedProperties(Sequence<Property> & _rProps) const3086 void OBoundControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
3087 {
3088 BEGIN_DESCRIBE_PROPERTIES( 5, OControlModel )
3089 DECL_PROP1 ( CONTROLSOURCE, ::rtl::OUString, BOUND );
3090 DECL_IFACE_PROP3( BOUNDFIELD, XPropertySet, BOUND, READONLY, TRANSIENT );
3091 DECL_IFACE_PROP2( CONTROLLABEL, XPropertySet, BOUND, MAYBEVOID );
3092 DECL_PROP2 ( CONTROLSOURCEPROPERTY, ::rtl::OUString, READONLY, TRANSIENT );
3093 DECL_BOOL_PROP1 ( INPUT_REQUIRED, BOUND );
3094 END_DESCRIBE_PROPERTIES()
3095 }
3096
3097 // -----------------------------------------------------------------------------
3098
3099 //.........................................................................
3100 }
3101 //... namespace frm .......................................................
3102