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