1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #include "precompiled_reportdesign.hxx"
24 
25 #include "formatnormalizer.hxx"
26 #include "RptModel.hxx"
27 
28 /** === begin UNO includes === **/
29 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
30 #include <com/sun/star/sdb/XParametersSupplier.hpp>
31 #include <com/sun/star/util/XNumberFormatTypes.hpp>
32 /** === end UNO includes === **/
33 
34 #include <dbaccess/dbsubcomponentcontroller.hxx>
35 #include <unotools/syslocale.hxx>
36 #include <connectivity/statementcomposer.hxx>
37 #include <connectivity/dbtools.hxx>
38 #include <tools/diagnose_ex.h>
39 
40 //........................................................................
41 namespace rptui
42 {
43 //........................................................................
44 
45 	/** === begin UNO using === **/
46     using ::com::sun::star::uno::Reference;
47     using ::com::sun::star::report::XReportDefinition;
48     using ::com::sun::star::report::XFormattedField;
49     using ::com::sun::star::uno::UNO_QUERY;
50     using ::com::sun::star::sdb::XSingleSelectQueryComposer;
51     using ::com::sun::star::sdbcx::XColumnsSupplier;
52     using ::com::sun::star::container::XIndexAccess;
53     using ::com::sun::star::beans::XPropertySet;
54     using ::com::sun::star::uno::UNO_QUERY_THROW;
55     using ::com::sun::star::uno::Exception;
56     using ::com::sun::star::sdb::XParametersSupplier;
57     using ::com::sun::star::sdbc::SQLException;
58     using ::com::sun::star::util::XNumberFormatsSupplier;
59     using ::com::sun::star::util::XNumberFormatTypes;
60     using ::com::sun::star::uno::makeAny;
61 	/** === end UNO using === **/
62 
63 	//====================================================================
64 	//= FormatNormalizer
65 	//====================================================================
DBG_NAME(rpt_FormatNormalizer)66     DBG_NAME(rpt_FormatNormalizer)
67 	//--------------------------------------------------------------------
68     FormatNormalizer::FormatNormalizer( const OReportModel& _rModel )
69         :m_rModel( _rModel )
70         ,m_xReportDefinition( )
71         ,m_bFieldListDirty( true )
72     {
73         DBG_CTOR(rpt_FormatNormalizer,NULL);
74     }
75 
76 	//--------------------------------------------------------------------
~FormatNormalizer()77     FormatNormalizer::~FormatNormalizer()
78     {
79         DBG_DTOR(rpt_FormatNormalizer,NULL);
80     }
81 
82 	//--------------------------------------------------------------------
notifyPropertyChange(const::com::sun::star::beans::PropertyChangeEvent & _rEvent)83     void FormatNormalizer::notifyPropertyChange( const ::com::sun::star::beans::PropertyChangeEvent& _rEvent )
84     {
85         if ( !impl_lateInit() )
86             return;
87 
88         if ( ( _rEvent.Source == m_xReportDefinition ) && m_xReportDefinition.is() )
89         {
90             impl_onDefinitionPropertyChange( _rEvent.PropertyName );
91             return;
92         }
93 
94         Reference< XFormattedField > xFormatted( _rEvent.Source, UNO_QUERY );
95         if ( xFormatted.is() )
96             impl_onFormattedProperttyChange( xFormatted, _rEvent.PropertyName );
97     }
98 
99 	//--------------------------------------------------------------------
notifyElementInserted(const::com::sun::star::uno::Reference<::com::sun::star::uno::XInterface> & _rxElement)100     void FormatNormalizer::notifyElementInserted( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxElement )
101     {
102         if ( !impl_lateInit() )
103             return;
104 
105         Reference< XFormattedField > xFormatted( _rxElement, UNO_QUERY );
106         if ( !xFormatted.is() )
107             return;
108 
109         impl_adjustFormatToDataFieldType_nothrow( xFormatted );
110     }
111 
112 	//--------------------------------------------------------------------
impl_lateInit()113     bool FormatNormalizer::impl_lateInit()
114     {
115         if ( m_xReportDefinition.is() )
116             return true;
117 
118         m_xReportDefinition = m_rModel.getReportDefinition();
119         return m_xReportDefinition.is();
120     }
121 
122 	//--------------------------------------------------------------------
impl_onDefinitionPropertyChange(const::rtl::OUString & _rChangedPropName)123     void FormatNormalizer::impl_onDefinitionPropertyChange( const ::rtl::OUString& _rChangedPropName )
124     {
125         if  (   !_rChangedPropName.equalsAscii( "Command" )
126             &&  !_rChangedPropName.equalsAscii( "CommandType" )
127             &&  !_rChangedPropName.equalsAscii( "EscapeProcessing" )
128             )
129             // nothing we're interested in
130             return;
131         m_bFieldListDirty = true;
132     }
133 
134 	//--------------------------------------------------------------------
impl_onFormattedProperttyChange(const Reference<XFormattedField> & _rxFormatted,const::rtl::OUString & _rChangedPropName)135     void FormatNormalizer::impl_onFormattedProperttyChange( const Reference< XFormattedField >& _rxFormatted, const ::rtl::OUString& _rChangedPropName )
136     {
137         if  ( !_rChangedPropName.equalsAscii( "DataField" ) )
138             // nothing we're interested in
139             return;
140 
141         impl_adjustFormatToDataFieldType_nothrow( _rxFormatted );
142     }
143 
144 	//--------------------------------------------------------------------
145     namespace
146     {
lcl_collectFields_throw(const Reference<XIndexAccess> & _rxColumns,FormatNormalizer::FieldList & _inout_rFields)147         void lcl_collectFields_throw( const Reference< XIndexAccess >& _rxColumns, FormatNormalizer::FieldList& _inout_rFields )
148         {
149             try
150             {
151                 sal_Int32 nCount( _rxColumns->getCount() );
152                 _inout_rFields.reserve( _inout_rFields.size() + (size_t)nCount );
153 
154                 Reference< XPropertySet > xColumn;
155                 FormatNormalizer::Field aField;
156 
157                 for ( sal_Int32 i=0; i<nCount; ++i )
158                 {
159                     xColumn.set( _rxColumns->getByIndex( i ), UNO_QUERY_THROW );
160                     OSL_VERIFY( xColumn->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Name"       ) ) ) >>= aField.sName       );
161                     OSL_VERIFY( xColumn->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Type"       ) ) ) >>= aField.nDataType   );
162                     OSL_VERIFY( xColumn->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scale"      ) ) ) >>= aField.nScale      );
163                     OSL_VERIFY( xColumn->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsCurrency" ) ) ) >>= aField.bIsCurrency );
164                     _inout_rFields.push_back( aField );
165                 }
166             }
167             catch( const Exception& )
168             {
169             	DBG_UNHANDLED_EXCEPTION();
170             }
171         }
172     }
173 
174 	//--------------------------------------------------------------------
impl_ensureUpToDateFieldList_nothrow()175     bool FormatNormalizer::impl_ensureUpToDateFieldList_nothrow()
176     {
177         if ( !m_bFieldListDirty )
178             return true;
179         m_aFields.resize( 0 );
180 
181         OSL_PRECOND( m_xReportDefinition.is(), "FormatNormalizer::impl_ensureUpToDateFieldList_nothrow: no report definition!" );
182         if ( !m_xReportDefinition.is() )
183             return false;
184 
185         ::dbaui::DBSubComponentController* pController( m_rModel.getController() );
186         OSL_ENSURE( pController, "FormatNormalizer::impl_ensureUpToDateFieldList_nothrow: no controller? how can *this* happen?!" );
187         if ( !pController )
188             return false;
189 
190         try
191         {
192             ::dbtools::StatementComposer aComposer( pController->getConnection(), m_xReportDefinition->getCommand(),
193                 m_xReportDefinition->getCommandType(), m_xReportDefinition->getEscapeProcessing() );
194 
195             Reference< XSingleSelectQueryComposer > xComposer( aComposer.getComposer() );
196             if ( !xComposer.is() )
197                 return false;
198 
199 
200             Reference< XColumnsSupplier > xSuppCols( xComposer, UNO_QUERY_THROW );
201             Reference< XIndexAccess > xColumns( xSuppCols->getColumns(), UNO_QUERY_THROW );
202             lcl_collectFields_throw( xColumns, m_aFields );
203 
204             Reference< XParametersSupplier > xSuppParams( xComposer, UNO_QUERY_THROW );
205             Reference< XIndexAccess > xParams( xSuppParams->getParameters(), UNO_QUERY_THROW );
206             lcl_collectFields_throw( xParams, m_aFields );
207         }
208         catch( const SQLException& )
209         {
210             // silence it. This might happen for instance when the user sets an non-existent table,
211             // or things like this
212         }
213         catch( const Exception& )
214         {
215         	DBG_UNHANDLED_EXCEPTION();
216         }
217 
218         m_bFieldListDirty = false;
219         return true;
220     }
221 
222 	//--------------------------------------------------------------------
impl_adjustFormatToDataFieldType_nothrow(const Reference<XFormattedField> & _rxFormatted)223     void FormatNormalizer::impl_adjustFormatToDataFieldType_nothrow( const Reference< XFormattedField >& _rxFormatted )
224     {
225         if ( !impl_ensureUpToDateFieldList_nothrow() )
226             // unable to obtain a recent field list
227             return;
228 
229         try
230         {
231             sal_Int32 nFormatKey = _rxFormatted->getFormatKey();
232             if ( nFormatKey != 0 )
233                 // it's not the "standard numeric" format -> not interested in
234                 return;
235 
236             ::rtl::OUString sDataField( _rxFormatted->getDataField() );
237             const ::rtl::OUString sFieldPrefix( RTL_CONSTASCII_USTRINGPARAM( "field:[" ) );
238             if ( sDataField.indexOf( sFieldPrefix ) != 0 )
239                 // not bound to a table field
240                 // TODO: we might also do this kind of thing for functions and expressions ...
241                 return;
242             if ( sDataField.getStr()[ sDataField.getLength() - 1 ] != ']' )
243             {
244                 // last character is not the closing brace
245                 OSL_ENSURE( false, "FormatNormalizer::impl_adjustFormatToDataFieldType_nothrow: suspicious data field value!" );
246                 return;
247             }
248             sDataField = sDataField.copy( sFieldPrefix.getLength(), sDataField.getLength() - sFieldPrefix.getLength() - 1 );
249 
250             FieldList::const_iterator field = m_aFields.begin();
251             for ( ; field != m_aFields.end(); ++field )
252             {
253                 if ( field->sName == sDataField )
254                     break;
255             }
256             if ( field == m_aFields.end() )
257                 // unknown field
258                 return;
259 
260 		    Reference< XNumberFormatsSupplier >  xSuppNumFmts( _rxFormatted->getFormatsSupplier(), UNO_QUERY_THROW );
261             Reference< XNumberFormatTypes > xNumFmtTypes( xSuppNumFmts->getNumberFormats(), UNO_QUERY_THROW );
262 
263             nFormatKey = ::dbtools::getDefaultNumberFormat( field->nDataType, field->nScale, field->bIsCurrency, xNumFmtTypes,
264                 SvtSysLocale().GetLocaleData().getLocale() );
265             _rxFormatted->setFormatKey( nFormatKey );
266         }
267         catch( const Exception& )
268         {
269         	DBG_UNHANDLED_EXCEPTION();
270         }
271     }
272 
273 //........................................................................
274 } // namespace rptui
275 //........................................................................
276