1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #include "FormattedField.hxx"
20 #include "services.hxx"
21 #include "property.hrc"
22 #include "property.hxx"
23 #include "frm_resource.hxx"
24 #include "frm_resource.hrc"
25 #include "propertybaghelper.hxx"
26 #include <comphelper/sequence.hxx>
27 #include <comphelper/numbers.hxx>
28 #include <connectivity/dbtools.hxx>
29 #include <connectivity/dbconversion.hxx>
30 #include <svl/zforlist.hxx>
31 #include <svl/numuno.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/settings.hxx>
34 #include <tools/debug.hxx>
35 #include <tools/wintypes.hxx>
36 #include <i18nlangtag/languagetag.hxx>
37 #include <rtl/textenc.h>
38 #include <com/sun/star/sdbc/DataType.hpp>
39 #include <com/sun/star/util/NumberFormat.hpp>
40 #include <com/sun/star/util/Date.hpp>
41 #include <com/sun/star/util/Time.hpp>
42 #include <com/sun/star/awt/MouseEvent.hpp>
43 #include <com/sun/star/form/XSubmit.hpp>
44 #include <com/sun/star/awt/XWindow.hpp>
45 #include <com/sun/star/awt/XKeyListener.hpp>
46 #include <com/sun/star/form/FormComponentType.hpp>
47 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
48 #include <com/sun/star/util/XNumberFormatTypes.hpp>
49 #include <com/sun/star/form/XForm.hpp>
50 #include <com/sun/star/container/XIndexAccess.hpp>
51 #include <osl/mutex.hxx>
52 // needed as long as we use the SolarMutex
53 #include <comphelper/streamsection.hxx>
54 #include <cppuhelper/weakref.hxx>
55 #include <unotools/desktopterminationobserver.hxx>
60 using namespace dbtools
;
61 using namespace ::com::sun::star::uno
;
62 using namespace ::com::sun::star::sdb
;
63 using namespace ::com::sun::star::sdbc
;
64 using namespace ::com::sun::star::sdbcx
;
65 using namespace ::com::sun::star::beans
;
66 using namespace ::com::sun::star::container
;
67 using namespace ::com::sun::star::form
;
68 using namespace ::com::sun::star::awt
;
69 using namespace ::com::sun::star::io
;
70 using namespace ::com::sun::star::lang
;
71 using namespace ::com::sun::star::util
;
72 using namespace ::com::sun::star::form::binding
;
76 typedef com::sun::star::util::Date UNODate
;
77 typedef com::sun::star::util::Time UNOTime
;
78 typedef com::sun::star::util::DateTime UNODateTime
;
83 class StandardFormatsSupplier
: protected SvNumberFormatsSupplierObj
, public ::utl::ITerminationListener
86 SvNumberFormatter
* m_pMyPrivateFormatter
;
87 static WeakReference
< XNumberFormatsSupplier
> s_xDefaultFormatsSupplier
;
89 static Reference
< XNumberFormatsSupplier
> get( const Reference
< XComponentContext
>& _rxORB
);
90 using SvNumberFormatsSupplierObj::operator new;
91 using SvNumberFormatsSupplierObj::operator delete;
93 StandardFormatsSupplier(const Reference
< XComponentContext
>& _rxFactory
,LanguageType _eSysLanguage
);
94 virtual ~StandardFormatsSupplier();
96 virtual bool queryTermination() const SAL_OVERRIDE
;
97 virtual void notifyTermination() SAL_OVERRIDE
;
99 WeakReference
< XNumberFormatsSupplier
> StandardFormatsSupplier::s_xDefaultFormatsSupplier
;
100 StandardFormatsSupplier::StandardFormatsSupplier(const Reference
< XComponentContext
> & _rxContext
,LanguageType _eSysLanguage
)
101 :SvNumberFormatsSupplierObj()
102 ,m_pMyPrivateFormatter(new SvNumberFormatter(_rxContext
, _eSysLanguage
))
104 SetNumberFormatter(m_pMyPrivateFormatter
);
106 ::utl::DesktopTerminationObserver::registerTerminationListener( this );
108 StandardFormatsSupplier::~StandardFormatsSupplier()
110 ::utl::DesktopTerminationObserver::revokeTerminationListener( this );
111 DELETEZ( m_pMyPrivateFormatter
);
113 Reference
< XNumberFormatsSupplier
> StandardFormatsSupplier::get( const Reference
< XComponentContext
>& _rxORB
)
115 LanguageType eSysLanguage
= LANGUAGE_SYSTEM
;
117 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
118 Reference
< XNumberFormatsSupplier
> xSupplier
= s_xDefaultFormatsSupplier
;
119 if ( xSupplier
.is() )
121 // get the Office's locale
122 eSysLanguage
= SvtSysLocale().GetLanguageTag().getLanguageType( false);
124 StandardFormatsSupplier
* pSupplier
= new StandardFormatsSupplier( _rxORB
, eSysLanguage
);
125 Reference
< XNumberFormatsSupplier
> xNewlyCreatedSupplier( pSupplier
);
127 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
128 Reference
< XNumberFormatsSupplier
> xSupplier
= s_xDefaultFormatsSupplier
;
129 if ( xSupplier
.is() )
130 // somebody used the small time frame where the mutex was not locked to create and set
133 s_xDefaultFormatsSupplier
= xNewlyCreatedSupplier
;
135 return xNewlyCreatedSupplier
;
137 bool StandardFormatsSupplier::queryTermination() const
141 void StandardFormatsSupplier::notifyTermination()
143 Reference
< XNumberFormatsSupplier
> xKeepAlive
= this;
144 // when the application is terminating, release our static reference so that we are cleared/destructed
145 // earlier than upon unloading the library
147 s_xDefaultFormatsSupplier
= WeakReference
< XNumberFormatsSupplier
>( );
148 SetNumberFormatter( NULL
);
149 DELETEZ( m_pMyPrivateFormatter
);
151 Sequence
<Type
> OFormattedControl::_getTypes()
153 return ::comphelper::concatSequences(
154 OFormattedControl_BASE::getTypes(),
155 OBoundControl::_getTypes()
158 Any SAL_CALL
OFormattedControl::queryAggregation(const Type
& _rType
) throw (RuntimeException
, std::exception
)
160 Any aReturn
= OBoundControl::queryAggregation(_rType
);
161 if (!aReturn
.hasValue())
162 aReturn
= OFormattedControl_BASE::queryInterface(_rType
);
165 OFormattedControl::OFormattedControl(const Reference
<XComponentContext
>& _rxFactory
)
166 :OBoundControl(_rxFactory
, VCL_CONTROL_FORMATTEDFIELD
)
169 osl_atomic_increment(&m_refCount
);
171 Reference
<XWindow
> xComp
;
172 if (query_aggregation(m_xAggregate
, xComp
))
174 xComp
->addKeyListener(this);
177 osl_atomic_decrement(&m_refCount
);
179 OFormattedControl::~OFormattedControl()
182 Application::RemoveUserEvent( m_nKeyEvent
);
183 if (!OComponentHelper::rBHelper
.bDisposed
)
191 void OFormattedControl::disposing(const EventObject
& _rSource
) throw(RuntimeException
, std::exception
)
193 OBoundControl::disposing(_rSource
);
195 void OFormattedControl::keyPressed(const ::com::sun::star::awt::KeyEvent
& e
) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
197 if( e
.KeyCode
!= KEY_RETURN
|| e
.Modifiers
!= 0 )
199 // Is the control located in a form with a Submit URL?
200 Reference
<com::sun::star::beans::XPropertySet
> xSet(getModel(), UNO_QUERY
);
203 Reference
<XFormComponent
> xFComp(xSet
, UNO_QUERY
);
204 InterfaceRef xParent
= xFComp
->getParent();
207 Reference
<com::sun::star::beans::XPropertySet
> xFormSet(xParent
, UNO_QUERY
);
210 Any
aTmp(xFormSet
->getPropertyValue( PROPERTY_TARGET_URL
));
211 if (!isA(aTmp
, static_cast< OUString
* >(NULL
)) ||
212 getString(aTmp
).isEmpty() )
214 Reference
<XIndexAccess
> xElements(xParent
, UNO_QUERY
);
215 sal_Int32 nCount
= xElements
->getCount();
218 Reference
<com::sun::star::beans::XPropertySet
> xFCSet
;
219 for( sal_Int32 nIndex
=0; nIndex
< nCount
; nIndex
++ )
221 // Any aElement(xElements->getByIndex(nIndex));
222 xElements
->getByIndex(nIndex
) >>= xFCSet
;
223 if (hasProperty(PROPERTY_CLASSID
, xFCSet
) &&
224 getINT16(xFCSet
->getPropertyValue(PROPERTY_CLASSID
)) == FormComponentType::TEXTFIELD
)
226 // Found another Edit -> Do not submit then
232 // Because we're still in the Handler, execute submit asynchronously
234 Application::RemoveUserEvent( m_nKeyEvent
);
235 m_nKeyEvent
= Application::PostUserEvent( LINK(this, OFormattedControl
,
239 void OFormattedControl::keyReleased(const ::com::sun::star::awt::KeyEvent
& /*e*/) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
243 IMPL_LINK_NOARG(OFormattedControl
, OnKeyPressed
)
246 Reference
<XFormComponent
> xFComp(getModel(), UNO_QUERY
);
247 InterfaceRef xParent
= xFComp
->getParent();
248 Reference
<XSubmit
> xSubmit(xParent
, UNO_QUERY
);
250 xSubmit
->submit( Reference
<XControl
> (), ::com::sun::star::awt::MouseEvent() );
254 StringSequence
OFormattedControl::getSupportedServiceNames() throw(std::exception
)
256 StringSequence aSupported
= OBoundControl::getSupportedServiceNames();
257 aSupported
.realloc(aSupported
.getLength() + 2);
258 OUString
*pArray
= aSupported
.getArray();
259 pArray
[aSupported
.getLength()-2] = FRM_SUN_CONTROL_FORMATTEDFIELD
;
260 pArray
[aSupported
.getLength()-1] = STARDIV_ONE_FORM_CONTROL_FORMATTEDFIELD
;
264 void OFormattedControl::setDesignMode(sal_Bool bOn
) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
266 OBoundControl::setDesignMode(bOn
);
269 void OFormattedModel::implConstruct()
272 m_bOriginalNumeric
= false;
274 m_xOriginalFormatter
= NULL
;
275 m_nKeyType
= NumberFormat::UNDEFINED
;
276 m_aNullDate
= DBTypeConversion::getStandardDate();
277 m_nFieldType
= DataType::OTHER
;
278 // default our formats supplier
279 osl_atomic_increment(&m_refCount
);
280 setPropertyToDefaultByHandle(PROPERTY_ID_FORMATSSUPPLIER
);
281 osl_atomic_decrement(&m_refCount
);
282 startAggregatePropertyListening( PROPERTY_FORMATKEY
);
283 startAggregatePropertyListening( PROPERTY_FORMATSSUPPLIER
);
285 OFormattedModel::OFormattedModel(const Reference
<XComponentContext
>& _rxFactory
)
286 :OEditBaseModel(_rxFactory
, VCL_CONTROLMODEL_FORMATTEDFIELD
, FRM_SUN_CONTROL_FORMATTEDFIELD
, true, true )
287 // use the old control name for compytibility reasons
288 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
291 m_nClassId
= FormComponentType::TEXTFIELD
;
292 initValueProperty( PROPERTY_EFFECTIVE_VALUE
, PROPERTY_ID_EFFECTIVE_VALUE
);
294 OFormattedModel::OFormattedModel( const OFormattedModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
)
295 :OEditBaseModel( _pOriginal
, _rxFactory
)
296 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
301 OFormattedModel::~OFormattedModel()
306 IMPLEMENT_DEFAULT_CLONING( OFormattedModel
)
308 void SAL_CALL
OFormattedModel::disposing()
310 OErrorBroadcaster::disposing();
311 OEditBaseModel::disposing();
315 StringSequence
OFormattedModel::getSupportedServiceNames() throw(std::exception
)
317 StringSequence aSupported
= OEditBaseModel::getSupportedServiceNames();
318 sal_Int32 nOldLen
= aSupported
.getLength();
319 aSupported
.realloc( nOldLen
+ 9 );
320 OUString
* pStoreTo
= aSupported
.getArray() + nOldLen
;
321 *pStoreTo
++ = BINDABLE_CONTROL_MODEL
;
322 *pStoreTo
++ = DATA_AWARE_CONTROL_MODEL
;
323 *pStoreTo
++ = VALIDATABLE_CONTROL_MODEL
;
324 *pStoreTo
++ = BINDABLE_DATA_AWARE_CONTROL_MODEL
;
325 *pStoreTo
++ = VALIDATABLE_BINDABLE_CONTROL_MODEL
;
326 *pStoreTo
++ = FRM_SUN_COMPONENT_FORMATTEDFIELD
;
327 *pStoreTo
++ = FRM_SUN_COMPONENT_DATABASE_FORMATTEDFIELD
;
328 *pStoreTo
++ = BINDABLE_DATABASE_FORMATTED_FIELD
;
329 *pStoreTo
++ = FRM_COMPONENT_FORMATTEDFIELD
;
334 Any SAL_CALL
OFormattedModel::queryAggregation(const Type
& _rType
) throw(RuntimeException
, std::exception
)
336 Any aReturn
= OEditBaseModel::queryAggregation( _rType
);
337 return aReturn
.hasValue() ? aReturn
: OErrorBroadcaster::queryInterface( _rType
);
341 Sequence
< Type
> OFormattedModel::_getTypes()
343 return ::comphelper::concatSequences(
344 OEditBaseModel::_getTypes(),
345 OErrorBroadcaster::getTypes()
350 OUString SAL_CALL
OFormattedModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
352 return OUString(FRM_COMPONENT_EDIT
);
356 void OFormattedModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
358 BEGIN_DESCRIBE_PROPERTIES( 3, OEditBaseModel
)
359 DECL_BOOL_PROP1(EMPTY_IS_NULL
, BOUND
);
360 DECL_PROP1(TABINDEX
, sal_Int16
, BOUND
);
361 DECL_BOOL_PROP2(FILTERPROPOSAL
, BOUND
, MAYBEDEFAULT
);
362 END_DESCRIBE_PROPERTIES();
365 void OFormattedModel::describeAggregateProperties( Sequence
< Property
>& _rAggregateProps
) const
367 OEditBaseModel::describeAggregateProperties( _rAggregateProps
);
368 // TreatAsNumeric is not transient: we want to attach it to the UI
369 // This is necessary to make EffectiveDefault (which may be text or a number) meaningful
370 ModifyPropertyAttributes(_rAggregateProps
, PROPERTY_TREATASNUMERIC
, 0, PropertyAttribute::TRANSIENT
);
371 // Same for FormatKey
372 // (though the paragraph above for the TreatAsNumeric does not hold anymore - we do not have an UI for this.
373 // But we have for the format key ...)
374 ModifyPropertyAttributes(_rAggregateProps
, PROPERTY_FORMATKEY
, 0, PropertyAttribute::TRANSIENT
);
375 RemoveProperty(_rAggregateProps
, PROPERTY_STRICTFORMAT
);
376 // no strict format property for formatted fields: it does not make sense, 'cause
377 // there is no general way to decide which characters/sub strings are allowed during the input of an
378 // arbitraryly formatted control
381 void OFormattedModel::getFastPropertyValue(Any
& rValue
, sal_Int32 nHandle
) const
383 OEditBaseModel::getFastPropertyValue(rValue
, nHandle
);
386 void OFormattedModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
, const Any
& rValue
) throw ( ::com::sun::star::uno::Exception
, std::exception
)
388 OEditBaseModel::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
391 sal_Bool
OFormattedModel::convertFastPropertyValue(Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
392 throw( IllegalArgumentException
)
394 return OEditBaseModel::convertFastPropertyValue(rConvertedValue
, rOldValue
, nHandle
, rValue
);
397 void OFormattedModel::setPropertyToDefaultByHandle(sal_Int32 nHandle
)
399 if (nHandle
== PROPERTY_ID_FORMATSSUPPLIER
)
401 Reference
<XNumberFormatsSupplier
> xSupplier
= calcDefaultFormatsSupplier();
402 DBG_ASSERT(m_xAggregateSet
.is(), "OFormattedModel::setPropertyToDefaultByHandle(FORMATSSUPPLIER) : have no aggregate !");
403 if (m_xAggregateSet
.is())
404 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATSSUPPLIER
, makeAny(xSupplier
));
407 OEditBaseModel::setPropertyToDefaultByHandle(nHandle
);
410 void OFormattedModel::setPropertyToDefault(const OUString
& aPropertyName
) throw( com::sun::star::beans::UnknownPropertyException
, RuntimeException
, std::exception
)
412 OPropertyArrayAggregationHelper
& rPH
= m_aPropertyBagHelper
.getInfoHelper();
413 sal_Int32 nHandle
= rPH
.getHandleByName( aPropertyName
);
414 if (nHandle
== PROPERTY_ID_FORMATSSUPPLIER
)
415 setPropertyToDefaultByHandle(PROPERTY_ID_FORMATSSUPPLIER
);
417 OEditBaseModel::setPropertyToDefault(aPropertyName
);
420 Any
OFormattedModel::getPropertyDefaultByHandle( sal_Int32 nHandle
) const
422 if (nHandle
== PROPERTY_ID_FORMATSSUPPLIER
)
424 Reference
<XNumberFormatsSupplier
> xSupplier
= calcDefaultFormatsSupplier();
425 return makeAny(xSupplier
);
428 return OEditBaseModel::getPropertyDefaultByHandle(nHandle
);
431 Any SAL_CALL
OFormattedModel::getPropertyDefault( const OUString
& aPropertyName
) throw( com::sun::star::beans::UnknownPropertyException
, RuntimeException
, std::exception
)
433 OPropertyArrayAggregationHelper
& rPH
= m_aPropertyBagHelper
.getInfoHelper();
434 sal_Int32 nHandle
= rPH
.getHandleByName( aPropertyName
);
435 if (nHandle
== PROPERTY_ID_FORMATSSUPPLIER
)
436 return getPropertyDefaultByHandle(PROPERTY_ID_FORMATSSUPPLIER
);
438 return OEditBaseModel::getPropertyDefault(aPropertyName
);
441 void OFormattedModel::_propertyChanged( const com::sun::star::beans::PropertyChangeEvent
& evt
) throw(RuntimeException
)
443 // TODO: check how this works with external bindings
444 OSL_ENSURE( evt
.Source
== m_xAggregateSet
, "OFormattedModel::_propertyChanged: where did this come from?" );
445 if ( evt
.Source
== m_xAggregateSet
)
447 Reference
< XPropertySet
> xSourceSet( evt
.Source
, UNO_QUERY
);
448 if ( evt
.PropertyName
== PROPERTY_FORMATKEY
)
450 if ( evt
.NewValue
.getValueType().getTypeClass() == TypeClass_LONG
)
454 ::osl::MutexGuard
aGuard( m_aMutex
);
455 Reference
<XNumberFormatsSupplier
> xSupplier( calcFormatsSupplier() );
456 m_nKeyType
= getNumberFormatType(xSupplier
->getNumberFormats(), getINT32( evt
.NewValue
) );
457 // as m_aSaveValue (which is used by commitControlValueToDbColumn) is format dependent we have
458 // to recalc it, which is done by translateDbColumnToControlValue
459 if ( m_xColumn
.is() && m_xAggregateFastSet
.is() && !m_xCursor
->isBeforeFirst() && !m_xCursor
->isAfterLast())
461 setControlValue( translateDbColumnToControlValue(), eOther
);
463 // if we're connected to an external value binding, then re-calculate the type
464 // used to exchange the value - it depends on the format, too
465 if ( hasExternalValueBinding() )
467 calculateExternalValueType();
470 catch(const Exception
&)
476 if ( evt
.PropertyName
== PROPERTY_FORMATSSUPPLIER
)
478 updateFormatterNullDate();
481 OBoundControlModel::_propertyChanged( evt
);
485 void OFormattedModel::updateFormatterNullDate()
487 // calc the current NULL date
488 Reference
< XNumberFormatsSupplier
> xSupplier( calcFormatsSupplier() );
489 if ( xSupplier
.is() )
490 xSupplier
->getNumberFormatSettings()->getPropertyValue("NullDate") >>= m_aNullDate
;
493 Reference
< XNumberFormatsSupplier
> OFormattedModel::calcFormatsSupplier() const
495 Reference
<XNumberFormatsSupplier
> xSupplier
;
496 DBG_ASSERT(m_xAggregateSet
.is(), "OFormattedModel::calcFormatsSupplier : have no aggregate !");
497 // Does my aggregate model have a FormatSupplier?
498 if( m_xAggregateSet
.is() )
499 m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATSSUPPLIER
) >>= xSupplier
;
501 // check if my parent form has a supplier
502 xSupplier
= calcFormFormatsSupplier();
504 xSupplier
= calcDefaultFormatsSupplier();
505 DBG_ASSERT(xSupplier
.is(), "OFormattedModel::calcFormatsSupplier : no supplier !");
506 // We should have one by now
510 Reference
<XNumberFormatsSupplier
> OFormattedModel::calcFormFormatsSupplier() const
512 Reference
<XChild
> xMe(
513 static_cast<XWeak
*>(const_cast<OFormattedModel
*>(this)),
514 css::uno::UNO_QUERY
);
515 // By this we make sure that we get the right object even when aggregating
516 DBG_ASSERT(xMe
.is(), "OFormattedModel::calcFormFormatsSupplier : I should have a content interface !");
517 // Iterate through until we reach a StartForm (starting with an own Parent)
518 Reference
<XChild
> xParent(xMe
->getParent(), UNO_QUERY
);
519 Reference
<XForm
> xNextParentForm(xParent
, UNO_QUERY
);
520 while (!xNextParentForm
.is() && xParent
.is())
522 xParent
.set(xParent
->getParent(), css::uno::UNO_QUERY
);
523 xNextParentForm
.set(xParent
, css::uno::UNO_QUERY
);
525 if (!xNextParentForm
.is())
527 OSL_FAIL("OFormattedModel::calcFormFormatsSupplier : have no ancestor which is a form !");
530 // The FormatSupplier of my ancestor (if it has one)
531 Reference
< XRowSet
> xRowSet( xNextParentForm
, UNO_QUERY
);
532 Reference
< XNumberFormatsSupplier
> xSupplier
;
534 xSupplier
= getNumberFormats( getConnection(xRowSet
), true, getContext() );
538 Reference
< XNumberFormatsSupplier
> OFormattedModel::calcDefaultFormatsSupplier() const
540 return StandardFormatsSupplier::get( getContext() );
544 void OFormattedModel::loaded(const EventObject
& rEvent
) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
546 // HACK: our onConnectedDbColumn accesses our NumberFormatter which locks the solar mutex (as it doesn't have
547 // an own one). To prevent deadlocks with other threads which may request a property from us in an
548 // UI-triggered action (e.g. an tooltip) we lock the solar mutex _here_ before our base class locks
549 // it's own muext (which is used for property requests)
550 // alternative a): we use two mutexes, one which is passed to the OPropertysetHelper and used for
551 // property requests and one for our own code. This would need a lot of code rewriting
552 // alternative b): The NumberFormatter has to be really threadsafe (with an own mutex), which is
553 // the only "clean" solution for me.
554 SolarMutexGuard aGuard
;
555 OEditBaseModel::loaded(rEvent
);
558 void OFormattedModel::onConnectedDbColumn( const Reference
< XInterface
>& _rxForm
)
560 m_xOriginalFormatter
= NULL
;
561 // get some properties of the field
562 m_nFieldType
= DataType::OTHER
;
563 Reference
<XPropertySet
> xField
= getField();
565 xField
->getPropertyValue( PROPERTY_FIELDTYPE
) >>= m_nFieldType
;
566 sal_Int32 nFormatKey
= 0;
567 DBG_ASSERT(m_xAggregateSet
.is(), "OFormattedModel::onConnectedDbColumn : have no aggregate !");
568 if (m_xAggregateSet
.is())
569 { // all the following doesn't make any sense if we have no aggregate ...
570 Any aSupplier
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATSSUPPLIER
);
571 DBG_ASSERT( aSupplier
.hasValue(), "OFormattedModel::onConnectedDbColumn : invalid property value !" );
572 // This should've been set to the correct value in the ctor or in the read
573 Any aFmtKey
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATKEY
);
574 if ( !(aFmtKey
>>= nFormatKey
) )
575 { // nobody gave us a format to use. So we examine the field we're bound to for a
576 // format key, and use it ourself, too
577 sal_Int32 nType
= DataType::VARCHAR
;
580 aFmtKey
= xField
->getPropertyValue(PROPERTY_FORMATKEY
);
581 xField
->getPropertyValue(PROPERTY_FIELDTYPE
) >>= nType
;
583 Reference
<XNumberFormatsSupplier
> xSupplier
= calcFormFormatsSupplier();
584 DBG_ASSERT(xSupplier
.is(), "OFormattedModel::onConnectedDbColumn : bound to a field but no parent with a formatter ? how this ?");
587 m_bOriginalNumeric
= getBOOL(getPropertyValue(PROPERTY_TREATASNUMERIC
));
588 if (!aFmtKey
.hasValue())
589 { // we aren't bound to a field (or this field's format is invalid)
590 // -> determine the standard text (or numeric) format of the supplier
591 Reference
<XNumberFormatTypes
> xTypes(xSupplier
->getNumberFormats(), UNO_QUERY
);
594 Locale aApplicationLocale
= Application::GetSettings().GetUILanguageTag().getLocale();
595 if (m_bOriginalNumeric
)
596 aFmtKey
<<= (sal_Int32
)xTypes
->getStandardFormat(NumberFormat::NUMBER
, aApplicationLocale
);
598 aFmtKey
<<= (sal_Int32
)xTypes
->getStandardFormat(NumberFormat::TEXT
, aApplicationLocale
);
601 aSupplier
>>= m_xOriginalFormatter
;
602 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATSSUPPLIER
, makeAny(xSupplier
));
603 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATKEY
, aFmtKey
);
604 // Adapt the NumericFalg to my bound field
611 case DataType::BOOLEAN
:
612 case DataType::TINYINT
:
613 case DataType::SMALLINT
:
614 case DataType::INTEGER
:
615 case DataType::BIGINT
:
616 case DataType::FLOAT
:
618 case DataType::DOUBLE
:
619 case DataType::NUMERIC
:
620 case DataType::DECIMAL
:
623 case DataType::TIMESTAMP
:
629 m_bNumeric
= m_bOriginalNumeric
;
630 setPropertyValue(PROPERTY_TREATASNUMERIC
, makeAny(m_bNumeric
));
631 OSL_VERIFY( aFmtKey
>>= nFormatKey
);
635 Reference
<XNumberFormatsSupplier
> xSupplier
= calcFormatsSupplier();
636 m_bNumeric
= getBOOL( getPropertyValue( PROPERTY_TREATASNUMERIC
) );
637 m_nKeyType
= getNumberFormatType( xSupplier
->getNumberFormats(), nFormatKey
);
638 xSupplier
->getNumberFormatSettings()->getPropertyValue("NullDate") >>= m_aNullDate
;
639 OEditBaseModel::onConnectedDbColumn( _rxForm
);
642 void OFormattedModel::onDisconnectedDbColumn()
644 OEditBaseModel::onDisconnectedDbColumn();
645 if (m_xOriginalFormatter
.is())
646 { // Our aggregated model does not hold any Format information
647 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATSSUPPLIER
, makeAny(m_xOriginalFormatter
));
648 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATKEY
, Any());
649 setPropertyValue(PROPERTY_TREATASNUMERIC
, makeAny(m_bOriginalNumeric
));
650 m_xOriginalFormatter
= NULL
;
652 m_nFieldType
= DataType::OTHER
;
653 m_nKeyType
= NumberFormat::UNDEFINED
;
654 m_aNullDate
= DBTypeConversion::getStandardDate();
657 void OFormattedModel::write(const Reference
<XObjectOutputStream
>& _rxOutStream
) throw ( ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
659 OEditBaseModel::write(_rxOutStream
);
660 _rxOutStream
->writeShort(0x0003);
661 DBG_ASSERT(m_xAggregateSet
.is(), "OFormattedModel::write : have no aggregate !");
662 // Bring my Format (may be void) to a persistent Format.
663 // The Supplier together with the Key is already persistent, but that doesn't mean
664 // we have to save the Supplier (which would be quite some overhead)
665 Reference
<XNumberFormatsSupplier
> xSupplier
;
667 bool bVoidKey
= true;
668 if (m_xAggregateSet
.is())
670 Any aSupplier
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATSSUPPLIER
);
671 if (aSupplier
.getValueType().getTypeClass() != TypeClass_VOID
)
673 OSL_VERIFY( aSupplier
>>= xSupplier
);
675 aFmtKey
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATKEY
);
676 bVoidKey
= (!xSupplier
.is() || !aFmtKey
.hasValue()) || (isLoaded() && m_xOriginalFormatter
.is());
677 // (no Format and/or Key) OR (loaded and faked Formatter)
679 _rxOutStream
->writeBoolean(!bVoidKey
);
682 // Create persistent values from the FormatKey and the Formatter
683 Any aKey
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATKEY
);
684 sal_Int32 nKey
= aKey
.hasValue() ? getINT32(aKey
) : 0;
685 Reference
<XNumberFormats
> xFormats
= xSupplier
->getNumberFormats();
686 OUString sFormatDescription
;
687 LanguageType eFormatLanguage
= LANGUAGE_DONTKNOW
;
688 static const char s_aLocaleProp
[] = "Locale";
689 Reference
<com::sun::star::beans::XPropertySet
> xFormat
= xFormats
->getByKey(nKey
);
690 if (hasProperty(s_aLocaleProp
, xFormat
))
692 Any aLocale
= xFormat
->getPropertyValue(s_aLocaleProp
);
693 DBG_ASSERT(isA(aLocale
, static_cast<Locale
*>(NULL
)), "OFormattedModel::write : invalid language property !");
694 if (isA(aLocale
, static_cast<Locale
*>(NULL
)))
696 Locale
const * pLocale
= static_cast<Locale
const *>(aLocale
.getValue());
697 eFormatLanguage
= LanguageTag::convertToLanguageType( *pLocale
, false);
700 static const char s_aFormatStringProp
[] = "FormatString";
701 if (hasProperty(s_aFormatStringProp
, xFormat
))
702 xFormat
->getPropertyValue(s_aFormatStringProp
) >>= sFormatDescription
;
703 _rxOutStream
->writeUTF(sFormatDescription
);
704 _rxOutStream
->writeLong((sal_Int32
)eFormatLanguage
);
706 // version 2 : write the properties common to all OEditBaseModels
707 writeCommonEditProperties(_rxOutStream
);
708 // version 3 : write the effective value property of the aggregate
709 // Due to a bug within the UnoControlFormattedFieldModel implementation (our default aggregate)
710 // this props value isn't correctly read and this can't be corrected without being incompatible.
711 // so we have our own handling.
712 // and to be a little bit more compatible we make the following section skippable
714 OStreamSection
aDownCompat(_rxOutStream
);
715 // a sub version within the skippable block
716 _rxOutStream
->writeShort(0x0000);
717 // version 0: the effective value of the aggregate
719 if (m_xAggregateSet
.is())
721 try { aEffectiveValue
= m_xAggregateSet
->getPropertyValue(PROPERTY_EFFECTIVE_VALUE
); } catch(const Exception
&) { }
724 OStreamSection
aDownCompat2(_rxOutStream
);
725 switch (aEffectiveValue
.getValueType().getTypeClass())
727 case TypeClass_STRING
:
728 _rxOutStream
->writeShort(0x0000);
729 _rxOutStream
->writeUTF(::comphelper::getString(aEffectiveValue
));
731 case TypeClass_DOUBLE
:
732 _rxOutStream
->writeShort(0x0001);
733 _rxOutStream
->writeDouble(::comphelper::getDouble(aEffectiveValue
));
735 default: // void and all unknown states
736 DBG_ASSERT(!aEffectiveValue
.hasValue(), "FmXFormattedModel::write : unknown property value type !");
737 _rxOutStream
->writeShort(0x0002);
744 void OFormattedModel::read(const Reference
<XObjectInputStream
>& _rxInStream
) throw ( ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
746 OEditBaseModel::read(_rxInStream
);
747 sal_uInt16 nVersion
= _rxInStream
->readShort();
748 Reference
<XNumberFormatsSupplier
> xSupplier
;
756 bool bNonVoidKey
= _rxInStream
->readBoolean();
759 // read string and language...
760 OUString sFormatDescription
= _rxInStream
->readUTF();
761 LanguageType eDescriptionLanguage
= (LanguageType
)_rxInStream
->readLong();
762 // and let a formatter roll dice based on that to create a key...
763 xSupplier
= calcFormatsSupplier();
764 // calcFormatsSupplier first takes the one from the model, then one from the starform, then a new one...
765 Reference
<XNumberFormats
> xFormats
= xSupplier
->getNumberFormats();
768 Locale
aDescriptionLanguage( LanguageTag::convertToLocale(eDescriptionLanguage
));
769 nKey
= xFormats
->queryKey(sFormatDescription
, aDescriptionLanguage
, sal_False
);
770 if (nKey
== (sal_Int32
)-1)
771 { // does not yet exist in my formatter...
772 nKey
= xFormats
->addNew(sFormatDescription
, aDescriptionLanguage
);
776 if ((nVersion
== 0x0002) || (nVersion
== 0x0003))
777 readCommonEditProperties(_rxInStream
);
778 if (nVersion
== 0x0003)
779 { // since version 3 there is a "skippable" block at this position
780 OStreamSection
aDownCompat(_rxInStream
);
781 sal_Int16 nSubVersion
= _rxInStream
->readShort();
783 // version 0 and higher : the "effective value" property
786 OStreamSection
aDownCompat2(_rxInStream
);
787 switch (_rxInStream
->readShort())
790 aEffectiveValue
<<= _rxInStream
->readUTF();
793 aEffectiveValue
<<= (double)_rxInStream
->readDouble();
798 OSL_FAIL("FmXFormattedModel::read : unknown effective value type !");
801 // this property is only to be set if we have no control source : in all other cases the base class did a
802 // reset after it's read and this set the effective value to a default value
803 if ( m_xAggregateSet
.is() && getControlSource().isEmpty() )
807 m_xAggregateSet
->setPropertyValue(PROPERTY_EFFECTIVE_VALUE
, aEffectiveValue
);
809 catch(const Exception
&)
817 OSL_FAIL("OFormattedModel::read : unknown version !");
818 // then the format of the aggregated set stay like it was during creation: void
819 defaultCommonEditProperties();
822 if ((nKey
!= -1) && m_xAggregateSet
.is())
824 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATSSUPPLIER
, makeAny(xSupplier
));
825 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATKEY
, makeAny((sal_Int32
)nKey
));
829 setPropertyToDefault(PROPERTY_FORMATSSUPPLIER
);
830 setPropertyToDefault(PROPERTY_FORMATKEY
);
834 sal_uInt16
OFormattedModel::getPersistenceFlags() const
836 return (OEditBaseModel::getPersistenceFlags() & ~PF_HANDLE_COMMON_PROPS
);
837 // a) we do our own call to writeCommonEditProperties
840 bool OFormattedModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
842 Any
aControlValue( m_xAggregateFastSet
->getFastPropertyValue( getValuePropertyAggHandle() ) );
843 if ( aControlValue
!= m_aSaveValue
)
845 // empty string + EmptyIsNull = void
846 if ( !aControlValue
.hasValue()
847 || ( ( aControlValue
.getValueType().getTypeClass() == TypeClass_STRING
)
848 && getString( aControlValue
).isEmpty()
852 m_xColumnUpdate
->updateNull();
858 if ( aControlValue
.getValueType().getTypeClass() == TypeClass_DOUBLE
|| (aControlValue
>>= f
)) // #i110323
860 DBTypeConversion::setValue( m_xColumnUpdate
, m_aNullDate
, getDouble( aControlValue
), m_nKeyType
);
864 DBG_ASSERT( aControlValue
.getValueType().getTypeClass() == TypeClass_STRING
, "OFormattedModel::commitControlValueToDbColumn: invalud value type !" );
865 m_xColumnUpdate
->updateString( getString( aControlValue
) );
868 catch(const Exception
&)
873 m_aSaveValue
= aControlValue
;
878 void OFormattedModel::onConnectedExternalValue( )
880 OEditBaseModel::onConnectedExternalValue();
881 updateFormatterNullDate();
884 Any
OFormattedModel::translateExternalValueToControlValue( const Any
& _rExternalValue
) const
887 switch( _rExternalValue
.getValueTypeClass() )
891 case TypeClass_STRING
:
892 aControlValue
= _rExternalValue
;
894 case TypeClass_BOOLEAN
:
896 bool bExternalValue
= false;
897 _rExternalValue
>>= bExternalValue
;
898 aControlValue
<<= (double)( bExternalValue
? 1 : 0 );
903 if ( _rExternalValue
.getValueType().equals( cppu::UnoType
< UNODate
>::get() ) )
906 _rExternalValue
>>= aDate
;
907 aControlValue
<<= DBTypeConversion::toDouble( aDate
, m_aNullDate
);
909 else if ( _rExternalValue
.getValueType().equals( cppu::UnoType
< UNOTime
>::get() ) )
912 _rExternalValue
>>= aTime
;
913 aControlValue
<<= DBTypeConversion::toDouble( aTime
);
915 else if ( _rExternalValue
.getValueType().equals( cppu::UnoType
< UNODateTime
>::get() ) )
917 UNODateTime aDateTime
;
918 _rExternalValue
>>= aDateTime
;
919 aControlValue
<<= DBTypeConversion::toDouble( aDateTime
, m_aNullDate
);
923 OSL_ENSURE( _rExternalValue
.getValueTypeClass() == TypeClass_DOUBLE
,
924 "OFormattedModel::translateExternalValueToControlValue: don't know how to translate this type!" );
926 OSL_VERIFY( _rExternalValue
>>= fValue
);
927 aControlValue
<<= fValue
;
931 return aControlValue
;
934 Any
OFormattedModel::translateControlValueToExternalValue( ) const
936 OSL_PRECOND( hasExternalValueBinding(),
937 "OFormattedModel::translateControlValueToExternalValue: precondition not met!" );
938 Any
aControlValue( getControlValue() );
939 if ( !aControlValue
.hasValue() )
940 return aControlValue
;
942 // translate into the external value type
943 Type
aExternalValueType( getExternalValueType() );
944 switch ( aExternalValueType
.getTypeClass() )
946 case TypeClass_STRING
:
949 if ( aControlValue
>>= sString
)
951 aExternalValue
<<= sString
;
956 case TypeClass_BOOLEAN
:
959 OSL_VERIFY( aControlValue
>>= fValue
);
960 // if this asserts ... well, the somebody set the TreatAsNumeric property to false,
961 // and the control value is a string. This implies some weird misconfiguration
962 // of the FormattedModel, so we won't care for it for the moment.
963 aExternalValue
<<= fValue
!= 0.0;
969 OSL_VERIFY( aControlValue
>>= fValue
);
970 // if this asserts ... well, the somebody set the TreatAsNumeric property to false,
971 // and the control value is a string. This implies some weird misconfiguration
972 // of the FormattedModel, so we won't care for it for the moment.
973 if ( aExternalValueType
.equals( cppu::UnoType
< UNODate
>::get() ) )
975 aExternalValue
<<= DBTypeConversion::toDate( fValue
, m_aNullDate
);
977 else if ( aExternalValueType
.equals( cppu::UnoType
< UNOTime
>::get() ) )
979 aExternalValue
<<= DBTypeConversion::toTime( fValue
);
981 else if ( aExternalValueType
.equals( cppu::UnoType
< UNODateTime
>::get() ) )
983 aExternalValue
<<= DBTypeConversion::toDateTime( fValue
, m_aNullDate
);
987 OSL_ENSURE( aExternalValueType
.equals( cppu::UnoType
< double >::get() ),
988 "OFormattedModel::translateControlValueToExternalValue: don't know how to translate this type!" );
989 aExternalValue
<<= fValue
;
994 return aExternalValue
;
997 Any
OFormattedModel::translateDbColumnToControlValue()
1000 m_aSaveValue
<<= DBTypeConversion::getValue( m_xColumn
, m_aNullDate
); // #100056# OJ
1002 m_aSaveValue
<<= m_xColumn
->getString();
1003 if ( m_xColumn
->wasNull() )
1004 m_aSaveValue
.clear();
1005 return m_aSaveValue
;
1008 Sequence
< Type
> OFormattedModel::getSupportedBindingTypes()
1010 ::std::list
< Type
> aTypes
;
1011 aTypes
.push_back( cppu::UnoType
< double >::get() );
1012 switch ( m_nKeyType
& ~NumberFormat::DEFINED
)
1014 case NumberFormat::DATE
:
1015 aTypes
.push_front(cppu::UnoType
< UNODate
>::get() );
1017 case NumberFormat::TIME
:
1018 aTypes
.push_front(cppu::UnoType
< UNOTime
>::get() );
1020 case NumberFormat::DATETIME
:
1021 aTypes
.push_front(cppu::UnoType
< UNODateTime
>::get() );
1023 case NumberFormat::TEXT
:
1024 aTypes
.push_front(cppu::UnoType
< OUString
>::get() );
1026 case NumberFormat::LOGICAL
:
1027 aTypes
.push_front(cppu::UnoType
< sal_Bool
>::get() );
1030 Sequence
< Type
> aTypesRet( aTypes
.size() );
1031 ::std::copy( aTypes
.begin(), aTypes
.end(), aTypesRet
.getArray() );
1035 Any
OFormattedModel::getDefaultForReset() const
1037 return m_xAggregateSet
->getPropertyValue( PROPERTY_EFFECTIVE_DEFAULT
);
1040 void OFormattedModel::resetNoBroadcast()
1042 OEditBaseModel::resetNoBroadcast();
1043 m_aSaveValue
.clear();
1048 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface
* SAL_CALL
1049 com_sun_star_form_OFormattedControl_get_implementation(::com::sun::star::uno::XComponentContext
* component
,
1050 ::com::sun::star::uno::Sequence
<css::uno::Any
> const &)
1052 return cppu::acquire(new frm::OFormattedControl(component
));
1055 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */