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 .
21 #include "FormattedField.hxx"
22 #include "services.hxx"
23 #include "property.hrc"
24 #include "property.hxx"
25 #include "frm_resource.hxx"
26 #include "frm_resource.hrc"
27 #include "propertybaghelper.hxx"
28 #include <comphelper/sequence.hxx>
29 #include <comphelper/numbers.hxx>
30 #include <connectivity/dbtools.hxx>
31 #include <connectivity/dbconversion.hxx>
32 #include <svl/zforlist.hxx>
33 #include <svl/numuno.hxx>
34 #include <vcl/svapp.hxx>
35 #include <tools/debug.hxx>
36 #include <tools/wintypes.hxx>
37 #include <i18nlangtag/languagetag.hxx>
38 #include <rtl/textenc.h>
39 #include <com/sun/star/sdbc/DataType.hpp>
40 #include <com/sun/star/util/NumberFormat.hpp>
41 #include <com/sun/star/util/Date.hpp>
42 #include <com/sun/star/util/Time.hpp>
43 #include <com/sun/star/awt/MouseEvent.hpp>
44 #include <com/sun/star/form/XSubmit.hpp>
45 #include <com/sun/star/awt/XWindow.hpp>
46 #include <com/sun/star/awt/XKeyListener.hpp>
47 #include <com/sun/star/form/FormComponentType.hpp>
48 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
49 #include <com/sun/star/util/XNumberFormatTypes.hpp>
50 #include <com/sun/star/form/XForm.hpp>
51 #include <com/sun/star/container/XIndexAccess.hpp>
52 #include <osl/mutex.hxx>
53 // needed as long as we use the SolarMutex
54 #include <comphelper/streamsection.hxx>
55 #include <cppuhelper/weakref.hxx>
56 #include <unotools/desktopterminationobserver.hxx>
61 using namespace dbtools
;
62 using namespace ::com::sun::star::uno
;
63 using namespace ::com::sun::star::sdb
;
64 using namespace ::com::sun::star::sdbc
;
65 using namespace ::com::sun::star::sdbcx
;
66 using namespace ::com::sun::star::beans
;
67 using namespace ::com::sun::star::container
;
68 using namespace ::com::sun::star::form
;
69 using namespace ::com::sun::star::awt
;
70 using namespace ::com::sun::star::io
;
71 using namespace ::com::sun::star::lang
;
72 using namespace ::com::sun::star::util
;
73 using namespace ::com::sun::star::form::binding
;
77 typedef com::sun::star::util::Date UNODate
;
78 typedef com::sun::star::util::Time UNOTime
;
79 typedef com::sun::star::util::DateTime UNODateTime
;
82 //.........................................................................
86 /*************************************************************************/
88 class StandardFormatsSupplier
: protected SvNumberFormatsSupplierObj
, public ::utl::ITerminationListener
91 SvNumberFormatter
* m_pMyPrivateFormatter
;
92 static WeakReference
< XNumberFormatsSupplier
> s_xDefaultFormatsSupplier
;
95 static Reference
< XNumberFormatsSupplier
> get( const Reference
< XComponentContext
>& _rxORB
);
97 using SvNumberFormatsSupplierObj::operator new;
98 using SvNumberFormatsSupplierObj::operator delete;
101 StandardFormatsSupplier(const Reference
< XComponentContext
>& _rxFactory
,LanguageType _eSysLanguage
);
102 ~StandardFormatsSupplier();
105 virtual bool queryTermination() const;
106 virtual void notifyTermination();
109 //------------------------------------------------------------------
110 WeakReference
< XNumberFormatsSupplier
> StandardFormatsSupplier::s_xDefaultFormatsSupplier
;
112 //------------------------------------------------------------------
113 StandardFormatsSupplier::StandardFormatsSupplier(const Reference
< XComponentContext
> & _rxContext
,LanguageType _eSysLanguage
)
114 :SvNumberFormatsSupplierObj()
115 ,m_pMyPrivateFormatter(new SvNumberFormatter(_rxContext
, _eSysLanguage
))
117 SetNumberFormatter(m_pMyPrivateFormatter
);
120 ::utl::DesktopTerminationObserver::registerTerminationListener( this );
123 //------------------------------------------------------------------
124 StandardFormatsSupplier::~StandardFormatsSupplier()
126 ::utl::DesktopTerminationObserver::revokeTerminationListener( this );
128 DELETEZ( m_pMyPrivateFormatter
);
131 //------------------------------------------------------------------
132 Reference
< XNumberFormatsSupplier
> StandardFormatsSupplier::get( const Reference
< XComponentContext
>& _rxORB
)
134 LanguageType eSysLanguage
= LANGUAGE_SYSTEM
;
136 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
137 Reference
< XNumberFormatsSupplier
> xSupplier
= s_xDefaultFormatsSupplier
;
138 if ( xSupplier
.is() )
141 // get the Office's locale
142 eSysLanguage
= SvtSysLocale().GetLanguageTag().getLanguageType( false);
145 StandardFormatsSupplier
* pSupplier
= new StandardFormatsSupplier( _rxORB
, eSysLanguage
);
146 Reference
< XNumberFormatsSupplier
> xNewlyCreatedSupplier( pSupplier
);
149 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
150 Reference
< XNumberFormatsSupplier
> xSupplier
= s_xDefaultFormatsSupplier
;
151 if ( xSupplier
.is() )
152 // somebody used the small time frame where the mutex was not locked to create and set
156 s_xDefaultFormatsSupplier
= xNewlyCreatedSupplier
;
159 return xNewlyCreatedSupplier
;
162 //------------------------------------------------------------------
163 bool StandardFormatsSupplier::queryTermination() const
168 //------------------------------------------------------------------
169 void StandardFormatsSupplier::notifyTermination()
171 Reference
< XNumberFormatsSupplier
> xKeepAlive
= this;
172 // when the application is terminating, release our static reference so that we are cleared/destructed
173 // earlier than upon unloading the library
175 s_xDefaultFormatsSupplier
= WeakReference
< XNumberFormatsSupplier
>( );
177 SetNumberFormatter( NULL
);
178 DELETEZ( m_pMyPrivateFormatter
);
181 /*************************************************************************/
182 //------------------------------------------------------------------
183 InterfaceRef SAL_CALL
OFormattedControl_CreateInstance(const Reference
<XMultiServiceFactory
>& _rxFactory
)
185 return *(new OFormattedControl(_rxFactory
));
188 //------------------------------------------------------------------
189 Sequence
<Type
> OFormattedControl::_getTypes()
191 return ::comphelper::concatSequences(
192 OFormattedControl_BASE::getTypes(),
193 OBoundControl::_getTypes()
197 //------------------------------------------------------------------
198 Any SAL_CALL
OFormattedControl::queryAggregation(const Type
& _rType
) throw (RuntimeException
)
200 Any aReturn
= OBoundControl::queryAggregation(_rType
);
201 if (!aReturn
.hasValue())
202 aReturn
= OFormattedControl_BASE::queryInterface(_rType
);
207 DBG_NAME(OFormattedControl
);
208 //------------------------------------------------------------------------------
209 OFormattedControl::OFormattedControl(const Reference
<XMultiServiceFactory
>& _rxFactory
)
210 :OBoundControl(_rxFactory
, VCL_CONTROL_FORMATTEDFIELD
)
213 DBG_CTOR(OFormattedControl
,NULL
);
215 increment(m_refCount
);
217 Reference
<XWindow
> xComp
;
218 if (query_aggregation(m_xAggregate
, xComp
))
220 xComp
->addKeyListener(this);
223 decrement(m_refCount
);
226 //------------------------------------------------------------------------------
227 OFormattedControl::~OFormattedControl()
230 Application::RemoveUserEvent( m_nKeyEvent
);
232 if (!OComponentHelper::rBHelper
.bDisposed
)
238 DBG_DTOR(OFormattedControl
,NULL
);
242 //------------------------------------------------------------------------------
243 void OFormattedControl::disposing(const EventObject
& _rSource
) throw(RuntimeException
)
245 OBoundControl::disposing(_rSource
);
248 //------------------------------------------------------------------------------
249 void OFormattedControl::keyPressed(const ::com::sun::star::awt::KeyEvent
& e
) throw ( ::com::sun::star::uno::RuntimeException
)
251 if( e
.KeyCode
!= KEY_RETURN
|| e
.Modifiers
!= 0 )
254 // Steht das Control in einem Formular mit einer Submit-URL?
255 Reference
<com::sun::star::beans::XPropertySet
> xSet(getModel(), UNO_QUERY
);
259 Reference
<XFormComponent
> xFComp(xSet
, UNO_QUERY
);
260 InterfaceRef xParent
= xFComp
->getParent();
264 Reference
<com::sun::star::beans::XPropertySet
> xFormSet(xParent
, UNO_QUERY
);
268 Any
aTmp(xFormSet
->getPropertyValue( PROPERTY_TARGET_URL
));
269 if (!isA(aTmp
, static_cast< OUString
* >(NULL
)) ||
270 getString(aTmp
).isEmpty() )
273 Reference
<XIndexAccess
> xElements(xParent
, UNO_QUERY
);
274 sal_Int32 nCount
= xElements
->getCount();
278 Reference
<com::sun::star::beans::XPropertySet
> xFCSet
;
279 for( sal_Int32 nIndex
=0; nIndex
< nCount
; nIndex
++ )
281 // Any aElement(xElements->getByIndex(nIndex));
282 xElements
->getByIndex(nIndex
) >>= xFCSet
;
284 if (hasProperty(PROPERTY_CLASSID
, xFCSet
) &&
285 getINT16(xFCSet
->getPropertyValue(PROPERTY_CLASSID
)) == FormComponentType::TEXTFIELD
)
287 // Noch ein weiteres Edit gefunden ==> dann nicht submitten
294 // Da wir noch im Haender stehen, submit asynchron ausloesen
296 Application::RemoveUserEvent( m_nKeyEvent
);
297 m_nKeyEvent
= Application::PostUserEvent( LINK(this, OFormattedControl
,
301 //------------------------------------------------------------------------------
302 void OFormattedControl::keyReleased(const ::com::sun::star::awt::KeyEvent
& /*e*/) throw ( ::com::sun::star::uno::RuntimeException
)
306 //------------------------------------------------------------------------------
307 IMPL_LINK(OFormattedControl
, OnKeyPressed
, void*, /*EMPTYARG*/)
311 Reference
<XFormComponent
> xFComp(getModel(), UNO_QUERY
);
312 InterfaceRef xParent
= xFComp
->getParent();
313 Reference
<XSubmit
> xSubmit(xParent
, UNO_QUERY
);
315 xSubmit
->submit( Reference
<XControl
> (), ::com::sun::star::awt::MouseEvent() );
319 //------------------------------------------------------------------------------
320 StringSequence
OFormattedControl::getSupportedServiceNames() throw()
322 StringSequence aSupported
= OBoundControl::getSupportedServiceNames();
323 aSupported
.realloc(aSupported
.getLength() + 1);
325 OUString
*pArray
= aSupported
.getArray();
326 pArray
[aSupported
.getLength()-1] = FRM_SUN_CONTROL_FORMATTEDFIELD
;
330 //------------------------------------------------------------------------------
331 void OFormattedControl::setDesignMode(sal_Bool bOn
) throw ( ::com::sun::star::uno::RuntimeException
)
333 OBoundControl::setDesignMode(bOn
);
336 /*************************************************************************/
337 DBG_NAME(OFormattedModel
)
338 //------------------------------------------------------------------
339 void OFormattedModel::implConstruct()
342 m_bOriginalNumeric
= sal_False
;
343 m_bNumeric
= sal_False
;
344 m_xOriginalFormatter
= NULL
;
345 m_nKeyType
= NumberFormat::UNDEFINED
;
346 m_aNullDate
= DBTypeConversion::getStandardDate();
347 m_nFieldType
= DataType::OTHER
;
349 // default our formats supplier
350 increment(m_refCount
);
351 setPropertyToDefaultByHandle(PROPERTY_ID_FORMATSSUPPLIER
);
352 decrement(m_refCount
);
354 startAggregatePropertyListening( PROPERTY_FORMATKEY
);
355 startAggregatePropertyListening( PROPERTY_FORMATSSUPPLIER
);
358 //------------------------------------------------------------------
359 OFormattedModel::OFormattedModel(const Reference
<XMultiServiceFactory
>& _rxFactory
)
360 :OEditBaseModel(_rxFactory
, VCL_CONTROLMODEL_FORMATTEDFIELD
, FRM_SUN_CONTROL_FORMATTEDFIELD
, sal_True
, sal_True
)
361 // use the old control name for compytibility reasons
362 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
364 DBG_CTOR(OFormattedModel
, NULL
);
368 m_nClassId
= FormComponentType::TEXTFIELD
;
369 initValueProperty( PROPERTY_EFFECTIVE_VALUE
, PROPERTY_ID_EFFECTIVE_VALUE
);
372 //------------------------------------------------------------------
373 OFormattedModel::OFormattedModel( const OFormattedModel
* _pOriginal
, const Reference
< XMultiServiceFactory
>& _rxFactory
)
374 :OEditBaseModel( _pOriginal
, _rxFactory
)
375 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
377 DBG_CTOR(OFormattedModel
, NULL
);
382 //------------------------------------------------------------------------------
383 OFormattedModel::~OFormattedModel()
385 DBG_DTOR(OFormattedModel
, NULL
);
389 //------------------------------------------------------------------------------
390 IMPLEMENT_DEFAULT_CLONING( OFormattedModel
)
392 //------------------------------------------------------------------------------
393 void SAL_CALL
OFormattedModel::disposing()
395 OErrorBroadcaster::disposing();
396 OEditBaseModel::disposing();
400 //------------------------------------------------------------------------------
401 StringSequence
OFormattedModel::getSupportedServiceNames() throw()
403 StringSequence aSupported
= OEditBaseModel::getSupportedServiceNames();
405 sal_Int32 nOldLen
= aSupported
.getLength();
406 aSupported
.realloc( nOldLen
+ 8 );
407 OUString
* pStoreTo
= aSupported
.getArray() + nOldLen
;
409 *pStoreTo
++ = BINDABLE_CONTROL_MODEL
;
410 *pStoreTo
++ = DATA_AWARE_CONTROL_MODEL
;
411 *pStoreTo
++ = VALIDATABLE_CONTROL_MODEL
;
413 *pStoreTo
++ = BINDABLE_DATA_AWARE_CONTROL_MODEL
;
414 *pStoreTo
++ = VALIDATABLE_BINDABLE_CONTROL_MODEL
;
416 *pStoreTo
++ = FRM_SUN_COMPONENT_FORMATTEDFIELD
;
417 *pStoreTo
++ = FRM_SUN_COMPONENT_DATABASE_FORMATTEDFIELD
;
418 *pStoreTo
++ = BINDABLE_DATABASE_FORMATTED_FIELD
;
424 //------------------------------------------------------------------------------
425 Any SAL_CALL
OFormattedModel::queryAggregation(const Type
& _rType
) throw(RuntimeException
)
427 Any aReturn
= OEditBaseModel::queryAggregation( _rType
);
428 return aReturn
.hasValue() ? aReturn
: OErrorBroadcaster::queryInterface( _rType
);
432 //------------------------------------------------------------------------------
433 Sequence
< Type
> OFormattedModel::_getTypes()
435 return ::comphelper::concatSequences(
436 OEditBaseModel::_getTypes(),
437 OErrorBroadcaster::getTypes()
442 //------------------------------------------------------------------------------
443 OUString SAL_CALL
OFormattedModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException
)
445 return OUString(FRM_COMPONENT_EDIT
);
449 //------------------------------------------------------------------------------
450 void OFormattedModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
452 BEGIN_DESCRIBE_PROPERTIES( 3, OEditBaseModel
)
453 DECL_BOOL_PROP1(EMPTY_IS_NULL
, BOUND
);
454 DECL_PROP1(TABINDEX
, sal_Int16
, BOUND
);
455 DECL_BOOL_PROP2(FILTERPROPOSAL
, BOUND
, MAYBEDEFAULT
);
456 END_DESCRIBE_PROPERTIES();
459 //------------------------------------------------------------------------------
460 void OFormattedModel::describeAggregateProperties( Sequence
< Property
>& _rAggregateProps
) const
462 OEditBaseModel::describeAggregateProperties( _rAggregateProps
);
464 // TreatAsNumeric nicht transient : wir wollen es an der UI anbinden (ist noetig, um dem EffectiveDefault
465 // - der kann Text oder Zahl sein - einen Sinn zu geben)
466 ModifyPropertyAttributes(_rAggregateProps
, PROPERTY_TREATASNUMERIC
, 0, PropertyAttribute::TRANSIENT
);
467 // same for FormatKey
468 // (though the paragraph above for the TreatAsNumeric does not hold anymore - we do not have an UI for this.
469 // But we have for the format key ...)
470 ModifyPropertyAttributes(_rAggregateProps
, PROPERTY_FORMATKEY
, 0, PropertyAttribute::TRANSIENT
);
472 RemoveProperty(_rAggregateProps
, PROPERTY_STRICTFORMAT
);
473 // no strict format property for formatted fields: it does not make sense, 'cause
474 // there is no general way to decide which characters/sub strings are allowed during the input of an
475 // arbitraryly formatted control
478 //------------------------------------------------------------------------------
479 void OFormattedModel::getFastPropertyValue(Any
& rValue
, sal_Int32 nHandle
) const
481 OEditBaseModel::getFastPropertyValue(rValue
, nHandle
);
484 //------------------------------------------------------------------------------
485 void OFormattedModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
, const Any
& rValue
) throw ( ::com::sun::star::uno::Exception
)
487 OEditBaseModel::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
490 //------------------------------------------------------------------------------
491 sal_Bool
OFormattedModel::convertFastPropertyValue(Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
492 throw( IllegalArgumentException
)
494 return OEditBaseModel::convertFastPropertyValue(rConvertedValue
, rOldValue
, nHandle
, rValue
);
497 //------------------------------------------------------------------------------
498 void OFormattedModel::setPropertyToDefaultByHandle(sal_Int32 nHandle
)
500 if (nHandle
== PROPERTY_ID_FORMATSSUPPLIER
)
502 Reference
<XNumberFormatsSupplier
> xSupplier
= calcDefaultFormatsSupplier();
503 DBG_ASSERT(m_xAggregateSet
.is(), "OFormattedModel::setPropertyToDefaultByHandle(FORMATSSUPPLIER) : have no aggregate !");
504 if (m_xAggregateSet
.is())
505 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATSSUPPLIER
, makeAny(xSupplier
));
508 OEditBaseModel::setPropertyToDefaultByHandle(nHandle
);
511 //------------------------------------------------------------------------------
512 void OFormattedModel::setPropertyToDefault(const OUString
& aPropertyName
) throw( com::sun::star::beans::UnknownPropertyException
, RuntimeException
)
514 OPropertyArrayAggregationHelper
& rPH
= m_aPropertyBagHelper
.getInfoHelper();
515 sal_Int32 nHandle
= rPH
.getHandleByName( aPropertyName
);
517 if (nHandle
== PROPERTY_ID_FORMATSSUPPLIER
)
518 setPropertyToDefaultByHandle(PROPERTY_ID_FORMATSSUPPLIER
);
520 OEditBaseModel::setPropertyToDefault(aPropertyName
);
523 //------------------------------------------------------------------------------
524 Any
OFormattedModel::getPropertyDefaultByHandle( sal_Int32 nHandle
) const
526 if (nHandle
== PROPERTY_ID_FORMATSSUPPLIER
)
528 Reference
<XNumberFormatsSupplier
> xSupplier
= calcDefaultFormatsSupplier();
529 return makeAny(xSupplier
);
532 return OEditBaseModel::getPropertyDefaultByHandle(nHandle
);
535 //------------------------------------------------------------------------------
536 Any SAL_CALL
OFormattedModel::getPropertyDefault( const OUString
& aPropertyName
) throw( com::sun::star::beans::UnknownPropertyException
, RuntimeException
)
538 OPropertyArrayAggregationHelper
& rPH
= m_aPropertyBagHelper
.getInfoHelper();
539 sal_Int32 nHandle
= rPH
.getHandleByName( aPropertyName
);
541 if (nHandle
== PROPERTY_ID_FORMATSSUPPLIER
)
542 return getPropertyDefaultByHandle(PROPERTY_ID_FORMATSSUPPLIER
);
544 return OEditBaseModel::getPropertyDefault(aPropertyName
);
547 //------------------------------------------------------------------------------
548 void OFormattedModel::_propertyChanged( const com::sun::star::beans::PropertyChangeEvent
& evt
) throw(RuntimeException
)
550 // TODO: check how this works with external bindings
552 OSL_ENSURE( evt
.Source
== m_xAggregateSet
, "OFormattedModel::_propertyChanged: where did this come from?" );
553 if ( evt
.Source
== m_xAggregateSet
)
555 Reference
< XPropertySet
> xSourceSet( evt
.Source
, UNO_QUERY
);
556 if ( evt
.PropertyName
.equals( PROPERTY_FORMATKEY
) )
558 if ( evt
.NewValue
.getValueType().getTypeClass() == TypeClass_LONG
)
562 ::osl::MutexGuard
aGuard( m_aMutex
);
564 Reference
<XNumberFormatsSupplier
> xSupplier( calcFormatsSupplier() );
565 m_nKeyType
= getNumberFormatType(xSupplier
->getNumberFormats(), getINT32( evt
.NewValue
) );
567 // as m_aSaveValue (which is used by commitControlValueToDbColumn) is format dependent we have
568 // to recalc it, which is done by translateDbColumnToControlValue
569 if ( m_xColumn
.is() && m_xAggregateFastSet
.is() && !m_xCursor
->isBeforeFirst() && !m_xCursor
->isAfterLast())
571 setControlValue( translateDbColumnToControlValue(), eOther
);
574 // if we're connected to an external value binding, then re-calculate the type
575 // used to exchange the value - it depends on the format, too
576 if ( hasExternalValueBinding() )
578 calculateExternalValueType();
581 catch(const Exception
&)
588 if ( evt
.PropertyName
.equals( PROPERTY_FORMATSSUPPLIER
) )
590 updateFormatterNullDate();
594 OBoundControlModel::_propertyChanged( evt
);
598 //------------------------------------------------------------------------------
599 void OFormattedModel::updateFormatterNullDate()
601 // calc the current NULL date
602 Reference
< XNumberFormatsSupplier
> xSupplier( calcFormatsSupplier() );
603 if ( xSupplier
.is() )
604 xSupplier
->getNumberFormatSettings()->getPropertyValue( OUString( "NullDate" ) ) >>= m_aNullDate
;
607 //------------------------------------------------------------------------------
608 Reference
< XNumberFormatsSupplier
> OFormattedModel::calcFormatsSupplier() const
610 Reference
<XNumberFormatsSupplier
> xSupplier
;
612 DBG_ASSERT(m_xAggregateSet
.is(), "OFormattedModel::calcFormatsSupplier : have no aggregate !");
613 // hat mein aggregiertes Model einen FormatSupplier ?
614 if( m_xAggregateSet
.is() )
615 m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATSSUPPLIER
) >>= xSupplier
;
618 // check if my parent form has a supplier
619 xSupplier
= calcFormFormatsSupplier();
622 xSupplier
= calcDefaultFormatsSupplier();
624 DBG_ASSERT(xSupplier
.is(), "OFormattedModel::calcFormatsSupplier : no supplier !");
625 // jetzt sollte aber einer da sein
629 //------------------------------------------------------------------------------
630 Reference
<XNumberFormatsSupplier
> OFormattedModel::calcFormFormatsSupplier() const
632 Reference
<XChild
> xMe
;
633 query_interface(static_cast<XWeak
*>(const_cast<OFormattedModel
*>(this)), xMe
);
634 // damit stellen wir sicher, dass wir auch fuer den Fall der Aggregation das richtige
636 DBG_ASSERT(xMe
.is(), "OFormattedModel::calcFormFormatsSupplier : I should have a content interface !");
638 // jetzt durchhangeln nach oben, bis wir auf eine starform treffen (angefangen mit meinem eigenen Parent)
639 Reference
<XChild
> xParent(xMe
->getParent(), UNO_QUERY
);
640 Reference
<XForm
> xNextParentForm(xParent
, UNO_QUERY
);
641 while (!xNextParentForm
.is() && xParent
.is())
643 xParent
= xParent
.query( xParent
->getParent() );
644 xNextParentForm
= xNextParentForm
.query( xParent
);
647 if (!xNextParentForm
.is())
649 OSL_FAIL("OFormattedModel::calcFormFormatsSupplier : have no ancestor which is a form !");
653 // den FormatSupplier von meinem Vorfahren (falls der einen hat)
654 Reference
< XRowSet
> xRowSet( xNextParentForm
, UNO_QUERY
);
655 Reference
< XNumberFormatsSupplier
> xSupplier
;
657 xSupplier
= getNumberFormats( getConnection(xRowSet
), sal_True
, getContext().getUNOContext() );
661 //------------------------------------------------------------------------------
662 Reference
< XNumberFormatsSupplier
> OFormattedModel::calcDefaultFormatsSupplier() const
664 return StandardFormatsSupplier::get( getContext().getUNOContext() );
668 //------------------------------------------------------------------------------
669 void OFormattedModel::loaded(const EventObject
& rEvent
) throw ( ::com::sun::star::uno::RuntimeException
)
671 // HACK : our onConnectedDbColumn accesses our NumberFormatter which locks the solar mutex (as it doesn't have
672 // an own one). To prevent deadlocks with other threads which may request a property from us in an
673 // UI-triggered action (e.g. an tooltip) we lock the solar mutex _here_ before our base class locks
674 // it's own muext (which is used for property requests)
675 // alternative a): we use two mutexes, one which is passed to the OPropertysetHelper and used for
676 // property requests and one for our own code. This would need a lot of code rewriting
677 // alternative b): The NumberFormatter has to be really threadsafe (with an own mutex), which is
678 // the only "clean" solution for me.
680 SolarMutexGuard aGuard
;
681 OEditBaseModel::loaded(rEvent
);
684 //------------------------------------------------------------------------------
685 void OFormattedModel::onConnectedDbColumn( const Reference
< XInterface
>& _rxForm
)
687 m_xOriginalFormatter
= NULL
;
689 // get some properties of the field
690 m_nFieldType
= DataType::OTHER
;
691 Reference
<XPropertySet
> xField
= getField();
693 xField
->getPropertyValue( PROPERTY_FIELDTYPE
) >>= m_nFieldType
;
695 sal_Int32 nFormatKey
= 0;
697 DBG_ASSERT(m_xAggregateSet
.is(), "OFormattedModel::onConnectedDbColumn : have no aggregate !");
698 if (m_xAggregateSet
.is())
699 { // all the following doesn't make any sense if we have no aggregate ...
700 Any aSupplier
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATSSUPPLIER
);
701 DBG_ASSERT( aSupplier
.hasValue(), "OFormattedModel::onConnectedDbColumn : invalid property value !" );
702 // das sollte im Constructor oder im read auf was richtiges gesetzt worden sein
704 Any aFmtKey
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATKEY
);
705 if ( !(aFmtKey
>>= nFormatKey
) )
706 { // nobody gave us a format to use. So we examine the field we're bound to for a
707 // format key, and use it ourself, too
708 sal_Int32 nType
= DataType::VARCHAR
;
711 aFmtKey
= xField
->getPropertyValue(PROPERTY_FORMATKEY
);
712 xField
->getPropertyValue(PROPERTY_FIELDTYPE
) >>= nType
;
715 Reference
<XNumberFormatsSupplier
> xSupplier
= calcFormFormatsSupplier();
716 DBG_ASSERT(xSupplier
.is(), "OFormattedModel::onConnectedDbColumn : bound to a field but no parent with a formatter ? how this ?");
719 m_bOriginalNumeric
= getBOOL(getPropertyValue(PROPERTY_TREATASNUMERIC
));
721 if (!aFmtKey
.hasValue())
722 { // we aren't bound to a field (or this field's format is invalid)
723 // -> determine the standard text (or numeric) format of the supplier
724 Reference
<XNumberFormatTypes
> xTypes(xSupplier
->getNumberFormats(), UNO_QUERY
);
727 Locale aApplicationLocale
= Application::GetSettings().GetUILanguageTag().getLocale();
729 if (m_bOriginalNumeric
)
730 aFmtKey
<<= (sal_Int32
)xTypes
->getStandardFormat(NumberFormat::NUMBER
, aApplicationLocale
);
732 aFmtKey
<<= (sal_Int32
)xTypes
->getStandardFormat(NumberFormat::TEXT
, aApplicationLocale
);
736 aSupplier
>>= m_xOriginalFormatter
;
737 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATSSUPPLIER
, makeAny(xSupplier
));
738 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATKEY
, aFmtKey
);
740 // das Numeric-Flag an mein gebundenes Feld anpassen
743 m_bNumeric
= sal_False
;
747 case DataType::BOOLEAN
:
748 case DataType::TINYINT
:
749 case DataType::SMALLINT
:
750 case DataType::INTEGER
:
751 case DataType::BIGINT
:
752 case DataType::FLOAT
:
754 case DataType::DOUBLE
:
755 case DataType::NUMERIC
:
756 case DataType::DECIMAL
:
759 case DataType::TIMESTAMP
:
760 m_bNumeric
= sal_True
;
765 m_bNumeric
= m_bOriginalNumeric
;
767 setPropertyValue(PROPERTY_TREATASNUMERIC
, makeAny((sal_Bool
)m_bNumeric
));
769 OSL_VERIFY( aFmtKey
>>= nFormatKey
);
774 Reference
<XNumberFormatsSupplier
> xSupplier
= calcFormatsSupplier();
775 m_bNumeric
= getBOOL( getPropertyValue( PROPERTY_TREATASNUMERIC
) );
776 m_nKeyType
= getNumberFormatType( xSupplier
->getNumberFormats(), nFormatKey
);
777 xSupplier
->getNumberFormatSettings()->getPropertyValue( OUString("NullDate") ) >>= m_aNullDate
;
779 OEditBaseModel::onConnectedDbColumn( _rxForm
);
782 //------------------------------------------------------------------------------
783 void OFormattedModel::onDisconnectedDbColumn()
785 OEditBaseModel::onDisconnectedDbColumn();
786 if (m_xOriginalFormatter
.is())
787 { // unser aggregiertes Model hatte keinerlei Format-Informationen
788 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATSSUPPLIER
, makeAny(m_xOriginalFormatter
));
789 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATKEY
, Any());
790 setPropertyValue(PROPERTY_TREATASNUMERIC
, makeAny((sal_Bool
)m_bOriginalNumeric
));
791 m_xOriginalFormatter
= NULL
;
794 m_nFieldType
= DataType::OTHER
;
795 m_nKeyType
= NumberFormat::UNDEFINED
;
796 m_aNullDate
= DBTypeConversion::getStandardDate();
799 //------------------------------------------------------------------------------
800 void OFormattedModel::write(const Reference
<XObjectOutputStream
>& _rxOutStream
) throw ( ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
)
802 OEditBaseModel::write(_rxOutStream
);
803 _rxOutStream
->writeShort(0x0003);
805 DBG_ASSERT(m_xAggregateSet
.is(), "OFormattedModel::write : have no aggregate !");
807 // mein Format (evtl. void) in ein persistentes Format bringen (der Supplier zusammen mit dem Key ist es zwar auch,
808 // aber deswegen muessen wir ja nicht gleich den ganzen Supplier speichern, das waere ein klein wenig Overhead ;)
810 Reference
<XNumberFormatsSupplier
> xSupplier
;
812 sal_Bool bVoidKey
= sal_True
;
813 if (m_xAggregateSet
.is())
815 Any aSupplier
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATSSUPPLIER
);
816 if (aSupplier
.getValueType().getTypeClass() != TypeClass_VOID
)
818 OSL_VERIFY( aSupplier
>>= xSupplier
);
821 aFmtKey
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATKEY
);
822 bVoidKey
= (!xSupplier
.is() || !aFmtKey
.hasValue()) || (isLoaded() && m_xOriginalFormatter
.is());
823 // (kein Fomatter und/oder Key) oder (loaded und faked Formatter)
826 _rxOutStream
->writeBoolean(!bVoidKey
);
829 // aus dem FormatKey und dem Formatter persistente Angaben basteln
831 Any aKey
= m_xAggregateSet
->getPropertyValue(PROPERTY_FORMATKEY
);
832 sal_Int32 nKey
= aKey
.hasValue() ? getINT32(aKey
) : 0;
834 Reference
<XNumberFormats
> xFormats
= xSupplier
->getNumberFormats();
836 OUString sFormatDescription
;
837 LanguageType eFormatLanguage
= LANGUAGE_DONTKNOW
;
839 static const OUString
s_aLocaleProp ("Locale");
840 Reference
<com::sun::star::beans::XPropertySet
> xFormat
= xFormats
->getByKey(nKey
);
841 if (hasProperty(s_aLocaleProp
, xFormat
))
843 Any aLocale
= xFormat
->getPropertyValue(s_aLocaleProp
);
844 DBG_ASSERT(isA(aLocale
, static_cast<Locale
*>(NULL
)), "OFormattedModel::write : invalid language property !");
845 if (isA(aLocale
, static_cast<Locale
*>(NULL
)))
847 Locale
* pLocale
= (Locale
*)aLocale
.getValue();
848 eFormatLanguage
= LanguageTag( *pLocale
).getLanguageType( false);
852 static const OUString
s_aFormatStringProp ("FormatString");
853 if (hasProperty(s_aFormatStringProp
, xFormat
))
854 xFormat
->getPropertyValue(s_aFormatStringProp
) >>= sFormatDescription
;
856 _rxOutStream
->writeUTF(sFormatDescription
);
857 _rxOutStream
->writeLong((sal_Int32
)eFormatLanguage
);
860 // version 2 : write the properties common to all OEditBaseModels
861 writeCommonEditProperties(_rxOutStream
);
863 // version 3 : write the effective value property of the aggregate
864 // Due to a bug within the UnoControlFormattedFieldModel implementation (our default aggregate) this props value isn't correctly read
865 // and this can't be corrected without being incompatible.
866 // so we have our own handling.
868 // and to be a little bit more compatible we make the following section skippable
870 Reference
< XDataOutputStream
> xOut(_rxOutStream
, UNO_QUERY
);
871 OStreamSection
aDownCompat(xOut
);
873 // a sub version within the skippable block
874 _rxOutStream
->writeShort(0x0000);
876 // version 0: the effective value of the aggregate
878 if (m_xAggregateSet
.is())
880 try { aEffectiveValue
= m_xAggregateSet
->getPropertyValue(PROPERTY_EFFECTIVE_VALUE
); } catch(const Exception
&) { }
884 OStreamSection
aDownCompat2(xOut
);
885 switch (aEffectiveValue
.getValueType().getTypeClass())
887 case TypeClass_STRING
:
888 _rxOutStream
->writeShort(0x0000);
889 _rxOutStream
->writeUTF(::comphelper::getString(aEffectiveValue
));
891 case TypeClass_DOUBLE
:
892 _rxOutStream
->writeShort(0x0001);
893 _rxOutStream
->writeDouble(::comphelper::getDouble(aEffectiveValue
));
895 default: // void and all unknown states
896 DBG_ASSERT(!aEffectiveValue
.hasValue(), "FmXFormattedModel::write : unknown property value type !");
897 _rxOutStream
->writeShort(0x0002);
904 //------------------------------------------------------------------------------
905 void OFormattedModel::read(const Reference
<XObjectInputStream
>& _rxInStream
) throw ( ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
)
907 OEditBaseModel::read(_rxInStream
);
908 sal_uInt16 nVersion
= _rxInStream
->readShort();
910 Reference
<XNumberFormatsSupplier
> xSupplier
;
918 sal_Bool bNonVoidKey
= _rxInStream
->readBoolean();
921 // den String und die Language lesen ....
922 OUString sFormatDescription
= _rxInStream
->readUTF();
923 LanguageType eDescriptionLanguage
= (LanguageType
)_rxInStream
->readLong();
925 // und daraus von einem Formatter zu einem Key zusammenwuerfeln lassen ...
926 xSupplier
= calcFormatsSupplier();
927 // calcFormatsSupplier nimmt erst den vom Model, dann einen von der starform, dann einen ganz neuen ....
928 Reference
<XNumberFormats
> xFormats
= xSupplier
->getNumberFormats();
932 Locale
aDescriptionLanguage( LanguageTag(eDescriptionLanguage
).getLocale());
934 nKey
= xFormats
->queryKey(sFormatDescription
, aDescriptionLanguage
, sal_False
);
935 if (nKey
== (sal_Int32
)-1)
936 { // noch nicht vorhanden in meinem Formatter ...
937 nKey
= xFormats
->addNew(sFormatDescription
, aDescriptionLanguage
);
941 if ((nVersion
== 0x0002) || (nVersion
== 0x0003))
942 readCommonEditProperties(_rxInStream
);
944 if (nVersion
== 0x0003)
945 { // since version 3 there is a "skippable" block at this position
946 Reference
< XDataInputStream
> xIn(_rxInStream
, UNO_QUERY
);
947 OStreamSection
aDownCompat(xIn
);
949 sal_Int16 nSubVersion
= _rxInStream
->readShort();
952 // version 0 and higher : the "effective value" property
955 OStreamSection
aDownCompat2(xIn
);
956 switch (_rxInStream
->readShort())
959 aEffectiveValue
<<= _rxInStream
->readUTF();
962 aEffectiveValue
<<= (double)_rxInStream
->readDouble();
967 OSL_FAIL("FmXFormattedModel::read : unknown effective value type !");
971 // this property is only to be set if we have no control source : in all other cases the base class did a
972 // reset after it's read and this set the effective value to a default value
973 if ( m_xAggregateSet
.is() && getControlSource().isEmpty() )
977 m_xAggregateSet
->setPropertyValue(PROPERTY_EFFECTIVE_VALUE
, aEffectiveValue
);
979 catch(const Exception
&)
987 OSL_FAIL("OFormattedModel::read : unknown version !");
988 // dann bleibt das Format des aggregierten Sets, wie es bei der Erzeugung ist : void
989 defaultCommonEditProperties();
993 if ((nKey
!= -1) && m_xAggregateSet
.is())
995 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATSSUPPLIER
, makeAny(xSupplier
));
996 m_xAggregateSet
->setPropertyValue(PROPERTY_FORMATKEY
, makeAny((sal_Int32
)nKey
));
1000 setPropertyToDefault(PROPERTY_FORMATSSUPPLIER
);
1001 setPropertyToDefault(PROPERTY_FORMATKEY
);
1005 //------------------------------------------------------------------------------
1006 sal_uInt16
OFormattedModel::getPersistenceFlags() const
1008 return (OEditBaseModel::getPersistenceFlags() & ~PF_HANDLE_COMMON_PROPS
);
1009 // a) we do our own call to writeCommonEditProperties
1012 //------------------------------------------------------------------------------
1013 sal_Bool
OFormattedModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
1015 Any
aControlValue( m_xAggregateFastSet
->getFastPropertyValue( getValuePropertyAggHandle() ) );
1016 if ( aControlValue
!= m_aSaveValue
)
1018 // Leerstring + EmptyIsNull = void
1019 if ( !aControlValue
.hasValue()
1020 || ( ( aControlValue
.getValueType().getTypeClass() == TypeClass_STRING
)
1021 && getString( aControlValue
).isEmpty()
1025 m_xColumnUpdate
->updateNull();
1031 if ( aControlValue
.getValueType().getTypeClass() == TypeClass_DOUBLE
|| (aControlValue
>>= f
)) // #i110323
1033 DBTypeConversion::setValue( m_xColumnUpdate
, m_aNullDate
, getDouble( aControlValue
), m_nKeyType
);
1037 DBG_ASSERT( aControlValue
.getValueType().getTypeClass() == TypeClass_STRING
, "OFormattedModel::commitControlValueToDbColumn: invalud value type !" );
1038 m_xColumnUpdate
->updateString( getString( aControlValue
) );
1041 catch(const Exception
&)
1046 m_aSaveValue
= aControlValue
;
1051 //------------------------------------------------------------------------------
1052 void OFormattedModel::onConnectedExternalValue( )
1054 OEditBaseModel::onConnectedExternalValue();
1055 updateFormatterNullDate();
1058 //------------------------------------------------------------------------------
1059 Any
OFormattedModel::translateExternalValueToControlValue( const Any
& _rExternalValue
) const
1062 switch( _rExternalValue
.getValueTypeClass() )
1064 case TypeClass_VOID
:
1067 case TypeClass_STRING
:
1068 aControlValue
= _rExternalValue
;
1071 case TypeClass_BOOLEAN
:
1073 sal_Bool bExternalValue
= sal_False
;
1074 _rExternalValue
>>= bExternalValue
;
1075 aControlValue
<<= (double)( bExternalValue
? 1 : 0 );
1081 if ( _rExternalValue
.getValueType().equals( ::getCppuType( static_cast< UNODate
* >( NULL
) ) ) )
1084 _rExternalValue
>>= aDate
;
1085 aControlValue
<<= DBTypeConversion::toDouble( aDate
, m_aNullDate
);
1087 else if ( _rExternalValue
.getValueType().equals( ::getCppuType( static_cast< UNOTime
* >( NULL
) ) ) )
1090 _rExternalValue
>>= aTime
;
1091 aControlValue
<<= DBTypeConversion::toDouble( aTime
);
1093 else if ( _rExternalValue
.getValueType().equals( ::getCppuType( static_cast< UNODateTime
* >( NULL
) ) ) )
1095 UNODateTime aDateTime
;
1096 _rExternalValue
>>= aDateTime
;
1097 aControlValue
<<= DBTypeConversion::toDouble( aDateTime
, m_aNullDate
);
1101 OSL_ENSURE( _rExternalValue
.getValueTypeClass() == TypeClass_DOUBLE
,
1102 "OFormattedModel::translateExternalValueToControlValue: don't know how to translate this type!" );
1104 OSL_VERIFY( _rExternalValue
>>= fValue
);
1105 aControlValue
<<= fValue
;
1110 return aControlValue
;
1113 //------------------------------------------------------------------------------
1114 Any
OFormattedModel::translateControlValueToExternalValue( ) const
1116 OSL_PRECOND( hasExternalValueBinding(),
1117 "OFormattedModel::translateControlValueToExternalValue: precondition not met!" );
1119 Any
aControlValue( getControlValue() );
1120 if ( !aControlValue
.hasValue() )
1121 return aControlValue
;
1125 // translate into the external value type
1126 Type
aExternalValueType( getExternalValueType() );
1127 switch ( aExternalValueType
.getTypeClass() )
1129 case TypeClass_STRING
:
1132 if ( aControlValue
>>= sString
)
1134 aExternalValue
<<= sString
;
1140 case TypeClass_BOOLEAN
:
1143 OSL_VERIFY( aControlValue
>>= fValue
);
1144 // if this asserts ... well, the somebody set the TreatAsNumeric property to false,
1145 // and the control value is a string. This implies some weird misconfiguration
1146 // of the FormattedModel, so we won't care for it for the moment.
1147 aExternalValue
<<= (sal_Bool
)( fValue
? sal_True
: sal_False
);
1154 OSL_VERIFY( aControlValue
>>= fValue
);
1155 // if this asserts ... well, the somebody set the TreatAsNumeric property to false,
1156 // and the control value is a string. This implies some weird misconfiguration
1157 // of the FormattedModel, so we won't care for it for the moment.
1159 if ( aExternalValueType
.equals( ::getCppuType( static_cast< UNODate
* >( NULL
) ) ) )
1161 aExternalValue
<<= DBTypeConversion::toDate( fValue
, m_aNullDate
);
1163 else if ( aExternalValueType
.equals( ::getCppuType( static_cast< UNOTime
* >( NULL
) ) ) )
1165 aExternalValue
<<= DBTypeConversion::toTime( fValue
);
1167 else if ( aExternalValueType
.equals( ::getCppuType( static_cast< UNODateTime
* >( NULL
) ) ) )
1169 aExternalValue
<<= DBTypeConversion::toDateTime( fValue
, m_aNullDate
);
1173 OSL_ENSURE( aExternalValueType
.equals( ::getCppuType( static_cast< double* >( NULL
) ) ),
1174 "OFormattedModel::translateControlValueToExternalValue: don't know how to translate this type!" );
1175 aExternalValue
<<= fValue
;
1180 return aExternalValue
;
1183 //------------------------------------------------------------------------------
1184 Any
OFormattedModel::translateDbColumnToControlValue()
1187 m_aSaveValue
<<= DBTypeConversion::getValue( m_xColumn
, m_aNullDate
); // #100056# OJ
1189 m_aSaveValue
<<= m_xColumn
->getString();
1191 if ( m_xColumn
->wasNull() )
1192 m_aSaveValue
.clear();
1194 return m_aSaveValue
;
1197 // -----------------------------------------------------------------------------
1198 Sequence
< Type
> OFormattedModel::getSupportedBindingTypes()
1200 ::std::list
< Type
> aTypes
;
1201 aTypes
.push_back( ::getCppuType( static_cast< double* >( NULL
) ) );
1203 switch ( m_nKeyType
& ~NumberFormat::DEFINED
)
1205 case NumberFormat::DATE
:
1206 aTypes
.push_front(::getCppuType( static_cast< UNODate
* >( NULL
) ) );
1208 case NumberFormat::TIME
:
1209 aTypes
.push_front(::getCppuType( static_cast< UNOTime
* >( NULL
) ) );
1211 case NumberFormat::DATETIME
:
1212 aTypes
.push_front(::getCppuType( static_cast< UNODateTime
* >( NULL
) ) );
1214 case NumberFormat::TEXT
:
1215 aTypes
.push_front(::getCppuType( static_cast< OUString
* >( NULL
) ) );
1217 case NumberFormat::LOGICAL
:
1218 aTypes
.push_front(::getCppuType( static_cast< sal_Bool
* >( NULL
) ) );
1222 Sequence
< Type
> aTypesRet( aTypes
.size() );
1223 ::std::copy( aTypes
.begin(), aTypes
.end(), aTypesRet
.getArray() );
1227 //------------------------------------------------------------------------------
1228 Any
OFormattedModel::getDefaultForReset() const
1230 return m_xAggregateSet
->getPropertyValue( PROPERTY_EFFECTIVE_DEFAULT
);
1233 //------------------------------------------------------------------------------
1234 void OFormattedModel::resetNoBroadcast()
1236 OEditBaseModel::resetNoBroadcast();
1237 m_aSaveValue
.clear();
1240 //.........................................................................
1242 //.........................................................................
1244 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */