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 <unordered_map>
45 using namespace ::com::sun::star::uno
;
46 using ::com::sun::star::util::XNumberFormatter
;
47 using ::com::sun::star::util::XNumberFormatter2
;
48 using ::com::sun::star::util::NumberFormatter
;
49 using ::com::sun::star::util::XNumberFormatsSupplier
;
50 using ::com::sun::star::util::NumberFormatsSupplier
;
51 using ::com::sun::star::beans::XPropertySet
;
52 using ::com::sun::star::lang::Locale
;
53 using ::com::sun::star::util::DateTime
;
54 using ::com::sun::star::util::XNumberFormatTypes
;
56 namespace NumberFormat
= ::com::sun::star::util::NumberFormat
;
58 typedef ::com::sun::star::util::Time UnoTime
;
59 typedef ::com::sun::star::util::Date UnoDate
;
67 double lcl_convertDateToDays( long const i_day
, long const i_month
, long const i_year
)
69 long const nNullDateDays
= ::Date::DateToDays( 1, 1, 1900 );
70 long const nValueDateDays
= ::Date::DateToDays( i_day
, i_month
, i_year
);
72 return nValueDateDays
- nNullDateDays
;
76 double lcl_convertTimeToDays( long const i_hours
, long const i_minutes
, long const i_seconds
, long const i_100thSeconds
)
78 return tools::Time( i_hours
, i_minutes
, i_seconds
, i_100thSeconds
).GetTimeInDays();
83 //= IValueNormalization
85 class SAL_NO_VTABLE IValueNormalization
88 virtual ~IValueNormalization() { }
90 /** converts the given <code>Any</code> into a <code>double</code> value to be fed into a number formatter
92 virtual double convertToDouble( Any
const & i_value
) const = 0;
94 /** returns the format key to be used for formatting values
96 virtual ::sal_Int32
getFormatKey() const = 0;
99 typedef ::boost::shared_ptr
< IValueNormalization
> PValueNormalization
;
100 typedef std::unordered_map
< OUString
, PValueNormalization
, OUStringHash
> NormalizerCache
;
103 //= CellValueConversion_Data
105 struct CellValueConversion_Data
107 Reference
< XNumberFormatter
> xNumberFormatter
;
108 bool bAttemptedFormatterCreation
;
109 NormalizerCache aNormalizers
;
111 CellValueConversion_Data()
113 ,bAttemptedFormatterCreation( false )
120 //= StandardFormatNormalizer
122 class StandardFormatNormalizer
: public IValueNormalization
125 StandardFormatNormalizer( Reference
< XNumberFormatter
> const & i_formatter
, ::sal_Int32
const i_numberFormatType
)
130 ENSURE_OR_THROW( i_formatter
.is(), "StandardFormatNormalizer: no formatter!" );
131 Reference
< XNumberFormatsSupplier
> const xSupplier( i_formatter
->getNumberFormatsSupplier(), UNO_SET_THROW
);
132 Reference
< XNumberFormatTypes
> const xTypes( xSupplier
->getNumberFormats(), UNO_QUERY_THROW
);
133 m_nFormatKey
= xTypes
->getStandardFormat( i_numberFormatType
, SvtSysLocale().GetLanguageTag().getLocale() );
135 catch( const Exception
& )
137 DBG_UNHANDLED_EXCEPTION();
141 virtual ::sal_Int32
getFormatKey() const SAL_OVERRIDE
147 ::sal_Int32 m_nFormatKey
;
151 //= DoubleNormalization
153 class DoubleNormalization
: public StandardFormatNormalizer
156 DoubleNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
157 :StandardFormatNormalizer( i_formatter
, NumberFormat::NUMBER
)
161 virtual double convertToDouble( Any
const & i_value
) const SAL_OVERRIDE
163 double returnValue(0);
164 ::rtl::math::setNan( &returnValue
);
165 OSL_VERIFY( i_value
>>= returnValue
);
169 virtual ~DoubleNormalization() { }
173 //= IntegerNormalization
175 class IntegerNormalization
: public StandardFormatNormalizer
178 IntegerNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
179 :StandardFormatNormalizer( i_formatter
, NumberFormat::NUMBER
)
183 virtual ~IntegerNormalization() {}
185 virtual double convertToDouble( Any
const & i_value
) const SAL_OVERRIDE
187 sal_Int64
value( 0 );
188 OSL_VERIFY( i_value
>>= value
);
194 //= BooleanNormalization
196 class BooleanNormalization
: public StandardFormatNormalizer
199 BooleanNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
200 :StandardFormatNormalizer( i_formatter
, NumberFormat::LOGICAL
)
204 virtual ~BooleanNormalization() {}
206 virtual double convertToDouble( Any
const & i_value
) const SAL_OVERRIDE
209 OSL_VERIFY( i_value
>>= value
);
210 return value
? 1 : 0;
215 //= DateTimeNormalization
217 class DateTimeNormalization
: public StandardFormatNormalizer
220 DateTimeNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
221 :StandardFormatNormalizer( i_formatter
, NumberFormat::DATETIME
)
225 virtual ~DateTimeNormalization() {}
227 virtual double convertToDouble( Any
const & i_value
) const SAL_OVERRIDE
229 double returnValue(0);
230 ::rtl::math::setNan( &returnValue
);
232 // extract actual UNO value
233 DateTime aDateTimeValue
;
234 ENSURE_OR_RETURN( i_value
>>= aDateTimeValue
, "allowed for DateTime values only", returnValue
);
237 returnValue
= lcl_convertDateToDays( aDateTimeValue
.Day
, aDateTimeValue
.Month
, aDateTimeValue
.Year
);
240 returnValue
+= lcl_convertTimeToDays(
241 aDateTimeValue
.Hours
, aDateTimeValue
.Minutes
, aDateTimeValue
.Seconds
, aDateTimeValue
.NanoSeconds
);
249 //= DateNormalization
251 class DateNormalization
: public StandardFormatNormalizer
254 DateNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
255 :StandardFormatNormalizer( i_formatter
, NumberFormat::DATE
)
259 virtual ~DateNormalization() {}
261 virtual double convertToDouble( Any
const & i_value
) const SAL_OVERRIDE
263 double returnValue(0);
264 ::rtl::math::setNan( &returnValue
);
268 ENSURE_OR_RETURN( i_value
>>= aDateValue
, "allowed for Date values only", returnValue
);
271 returnValue
= lcl_convertDateToDays( aDateValue
.Day
, aDateValue
.Month
, aDateValue
.Year
);
279 //= TimeNormalization
281 class TimeNormalization
: public StandardFormatNormalizer
284 TimeNormalization( Reference
< XNumberFormatter
> const & i_formatter
)
285 :StandardFormatNormalizer( i_formatter
, NumberFormat::TIME
)
289 virtual ~TimeNormalization() {}
291 virtual double convertToDouble( Any
const & i_value
) const SAL_OVERRIDE
293 double returnValue(0);
294 ::rtl::math::setNan( &returnValue
);
298 ENSURE_OR_RETURN( i_value
>>= aTimeValue
, "allowed for tools::Time values only", returnValue
);
301 returnValue
+= lcl_convertTimeToDays(
302 aTimeValue
.Hours
, aTimeValue
.Minutes
, aTimeValue
.Seconds
, aTimeValue
.NanoSeconds
);
315 bool lcl_ensureNumberFormatter( CellValueConversion_Data
& io_data
)
317 if ( io_data
.bAttemptedFormatterCreation
)
318 return io_data
.xNumberFormatter
.is();
319 io_data
.bAttemptedFormatterCreation
= true;
323 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
324 // a number formatter
325 Reference
< XNumberFormatter
> const xFormatter( NumberFormatter::create( xContext
), UNO_QUERY_THROW
);
327 // a supplier of number formats
328 Locale aLocale
= SvtSysLocale().GetLanguageTag().getLocale();
330 Reference
< XNumberFormatsSupplier
> const xSupplier
=
331 NumberFormatsSupplier::createWithLocale( xContext
, aLocale
);
333 // ensure a NullDate we will assume later on
334 UnoDate
const aNullDate( 1, 1, 1900 );
335 Reference
< XPropertySet
> const xFormatSettings( xSupplier
->getNumberFormatSettings(), UNO_SET_THROW
);
336 xFormatSettings
->setPropertyValue( "NullDate", makeAny( aNullDate
) );
339 xFormatter
->attachNumberFormatsSupplier( xSupplier
);
342 io_data
.xNumberFormatter
= xFormatter
;
344 catch( const Exception
& )
346 DBG_UNHANDLED_EXCEPTION();
349 return io_data
.xNumberFormatter
.is();
353 bool lcl_getValueNormalizer( CellValueConversion_Data
& io_data
, Type
const & i_valueType
,
354 PValueNormalization
& o_formatter
)
356 NormalizerCache::const_iterator pos
= io_data
.aNormalizers
.find( i_valueType
.getTypeName() );
357 if ( pos
== io_data
.aNormalizers
.end() )
359 // never encountered this type before
362 OUString
const sTypeName( i_valueType
.getTypeName() );
363 TypeClass
const eTypeClass
= i_valueType
.getTypeClass();
365 if ( sTypeName
.equals( ::cppu::UnoType
< DateTime
>::get().getTypeName() ) )
367 o_formatter
.reset( new DateTimeNormalization( io_data
.xNumberFormatter
) );
369 else if ( sTypeName
.equals( ::cppu::UnoType
< UnoDate
>::get().getTypeName() ) )
371 o_formatter
.reset( new DateNormalization( io_data
.xNumberFormatter
) );
373 else if ( sTypeName
.equals( ::cppu::UnoType
< UnoTime
>::get().getTypeName() ) )
375 o_formatter
.reset( new TimeNormalization( io_data
.xNumberFormatter
) );
377 else if ( sTypeName
.equals( ::cppu::UnoType
< sal_Bool
>::get().getTypeName() ) )
379 o_formatter
.reset( new BooleanNormalization( io_data
.xNumberFormatter
) );
381 else if ( sTypeName
.equals( ::cppu::UnoType
< double >::get().getTypeName() )
382 || sTypeName
.equals( ::cppu::UnoType
< float >::get().getTypeName() )
385 o_formatter
.reset( new DoubleNormalization( io_data
.xNumberFormatter
) );
387 else if ( ( eTypeClass
== TypeClass_BYTE
)
388 || ( eTypeClass
== TypeClass_SHORT
)
389 || ( eTypeClass
== TypeClass_UNSIGNED_SHORT
)
390 || ( eTypeClass
== TypeClass_LONG
)
391 || ( eTypeClass
== TypeClass_UNSIGNED_LONG
)
392 || ( eTypeClass
== TypeClass_HYPER
)
395 o_formatter
.reset( new IntegerNormalization( io_data
.xNumberFormatter
) );
399 SAL_WARN( "svtools.table", "unsupported type '" << sTypeName
<< "'!" );
401 io_data
.aNormalizers
[ sTypeName
] = o_formatter
;
404 o_formatter
= pos
->second
;
406 return !!o_formatter
;
411 //= CellValueConversion
414 CellValueConversion::CellValueConversion()
415 :m_pData( new CellValueConversion_Data
)
420 CellValueConversion::~CellValueConversion()
425 OUString
CellValueConversion::convertToString( const Any
& i_value
)
427 OUString sStringValue
;
428 if ( !i_value
.hasValue() )
431 if ( ! ( i_value
>>= sStringValue
) )
433 if ( lcl_ensureNumberFormatter( *m_pData
) )
435 PValueNormalization pNormalizer
;
436 if ( lcl_getValueNormalizer( *m_pData
, i_value
.getValueType(), pNormalizer
) )
440 double const formatterCompliantValue
= pNormalizer
->convertToDouble( i_value
);
441 sal_Int32
const formatKey
= pNormalizer
->getFormatKey();
442 sStringValue
= m_pData
->xNumberFormatter
->convertNumberToString(
443 formatKey
, formatterCompliantValue
);
445 catch( const Exception
& )
447 DBG_UNHANDLED_EXCEPTION();
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */