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