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