Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/connectivity/source/commontools/formattedcolumnvalue.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
21
#include <connectivity/formattedcolumnvalue.hxx>
22
#include <connectivity/dbtools.hxx>
23
#include <connectivity/dbconversion.hxx>
24
25
#include <com/sun/star/util/NumberFormatter.hpp>
26
#include <com/sun/star/util/Date.hpp>
27
#include <com/sun/star/sdbc/XConnection.hpp>
28
#include <com/sun/star/util/XNumberFormatTypes.hpp>
29
#include <com/sun/star/util/NumberFormat.hpp>
30
#include <com/sun/star/sdbc/DataType.hpp>
31
#include <com/sun/star/sdb/XColumn.hpp>
32
#include <com/sun/star/sdb/XColumnUpdate.hpp>
33
34
#include <comphelper/diagnose_ex.hxx>
35
#include <i18nlangtag/mslangid.hxx>
36
#include <i18nlangtag/languagetag.hxx>
37
#include <comphelper/numbers.hxx>
38
39
40
namespace dbtools
41
{
42
43
44
    using ::com::sun::star::uno::Reference;
45
    using ::com::sun::star::uno::UNO_QUERY;
46
    using ::com::sun::star::uno::UNO_QUERY_THROW;
47
    using ::com::sun::star::uno::UNO_SET_THROW;
48
    using ::com::sun::star::uno::Exception;
49
    using ::com::sun::star::uno::XComponentContext;
50
    using ::com::sun::star::sdbc::XRowSet;
51
    using ::com::sun::star::beans::XPropertySet;
52
    using ::com::sun::star::util::NumberFormatter;
53
    using ::com::sun::star::util::XNumberFormatter;
54
    using ::com::sun::star::util::Date;
55
    using ::com::sun::star::sdbc::XConnection;
56
    using ::com::sun::star::util::XNumberFormatsSupplier;
57
    using ::com::sun::star::beans::XPropertySetInfo;
58
    using ::com::sun::star::lang::Locale;
59
    using ::com::sun::star::util::XNumberFormatTypes;
60
    using ::com::sun::star::sdb::XColumn;
61
    using ::com::sun::star::sdb::XColumnUpdate;
62
63
    namespace DataType = ::com::sun::star::sdbc::DataType;
64
    namespace NumberFormat = ::com::sun::star::util::NumberFormat;
65
66
    struct FormattedColumnValue_Data
67
    {
68
        Reference< XNumberFormatter >   m_xFormatter;
69
        Date                            m_aNullDate;
70
        sal_Int32                       m_nFormatKey;
71
        sal_Int32                       m_nFieldType;
72
        sal_Int16                       m_nKeyType;
73
        bool                            m_bNumericField;
74
75
        Reference< XColumn >            m_xColumn;
76
        Reference< XColumnUpdate >      m_xColumnUpdate;
77
78
        FormattedColumnValue_Data()
79
0
            :m_aNullDate( DBTypeConversion::getStandardDate() )
80
0
            ,m_nFormatKey( 0 )
81
0
            ,m_nFieldType( DataType::OTHER )
82
0
            ,m_nKeyType( NumberFormat::UNDEFINED )
83
0
            ,m_bNumericField( false )
84
0
        {
85
0
        }
86
    };
87
88
89
    namespace
90
    {
91
92
        void lcl_clear_nothrow( FormattedColumnValue_Data& _rData )
93
0
        {
94
0
            _rData.m_xFormatter.clear();
95
0
            _rData.m_nFormatKey = 0;
96
0
            _rData.m_nFieldType = DataType::OTHER;
97
0
            _rData.m_nKeyType = NumberFormat::UNDEFINED;
98
0
            _rData.m_bNumericField = false;
99
100
0
            _rData.m_xColumn.clear();
101
0
            _rData.m_xColumnUpdate.clear();
102
0
        }
103
104
105
        void lcl_initColumnDataValue_nothrow( FormattedColumnValue_Data& _rData,
106
            const Reference< XNumberFormatter >& i_rNumberFormatter, const Reference< XPropertySet >& _rxColumn )
107
0
        {
108
0
            lcl_clear_nothrow( _rData );
109
110
0
            OSL_PRECOND( i_rNumberFormatter.is(), "lcl_initColumnDataValue_nothrow: no number formats -> no formatted values!" );
111
0
            if ( !i_rNumberFormatter.is() )
112
0
                return;
113
114
0
            try
115
0
            {
116
0
                Reference< XNumberFormatsSupplier > xNumberFormatsSupp( i_rNumberFormatter->getNumberFormatsSupplier(), UNO_SET_THROW );
117
118
                // remember the column
119
0
                _rData.m_xColumn.set( _rxColumn, UNO_QUERY_THROW );
120
0
                _rData.m_xColumnUpdate.set( _rxColumn, UNO_QUERY );
121
122
                // determine the field type, and whether it's a numeric field
123
0
                OSL_VERIFY( _rxColumn->getPropertyValue(u"Type"_ustr) >>= _rData.m_nFieldType );
124
125
0
                switch ( _rData.m_nFieldType )
126
0
                {
127
0
                    case DataType::DATE:
128
0
                    case DataType::TIME:
129
0
                    case DataType::TIME_WITH_TIMEZONE:
130
0
                    case DataType::TIMESTAMP:
131
0
                    case DataType::TIMESTAMP_WITH_TIMEZONE:
132
0
                    case DataType::BIT:
133
0
                    case DataType::BOOLEAN:
134
0
                    case DataType::TINYINT:
135
0
                    case DataType::SMALLINT:
136
0
                    case DataType::INTEGER:
137
0
                    case DataType::REAL:
138
0
                    case DataType::BIGINT:
139
0
                    case DataType::DOUBLE:
140
0
                    case DataType::NUMERIC:
141
0
                    case DataType::DECIMAL:
142
0
                        _rData.m_bNumericField = true;
143
0
                        break;
144
0
                    default:
145
0
                        _rData.m_bNumericField = false;
146
0
                        break;
147
0
                }
148
149
                // get the format key of our bound field
150
0
                Reference< XPropertySetInfo > xPSI( _rxColumn->getPropertySetInfo(), UNO_SET_THROW );
151
0
                bool bHaveFieldFormat = false;
152
0
                static constexpr OUString sFormatKeyProperty( u"FormatKey"_ustr );
153
0
                if ( xPSI->hasPropertyByName( sFormatKeyProperty ) )
154
0
                {
155
0
                    bHaveFieldFormat = ( _rxColumn->getPropertyValue( sFormatKeyProperty ) >>= _rData.m_nFormatKey );
156
0
                }
157
0
                if ( !bHaveFieldFormat )
158
0
                {
159
                    // fall back to a format key as indicated by the field type
160
0
                    Locale aSystemLocale( LanguageTag( MsLangId::getConfiguredSystemLanguage() ).getLocale() );
161
0
                    Reference< XNumberFormatTypes > xNumTypes( xNumberFormatsSupp->getNumberFormats(), UNO_QUERY_THROW );
162
0
                    _rData.m_nFormatKey = getDefaultNumberFormat( _rxColumn, xNumTypes, aSystemLocale );
163
0
                }
164
165
                // some more formatter settings
166
0
                _rData.m_nKeyType  = ::comphelper::getNumberFormatType( xNumberFormatsSupp->getNumberFormats(), _rData.m_nFormatKey );
167
0
                Reference< XPropertySet > xFormatSettings( xNumberFormatsSupp->getNumberFormatSettings(), UNO_SET_THROW );
168
0
                OSL_VERIFY( xFormatSettings->getPropertyValue(u"NullDate"_ustr) >>= _rData.m_aNullDate );
169
170
                // remember the formatter
171
0
                _rData.m_xFormatter = i_rNumberFormatter;
172
0
            }
173
0
            catch( const Exception& )
174
0
            {
175
0
                DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
176
0
            }
177
0
        }
178
179
180
        void lcl_initColumnDataValue_nothrow( const Reference<XComponentContext>& i_rContext, FormattedColumnValue_Data& i_rData,
181
            const Reference< XRowSet >& i_rRowSet, const Reference< XPropertySet >& i_rColumn )
182
0
        {
183
0
            OSL_PRECOND( i_rRowSet.is(), "lcl_initColumnDataValue_nothrow: no row set!" );
184
0
            if ( !i_rRowSet.is() )
185
0
                return;
186
187
0
            Reference< XNumberFormatter > xNumberFormatter;
188
0
            try
189
0
            {
190
                // get the number formats supplier of the connection of the form
191
0
                Reference< XConnection > xConnection( getConnection( i_rRowSet ), UNO_SET_THROW );
192
0
                Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection, true, i_rContext ), UNO_SET_THROW );
193
194
                // create a number formatter for it
195
0
                xNumberFormatter.set( NumberFormatter::create( i_rContext ), UNO_QUERY_THROW );
196
0
                xNumberFormatter->attachNumberFormatsSupplier( xSupplier );
197
0
            }
198
0
            catch( const Exception& )
199
0
            {
200
0
                DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
201
0
            }
202
203
0
            lcl_initColumnDataValue_nothrow( i_rData, xNumberFormatter, i_rColumn );
204
0
        }
205
    }
206
207
    FormattedColumnValue::FormattedColumnValue( const Reference< XComponentContext >& _rxContext,
208
            const Reference< XRowSet >& _rxRowSet, const Reference< XPropertySet >& i_rColumn )
209
0
        :m_pData( new FormattedColumnValue_Data )
210
0
    {
211
0
        lcl_initColumnDataValue_nothrow( _rxContext, *m_pData, _rxRowSet, i_rColumn );
212
0
    }
213
214
215
    FormattedColumnValue::FormattedColumnValue( const Reference< XNumberFormatter >& i_rNumberFormatter,
216
            const Reference< XPropertySet >& _rxColumn )
217
0
        :m_pData( new FormattedColumnValue_Data )
218
0
    {
219
0
        lcl_initColumnDataValue_nothrow( *m_pData, i_rNumberFormatter, _rxColumn );
220
0
    }
221
222
223
    FormattedColumnValue::~FormattedColumnValue()
224
0
    {
225
0
        lcl_clear_nothrow( *m_pData );
226
0
    }
227
228
    sal_Int16 FormattedColumnValue::getKeyType() const
229
0
    {
230
0
        return m_pData->m_nKeyType;
231
0
    }
232
233
234
    const Reference< XColumn >& FormattedColumnValue::getColumn() const
235
0
    {
236
0
        return m_pData->m_xColumn;
237
0
    }
238
239
    bool FormattedColumnValue::setFormattedValue( const OUString& _rFormattedStringValue ) const
240
0
    {
241
0
        OSL_PRECOND( m_pData->m_xColumnUpdate.is(), "FormattedColumnValue::setFormattedValue: no column!" );
242
0
        if ( !m_pData->m_xColumnUpdate.is() )
243
0
            return false;
244
245
0
        try
246
0
        {
247
0
            if ( m_pData->m_bNumericField )
248
0
            {
249
0
                ::dbtools::DBTypeConversion::setValue( m_pData->m_xColumnUpdate, m_pData->m_xFormatter, m_pData->m_aNullDate,
250
0
                    _rFormattedStringValue, m_pData->m_nFormatKey, ::sal::static_int_cast< sal_Int16 >( m_pData->m_nFieldType ),
251
0
                    m_pData->m_nKeyType );
252
0
            }
253
0
            else
254
0
            {
255
0
                m_pData->m_xColumnUpdate->updateString( _rFormattedStringValue );
256
0
            }
257
0
        }
258
0
        catch( const Exception& )
259
0
        {
260
0
            return false;
261
0
        }
262
0
        return true;
263
0
    }
264
265
266
    OUString FormattedColumnValue::getFormattedValue() const
267
0
    {
268
0
        OSL_PRECOND( m_pData->m_xColumn.is(), "FormattedColumnValue::setFormattedValue: no column!" );
269
270
0
        OUString sStringValue;
271
0
        if ( m_pData->m_xColumn.is() )
272
0
        {
273
0
            if ( m_pData->m_bNumericField )
274
0
            {
275
0
                sStringValue = DBTypeConversion::getFormattedValue(
276
0
                    m_pData->m_xColumn, m_pData->m_xFormatter, m_pData->m_aNullDate, m_pData->m_nFormatKey, m_pData->m_nKeyType
277
0
                );
278
0
            }
279
0
            else
280
0
            {
281
0
                sStringValue = m_pData->m_xColumn->getString();
282
0
            }
283
0
        }
284
0
        return sStringValue;
285
0
    }
286
287
288
} // namespace dbtools
289
290
291
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */