bump product version to 5.0.4.1
[LibreOffice.git] / forms / source / component / FormattedField.cxx
blob79eab7e334ebb837213494f9794733c992872c0c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
56 #include <list>
57 #include <algorithm>
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;
74 namespace
76 typedef com::sun::star::util::Date UNODate;
77 typedef com::sun::star::util::Time UNOTime;
78 typedef com::sun::star::util::DateTime UNODateTime;
81 namespace frm
83 class StandardFormatsSupplier : protected SvNumberFormatsSupplierObj, public ::utl::ITerminationListener
85 protected:
86 SvNumberFormatter* m_pMyPrivateFormatter;
87 static WeakReference< XNumberFormatsSupplier > s_xDefaultFormatsSupplier;
88 public:
89 static Reference< XNumberFormatsSupplier > get( const Reference< XComponentContext >& _rxORB );
90 using SvNumberFormatsSupplierObj::operator new;
91 using SvNumberFormatsSupplierObj::operator delete;
92 protected:
93 StandardFormatsSupplier(const Reference< XComponentContext >& _rxFactory,LanguageType _eSysLanguage);
94 virtual ~StandardFormatsSupplier();
95 protected:
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);
105 // #i29147#
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() )
120 return xSupplier;
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
131 // the supplier
132 return xSupplier;
133 s_xDefaultFormatsSupplier = xNewlyCreatedSupplier;
135 return xNewlyCreatedSupplier;
137 bool StandardFormatsSupplier::queryTermination() const
139 return true;
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
146 // #i29147#
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);
163 return aReturn;
165 OFormattedControl::OFormattedControl(const Reference<XComponentContext>& _rxFactory)
166 :OBoundControl(_rxFactory, VCL_CONTROL_FORMATTEDFIELD)
167 ,m_nKeyEvent(0)
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()
181 if( m_nKeyEvent )
182 Application::RemoveUserEvent( m_nKeyEvent );
183 if (!OComponentHelper::rBHelper.bDisposed)
185 acquire();
186 dispose();
190 // XKeyListener
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 )
198 return;
199 // Is the control located in a form with a Submit URL?
200 Reference<com::sun::star::beans::XPropertySet> xSet(getModel(), UNO_QUERY);
201 if( !xSet.is() )
202 return;
203 Reference<XFormComponent> xFComp(xSet, UNO_QUERY);
204 InterfaceRef xParent = xFComp->getParent();
205 if( !xParent.is() )
206 return;
207 Reference<com::sun::star::beans::XPropertySet> xFormSet(xParent, UNO_QUERY);
208 if( !xFormSet.is() )
209 return;
210 Any aTmp(xFormSet->getPropertyValue( PROPERTY_TARGET_URL ));
211 if (!isA(aTmp, static_cast< OUString* >(NULL)) ||
212 getString(aTmp).isEmpty() )
213 return;
214 Reference<XIndexAccess> xElements(xParent, UNO_QUERY);
215 sal_Int32 nCount = xElements->getCount();
216 if( nCount > 1 )
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
227 if (xFCSet != xSet)
228 return;
232 // Because we're still in the Handler, execute submit asynchronously
233 if( m_nKeyEvent )
234 Application::RemoveUserEvent( m_nKeyEvent );
235 m_nKeyEvent = Application::PostUserEvent( LINK(this, OFormattedControl,
236 OnKeyPressed) );
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)
245 m_nKeyEvent = 0;
246 Reference<XFormComponent> xFComp(getModel(), UNO_QUERY);
247 InterfaceRef xParent = xFComp->getParent();
248 Reference<XSubmit> xSubmit(xParent, UNO_QUERY);
249 if (xSubmit.is())
250 xSubmit->submit( Reference<XControl> (), ::com::sun::star::awt::MouseEvent() );
251 return 0L;
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;
261 return aSupported;
264 void OFormattedControl::setDesignMode(sal_Bool bOn) throw ( ::com::sun::star::uno::RuntimeException, std::exception)
266 OBoundControl::setDesignMode(bOn);
269 void OFormattedModel::implConstruct()
271 // members
272 m_bOriginalNumeric = false;
273 m_bNumeric = 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 )
290 implConstruct();
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 )
298 implConstruct();
301 OFormattedModel::~OFormattedModel()
305 // XCloneable
306 IMPLEMENT_DEFAULT_CLONING( OFormattedModel )
308 void SAL_CALL OFormattedModel::disposing()
310 OErrorBroadcaster::disposing();
311 OEditBaseModel::disposing();
314 // XServiceInfo
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;
330 return aSupported;
333 // XAggregation
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 );
340 // XTypeProvider
341 Sequence< Type > OFormattedModel::_getTypes()
343 return ::comphelper::concatSequences(
344 OEditBaseModel::_getTypes(),
345 OErrorBroadcaster::getTypes()
349 // XPersistObject
350 OUString SAL_CALL OFormattedModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException, std::exception)
352 return OUString(FRM_COMPONENT_EDIT);
355 // XPropertySet
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));
406 else
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);
416 else
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);
427 else
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);
437 else
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&)
474 return;
476 if ( evt.PropertyName == PROPERTY_FORMATSSUPPLIER )
478 updateFormatterNullDate();
479 return;
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;
500 if (!xSupplier.is())
501 // check if my parent form has a supplier
502 xSupplier = calcFormFormatsSupplier();
503 if (!xSupplier.is())
504 xSupplier = calcDefaultFormatsSupplier();
505 DBG_ASSERT(xSupplier.is(), "OFormattedModel::calcFormatsSupplier : no supplier !");
506 // We should have one by now
507 return xSupplier;
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 !");
528 return NULL;
530 // The FormatSupplier of my ancestor (if it has one)
531 Reference< XRowSet > xRowSet( xNextParentForm, UNO_QUERY );
532 Reference< XNumberFormatsSupplier > xSupplier;
533 if (xRowSet.is())
534 xSupplier = getNumberFormats( getConnection(xRowSet), true, getContext() );
535 return xSupplier;
538 Reference< XNumberFormatsSupplier > OFormattedModel::calcDefaultFormatsSupplier() const
540 return StandardFormatsSupplier::get( getContext() );
543 // XBoundComponent
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();
564 if ( xField.is() )
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;
578 if (xField.is())
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 ?");
585 if (xSupplier.is())
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);
592 if (xTypes.is())
594 Locale aApplicationLocale = Application::GetSettings().GetUILanguageTag().getLocale();
595 if (m_bOriginalNumeric)
596 aFmtKey <<= (sal_Int32)xTypes->getStandardFormat(NumberFormat::NUMBER, aApplicationLocale);
597 else
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
605 if (xField.is())
607 m_bNumeric = false;
608 switch (nType)
610 case DataType::BIT:
611 case DataType::BOOLEAN:
612 case DataType::TINYINT:
613 case DataType::SMALLINT:
614 case DataType::INTEGER:
615 case DataType::BIGINT:
616 case DataType::FLOAT:
617 case DataType::REAL:
618 case DataType::DOUBLE:
619 case DataType::NUMERIC:
620 case DataType::DECIMAL:
621 case DataType::DATE:
622 case DataType::TIME:
623 case DataType::TIMESTAMP:
624 m_bNumeric = true;
625 break;
628 else
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;
666 Any aFmtKey;
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);
680 if (!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
718 Any aEffectiveValue;
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));
730 break;
731 case TypeClass_DOUBLE:
732 _rxOutStream->writeShort(0x0001);
733 _rxOutStream->writeDouble(::comphelper::getDouble(aEffectiveValue));
734 break;
735 default: // void and all unknown states
736 DBG_ASSERT(!aEffectiveValue.hasValue(), "FmXFormattedModel::write : unknown property value type !");
737 _rxOutStream->writeShort(0x0002);
738 break;
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;
749 sal_Int32 nKey = -1;
750 switch (nVersion)
752 case 0x0001 :
753 case 0x0002 :
754 case 0x0003 :
756 bool bNonVoidKey = _rxInStream->readBoolean();
757 if (bNonVoidKey)
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();
766 if (xFormats.is())
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();
782 (void)nSubVersion;
783 // version 0 and higher : the "effective value" property
784 Any aEffectiveValue;
786 OStreamSection aDownCompat2(_rxInStream);
787 switch (_rxInStream->readShort())
789 case 0: // String
790 aEffectiveValue <<= _rxInStream->readUTF();
791 break;
792 case 1: // double
793 aEffectiveValue <<= (double)_rxInStream->readDouble();
794 break;
795 case 2:
796 break;
797 case 3:
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&)
815 break;
816 default :
817 OSL_FAIL("OFormattedModel::read : unknown version !");
818 // then the format of the aggregated set stay like it was during creation: void
819 defaultCommonEditProperties();
820 break;
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));
827 else
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()
849 && m_bEmptyIsNull
852 m_xColumnUpdate->updateNull();
853 else
857 double f = 0.0;
858 if ( aControlValue.getValueType().getTypeClass() == TypeClass_DOUBLE || (aControlValue >>= f)) // #i110323
860 DBTypeConversion::setValue( m_xColumnUpdate, m_aNullDate, getDouble( aControlValue ), m_nKeyType );
862 else
864 DBG_ASSERT( aControlValue.getValueType().getTypeClass() == TypeClass_STRING, "OFormattedModel::commitControlValueToDbColumn: invalud value type !" );
865 m_xColumnUpdate->updateString( getString( aControlValue ) );
868 catch(const Exception&)
870 return false;
873 m_aSaveValue = aControlValue;
875 return true;
878 void OFormattedModel::onConnectedExternalValue( )
880 OEditBaseModel::onConnectedExternalValue();
881 updateFormatterNullDate();
884 Any OFormattedModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
886 Any aControlValue;
887 switch( _rExternalValue.getValueTypeClass() )
889 case TypeClass_VOID:
890 break;
891 case TypeClass_STRING:
892 aControlValue = _rExternalValue;
893 break;
894 case TypeClass_BOOLEAN:
896 bool bExternalValue = false;
897 _rExternalValue >>= bExternalValue;
898 aControlValue <<= (double)( bExternalValue ? 1 : 0 );
900 break;
901 default:
903 if ( _rExternalValue.getValueType().equals( cppu::UnoType< UNODate >::get() ) )
905 UNODate aDate;
906 _rExternalValue >>= aDate;
907 aControlValue <<= DBTypeConversion::toDouble( aDate, m_aNullDate );
909 else if ( _rExternalValue.getValueType().equals( cppu::UnoType< UNOTime >::get() ) )
911 UNOTime aTime;
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 );
921 else
923 OSL_ENSURE( _rExternalValue.getValueTypeClass() == TypeClass_DOUBLE,
924 "OFormattedModel::translateExternalValueToControlValue: don't know how to translate this type!" );
925 double fValue = 0;
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;
941 Any aExternalValue;
942 // translate into the external value type
943 Type aExternalValueType( getExternalValueType() );
944 switch ( aExternalValueType.getTypeClass() )
946 case TypeClass_STRING:
948 OUString sString;
949 if ( aControlValue >>= sString )
951 aExternalValue <<= sString;
952 break;
955 // NO break here!
956 case TypeClass_BOOLEAN:
958 double fValue = 0;
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;
965 break;
966 default:
968 double fValue = 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 );
985 else
987 OSL_ENSURE( aExternalValueType.equals( cppu::UnoType< double >::get() ),
988 "OFormattedModel::translateControlValueToExternalValue: don't know how to translate this type!" );
989 aExternalValue <<= fValue;
992 break;
994 return aExternalValue;
997 Any OFormattedModel::translateDbColumnToControlValue()
999 if ( m_bNumeric )
1000 m_aSaveValue <<= DBTypeConversion::getValue( m_xColumn, m_aNullDate ); // #100056# OJ
1001 else
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() );
1016 break;
1017 case NumberFormat::TIME:
1018 aTypes.push_front(cppu::UnoType< UNOTime >::get() );
1019 break;
1020 case NumberFormat::DATETIME:
1021 aTypes.push_front(cppu::UnoType< UNODateTime >::get() );
1022 break;
1023 case NumberFormat::TEXT:
1024 aTypes.push_front(cppu::UnoType< OUString >::get() );
1025 break;
1026 case NumberFormat::LOGICAL:
1027 aTypes.push_front(cppu::UnoType< sal_Bool >::get() );
1028 break;
1030 Sequence< Type > aTypesRet( aTypes.size() );
1031 ::std::copy( aTypes.begin(), aTypes.end(), aTypesRet.getArray() );
1032 return aTypesRet;
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: */