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/NumberFormatsSupplier.hpp>
23 #include <com/sun/star/util/NumberFormatter.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 <sal/log.hxx>
31 #include <tools/date.hxx>
32 #include <tools/time.hxx>
33 #include <comphelper/diagnose_ex.hxx>
34 #include <tools/long.hxx>
35 #include <unotools/syslocale.hxx>
36 #include <i18nlangtag/languagetag.hxx>
37 #include <comphelper/processfactory.hxx>
44 using namespace ::com::sun::star::uno
;
45 using ::com::sun::star::util::XNumberFormatter
;
46 using ::com::sun::star::util::NumberFormatter
;
47 using ::com::sun::star::util::XNumberFormatsSupplier
;
48 using ::com::sun::star::util::NumberFormatsSupplier
;
49 using ::com::sun::star::beans::XPropertySet
;
50 using ::com::sun::star::lang::Locale
;
51 using ::com::sun::star::util::DateTime
;
52 using ::com::sun::star::util::XNumberFormatTypes
;
54 namespace NumberFormat
= ::com::sun::star::util::NumberFormat
;
60 double lcl_convertDateToDays(sal_uInt16
const i_day
, sal_uInt16
const i_month
,
61 sal_Int16
const i_year
)
63 tools::Long
const nNullDateDays
= ::Date::DateToDays(1, 1, 1900);
64 tools::Long
const nValueDateDays
= ::Date::DateToDays(i_day
, i_month
, i_year
);
66 return nValueDateDays
- nNullDateDays
;
69 double lcl_convertTimeToDays(tools::Long
const i_hours
, tools::Long
const i_minutes
,
70 tools::Long
const i_seconds
, tools::Long
const i_100thSeconds
)
72 return tools::Time(i_hours
, i_minutes
, i_seconds
, i_100thSeconds
).GetTimeInDays();
76 //= StandardFormatNormalizer
78 StandardFormatNormalizer::StandardFormatNormalizer(Reference
<XNumberFormatter
> const& i_formatter
,
79 ::sal_Int32
const i_numberFormatType
)
84 ENSURE_OR_THROW(i_formatter
.is(), "StandardFormatNormalizer: no formatter!");
85 Reference
<XNumberFormatsSupplier
> const xSupplier(i_formatter
->getNumberFormatsSupplier(),
87 Reference
<XNumberFormatTypes
> const xTypes(xSupplier
->getNumberFormats(), UNO_QUERY_THROW
);
88 m_nFormatKey
= xTypes
->getStandardFormat(i_numberFormatType
,
89 SvtSysLocale().GetLanguageTag().getLocale());
91 catch (const Exception
&)
93 DBG_UNHANDLED_EXCEPTION("svtools.table");
97 //= DoubleNormalization
101 class DoubleNormalization
: public StandardFormatNormalizer
104 explicit DoubleNormalization(Reference
<XNumberFormatter
> const& i_formatter
)
105 : StandardFormatNormalizer(i_formatter
, NumberFormat::NUMBER
)
109 virtual double convertToDouble(Any
const& i_value
) const override
111 double returnValue
= std::numeric_limits
<double>::quiet_NaN();
112 OSL_VERIFY(i_value
>>= returnValue
);
117 //= IntegerNormalization
119 class IntegerNormalization
: public StandardFormatNormalizer
122 explicit IntegerNormalization(Reference
<XNumberFormatter
> const& i_formatter
)
123 : StandardFormatNormalizer(i_formatter
, NumberFormat::NUMBER
)
127 virtual double convertToDouble(Any
const& i_value
) const override
130 OSL_VERIFY(i_value
>>= value
);
135 //= BooleanNormalization
137 class BooleanNormalization
: public StandardFormatNormalizer
140 explicit BooleanNormalization(Reference
<XNumberFormatter
> const& i_formatter
)
141 : StandardFormatNormalizer(i_formatter
, NumberFormat::LOGICAL
)
145 virtual double convertToDouble(Any
const& i_value
) const override
148 OSL_VERIFY(i_value
>>= value
);
149 return value
? 1 : 0;
153 //= DateTimeNormalization
155 class DateTimeNormalization
: public StandardFormatNormalizer
158 explicit DateTimeNormalization(Reference
<XNumberFormatter
> const& i_formatter
)
159 : StandardFormatNormalizer(i_formatter
, NumberFormat::DATETIME
)
163 virtual double convertToDouble(Any
const& i_value
) const override
165 double returnValue
= std::numeric_limits
<double>::quiet_NaN();
167 // extract actual UNO value
168 DateTime aDateTimeValue
;
169 ENSURE_OR_RETURN(i_value
>>= aDateTimeValue
, "allowed for DateTime values only",
174 = lcl_convertDateToDays(aDateTimeValue
.Day
, aDateTimeValue
.Month
, aDateTimeValue
.Year
);
177 returnValue
+= lcl_convertTimeToDays(aDateTimeValue
.Hours
, aDateTimeValue
.Minutes
,
178 aDateTimeValue
.Seconds
, aDateTimeValue
.NanoSeconds
);
185 //= DateNormalization
187 class DateNormalization
: public StandardFormatNormalizer
190 explicit DateNormalization(Reference
<XNumberFormatter
> const& i_formatter
)
191 : StandardFormatNormalizer(i_formatter
, NumberFormat::DATE
)
195 virtual double convertToDouble(Any
const& i_value
) const override
197 double returnValue
= std::numeric_limits
<double>::quiet_NaN();
200 css::util::Date aDateValue
;
201 ENSURE_OR_RETURN(i_value
>>= aDateValue
, "allowed for Date values only", returnValue
);
204 returnValue
= lcl_convertDateToDays(aDateValue
.Day
, aDateValue
.Month
, aDateValue
.Year
);
211 //= TimeNormalization
213 class TimeNormalization
: public StandardFormatNormalizer
216 explicit TimeNormalization(Reference
<XNumberFormatter
> const& i_formatter
)
217 : StandardFormatNormalizer(i_formatter
, NumberFormat::TIME
)
221 virtual double convertToDouble(Any
const& i_value
) const override
223 double returnValue
= std::numeric_limits
<double>::quiet_NaN();
226 css::util::Time aTimeValue
;
227 ENSURE_OR_RETURN(i_value
>>= aTimeValue
, "allowed for tools::Time values only",
231 returnValue
+= lcl_convertTimeToDays(aTimeValue
.Hours
, aTimeValue
.Minutes
,
232 aTimeValue
.Seconds
, aTimeValue
.NanoSeconds
);
242 bool CellValueConversion::ensureNumberFormatter()
244 if (bAttemptedFormatterCreation
)
245 return xNumberFormatter
.is();
246 bAttemptedFormatterCreation
= true;
250 const Reference
<XComponentContext
>& xContext
= ::comphelper::getProcessComponentContext();
251 // a number formatter
252 Reference
<XNumberFormatter
> const xFormatter(NumberFormatter::create(xContext
),
255 // a supplier of number formats
256 Locale aLocale
= SvtSysLocale().GetLanguageTag().getLocale();
258 Reference
<XNumberFormatsSupplier
> const xSupplier
259 = NumberFormatsSupplier::createWithLocale(xContext
, aLocale
);
261 // ensure a NullDate we will assume later on
262 css::util::Date
const aNullDate(1, 1, 1900);
263 Reference
<XPropertySet
> const xFormatSettings(xSupplier
->getNumberFormatSettings(),
265 xFormatSettings
->setPropertyValue(u
"NullDate"_ustr
, Any(aNullDate
));
268 xFormatter
->attachNumberFormatsSupplier(xSupplier
);
271 xNumberFormatter
= xFormatter
;
273 catch (const Exception
&)
275 DBG_UNHANDLED_EXCEPTION("svtools.table");
278 return xNumberFormatter
.is();
281 bool CellValueConversion::getValueNormalizer(Type
const& i_valueType
,
282 std::shared_ptr
<StandardFormatNormalizer
>& o_formatter
)
284 auto pos
= aNormalizers
.find(i_valueType
.getTypeName());
285 if (pos
== aNormalizers
.end())
287 // never encountered this type before
290 OUString
const sTypeName(i_valueType
.getTypeName());
291 TypeClass
const eTypeClass
= i_valueType
.getTypeClass();
293 if (sTypeName
== ::cppu::UnoType
<DateTime
>::get().getTypeName())
295 o_formatter
= std::make_shared
<DateTimeNormalization
>(xNumberFormatter
);
297 else if (sTypeName
== ::cppu::UnoType
<css::util::Date
>::get().getTypeName())
299 o_formatter
= std::make_shared
<DateNormalization
>(xNumberFormatter
);
301 else if (sTypeName
== ::cppu::UnoType
<css::util::Time
>::get().getTypeName())
303 o_formatter
= std::make_shared
<TimeNormalization
>(xNumberFormatter
);
305 else if (sTypeName
== ::cppu::UnoType
<sal_Bool
>::get().getTypeName())
307 o_formatter
= std::make_shared
<BooleanNormalization
>(xNumberFormatter
);
309 else if (sTypeName
== ::cppu::UnoType
<double>::get().getTypeName()
310 || sTypeName
== ::cppu::UnoType
<float>::get().getTypeName())
312 o_formatter
= std::make_shared
<DoubleNormalization
>(xNumberFormatter
);
314 else if ((eTypeClass
== TypeClass_BYTE
) || (eTypeClass
== TypeClass_SHORT
)
315 || (eTypeClass
== TypeClass_UNSIGNED_SHORT
) || (eTypeClass
== TypeClass_LONG
)
316 || (eTypeClass
== TypeClass_UNSIGNED_LONG
) || (eTypeClass
== TypeClass_HYPER
))
318 o_formatter
= std::make_shared
<IntegerNormalization
>(xNumberFormatter
);
322 SAL_WARN("svtools.table", "unsupported type '" << sTypeName
<< "'!");
324 aNormalizers
[sTypeName
] = o_formatter
;
327 o_formatter
= pos
->second
;
329 return bool(o_formatter
);
332 //= CellValueConversion
334 CellValueConversion::CellValueConversion()
336 , bAttemptedFormatterCreation(false)
341 CellValueConversion::~CellValueConversion() {}
343 OUString
CellValueConversion::convertToString(const Any
& i_value
)
345 OUString sStringValue
;
346 if (!i_value
.hasValue())
349 if (!(i_value
>>= sStringValue
))
351 if (ensureNumberFormatter())
353 std::shared_ptr
<StandardFormatNormalizer
> pNormalizer
;
354 if (getValueNormalizer(i_value
.getValueType(), pNormalizer
))
358 double const formatterCompliantValue
= pNormalizer
->convertToDouble(i_value
);
359 sal_Int32
const formatKey
= pNormalizer
->getFormatKey();
360 sStringValue
= xNumberFormatter
->convertNumberToString(formatKey
,
361 formatterCompliantValue
);
363 catch (const Exception
&)
365 DBG_UNHANDLED_EXCEPTION("svtools.table");
376 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */