Bump version to 5.0-14
[LibreOffice.git] / svtools / source / table / cellvalueconversion.cxx
bloba5eb77097e922c6404cc04ab981b17ea0b9ec3c4
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 .
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>
41 namespace svt
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;
62 //= helper
64 namespace
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
87 public:
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()
112 :xNumberFormatter()
113 ,bAttemptedFormatterCreation( false )
114 ,aNormalizers()
120 //= StandardFormatNormalizer
122 class StandardFormatNormalizer : public IValueNormalization
124 protected:
125 StandardFormatNormalizer( Reference< XNumberFormatter > const & i_formatter, ::sal_Int32 const i_numberFormatType )
126 :m_nFormatKey( 0 )
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
143 return m_nFormatKey;
146 private:
147 ::sal_Int32 m_nFormatKey;
151 //= DoubleNormalization
153 class DoubleNormalization : public StandardFormatNormalizer
155 public:
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 );
166 return returnValue;
169 virtual ~DoubleNormalization() { }
173 //= IntegerNormalization
175 class IntegerNormalization : public StandardFormatNormalizer
177 public:
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 );
189 return value;
194 //= BooleanNormalization
196 class BooleanNormalization : public StandardFormatNormalizer
198 public:
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
208 bool value( false );
209 OSL_VERIFY( i_value >>= value );
210 return value ? 1 : 0;
215 //= DateTimeNormalization
217 class DateTimeNormalization : public StandardFormatNormalizer
219 public:
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 );
236 // date part
237 returnValue = lcl_convertDateToDays( aDateTimeValue.Day, aDateTimeValue.Month, aDateTimeValue.Year );
239 // time part
240 returnValue += lcl_convertTimeToDays(
241 aDateTimeValue.Hours, aDateTimeValue.Minutes, aDateTimeValue.Seconds, aDateTimeValue.NanoSeconds );
243 // done
244 return returnValue;
249 //= DateNormalization
251 class DateNormalization : public StandardFormatNormalizer
253 public:
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 );
266 // extract
267 UnoDate aDateValue;
268 ENSURE_OR_RETURN( i_value >>= aDateValue, "allowed for Date values only", returnValue );
270 // convert
271 returnValue = lcl_convertDateToDays( aDateValue.Day, aDateValue.Month, aDateValue.Year );
273 // done
274 return returnValue;
279 //= TimeNormalization
281 class TimeNormalization : public StandardFormatNormalizer
283 public:
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 );
296 // extract
297 UnoTime aTimeValue;
298 ENSURE_OR_RETURN( i_value >>= aTimeValue, "allowed for tools::Time values only", returnValue );
300 // convert
301 returnValue += lcl_convertTimeToDays(
302 aTimeValue.Hours, aTimeValue.Minutes, aTimeValue.Seconds, aTimeValue.NanoSeconds );
304 // done
305 return returnValue;
310 //= operations
312 namespace
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 ) );
338 // knit
339 xFormatter->attachNumberFormatsSupplier( xSupplier );
341 // done
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
360 o_formatter.reset();
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 ) );
397 else
399 SAL_WARN( "svtools.table", "unsupported type '" << sTypeName << "'!" );
401 io_data.aNormalizers[ sTypeName ] = o_formatter;
403 else
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() )
429 return sStringValue;
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();
453 return sStringValue;
457 } // namespace svt
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */