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 .
20 #include "cellvalueconversion.hxx"
22 #include <com/sun/star/util/NumberFormatter.hpp>
23 #include <com/sun/star/util/NumberFormatsSupplier.hpp>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/util/Date.hpp>
26 #include <com/sun/star/util/Time.hpp>
27 #include <com/sun/star/util/DateTime.hpp>
28 #include <com/sun/star/util/XNumberFormatTypes.hpp>
29 #include <com/sun/star/util/NumberFormat.hpp>
30 #include <rtl/strbuf.hxx>
31 #include <rtl/math.hxx>
32 #include <tools/date.hxx>
33 #include <tools/time.hxx>
34 #include <tools/diagnose_ex.h>
35 #include <unotools/syslocale.hxx>
36 #include <comphelper/processfactory.hxx>
38 #include <boost/shared_ptr.hpp>
39 #include <boost/unordered_map.hpp>
41 //......................................................................................................................
44 //......................................................................................................................
46 using namespace ::com::sun::star::uno
;
47 using ::com::sun::star::util::XNumberFormatter
;
48 using ::com::sun::star::util::XNumberFormatter2
;
49 using ::com::sun::star::util::NumberFormatter
;
50 using ::com::sun::star::util::XNumberFormatsSupplier
;
51 using ::com::sun::star::util::NumberFormatsSupplier
;
52 using ::com::sun::star::beans::XPropertySet
;
53 using ::com::sun::star::lang::Locale
;
54 using ::com::sun::star::util::DateTime
;
55 using ::com::sun::star::util::XNumberFormatTypes
;
57 namespace NumberFormat
= ::com::sun::star::util::NumberFormat
;
59 typedef ::com::sun::star::util::Time UnoTime
;
60 typedef ::com::sun::star::util::Date UnoDate
;
62 //==================================================================================================================
64 //==================================================================================================================
67 //--------------------------------------------------------------------------------------------------------------
68 double lcl_convertDateToDays( long const i_day
, long const i_month
, long const i_year
)
70 long const nNullDateDays
= ::Date::DateToDays( 1, 1, 1900 );
71 long const nValueDateDays
= ::Date::DateToDays( i_day
, i_month
, i_year
);
73 return nValueDateDays
- nNullDateDays
;
76 //--------------------------------------------------------------------------------------------------------------
77 double lcl_convertTimeToDays( long const i_hours
, long const i_minutes
, long const i_seconds
, long const i_100thSeconds
)
79 return Time( i_hours
, i_minutes
, i_seconds
, i_100thSeconds
).GetTimeInDays();
83 //==================================================================================================================
84 //= IValueNormalization
85 //==================================================================================================================
86 class SAL_NO_VTABLE IValueNormalization
89 virtual ~IValueNormalization() { }
91 /** converts the given <code>Any</code> into a <code>double</code> value to be fed into a number formatter
93 virtual double convertToDouble( Any
const & i_value
) const = 0;
95 /** returns the format key to be used for formatting values
97 virtual ::sal_Int32
getFormatKey() const = 0;
100 typedef ::boost::shared_ptr
< IValueNormalization
> PValueNormalization
;
101 typedef ::boost::unordered_map
< OUString
, PValueNormalization
, OUStringHash
> NormalizerCache
;
103 //==================================================================================================================
104 //= CellValueConversion_Data
105 //==================================================================================================================
106 struct CellValueConversion_Data
108 Reference
< XNumberFormatter
> xNumberFormatter
;
109 bool bAttemptedFormatterCreation
;
110 NormalizerCache aNormalizers
;
112 CellValueConversion_Data()
114 ,bAttemptedFormatterCreation( false )
120 //==================================================================================================================
121 //= StandardFormatNormalizer
122 //==================================================================================================================
123 class StandardFormatNormalizer
: public IValueNormalization
126 StandardFormatNormalizer( Reference
< XNumberFormatter
> const & i_formatter
, ::sal_Int32
const i_numberFormatType
)
131 ENSURE_OR_THROW( i_formatter
.is(), "StandardFormatNormalizer: no formatter!" );
132 Reference
< XNumberFormatsSupplier
> const xSupplier( i_formatter
->getNumberFormatsSupplier(), UNO_SET_THROW
);
133 Reference
< XNumberFormatTypes
> const xTypes( xSupplier
->getNumberFormats(), UNO_QUERY_THROW
);
134 m_nFormatKey
= xTypes
->getStandardFormat( i_numberFormatType
, SvtSysLocale().GetLanguageTag().getLocale() );
136 catch( const Exception
& )
138 DBG_UNHANDLED_EXCEPTION();
142 virtual ::sal_Int32
getFormatKey() const
148 ::sal_Int32 m_nFormatKey
;
151 //==================================================================================================================
152 //= DoubleNormalization
153 //==================================================================================================================
154 class DoubleNormalization
: public StandardFormatNormalizer
157 DoubleNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
158 :StandardFormatNormalizer( i_formatter
, NumberFormat::NUMBER
)
162 virtual double convertToDouble( Any
const & i_value
) const
164 double returnValue(0);
165 ::rtl::math::setNan( &returnValue
);
166 OSL_VERIFY( i_value
>>= returnValue
);
170 virtual ~DoubleNormalization() { }
173 //==================================================================================================================
174 //= IntegerNormalization
175 //==================================================================================================================
176 class IntegerNormalization
: public StandardFormatNormalizer
179 IntegerNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
180 :StandardFormatNormalizer( i_formatter
, NumberFormat::NUMBER
)
184 virtual ~IntegerNormalization() {}
186 virtual double convertToDouble( Any
const & i_value
) const
188 sal_Int64
value( 0 );
189 OSL_VERIFY( i_value
>>= value
);
194 //==================================================================================================================
195 //= BooleanNormalization
196 //==================================================================================================================
197 class BooleanNormalization
: public StandardFormatNormalizer
200 BooleanNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
201 :StandardFormatNormalizer( i_formatter
, NumberFormat::LOGICAL
)
205 virtual ~BooleanNormalization() {}
207 virtual double convertToDouble( Any
const & i_value
) const
210 OSL_VERIFY( i_value
>>= value
);
211 return value
? 1 : 0;
215 //==================================================================================================================
216 //= DateTimeNormalization
217 //==================================================================================================================
218 class DateTimeNormalization
: public StandardFormatNormalizer
221 DateTimeNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
222 :StandardFormatNormalizer( i_formatter
, NumberFormat::DATETIME
)
226 virtual ~DateTimeNormalization() {}
228 virtual double convertToDouble( Any
const & i_value
) const
230 double returnValue(0);
231 ::rtl::math::setNan( &returnValue
);
233 // extract actual UNO value
234 DateTime aDateTimeValue
;
235 ENSURE_OR_RETURN( i_value
>>= aDateTimeValue
, "allowed for DateTime values only", returnValue
);
238 returnValue
= lcl_convertDateToDays( aDateTimeValue
.Day
, aDateTimeValue
.Month
, aDateTimeValue
.Year
);
241 returnValue
+= lcl_convertTimeToDays(
242 aDateTimeValue
.Hours
, aDateTimeValue
.Minutes
, aDateTimeValue
.Seconds
, aDateTimeValue
.NanoSeconds
);
249 //==================================================================================================================
250 //= DateNormalization
251 //==================================================================================================================
252 class DateNormalization
: public StandardFormatNormalizer
255 DateNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
256 :StandardFormatNormalizer( i_formatter
, NumberFormat::DATE
)
260 virtual ~DateNormalization() {}
262 virtual double convertToDouble( Any
const & i_value
) const
264 double returnValue(0);
265 ::rtl::math::setNan( &returnValue
);
269 ENSURE_OR_RETURN( i_value
>>= aDateValue
, "allowed for Date values only", returnValue
);
272 returnValue
= lcl_convertDateToDays( aDateValue
.Day
, aDateValue
.Month
, aDateValue
.Year
);
279 //==================================================================================================================
280 //= TimeNormalization
281 //==================================================================================================================
282 class TimeNormalization
: public StandardFormatNormalizer
285 TimeNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
286 :StandardFormatNormalizer( i_formatter
, NumberFormat::TIME
)
290 virtual ~TimeNormalization() {}
292 virtual double convertToDouble( Any
const & i_value
) const
294 double returnValue(0);
295 ::rtl::math::setNan( &returnValue
);
299 ENSURE_OR_RETURN( i_value
>>= aTimeValue
, "allowed for Time values only", returnValue
);
302 returnValue
+= lcl_convertTimeToDays(
303 aTimeValue
.Hours
, aTimeValue
.Minutes
, aTimeValue
.Seconds
, aTimeValue
.NanoSeconds
);
310 //==================================================================================================================
312 //==================================================================================================================
315 //--------------------------------------------------------------------------------------------------------------
316 bool lcl_ensureNumberFormatter( CellValueConversion_Data
& io_data
)
318 if ( io_data
.bAttemptedFormatterCreation
)
319 return io_data
.xNumberFormatter
.is();
320 io_data
.bAttemptedFormatterCreation
= true;
324 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
325 // a number formatter
326 Reference
< XNumberFormatter
> const xFormatter( NumberFormatter::create( xContext
), UNO_QUERY_THROW
);
328 // a supplier of number formats
329 Locale aLocale
= SvtSysLocale().GetLanguageTag().getLocale();
331 Reference
< XNumberFormatsSupplier
> const xSupplier
=
332 NumberFormatsSupplier::createWithLocale( xContext
, aLocale
);
334 // ensure a NullDate we will assume later on
335 UnoDate
const aNullDate( 1, 1, 1900 );
336 Reference
< XPropertySet
> const xFormatSettings( xSupplier
->getNumberFormatSettings(), UNO_SET_THROW
);
337 xFormatSettings
->setPropertyValue( "NullDate", makeAny( aNullDate
) );
340 xFormatter
->attachNumberFormatsSupplier( xSupplier
);
343 io_data
.xNumberFormatter
= xFormatter
;
345 catch( const Exception
& )
347 DBG_UNHANDLED_EXCEPTION();
350 return io_data
.xNumberFormatter
.is();
353 //--------------------------------------------------------------------------------------------------------------
354 bool lcl_getValueNormalizer( CellValueConversion_Data
& io_data
, Type
const & i_valueType
,
355 PValueNormalization
& o_formatter
)
357 NormalizerCache::const_iterator pos
= io_data
.aNormalizers
.find( i_valueType
.getTypeName() );
358 if ( pos
== io_data
.aNormalizers
.end() )
360 // never encountered this type before
363 OUString
const sTypeName( i_valueType
.getTypeName() );
364 TypeClass
const eTypeClass
= i_valueType
.getTypeClass();
366 if ( sTypeName
.equals( ::cppu::UnoType
< DateTime
>::get().getTypeName() ) )
368 o_formatter
.reset( new DateTimeNormalization( io_data
.xNumberFormatter
) );
370 else if ( sTypeName
.equals( ::cppu::UnoType
< UnoDate
>::get().getTypeName() ) )
372 o_formatter
.reset( new DateNormalization( io_data
.xNumberFormatter
) );
374 else if ( sTypeName
.equals( ::cppu::UnoType
< UnoTime
>::get().getTypeName() ) )
376 o_formatter
.reset( new TimeNormalization( io_data
.xNumberFormatter
) );
378 else if ( sTypeName
.equals( ::cppu::UnoType
< ::sal_Bool
>::get().getTypeName() ) )
380 o_formatter
.reset( new BooleanNormalization( io_data
.xNumberFormatter
) );
382 else if ( sTypeName
.equals( ::cppu::UnoType
< double >::get().getTypeName() )
383 || sTypeName
.equals( ::cppu::UnoType
< float >::get().getTypeName() )
386 o_formatter
.reset( new DoubleNormalization( io_data
.xNumberFormatter
) );
388 else if ( ( eTypeClass
== TypeClass_BYTE
)
389 || ( eTypeClass
== TypeClass_SHORT
)
390 || ( eTypeClass
== TypeClass_UNSIGNED_SHORT
)
391 || ( eTypeClass
== TypeClass_LONG
)
392 || ( eTypeClass
== TypeClass_UNSIGNED_LONG
)
393 || ( eTypeClass
== TypeClass_HYPER
)
396 o_formatter
.reset( new IntegerNormalization( io_data
.xNumberFormatter
) );
400 SAL_WARN( "svtools.table", "unsupported type '" << sTypeName
<< "'!" );
402 io_data
.aNormalizers
[ sTypeName
] = o_formatter
;
405 o_formatter
= pos
->second
;
407 return !!o_formatter
;
411 //==================================================================================================================
412 //= CellValueConversion
413 //==================================================================================================================
414 //------------------------------------------------------------------------------------------------------------------
415 CellValueConversion::CellValueConversion()
416 :m_pData( new CellValueConversion_Data
)
420 //------------------------------------------------------------------------------------------------------------------
421 CellValueConversion::~CellValueConversion()
425 //------------------------------------------------------------------------------------------------------------------
426 OUString
CellValueConversion::convertToString( const Any
& i_value
)
428 OUString sStringValue
;
429 if ( !i_value
.hasValue() )
432 if ( ! ( i_value
>>= sStringValue
) )
434 if ( lcl_ensureNumberFormatter( *m_pData
) )
436 PValueNormalization pNormalizer
;
437 if ( lcl_getValueNormalizer( *m_pData
, i_value
.getValueType(), pNormalizer
) )
441 double const formatterCompliantValue
= pNormalizer
->convertToDouble( i_value
);
442 sal_Int32
const formatKey
= pNormalizer
->getFormatKey();
443 sStringValue
= m_pData
->xNumberFormatter
->convertNumberToString(
444 formatKey
, formatterCompliantValue
);
446 catch( const Exception
& )
448 DBG_UNHANDLED_EXCEPTION();
457 //......................................................................................................................
459 //......................................................................................................................
461 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */