/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include "cellvalueconversion.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace svt { using namespace ::com::sun::star::uno; using ::com::sun::star::util::XNumberFormatter; using ::com::sun::star::util::NumberFormatter; using ::com::sun::star::util::XNumberFormatsSupplier; using ::com::sun::star::util::NumberFormatsSupplier; using ::com::sun::star::beans::XPropertySet; using ::com::sun::star::lang::Locale; using ::com::sun::star::util::DateTime; using ::com::sun::star::util::XNumberFormatTypes; namespace NumberFormat = ::com::sun::star::util::NumberFormat; //= 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 tools::Time( i_hours, i_minutes, i_seconds, i_100thSeconds ).GetTimeInDays(); } } //= CellValueConversion_Data class StandardFormatNormalizer; struct CellValueConversion_Data { typedef std::unordered_map< OUString, std::shared_ptr< StandardFormatNormalizer >, OUStringHash > NormalizerCache; Reference< XNumberFormatter > xNumberFormatter; bool bAttemptedFormatterCreation; NormalizerCache aNormalizers; CellValueConversion_Data() :xNumberFormatter() ,bAttemptedFormatterCreation( false ) ,aNormalizers() { } }; //= StandardFormatNormalizer class StandardFormatNormalizer { public: /** converts the given Any into a double 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 */ sal_Int32 getFormatKey() const { return m_nFormatKey; } 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().GetLanguageTag().getLocale() ); } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } virtual ~StandardFormatNormalizer() {} private: ::sal_Int32 m_nFormatKey; }; //= DoubleNormalization class DoubleNormalization : public StandardFormatNormalizer { public: explicit DoubleNormalization( Reference< XNumberFormatter > const & i_formatter ) :StandardFormatNormalizer( i_formatter, NumberFormat::NUMBER ) { } virtual double convertToDouble( Any const & i_value ) const override { double returnValue(0); ::rtl::math::setNan( &returnValue ); OSL_VERIFY( i_value >>= returnValue ); return returnValue; } }; //= IntegerNormalization class IntegerNormalization : public StandardFormatNormalizer { public: explicit IntegerNormalization( Reference< XNumberFormatter > const & i_formatter ) :StandardFormatNormalizer( i_formatter, NumberFormat::NUMBER ) { } virtual double convertToDouble( Any const & i_value ) const override { sal_Int64 value( 0 ); OSL_VERIFY( i_value >>= value ); return value; } }; //= BooleanNormalization class BooleanNormalization : public StandardFormatNormalizer { public: explicit BooleanNormalization( Reference< XNumberFormatter > const & i_formatter ) :StandardFormatNormalizer( i_formatter, NumberFormat::LOGICAL ) { } virtual double convertToDouble( Any const & i_value ) const override { bool value( false ); OSL_VERIFY( i_value >>= value ); return value ? 1 : 0; } }; //= DateTimeNormalization class DateTimeNormalization : public StandardFormatNormalizer { public: explicit DateTimeNormalization( Reference< XNumberFormatter > const & i_formatter ) :StandardFormatNormalizer( i_formatter, NumberFormat::DATETIME ) { } virtual double convertToDouble( Any const & i_value ) const override { 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.NanoSeconds ); // done return returnValue; } }; //= DateNormalization class DateNormalization : public StandardFormatNormalizer { public: explicit DateNormalization( Reference< XNumberFormatter > const & i_formatter ) :StandardFormatNormalizer( i_formatter, NumberFormat::DATE ) { } virtual double convertToDouble( Any const & i_value ) const override { double returnValue(0); ::rtl::math::setNan( &returnValue ); // extract css::util::Date 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: explicit TimeNormalization( Reference< XNumberFormatter > const & i_formatter ) :StandardFormatNormalizer( i_formatter, NumberFormat::TIME ) { } virtual double convertToDouble( Any const & i_value ) const override { double returnValue(0); ::rtl::math::setNan( &returnValue ); // extract css::util::Time aTimeValue; ENSURE_OR_RETURN( i_value >>= aTimeValue, "allowed for tools::Time values only", returnValue ); // convert returnValue += lcl_convertTimeToDays( aTimeValue.Hours, aTimeValue.Minutes, aTimeValue.Seconds, aTimeValue.NanoSeconds ); // 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 { Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext(); // a number formatter Reference< XNumberFormatter > const xFormatter( NumberFormatter::create( xContext ), UNO_QUERY_THROW ); // a supplier of number formats Locale aLocale = SvtSysLocale().GetLanguageTag().getLocale(); Reference< XNumberFormatsSupplier > const xSupplier = NumberFormatsSupplier::createWithLocale( xContext, aLocale ); // ensure a NullDate we will assume later on css::util::Date const aNullDate( 1, 1, 1900 ); Reference< XPropertySet > const xFormatSettings( xSupplier->getNumberFormatSettings(), UNO_SET_THROW ); xFormatSettings->setPropertyValue( "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, std::shared_ptr< StandardFormatNormalizer > & o_formatter ) { CellValueConversion_Data::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(); 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< css::util::Date >::get().getTypeName() ) ) { o_formatter.reset( new DateNormalization( io_data.xNumberFormatter ) ); } else if ( sTypeName.equals( ::cppu::UnoType< css::util::Time >::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 { SAL_WARN( "svtools.table", "unsupported type '" << sTypeName << "'!" ); } io_data.aNormalizers[ sTypeName ] = o_formatter; } else o_formatter = pos->second; return !!o_formatter; } } //= CellValueConversion CellValueConversion::CellValueConversion() :m_pData( new CellValueConversion_Data ) { } CellValueConversion::~CellValueConversion() { } OUString CellValueConversion::convertToString( const Any& i_value ) { OUString sStringValue; if ( !i_value.hasValue() ) return sStringValue; if ( ! ( i_value >>= sStringValue ) ) { if ( lcl_ensureNumberFormatter( *m_pData ) ) { std::shared_ptr< StandardFormatNormalizer > 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 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */