1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25  ************************************************************************/
26 
27 #include "precompiled_svtools.hxx"
28 
29 #include "cellvalueconversion.hxx"
30 
31 /** === begin UNO includes === **/
32 #include <com/sun/star/util/XNumberFormatter.hpp>
33 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/util/Date.hpp>
36 #include <com/sun/star/util/DateTime.hpp>
37 #include <com/sun/star/util/Time.hpp>
38 #include <com/sun/star/util/XNumberFormatTypes.hpp>
39 #include <com/sun/star/util/NumberFormat.hpp>
40 /** === end UNO includes === **/
41 
42 #include <comphelper/componentcontext.hxx>
43 #include <rtl/math.hxx>
44 #include <rtl/strbuf.hxx>
45 #include <tools/date.hxx>
46 #include <tools/time.hxx>
47 #include <tools/diagnose_ex.h>
48 #include <unotools/syslocale.hxx>
49 
50 #include <boost/shared_ptr.hpp>
51 #include <hash_map>
52 
53 //......................................................................................................................
54 namespace svt
55 {
56 //......................................................................................................................
57 
58     /** === begin UNO using === **/
59     using ::com::sun::star::uno::Any;
60     using ::com::sun::star::util::XNumberFormatter;
61     using ::com::sun::star::uno::UNO_QUERY_THROW;
62     using ::com::sun::star::util::XNumberFormatsSupplier;
63     using ::com::sun::star::beans::XPropertySet;
64     using ::com::sun::star::uno::UNO_SET_THROW;
65     using ::com::sun::star::uno::Exception;
66     using ::com::sun::star::util::DateTime;
67     using ::com::sun::star::uno::TypeClass;
68     using ::com::sun::star::util::XNumberFormatTypes;
69     using ::com::sun::star::uno::Reference;
70     using ::com::sun::star::uno::Sequence;
71     using ::com::sun::star::uno::makeAny;
72     using ::com::sun::star::uno::Type;
73     using ::com::sun::star::uno::TypeClass_BYTE;
74     using ::com::sun::star::uno::TypeClass_SHORT;
75     using ::com::sun::star::uno::TypeClass_UNSIGNED_SHORT;
76     using ::com::sun::star::uno::TypeClass_LONG;
77     using ::com::sun::star::uno::TypeClass_UNSIGNED_LONG;
78     using ::com::sun::star::uno::TypeClass_HYPER;
79     /** === end UNO using === **/
80     namespace NumberFormat = ::com::sun::star::util::NumberFormat;
81 
82     typedef ::com::sun::star::util::Time UnoTime;
83     typedef ::com::sun::star::util::Date UnoDate;
84 
85     //==================================================================================================================
86     //= helper
87     //==================================================================================================================
88     namespace
89     {
90         //--------------------------------------------------------------------------------------------------------------
91         double lcl_convertDateToDays( long const i_day, long const i_month, long const i_year )
92         {
93             long const nNullDateDays = ::Date::DateToDays( 1, 1, 1900 );
94             long const nValueDateDays = ::Date::DateToDays( i_day, i_month, i_year );
95 
96             return nValueDateDays - nNullDateDays;
97         }
98 
99         //--------------------------------------------------------------------------------------------------------------
100         double lcl_convertTimeToDays( long const i_hours, long const i_minutes, long const i_seconds, long const i_100thSeconds )
101         {
102             return Time( i_hours, i_minutes, i_seconds, i_100thSeconds ).GetTimeInDays();
103         }
104     }
105 
106     //==================================================================================================================
107     //= IValueNormalization
108     //==================================================================================================================
109     class SAL_NO_VTABLE IValueNormalization
110     {
111     public:
112         virtual ~IValueNormalization() { }
113 
114         /** converts the given <code>Any</code> into a <code>double</code> value to be fed into a number formatter
115         */
116         virtual double convertToDouble( Any const & i_value ) const = 0;
117 
118         /** returns the format key to be used for formatting values
119         */
120         virtual ::sal_Int32 getFormatKey() const = 0;
121     };
122 
123     typedef ::boost::shared_ptr< IValueNormalization >                                      PValueNormalization;
124     typedef ::std::hash_map< ::rtl::OUString, PValueNormalization, ::rtl::OUStringHash >    NormalizerCache;
125 
126     //==================================================================================================================
127     //= CellValueConversion_Data
128     //==================================================================================================================
129     struct CellValueConversion_Data
130     {
131         ::comphelper::ComponentContext const    aContext;
132         Reference< XNumberFormatter >           xNumberFormatter;
133         bool                                    bAttemptedFormatterCreation;
134         NormalizerCache                         aNormalizers;
135 
136         CellValueConversion_Data( ::comphelper::ComponentContext const & i_context )
137             :aContext( i_context )
138             ,xNumberFormatter()
139             ,bAttemptedFormatterCreation( false )
140             ,aNormalizers()
141         {
142         }
143     };
144 
145     //==================================================================================================================
146     //= StandardFormatNormalizer
147     //==================================================================================================================
148     class StandardFormatNormalizer : public IValueNormalization
149     {
150     protected:
151         StandardFormatNormalizer( Reference< XNumberFormatter > const & i_formatter, ::sal_Int32 const i_numberFormatType )
152             :m_nFormatKey( 0 )
153         {
154             try
155             {
156                 ENSURE_OR_THROW( i_formatter.is(), "StandardFormatNormalizer: no formatter!" );
157                 Reference< XNumberFormatsSupplier > const xSupplier( i_formatter->getNumberFormatsSupplier(), UNO_SET_THROW );
158                 Reference< XNumberFormatTypes > const xTypes( xSupplier->getNumberFormats(), UNO_QUERY_THROW );
159                 m_nFormatKey = xTypes->getStandardFormat( i_numberFormatType, SvtSysLocale().GetLocale() );
160             }
161             catch( const Exception& )
162             {
163             	DBG_UNHANDLED_EXCEPTION();
164             }
165         }
166 
167         virtual ::sal_Int32 getFormatKey() const
168         {
169             return m_nFormatKey;
170         }
171 
172     private:
173         ::sal_Int32 m_nFormatKey;
174     };
175 
176     //==================================================================================================================
177     //= DoubleNormalization
178     //==================================================================================================================
179     class DoubleNormalization : public StandardFormatNormalizer
180     {
181     public:
182         DoubleNormalization( Reference< XNumberFormatter > const & i_formatter )
183             :StandardFormatNormalizer( i_formatter, NumberFormat::NUMBER )
184         {
185         }
186 
187         virtual double convertToDouble( Any const & i_value ) const
188         {
189             double returnValue(0);
190             ::rtl::math::setNan( &returnValue );
191             OSL_VERIFY( i_value >>= returnValue );
192             return returnValue;
193         }
194 
195         virtual ~DoubleNormalization() { }
196     };
197 
198     //==================================================================================================================
199     //= IntegerNormalization
200     //==================================================================================================================
201     class IntegerNormalization : public StandardFormatNormalizer
202     {
203     public:
204         IntegerNormalization( Reference< XNumberFormatter > const & i_formatter )
205             :StandardFormatNormalizer( i_formatter, NumberFormat::NUMBER )
206         {
207         }
208 
209         virtual ~IntegerNormalization() {}
210 
211         virtual double convertToDouble( Any const & i_value ) const
212         {
213             sal_Int64 value( 0 );
214             OSL_VERIFY( i_value >>= value );
215             return value;
216         }
217     };
218 
219     //==================================================================================================================
220     //= BooleanNormalization
221     //==================================================================================================================
222     class BooleanNormalization : public StandardFormatNormalizer
223     {
224     public:
225         BooleanNormalization( Reference< XNumberFormatter > const & i_formatter )
226             :StandardFormatNormalizer( i_formatter, NumberFormat::LOGICAL )
227         {
228         }
229 
230         virtual ~BooleanNormalization() {}
231 
232         virtual double convertToDouble( Any const & i_value ) const
233         {
234             bool value( false );
235             OSL_VERIFY( i_value >>= value );
236             return value ? 1 : 0;
237         }
238     };
239 
240     //==================================================================================================================
241     //= DateTimeNormalization
242     //==================================================================================================================
243     class DateTimeNormalization : public StandardFormatNormalizer
244     {
245     public:
246         DateTimeNormalization( Reference< XNumberFormatter > const & i_formatter )
247             :StandardFormatNormalizer( i_formatter, NumberFormat::DATETIME )
248         {
249         }
250 
251         virtual ~DateTimeNormalization() {}
252 
253         virtual double convertToDouble( Any const & i_value ) const
254         {
255             double returnValue(0);
256             ::rtl::math::setNan( &returnValue );
257 
258             // extract actual UNO value
259             DateTime aDateTimeValue;
260             ENSURE_OR_RETURN( i_value >>= aDateTimeValue, "allowed for DateTime values only", returnValue );
261 
262             // date part
263             returnValue = lcl_convertDateToDays( aDateTimeValue.Day, aDateTimeValue.Month, aDateTimeValue.Year );
264 
265             // time part
266             returnValue += lcl_convertTimeToDays(
267                 aDateTimeValue.Hours, aDateTimeValue.Minutes, aDateTimeValue.Seconds, aDateTimeValue.HundredthSeconds );
268 
269             // done
270             return returnValue;
271         }
272     };
273 
274     //==================================================================================================================
275     //= DateNormalization
276     //==================================================================================================================
277     class DateNormalization : public StandardFormatNormalizer
278     {
279     public:
280         DateNormalization( Reference< XNumberFormatter > const & i_formatter )
281             :StandardFormatNormalizer( i_formatter, NumberFormat::DATE )
282         {
283         }
284 
285         virtual ~DateNormalization() {}
286 
287         virtual double convertToDouble( Any const & i_value ) const
288         {
289             double returnValue(0);
290             ::rtl::math::setNan( &returnValue );
291 
292             // extract
293             UnoDate aDateValue;
294             ENSURE_OR_RETURN( i_value >>= aDateValue, "allowed for Date values only", returnValue );
295 
296             // convert
297             returnValue = lcl_convertDateToDays( aDateValue.Day, aDateValue.Month, aDateValue.Year );
298 
299             // done
300             return returnValue;
301         }
302     };
303 
304     //==================================================================================================================
305     //= TimeNormalization
306     //==================================================================================================================
307     class TimeNormalization : public StandardFormatNormalizer
308     {
309     public:
310         TimeNormalization( Reference< XNumberFormatter > const & i_formatter )
311             :StandardFormatNormalizer( i_formatter, NumberFormat::TIME )
312         {
313         }
314 
315         virtual ~TimeNormalization() {}
316 
317         virtual double convertToDouble( Any const & i_value ) const
318         {
319             double returnValue(0);
320             ::rtl::math::setNan( &returnValue );
321 
322             // extract
323             UnoTime aTimeValue;
324             ENSURE_OR_RETURN( i_value >>= aTimeValue, "allowed for Time values only", returnValue );
325 
326             // convert
327             returnValue += lcl_convertTimeToDays(
328                 aTimeValue.Hours, aTimeValue.Minutes, aTimeValue.Seconds, aTimeValue.HundredthSeconds );
329 
330             // done
331             return returnValue;
332         }
333     };
334 
335     //==================================================================================================================
336     //= operations
337     //==================================================================================================================
338     namespace
339     {
340         //--------------------------------------------------------------------------------------------------------------
341         bool lcl_ensureNumberFormatter( CellValueConversion_Data & io_data )
342         {
343             if ( io_data.bAttemptedFormatterCreation )
344                 return io_data.xNumberFormatter.is();
345             io_data.bAttemptedFormatterCreation = true;
346 
347             try
348             {
349                 // a number formatter
350                 Reference< XNumberFormatter > const xFormatter(
351                     io_data.aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY_THROW );
352 
353                 // a supplier of number formats
354                 Sequence< Any > aInitArgs(1);
355                 aInitArgs[0] <<= SvtSysLocale().GetLocale();
356 
357                 Reference< XNumberFormatsSupplier > const xSupplier(
358                     io_data.aContext.createComponentWithArguments( "com.sun.star.util.NumberFormatsSupplier", aInitArgs ),
359                     UNO_QUERY_THROW
360                 );
361 
362                 // ensure a NullDate we will assume later on
363                 UnoDate const aNullDate( 1, 1, 1900 );
364                 Reference< XPropertySet > const xFormatSettings( xSupplier->getNumberFormatSettings(), UNO_SET_THROW );
365                 xFormatSettings->setPropertyValue( ::rtl::OUString::createFromAscii( "NullDate" ), makeAny( aNullDate ) );
366 
367                 // knit
368                 xFormatter->attachNumberFormatsSupplier( xSupplier );
369 
370                 // done
371                 io_data.xNumberFormatter = xFormatter;
372             }
373             catch( const Exception& )
374             {
375             	DBG_UNHANDLED_EXCEPTION();
376             }
377 
378             return io_data.xNumberFormatter.is();
379         }
380 
381         //--------------------------------------------------------------------------------------------------------------
382         bool lcl_getValueNormalizer( CellValueConversion_Data & io_data, Type const & i_valueType,
383             PValueNormalization & o_formatter )
384         {
385             NormalizerCache::const_iterator pos = io_data.aNormalizers.find( i_valueType.getTypeName() );
386             if ( pos == io_data.aNormalizers.end() )
387             {
388                 // never encountered this type before
389                 o_formatter.reset();
390 
391                 ::rtl::OUString const sTypeName( i_valueType.getTypeName() );
392                 TypeClass const eTypeClass = i_valueType.getTypeClass();
393 
394                 if ( sTypeName.equals( ::cppu::UnoType< DateTime >::get().getTypeName() ) )
395                 {
396                     o_formatter.reset( new DateTimeNormalization( io_data.xNumberFormatter ) );
397                 }
398                 else if ( sTypeName.equals( ::cppu::UnoType< UnoDate >::get().getTypeName() ) )
399                 {
400                     o_formatter.reset( new DateNormalization( io_data.xNumberFormatter ) );
401                 }
402                 else if ( sTypeName.equals( ::cppu::UnoType< UnoTime >::get().getTypeName() ) )
403                 {
404                     o_formatter.reset( new TimeNormalization( io_data.xNumberFormatter ) );
405                 }
406                 else if ( sTypeName.equals( ::cppu::UnoType< ::sal_Bool >::get().getTypeName() ) )
407                 {
408                     o_formatter.reset( new BooleanNormalization( io_data.xNumberFormatter ) );
409                 }
410                 else if (   sTypeName.equals( ::cppu::UnoType< double >::get().getTypeName() )
411                         ||  sTypeName.equals( ::cppu::UnoType< float >::get().getTypeName() )
412                         )
413                 {
414                     o_formatter.reset( new DoubleNormalization( io_data.xNumberFormatter ) );
415                 }
416                 else if (   ( eTypeClass == TypeClass_BYTE )
417                         ||  ( eTypeClass == TypeClass_SHORT )
418                         ||  ( eTypeClass == TypeClass_UNSIGNED_SHORT )
419                         ||  ( eTypeClass == TypeClass_LONG )
420                         ||  ( eTypeClass == TypeClass_UNSIGNED_LONG )
421                         ||  ( eTypeClass == TypeClass_HYPER )
422                         )
423                 {
424                     o_formatter.reset( new IntegerNormalization( io_data.xNumberFormatter ) );
425                 }
426                 else
427                 {
428 #if OSL_DEBUG_LEVEL > 0
429                     ::rtl::OStringBuffer message( "lcl_getValueNormalizer: unsupported type '" );
430                     message.append( ::rtl::OUStringToOString( sTypeName, RTL_TEXTENCODING_ASCII_US ) );
431                     message.append( "'!" );
432                     OSL_ENSURE( false, message.makeStringAndClear() );
433 #endif
434                 }
435                 io_data.aNormalizers[ sTypeName ] = o_formatter;
436             }
437             else
438                 o_formatter = pos->second;
439 
440             return !!o_formatter;
441         }
442     }
443 
444     //==================================================================================================================
445     //= CellValueConversion
446     //==================================================================================================================
447     //------------------------------------------------------------------------------------------------------------------
448     CellValueConversion::CellValueConversion( ::comphelper::ComponentContext const & i_context )
449         :m_pData( new CellValueConversion_Data( i_context ) )
450     {
451     }
452 
453     //------------------------------------------------------------------------------------------------------------------
454     CellValueConversion::~CellValueConversion()
455     {
456     }
457 
458     //------------------------------------------------------------------------------------------------------------------
459     ::rtl::OUString CellValueConversion::convertToString( const Any& i_value )
460     {
461         ::rtl::OUString sStringValue;
462         if ( !i_value.hasValue() )
463             return sStringValue;
464 
465         if ( ! ( i_value >>= sStringValue ) )
466         {
467             if ( lcl_ensureNumberFormatter( *m_pData ) )
468             {
469                 PValueNormalization pNormalizer;
470                 if ( lcl_getValueNormalizer( *m_pData, i_value.getValueType(), pNormalizer ) )
471                 {
472                     try
473                     {
474                         double const formatterCompliantValue = pNormalizer->convertToDouble( i_value );
475                         sal_Int32 const formatKey = pNormalizer->getFormatKey();
476                         sStringValue = m_pData->xNumberFormatter->convertNumberToString(
477                             formatKey, formatterCompliantValue );
478                     }
479                     catch( const Exception& )
480                     {
481                     	DBG_UNHANDLED_EXCEPTION();
482                     }
483                 }
484             }
485         }
486 
487         return sStringValue;
488     }
489 
490 //......................................................................................................................
491 } // namespace svt
492 //......................................................................................................................
493