1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_connectivity.hxx"
30 
31 #include "connectivity/formattedcolumnvalue.hxx"
32 #include "connectivity/dbtools.hxx"
33 #include "connectivity/dbconversion.hxx"
34 
35 /** === begin UNO includes === **/
36 #include <com/sun/star/util/XNumberFormatter.hpp>
37 #include <com/sun/star/util/Date.hpp>
38 #include <com/sun/star/sdbc/XConnection.hpp>
39 #include <com/sun/star/util/XNumberFormatTypes.hpp>
40 #include <com/sun/star/util/NumberFormat.hpp>
41 #include <com/sun/star/sdbc/DataType.hpp>
42 /** === end UNO includes === **/
43 
44 //#include <unotools/syslocale.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <i18npool/mslangid.hxx>
47 #include <comphelper/numbers.hxx>
48 #include <comphelper/componentcontext.hxx>
49 #include <unotools/sharedunocomponent.hxx>
50 
51 //........................................................................
52 namespace dbtools
53 {
54 //........................................................................
55 
56 	/** === begin UNO using === **/
57 	using ::com::sun::star::uno::Reference;
58 	using ::com::sun::star::uno::UNO_QUERY;
59 	using ::com::sun::star::uno::UNO_QUERY_THROW;
60 	using ::com::sun::star::uno::UNO_SET_THROW;
61 	using ::com::sun::star::uno::Exception;
62 	using ::com::sun::star::uno::RuntimeException;
63 	using ::com::sun::star::uno::Any;
64 	using ::com::sun::star::uno::makeAny;
65     using ::com::sun::star::sdbc::XRowSet;
66     using ::com::sun::star::beans::XPropertySet;
67     using ::com::sun::star::util::XNumberFormatter;
68     using ::com::sun::star::util::Date;
69     using ::com::sun::star::sdbc::XConnection;
70     using ::com::sun::star::util::XNumberFormatsSupplier;
71     using ::com::sun::star::beans::XPropertySetInfo;
72     using ::com::sun::star::lang::Locale;
73     using ::com::sun::star::util::XNumberFormatTypes;
74     using ::com::sun::star::sdb::XColumn;
75     using ::com::sun::star::sdb::XColumnUpdate;
76     using ::com::sun::star::lang::XComponent;
77 	/** === end UNO using === **/
78     namespace DataType = ::com::sun::star::sdbc::DataType;
79     namespace NumberFormat = ::com::sun::star::util::NumberFormat;
80 
81 	//====================================================================
82 	//= FormattedColumnValue_Data
83 	//====================================================================
84     struct FormattedColumnValue_Data
85     {
86         Reference< XNumberFormatter >   m_xFormatter;
87         Date                            m_aNullDate;
88         sal_Int32                       m_nFormatKey;
89         sal_Int32                       m_nFieldType;
90         sal_Int16                       m_nKeyType;
91         bool                            m_bNumericField;
92 
93         Reference< XColumn >            m_xColumn;
94         Reference< XColumnUpdate >      m_xColumnUpdate;
95 
96         FormattedColumnValue_Data()
97             :m_xFormatter()
98             ,m_aNullDate( DBTypeConversion::getStandardDate() )
99             ,m_nFormatKey( 0 )
100 	        ,m_nFieldType( DataType::OTHER )
101 	        ,m_nKeyType( NumberFormat::UNDEFINED )
102             ,m_bNumericField( false )
103             ,m_xColumn()
104             ,m_xColumnUpdate()
105         {
106         }
107     };
108 
109 	//--------------------------------------------------------------------
110     namespace
111     {
112 	    //................................................................
113         void lcl_clear_nothrow( FormattedColumnValue_Data& _rData )
114         {
115             _rData.m_xFormatter.clear();
116             _rData.m_nFormatKey = 0;
117             _rData.m_nFieldType = DataType::OTHER;
118             _rData.m_nKeyType = NumberFormat::UNDEFINED;
119             _rData.m_bNumericField = false;
120 
121             _rData.m_xColumn.clear();
122             _rData.m_xColumnUpdate.clear();
123         }
124 
125         //................................................................
126         void lcl_initColumnDataValue_nothrow( FormattedColumnValue_Data& _rData,
127             const Reference< XNumberFormatter >& i_rNumberFormatter, const Reference< XPropertySet >& _rxColumn )
128         {
129             lcl_clear_nothrow( _rData );
130 
131             OSL_PRECOND( i_rNumberFormatter.is(), "lcl_initColumnDataValue_nothrow: no number formats -> no formatted values!" );
132             if ( !i_rNumberFormatter.is() )
133                 return;
134 
135             try
136             {
137                 Reference< XNumberFormatsSupplier > xNumberFormatsSupp( i_rNumberFormatter->getNumberFormatsSupplier(), UNO_SET_THROW );
138 
139                 // remember the column
140                 _rData.m_xColumn.set( _rxColumn, UNO_QUERY_THROW );
141                 _rData.m_xColumnUpdate.set( _rxColumn, UNO_QUERY );
142 
143                 // determine the field type, and whether it's a numeric field
144                 OSL_VERIFY( _rxColumn->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Type" ) ) ) >>= _rData.m_nFieldType );
145 
146                 switch ( _rData.m_nFieldType )
147                 {
148                     case DataType::DATE:
149                     case DataType::TIME:
150                     case DataType::TIMESTAMP:
151                     case DataType::BIT:
152                     case DataType::BOOLEAN:
153                     case DataType::TINYINT:
154                     case DataType::SMALLINT:
155                     case DataType::INTEGER:
156                     case DataType::REAL:
157                     case DataType::BIGINT:
158                     case DataType::DOUBLE:
159                     case DataType::NUMERIC:
160                     case DataType::DECIMAL:
161                         _rData.m_bNumericField = true;
162                         break;
163                     default:
164                         _rData.m_bNumericField = false;
165                         break;
166                 }
167 
168                 // get the format key of our bound field
169                 Reference< XPropertySetInfo > xPSI( _rxColumn->getPropertySetInfo(), UNO_QUERY_THROW );
170                 bool bHaveFieldFormat = false;
171                 const ::rtl::OUString sFormatKeyProperty( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FormatKey" ) ) );
172                 if ( xPSI->hasPropertyByName( sFormatKeyProperty ) )
173                 {
174                     bHaveFieldFormat = ( _rxColumn->getPropertyValue( sFormatKeyProperty ) >>= _rData.m_nFormatKey );
175                 }
176                 if ( !bHaveFieldFormat )
177                 {
178                     // fall back to a format key as indicated by the field type
179                     Locale aSystemLocale;
180                     MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage(), aSystemLocale );
181                     Reference< XNumberFormatTypes > xNumTypes( xNumberFormatsSupp->getNumberFormats(), UNO_QUERY_THROW );
182                     _rData.m_nFormatKey = getDefaultNumberFormat( _rxColumn, xNumTypes, aSystemLocale );
183                 }
184 
185                 // some more formatter settings
186                 _rData.m_nKeyType  = ::comphelper::getNumberFormatType( xNumberFormatsSupp->getNumberFormats(), _rData.m_nFormatKey );
187                 Reference< XPropertySet > xFormatSettings( xNumberFormatsSupp->getNumberFormatSettings(), UNO_QUERY_THROW );
188                 OSL_VERIFY( xFormatSettings->getPropertyValue( ::rtl::OUString::createFromAscii( "NullDate" ) ) >>= _rData.m_aNullDate );
189 
190                 // remember the formatter
191                 _rData.m_xFormatter = i_rNumberFormatter;
192             }
193             catch( const Exception& )
194             {
195     	        DBG_UNHANDLED_EXCEPTION();
196             }
197         }
198 
199         //................................................................
200         void lcl_initColumnDataValue_nothrow( const ::comphelper::ComponentContext& i_rContext, FormattedColumnValue_Data& i_rData,
201             const Reference< XRowSet >& i_rRowSet, const Reference< XPropertySet >& i_rColumn )
202         {
203             OSL_PRECOND( i_rRowSet.is(), "lcl_initColumnDataValue_nothrow: no row set!" );
204             if ( !i_rRowSet.is() )
205                 return;
206 
207             Reference< XNumberFormatter > xNumberFormatter;
208             try
209             {
210                 // get the number formats supplier of the connection of the form
211                 Reference< XConnection > xConnection( getConnection( i_rRowSet ), UNO_QUERY_THROW );
212                 Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection, sal_True, i_rContext.getLegacyServiceFactory() ), UNO_SET_THROW );
213 
214                 // create a number formatter for it
215                 xNumberFormatter.set( i_rContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY_THROW );
216 		        xNumberFormatter->attachNumberFormatsSupplier( xSupplier );
217             }
218             catch( const Exception& )
219             {
220             	DBG_UNHANDLED_EXCEPTION();
221             }
222 
223             lcl_initColumnDataValue_nothrow( i_rData, xNumberFormatter, i_rColumn );
224         }
225     }
226 
227 	//====================================================================
228 	//= FormattedColumnValue
229 	//====================================================================
230 	//--------------------------------------------------------------------
231     FormattedColumnValue::FormattedColumnValue( const ::comphelper::ComponentContext& i_rContext,
232             const Reference< XRowSet >& _rxRowSet, const Reference< XPropertySet >& i_rColumn )
233         :m_pData( new FormattedColumnValue_Data )
234     {
235         lcl_initColumnDataValue_nothrow( i_rContext, *m_pData, _rxRowSet, i_rColumn );
236     }
237 
238 	//--------------------------------------------------------------------
239     FormattedColumnValue::FormattedColumnValue( const Reference< XNumberFormatter >& i_rNumberFormatter,
240             const Reference< XPropertySet >& _rxColumn )
241         :m_pData( new FormattedColumnValue_Data )
242     {
243         lcl_initColumnDataValue_nothrow( *m_pData, i_rNumberFormatter, _rxColumn );
244     }
245 
246 	//--------------------------------------------------------------------
247     void FormattedColumnValue::clear()
248     {
249         lcl_clear_nothrow( *m_pData );
250     }
251 
252 	//--------------------------------------------------------------------
253     FormattedColumnValue::~FormattedColumnValue()
254     {
255         clear();
256     }
257 
258     //--------------------------------------------------------------------
259     sal_Int32 FormattedColumnValue::getFormatKey() const
260     {
261         return m_pData->m_nFormatKey;
262     }
263 
264     //--------------------------------------------------------------------
265     sal_Int32 FormattedColumnValue::getFieldType() const
266     {
267         return m_pData->m_nFieldType;
268     }
269 
270     //--------------------------------------------------------------------
271     sal_Int16 FormattedColumnValue::getKeyType() const
272     {
273         return m_pData->m_nKeyType;
274     }
275 
276     //--------------------------------------------------------------------
277     bool FormattedColumnValue::isNumericField() const
278     {
279         return m_pData->m_bNumericField;
280     }
281 
282 	//--------------------------------------------------------------------
283     const Reference< XColumn >& FormattedColumnValue::getColumn() const
284     {
285         return m_pData->m_xColumn;
286     }
287 
288 	//--------------------------------------------------------------------
289     const Reference< XColumnUpdate >& FormattedColumnValue::getColumnUpdate() const
290     {
291         return m_pData->m_xColumnUpdate;
292     }
293 
294 	//--------------------------------------------------------------------
295     bool FormattedColumnValue::setFormattedValue( const ::rtl::OUString& _rFormattedStringValue ) const
296     {
297         OSL_PRECOND( m_pData->m_xColumnUpdate.is(), "FormattedColumnValue::setFormattedValue: no column!" );
298         if ( !m_pData->m_xColumnUpdate.is() )
299             return false;
300 
301         try
302         {
303             if ( m_pData->m_bNumericField )
304             {
305                 ::dbtools::DBTypeConversion::setValue( m_pData->m_xColumnUpdate, m_pData->m_xFormatter, m_pData->m_aNullDate,
306                     _rFormattedStringValue, m_pData->m_nFormatKey, ::sal::static_int_cast< sal_Int16 >( m_pData->m_nFieldType ),
307                     m_pData->m_nKeyType );
308             }
309             else
310             {
311                 m_pData->m_xColumnUpdate->updateString( _rFormattedStringValue );
312             }
313         }
314         catch( const Exception& )
315         {
316             return false;
317         }
318         return true;
319     }
320 
321 	//--------------------------------------------------------------------
322     ::rtl::OUString FormattedColumnValue::getFormattedValue() const
323     {
324         OSL_PRECOND( m_pData->m_xColumn.is(), "FormattedColumnValue::setFormattedValue: no column!" );
325 
326         ::rtl::OUString sStringValue;
327         if ( m_pData->m_xColumn.is() )
328         {
329             if ( m_pData->m_bNumericField )
330             {
331                 sStringValue = DBTypeConversion::getFormattedValue(
332                     m_pData->m_xColumn, m_pData->m_xFormatter, m_pData->m_aNullDate, m_pData->m_nFormatKey, m_pData->m_nKeyType
333                 );
334             }
335             else
336             {
337                 sStringValue = m_pData->m_xColumn->getString();
338             }
339         }
340         return sStringValue;
341     }
342 
343 //........................................................................
344 } // namespace dbtools
345 //........................................................................
346