| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include "precompiled_svtools.hxx" |
| |
| #include "cellvalueconversion.hxx" |
| |
| /** === begin UNO includes === **/ |
| #include <com/sun/star/util/XNumberFormatter.hpp> |
| #include <com/sun/star/util/XNumberFormatsSupplier.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <com/sun/star/util/Date.hpp> |
| #include <com/sun/star/util/DateTime.hpp> |
| #include <com/sun/star/util/Time.hpp> |
| #include <com/sun/star/util/XNumberFormatTypes.hpp> |
| #include <com/sun/star/util/NumberFormat.hpp> |
| /** === end UNO includes === **/ |
| |
| #include <comphelper/componentcontext.hxx> |
| #include <rtl/math.hxx> |
| #include <rtl/strbuf.hxx> |
| #include <tools/date.hxx> |
| #include <tools/time.hxx> |
| #include <tools/diagnose_ex.h> |
| #include <unotools/syslocale.hxx> |
| |
| #include <boost/shared_ptr.hpp> |
| #include <hash_map> |
| |
| //...................................................................................................................... |
| namespace svt |
| { |
| //...................................................................................................................... |
| |
| /** === begin UNO using === **/ |
| using ::com::sun::star::uno::Any; |
| using ::com::sun::star::util::XNumberFormatter; |
| using ::com::sun::star::uno::UNO_QUERY_THROW; |
| using ::com::sun::star::util::XNumberFormatsSupplier; |
| using ::com::sun::star::beans::XPropertySet; |
| using ::com::sun::star::uno::UNO_SET_THROW; |
| using ::com::sun::star::uno::Exception; |
| using ::com::sun::star::util::DateTime; |
| using ::com::sun::star::uno::TypeClass; |
| using ::com::sun::star::util::XNumberFormatTypes; |
| using ::com::sun::star::uno::Reference; |
| using ::com::sun::star::uno::Sequence; |
| using ::com::sun::star::uno::makeAny; |
| using ::com::sun::star::uno::Type; |
| using ::com::sun::star::uno::TypeClass_BYTE; |
| using ::com::sun::star::uno::TypeClass_SHORT; |
| using ::com::sun::star::uno::TypeClass_UNSIGNED_SHORT; |
| using ::com::sun::star::uno::TypeClass_LONG; |
| using ::com::sun::star::uno::TypeClass_UNSIGNED_LONG; |
| using ::com::sun::star::uno::TypeClass_HYPER; |
| /** === end UNO using === **/ |
| namespace NumberFormat = ::com::sun::star::util::NumberFormat; |
| |
| typedef ::com::sun::star::util::Time UnoTime; |
| typedef ::com::sun::star::util::Date UnoDate; |
| |
| //================================================================================================================== |
| //= helper |
| //================================================================================================================== |
| namespace |
| { |
| //-------------------------------------------------------------------------------------------------------------- |
| double lcl_convertDateToDays( long const i_day, long const i_month, long const i_year ) |
| { |
| long const nNullDateDays = ::Date::DateToDays( 1, 1, 1900 ); |
| long const nValueDateDays = ::Date::DateToDays( i_day, i_month, i_year ); |
| |
| return nValueDateDays - nNullDateDays; |
| } |
| |
| //-------------------------------------------------------------------------------------------------------------- |
| double lcl_convertTimeToDays( long const i_hours, long const i_minutes, long const i_seconds, long const i_100thSeconds ) |
| { |
| return Time( i_hours, i_minutes, i_seconds, i_100thSeconds ).GetTimeInDays(); |
| } |
| } |
| |
| //================================================================================================================== |
| //= IValueNormalization |
| //================================================================================================================== |
| class SAL_NO_VTABLE IValueNormalization |
| { |
| public: |
| virtual ~IValueNormalization() { } |
| |
| /** converts the given <code>Any</code> into a <code>double</code> value to be fed into a number formatter |
| */ |
| virtual double convertToDouble( Any const & i_value ) const = 0; |
| |
| /** returns the format key to be used for formatting values |
| */ |
| virtual ::sal_Int32 getFormatKey() const = 0; |
| }; |
| |
| typedef ::boost::shared_ptr< IValueNormalization > PValueNormalization; |
| typedef ::std::hash_map< ::rtl::OUString, PValueNormalization, ::rtl::OUStringHash > NormalizerCache; |
| |
| //================================================================================================================== |
| //= CellValueConversion_Data |
| //================================================================================================================== |
| struct CellValueConversion_Data |
| { |
| ::comphelper::ComponentContext const aContext; |
| Reference< XNumberFormatter > xNumberFormatter; |
| bool bAttemptedFormatterCreation; |
| NormalizerCache aNormalizers; |
| |
| CellValueConversion_Data( ::comphelper::ComponentContext const & i_context ) |
| :aContext( i_context ) |
| ,xNumberFormatter() |
| ,bAttemptedFormatterCreation( false ) |
| ,aNormalizers() |
| { |
| } |
| }; |
| |
| //================================================================================================================== |
| //= StandardFormatNormalizer |
| //================================================================================================================== |
| class StandardFormatNormalizer : public IValueNormalization |
| { |
| protected: |
| StandardFormatNormalizer( Reference< XNumberFormatter > const & i_formatter, ::sal_Int32 const i_numberFormatType ) |
| :m_nFormatKey( 0 ) |
| { |
| try |
| { |
| ENSURE_OR_THROW( i_formatter.is(), "StandardFormatNormalizer: no formatter!" ); |
| Reference< XNumberFormatsSupplier > const xSupplier( i_formatter->getNumberFormatsSupplier(), UNO_SET_THROW ); |
| Reference< XNumberFormatTypes > const xTypes( xSupplier->getNumberFormats(), UNO_QUERY_THROW ); |
| m_nFormatKey = xTypes->getStandardFormat( i_numberFormatType, SvtSysLocale().GetLocale() ); |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| } |
| } |
| |
| virtual ::sal_Int32 getFormatKey() const |
| { |
| return m_nFormatKey; |
| } |
| |
| private: |
| ::sal_Int32 m_nFormatKey; |
| }; |
| |
| //================================================================================================================== |
| //= DoubleNormalization |
| //================================================================================================================== |
| class DoubleNormalization : public StandardFormatNormalizer |
| { |
| public: |
| DoubleNormalization( Reference< XNumberFormatter > const & i_formatter ) |
| :StandardFormatNormalizer( i_formatter, NumberFormat::NUMBER ) |
| { |
| } |
| |
| virtual double convertToDouble( Any const & i_value ) const |
| { |
| double returnValue(0); |
| ::rtl::math::setNan( &returnValue ); |
| OSL_VERIFY( i_value >>= returnValue ); |
| return returnValue; |
| } |
| |
| virtual ~DoubleNormalization() { } |
| }; |
| |
| //================================================================================================================== |
| //= IntegerNormalization |
| //================================================================================================================== |
| class IntegerNormalization : public StandardFormatNormalizer |
| { |
| public: |
| IntegerNormalization( Reference< XNumberFormatter > const & i_formatter ) |
| :StandardFormatNormalizer( i_formatter, NumberFormat::NUMBER ) |
| { |
| } |
| |
| virtual ~IntegerNormalization() {} |
| |
| virtual double convertToDouble( Any const & i_value ) const |
| { |
| sal_Int64 value( 0 ); |
| OSL_VERIFY( i_value >>= value ); |
| return value; |
| } |
| }; |
| |
| //================================================================================================================== |
| //= BooleanNormalization |
| //================================================================================================================== |
| class BooleanNormalization : public StandardFormatNormalizer |
| { |
| public: |
| BooleanNormalization( Reference< XNumberFormatter > const & i_formatter ) |
| :StandardFormatNormalizer( i_formatter, NumberFormat::LOGICAL ) |
| { |
| } |
| |
| virtual ~BooleanNormalization() {} |
| |
| virtual double convertToDouble( Any const & i_value ) const |
| { |
| bool value( false ); |
| OSL_VERIFY( i_value >>= value ); |
| return value ? 1 : 0; |
| } |
| }; |
| |
| //================================================================================================================== |
| //= DateTimeNormalization |
| //================================================================================================================== |
| class DateTimeNormalization : public StandardFormatNormalizer |
| { |
| public: |
| DateTimeNormalization( Reference< XNumberFormatter > const & i_formatter ) |
| :StandardFormatNormalizer( i_formatter, NumberFormat::DATETIME ) |
| { |
| } |
| |
| virtual ~DateTimeNormalization() {} |
| |
| virtual double convertToDouble( Any const & i_value ) const |
| { |
| double returnValue(0); |
| ::rtl::math::setNan( &returnValue ); |
| |
| // extract actual UNO value |
| DateTime aDateTimeValue; |
| ENSURE_OR_RETURN( i_value >>= aDateTimeValue, "allowed for DateTime values only", returnValue ); |
| |
| // date part |
| returnValue = lcl_convertDateToDays( aDateTimeValue.Day, aDateTimeValue.Month, aDateTimeValue.Year ); |
| |
| // time part |
| returnValue += lcl_convertTimeToDays( |
| aDateTimeValue.Hours, aDateTimeValue.Minutes, aDateTimeValue.Seconds, aDateTimeValue.HundredthSeconds ); |
| |
| // done |
| return returnValue; |
| } |
| }; |
| |
| //================================================================================================================== |
| //= DateNormalization |
| //================================================================================================================== |
| class DateNormalization : public StandardFormatNormalizer |
| { |
| public: |
| DateNormalization( Reference< XNumberFormatter > const & i_formatter ) |
| :StandardFormatNormalizer( i_formatter, NumberFormat::DATE ) |
| { |
| } |
| |
| virtual ~DateNormalization() {} |
| |
| virtual double convertToDouble( Any const & i_value ) const |
| { |
| double returnValue(0); |
| ::rtl::math::setNan( &returnValue ); |
| |
| // extract |
| UnoDate aDateValue; |
| ENSURE_OR_RETURN( i_value >>= aDateValue, "allowed for Date values only", returnValue ); |
| |
| // convert |
| returnValue = lcl_convertDateToDays( aDateValue.Day, aDateValue.Month, aDateValue.Year ); |
| |
| // done |
| return returnValue; |
| } |
| }; |
| |
| //================================================================================================================== |
| //= TimeNormalization |
| //================================================================================================================== |
| class TimeNormalization : public StandardFormatNormalizer |
| { |
| public: |
| TimeNormalization( Reference< XNumberFormatter > const & i_formatter ) |
| :StandardFormatNormalizer( i_formatter, NumberFormat::TIME ) |
| { |
| } |
| |
| virtual ~TimeNormalization() {} |
| |
| virtual double convertToDouble( Any const & i_value ) const |
| { |
| double returnValue(0); |
| ::rtl::math::setNan( &returnValue ); |
| |
| // extract |
| UnoTime aTimeValue; |
| ENSURE_OR_RETURN( i_value >>= aTimeValue, "allowed for Time values only", returnValue ); |
| |
| // convert |
| returnValue += lcl_convertTimeToDays( |
| aTimeValue.Hours, aTimeValue.Minutes, aTimeValue.Seconds, aTimeValue.HundredthSeconds ); |
| |
| // done |
| return returnValue; |
| } |
| }; |
| |
| //================================================================================================================== |
| //= operations |
| //================================================================================================================== |
| namespace |
| { |
| //-------------------------------------------------------------------------------------------------------------- |
| bool lcl_ensureNumberFormatter( CellValueConversion_Data & io_data ) |
| { |
| if ( io_data.bAttemptedFormatterCreation ) |
| return io_data.xNumberFormatter.is(); |
| io_data.bAttemptedFormatterCreation = true; |
| |
| try |
| { |
| // a number formatter |
| Reference< XNumberFormatter > const xFormatter( |
| io_data.aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY_THROW ); |
| |
| // a supplier of number formats |
| Sequence< Any > aInitArgs(1); |
| aInitArgs[0] <<= SvtSysLocale().GetLocale(); |
| |
| Reference< XNumberFormatsSupplier > const xSupplier( |
| io_data.aContext.createComponentWithArguments( "com.sun.star.util.NumberFormatsSupplier", aInitArgs ), |
| UNO_QUERY_THROW |
| ); |
| |
| // ensure a NullDate we will assume later on |
| UnoDate const aNullDate( 1, 1, 1900 ); |
| Reference< XPropertySet > const xFormatSettings( xSupplier->getNumberFormatSettings(), UNO_SET_THROW ); |
| xFormatSettings->setPropertyValue( ::rtl::OUString::createFromAscii( "NullDate" ), makeAny( aNullDate ) ); |
| |
| // knit |
| xFormatter->attachNumberFormatsSupplier( xSupplier ); |
| |
| // done |
| io_data.xNumberFormatter = xFormatter; |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| } |
| |
| return io_data.xNumberFormatter.is(); |
| } |
| |
| //-------------------------------------------------------------------------------------------------------------- |
| bool lcl_getValueNormalizer( CellValueConversion_Data & io_data, Type const & i_valueType, |
| PValueNormalization & o_formatter ) |
| { |
| NormalizerCache::const_iterator pos = io_data.aNormalizers.find( i_valueType.getTypeName() ); |
| if ( pos == io_data.aNormalizers.end() ) |
| { |
| // never encountered this type before |
| o_formatter.reset(); |
| |
| ::rtl::OUString const sTypeName( i_valueType.getTypeName() ); |
| TypeClass const eTypeClass = i_valueType.getTypeClass(); |
| |
| if ( sTypeName.equals( ::cppu::UnoType< DateTime >::get().getTypeName() ) ) |
| { |
| o_formatter.reset( new DateTimeNormalization( io_data.xNumberFormatter ) ); |
| } |
| else if ( sTypeName.equals( ::cppu::UnoType< UnoDate >::get().getTypeName() ) ) |
| { |
| o_formatter.reset( new DateNormalization( io_data.xNumberFormatter ) ); |
| } |
| else if ( sTypeName.equals( ::cppu::UnoType< UnoTime >::get().getTypeName() ) ) |
| { |
| o_formatter.reset( new TimeNormalization( io_data.xNumberFormatter ) ); |
| } |
| else if ( sTypeName.equals( ::cppu::UnoType< ::sal_Bool >::get().getTypeName() ) ) |
| { |
| o_formatter.reset( new BooleanNormalization( io_data.xNumberFormatter ) ); |
| } |
| else if ( sTypeName.equals( ::cppu::UnoType< double >::get().getTypeName() ) |
| || sTypeName.equals( ::cppu::UnoType< float >::get().getTypeName() ) |
| ) |
| { |
| o_formatter.reset( new DoubleNormalization( io_data.xNumberFormatter ) ); |
| } |
| else if ( ( eTypeClass == TypeClass_BYTE ) |
| || ( eTypeClass == TypeClass_SHORT ) |
| || ( eTypeClass == TypeClass_UNSIGNED_SHORT ) |
| || ( eTypeClass == TypeClass_LONG ) |
| || ( eTypeClass == TypeClass_UNSIGNED_LONG ) |
| || ( eTypeClass == TypeClass_HYPER ) |
| ) |
| { |
| o_formatter.reset( new IntegerNormalization( io_data.xNumberFormatter ) ); |
| } |
| else |
| { |
| #if OSL_DEBUG_LEVEL > 0 |
| ::rtl::OStringBuffer message( "lcl_getValueNormalizer: unsupported type '" ); |
| message.append( ::rtl::OUStringToOString( sTypeName, RTL_TEXTENCODING_ASCII_US ) ); |
| message.append( "'!" ); |
| OSL_ENSURE( false, message.getStr() ); |
| #endif |
| } |
| io_data.aNormalizers[ sTypeName ] = o_formatter; |
| } |
| else |
| o_formatter = pos->second; |
| |
| return !!o_formatter; |
| } |
| } |
| |
| //================================================================================================================== |
| //= CellValueConversion |
| //================================================================================================================== |
| //------------------------------------------------------------------------------------------------------------------ |
| CellValueConversion::CellValueConversion( ::comphelper::ComponentContext const & i_context ) |
| :m_pData( new CellValueConversion_Data( i_context ) ) |
| { |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| CellValueConversion::~CellValueConversion() |
| { |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| ::rtl::OUString CellValueConversion::convertToString( const Any& i_value ) |
| { |
| ::rtl::OUString sStringValue; |
| if ( !i_value.hasValue() ) |
| return sStringValue; |
| |
| if ( ! ( i_value >>= sStringValue ) ) |
| { |
| if ( lcl_ensureNumberFormatter( *m_pData ) ) |
| { |
| PValueNormalization pNormalizer; |
| if ( lcl_getValueNormalizer( *m_pData, i_value.getValueType(), pNormalizer ) ) |
| { |
| try |
| { |
| double const formatterCompliantValue = pNormalizer->convertToDouble( i_value ); |
| sal_Int32 const formatKey = pNormalizer->getFormatKey(); |
| sStringValue = m_pData->xNumberFormatter->convertNumberToString( |
| formatKey, formatterCompliantValue ); |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| } |
| } |
| } |
| } |
| |
| return sStringValue; |
| } |
| |
| //...................................................................................................................... |
| } // namespace svt |
| //...................................................................................................................... |