Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svl/source/numbers/numfmuno.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
#include <tools/color.hxx>
21
#include <o3tl/any.hxx>
22
#include <osl/mutex.hxx>
23
#include <osl/diagnose.h>
24
#include <rtl/character.hxx>
25
#include <rtl/ustring.hxx>
26
27
#include <com/sun/star/util/Date.hpp>
28
#include <com/sun/star/util/MalformedNumberFormatException.hpp>
29
#include <com/sun/star/util/NotNumericException.hpp>
30
#include <com/sun/star/beans/PropertyAttribute.hpp>
31
#include <comphelper/propertysequence.hxx>
32
#include <cppuhelper/supportsservice.hxx>
33
34
#include "numfmuno.hxx"
35
#include <svl/numformat.hxx>
36
#include <svl/numuno.hxx>
37
#include <svl/zforlist.hxx>
38
#include <svl/zformat.hxx>
39
#include <svl/itemprop.hxx>
40
#include <utility>
41
#include <algorithm>
42
43
using namespace com::sun::star;
44
45
constexpr OUString PROPERTYNAME_FMTSTR = u"FormatString"_ustr;
46
constexpr OUString PROPERTYNAME_LOCALE = u"Locale"_ustr;
47
constexpr OUString PROPERTYNAME_TYPE = u"Type"_ustr;
48
constexpr OUString PROPERTYNAME_COMMENT = u"Comment"_ustr;
49
constexpr OUString PROPERTYNAME_CURREXT = u"CurrencyExtension"_ustr;
50
constexpr OUString PROPERTYNAME_CURRSYM = u"CurrencySymbol"_ustr;
51
constexpr OUString PROPERTYNAME_CURRABB = u"CurrencyAbbreviation"_ustr;
52
constexpr OUString PROPERTYNAME_DECIMALS = u"Decimals"_ustr;
53
constexpr OUString PROPERTYNAME_LEADING = u"LeadingZeros"_ustr;
54
constexpr OUString PROPERTYNAME_NEGRED = u"NegativeRed"_ustr;
55
constexpr OUString PROPERTYNAME_STDFORM = u"StandardFormat"_ustr;
56
constexpr OUString PROPERTYNAME_THOUS = u"ThousandsSeparator"_ustr;
57
constexpr OUString PROPERTYNAME_USERDEF = u"UserDefined"_ustr;
58
59
constexpr OUString PROPERTYNAME_NOZERO = u"NoZero"_ustr;
60
constexpr OUString PROPERTYNAME_NULLDATE = u"NullDate"_ustr;
61
constexpr OUString PROPERTYNAME_STDDEC = u"StandardDecimals"_ustr;
62
constexpr OUString PROPERTYNAME_TWODIGIT = u"TwoDigitDateStart"_ustr;
63
64
// All without a Which-ID, Map only for PropertySetInfo
65
66
static std::span<const SfxItemPropertyMapEntry> lcl_GetNumberFormatPropertyMap()
67
0
{
68
0
    static const SfxItemPropertyMapEntry aNumberFormatPropertyMap_Impl[] =
69
0
    {
70
0
        {PROPERTYNAME_FMTSTR,   0, cppu::UnoType<OUString>::get(),    beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
71
0
        {PROPERTYNAME_LOCALE,   0, cppu::UnoType<lang::Locale>::get(),beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
72
0
        {PROPERTYNAME_TYPE,     0, cppu::UnoType<sal_Int16>::get(),   beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
73
0
        {PROPERTYNAME_COMMENT,  0, cppu::UnoType<OUString>::get(),    beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
74
0
        {PROPERTYNAME_CURREXT,  0, cppu::UnoType<OUString>::get(),    beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
75
0
        {PROPERTYNAME_CURRSYM,  0, cppu::UnoType<OUString>::get(),    beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
76
0
        {PROPERTYNAME_DECIMALS, 0, cppu::UnoType<sal_Int16>::get(),   beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
77
0
        {PROPERTYNAME_LEADING,  0, cppu::UnoType<sal_Int16>::get(),   beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
78
0
        {PROPERTYNAME_NEGRED,   0, cppu::UnoType<bool>::get(),         beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
79
0
        {PROPERTYNAME_STDFORM,  0, cppu::UnoType<bool>::get(),         beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
80
0
        {PROPERTYNAME_THOUS,    0, cppu::UnoType<bool>::get(),         beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
81
0
        {PROPERTYNAME_USERDEF,  0, cppu::UnoType<bool>::get(),         beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
82
0
        {PROPERTYNAME_CURRABB,  0, cppu::UnoType<OUString>::get(),    beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
83
0
    };
84
0
    return aNumberFormatPropertyMap_Impl;
85
0
}
86
87
static std::span<const SfxItemPropertyMapEntry> lcl_GetNumberSettingsPropertyMap()
88
1
{
89
1
    static const SfxItemPropertyMapEntry aNumberSettingsPropertyMap_Impl[] =
90
1
    {
91
1
        {PROPERTYNAME_NOZERO,   0, cppu::UnoType<bool>::get(),         beans::PropertyAttribute::BOUND, 0},
92
1
        {PROPERTYNAME_NULLDATE, 0, cppu::UnoType<util::Date>::get(),  beans::PropertyAttribute::BOUND, 0},
93
1
        {PROPERTYNAME_STDDEC,   0, cppu::UnoType<sal_Int16>::get(),   beans::PropertyAttribute::BOUND, 0},
94
1
        {PROPERTYNAME_TWODIGIT, 0, cppu::UnoType<sal_Int16>::get(),   beans::PropertyAttribute::BOUND, 0},
95
1
    };
96
1
    return aNumberSettingsPropertyMap_Impl;
97
1
}
98
99
static LanguageType lcl_GetLanguage( const lang::Locale& rLocale )
100
286k
{
101
286k
    LanguageType eRet = LanguageTag::convertToLanguageTypeWithFallback( rLocale );
102
286k
    if ( eRet == LANGUAGE_NONE )
103
1
        eRet = LANGUAGE_SYSTEM; //! or throw an exception?
104
105
286k
    return eRet;
106
286k
}
107
108
SvNumberFormatterServiceObj::SvNumberFormatterServiceObj()
109
3
{
110
3
}
111
112
SvNumberFormatterServiceObj::~SvNumberFormatterServiceObj()
113
0
{
114
0
}
115
116
// XNumberFormatter
117
118
void SAL_CALL SvNumberFormatterServiceObj::attachNumberFormatsSupplier( const uno::Reference<util::XNumberFormatsSupplier>& _xSupplier )
119
20.2k
{
120
20.2k
    ::rtl::Reference< SvNumberFormatsSupplierObj > xAutoReleaseOld;
121
122
    // SYNCHRONIZED ->
123
20.2k
    {
124
20.2k
        ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
125
126
20.2k
        SvNumberFormatsSupplierObj* pNew = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( _xSupplier );
127
20.2k
        if (!pNew)
128
0
            throw uno::RuntimeException(); // wrong object
129
130
20.2k
        xAutoReleaseOld = xSupplier;
131
132
20.2k
        xSupplier = pNew;
133
20.2k
        m_aMutex = xSupplier->getSharedMutex();
134
20.2k
    }
135
    // <- SYNCHRONIZED
136
20.2k
}
137
138
uno::Reference<util::XNumberFormatsSupplier> SAL_CALL SvNumberFormatterServiceObj::getNumberFormatsSupplier()
139
0
{
140
0
    ::osl::MutexGuard aGuard( m_aMutex );
141
0
    return xSupplier;
142
0
}
143
144
sal_Int32 SAL_CALL SvNumberFormatterServiceObj::detectNumberFormat( sal_Int32 nKey, const OUString& aString )
145
0
{
146
0
    ::osl::MutexGuard aGuard( m_aMutex );
147
148
0
    SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : nullptr;
149
0
    if (!pFormatter)
150
0
        throw uno::RuntimeException();
151
152
0
    sal_uInt32 nUKey = nKey;
153
0
    double fValue = 0.0;
154
0
    if ( !pFormatter->IsNumberFormat(aString, nUKey, fValue) )
155
0
        throw util::NotNumericException();
156
157
0
    return nUKey;
158
0
}
159
160
double SAL_CALL SvNumberFormatterServiceObj::convertStringToNumber( sal_Int32 nKey, const OUString& aString )
161
0
{
162
0
    ::osl::MutexGuard aGuard( m_aMutex );
163
164
0
    SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : nullptr;
165
0
    if (!pFormatter)
166
0
        throw uno::RuntimeException();
167
168
0
    sal_uInt32 nUKey = nKey;
169
0
    double fValue = 0.0;
170
0
    if ( !pFormatter->IsNumberFormat(aString, nUKey, fValue) )
171
0
        throw util::NotNumericException();
172
173
0
    return fValue;
174
0
}
175
176
OUString SAL_CALL SvNumberFormatterServiceObj::convertNumberToString( sal_Int32 nKey, double fValue )
177
0
{
178
0
    ::osl::MutexGuard aGuard( m_aMutex );
179
180
0
    OUString aRet;
181
0
    SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : nullptr;
182
0
    if (!pFormatter)
183
0
        throw uno::RuntimeException();
184
185
0
    const Color* pColor = nullptr;
186
0
    pFormatter->GetOutputString(fValue, nKey, aRet, &pColor);
187
188
0
    return aRet;
189
0
}
190
191
sal_Int32 SAL_CALL SvNumberFormatterServiceObj::queryColorForNumber( sal_Int32 nKey,
192
                                                                       double fValue,
193
                                                                       sal_Int32 aDefaultColor )
194
0
{
195
0
    ::osl::MutexGuard aGuard( m_aMutex );
196
197
0
    util::Color nRet = aDefaultColor; // color = sal_Int32
198
0
    SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : nullptr;
199
0
    if (!pFormatter)
200
0
        throw uno::RuntimeException();
201
202
0
    OUString aStr;
203
0
    const Color* pColor = nullptr;
204
0
    pFormatter->GetOutputString(fValue, nKey, aStr, &pColor);
205
0
    if (pColor)
206
0
        nRet = sal_uInt32(*pColor);
207
    // Else keep Default
208
209
0
    return nRet;
210
0
}
211
212
OUString SAL_CALL SvNumberFormatterServiceObj::formatString( sal_Int32 nKey,
213
                                                             const OUString& aString )
214
0
{
215
0
    ::osl::MutexGuard aGuard( m_aMutex );
216
217
0
    OUString aRet;
218
0
    SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : nullptr;
219
0
    if (!pFormatter)
220
0
    {
221
0
        throw uno::RuntimeException();
222
0
    }
223
224
0
    const Color* pColor = nullptr;
225
0
    pFormatter->GetOutputString(aString, nKey, aRet, &pColor);
226
227
0
    return aRet;
228
0
}
229
230
sal_Int32 SAL_CALL SvNumberFormatterServiceObj::queryColorForString( sal_Int32 nKey,
231
                                                                       const OUString& aString,
232
                                                                       sal_Int32 aDefaultColor )
233
0
{
234
0
    ::osl::MutexGuard aGuard( m_aMutex );
235
236
0
    util::Color nRet = aDefaultColor; // color = sal_Int32
237
0
    SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : nullptr;
238
0
    if (!pFormatter)
239
0
    {
240
0
        throw uno::RuntimeException();
241
0
    }
242
243
0
    OUString aStr;
244
0
    const Color* pColor = nullptr;
245
0
    pFormatter->GetOutputString(aString, nKey, aStr, &pColor);
246
0
    if (pColor)
247
0
    {
248
0
        nRet = sal_uInt32(*pColor);
249
0
    }
250
    // Else keep Default
251
252
0
    return nRet;
253
0
}
254
255
OUString SAL_CALL SvNumberFormatterServiceObj::getInputString( sal_Int32 nKey, double fValue )
256
0
{
257
0
    ::osl::MutexGuard aGuard( m_aMutex );
258
259
0
    SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : nullptr;
260
0
    if (!pFormatter)
261
0
        throw uno::RuntimeException();
262
263
0
    return pFormatter->GetInputLineString(fValue, nKey);
264
0
}
265
266
// XNumberFormatPreviewer
267
268
OUString SAL_CALL SvNumberFormatterServiceObj::convertNumberToPreviewString( const OUString& aFormat,
269
                                                                             double fValue,
270
                                                                             const lang::Locale& nLocale,
271
                                                                             sal_Bool bAllowEnglish )
272
0
{
273
0
    ::osl::MutexGuard aGuard( m_aMutex );
274
275
0
    OUString aRet;
276
0
    SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : nullptr;
277
0
    if (!pFormatter)
278
0
        throw uno::RuntimeException();
279
280
0
    LanguageType eLang = lcl_GetLanguage( nLocale );
281
0
    const Color* pColor = nullptr;
282
283
0
    bool bOk;
284
0
    if ( bAllowEnglish )
285
0
        bOk = pFormatter->GetPreviewStringGuess( aFormat, fValue, aRet, &pColor, eLang );
286
0
    else
287
0
        bOk = pFormatter->GetPreviewString( aFormat, fValue, aRet, &pColor, eLang );
288
289
0
    if (!bOk)
290
0
        throw util::MalformedNumberFormatException();
291
292
0
    return aRet;
293
0
}
294
295
sal_Int32 SAL_CALL SvNumberFormatterServiceObj::queryPreviewColorForNumber( const OUString& aFormat,
296
                                                                              double fValue,
297
                                                                              const lang::Locale& nLocale,
298
                                                                              sal_Bool bAllowEnglish,
299
                                                                              sal_Int32 aDefaultColor )
300
0
{
301
0
    ::osl::MutexGuard aGuard( m_aMutex );
302
303
0
    util::Color nRet = aDefaultColor; // color = sal_Int32
304
0
    SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : nullptr;
305
0
    if (!pFormatter)
306
0
        throw uno::RuntimeException();
307
308
0
    OUString aOutString;
309
0
    LanguageType eLang = lcl_GetLanguage( nLocale );
310
0
    const Color* pColor = nullptr;
311
312
0
    bool bOk;
313
0
    if ( bAllowEnglish )
314
0
        bOk = pFormatter->GetPreviewStringGuess( aFormat, fValue, aOutString, &pColor, eLang );
315
0
    else
316
0
        bOk = pFormatter->GetPreviewString( aFormat, fValue, aOutString, &pColor, eLang );
317
318
0
    if (!bOk)
319
0
        throw util::MalformedNumberFormatException();
320
321
0
    if (pColor)
322
0
        nRet = sal_uInt32(*pColor);
323
    // Else keep Default
324
325
0
    return nRet;
326
0
}
327
328
// XServiceInfo
329
330
OUString SAL_CALL SvNumberFormatterServiceObj::getImplementationName()
331
0
{
332
0
    return u"com.sun.star.uno.util.numbers.SvNumberFormatterServiceObject"_ustr;
333
0
}
334
335
sal_Bool SAL_CALL SvNumberFormatterServiceObj::supportsService( const OUString& ServiceName )
336
0
{
337
0
    return cppu::supportsService( this, ServiceName );
338
0
}
339
340
uno::Sequence<OUString> SAL_CALL SvNumberFormatterServiceObj::getSupportedServiceNames()
341
0
{
342
0
    return { u"com.sun.star.util.NumberFormatter"_ustr };
343
0
}
344
345
SvNumberFormatsObj::SvNumberFormatsObj( SvNumberFormatsSupplierObj& _rParent, ::comphelper::SharedMutex  _aMutex )
346
22.9k
    :m_xSupplier( &_rParent )
347
22.9k
    ,m_aMutex(std::move( _aMutex ))
348
22.9k
{
349
22.9k
}
350
351
SvNumberFormatsObj::~SvNumberFormatsObj()
352
22.9k
{
353
22.9k
}
354
355
// XNumberFormats
356
357
uno::Reference<beans::XPropertySet> SAL_CALL SvNumberFormatsObj::getByKey( sal_Int32 nKey )
358
0
{
359
0
    ::osl::MutexGuard aGuard( m_aMutex );
360
361
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
362
0
    const SvNumberformat* pFormat = pFormatter ? pFormatter->GetEntry(nKey) : nullptr;
363
0
    if (!pFormat)
364
0
        throw uno::RuntimeException();
365
366
0
    return new SvNumberFormatObj( *m_xSupplier, nKey, m_aMutex );
367
0
}
368
369
uno::Sequence<sal_Int32> SAL_CALL SvNumberFormatsObj::queryKeys( sal_Int16 nType,
370
                                                                 const lang::Locale& nLocale,
371
                                                                 sal_Bool bCreate )
372
0
{
373
0
    ::osl::MutexGuard aGuard( m_aMutex );
374
375
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
376
0
    if ( !pFormatter )
377
0
        throw uno::RuntimeException();
378
379
0
    sal_uInt32 nIndex = 0;
380
0
    LanguageType eLang = lcl_GetLanguage( nLocale );
381
0
    SvNumberFormatTable& rTable = bCreate ?
382
0
                                    pFormatter->ChangeCL( static_cast<SvNumFormatType>(nType), nIndex, eLang ) :
383
0
                                    pFormatter->GetEntryTable( static_cast<SvNumFormatType>(nType), nIndex, eLang );
384
0
    sal_uInt32 nCount = rTable.size();
385
0
    uno::Sequence<sal_Int32> aSeq(nCount);
386
0
    sal_Int32* pAry = aSeq.getArray();
387
0
    sal_uInt32 i=0;
388
0
    for (const auto& rEntry : rTable)
389
0
    {
390
0
        pAry[i] = rEntry.first;
391
0
        ++i;
392
0
    }
393
0
    return aSeq;
394
0
}
395
396
sal_Int32 SAL_CALL SvNumberFormatsObj::queryKey( const OUString& aFormat,
397
                                                 const lang::Locale& nLocale,
398
                                                 sal_Bool bScan )
399
0
{
400
0
    ::osl::MutexGuard aGuard( m_aMutex );
401
402
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
403
0
    if (!pFormatter)
404
0
        throw uno::RuntimeException();
405
406
0
    LanguageType eLang = lcl_GetLanguage( nLocale );
407
0
    if (bScan)
408
0
    {
409
        //! FIXME: Something still needs to happen here ...
410
0
    }
411
0
    sal_uInt32 nRet = pFormatter->GetEntryKey( aFormat, eLang );
412
0
    if (nRet == NUMBERFORMAT_ENTRY_NOT_FOUND)
413
0
    {
414
        // This seems to be a workaround for what maybe the bScan option was
415
        // intended for? Tokenize the format code?
416
417
        // The format string based search is vague and fuzzy, as it is case
418
        // sensitive, but the format string is only half way cased, the
419
        // keywords (except the "General" keyword) are uppercased and literals
420
        // of course are not. Clients using this queryKey() and if not
421
        // successful addNew() may still fail if the result of PutEntry() is
422
        // false because the format actually existed, just with a different
423
        // casing. The only clean way is to just use PutEntry() and ignore the
424
        // duplicate case, which clients can't because the API doesn't provide
425
        // the information.
426
        // Try just another possibility here, without any guarantee.
427
428
        // Use only ASCII upper, because keywords are only those.
429
        // Do not transliterate any quoted literals.
430
0
        const sal_Int32 nLen = aFormat.getLength();
431
0
        OUStringBuffer aBuf(0);
432
0
        sal_Unicode* p = aBuf.appendUninitialized( nLen + 1);
433
0
        std::copy_n( aFormat.getStr(), nLen + 1, p );   // including 0-char
434
0
        aBuf.setLength( nLen);
435
0
        assert(p == aBuf.getStr());
436
0
        sal_Unicode const * const pStop = p + aBuf.getLength();
437
0
        bool bQuoted = false;
438
0
        for ( ; p < pStop; ++p)
439
0
        {
440
0
            if (bQuoted)
441
0
            {
442
                // Format codes don't have embedded doubled quotes, i.e. "a""b"
443
                // is two literals displayed as `ab`.
444
0
                if (*p == '"')
445
0
                    bQuoted = false;
446
0
            }
447
0
            else if (*p == '"')
448
0
                bQuoted = true;
449
0
            else if (rtl::isAsciiLowerCase(*p))
450
0
                *p = rtl::toAsciiUpperCase(*p);
451
0
            else if (*p == '\\')
452
0
                ++p;            // skip escaped next char
453
                // Theoretically that should cater for UTF-32 with
454
                // iterateCodePoints(), but such character would not match any
455
                // of [a-z\"] in its UTF-16 units.
456
0
        }
457
0
        nRet = pFormatter->GetEntryKey( aBuf, eLang );
458
0
    }
459
0
    return static_cast<sal_Int32>(nRet);
460
0
}
461
462
sal_Int32 SAL_CALL SvNumberFormatsObj::addNew( const OUString& aFormat,
463
                                               const lang::Locale& nLocale )
464
0
{
465
0
    ::osl::MutexGuard aGuard( m_aMutex );
466
467
0
    sal_Int32 nRet = 0;
468
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
469
0
    if (!pFormatter)
470
0
        throw uno::RuntimeException();
471
472
0
    OUString aFormStr = aFormat;
473
0
    LanguageType eLang = lcl_GetLanguage( nLocale );
474
0
    sal_uInt32 nKey = 0;
475
0
    sal_Int32 nCheckPos = 0;
476
0
    SvNumFormatType nType = SvNumFormatType::ALL;
477
0
    bool bOk = pFormatter->PutEntry( aFormStr, nCheckPos, nType, nKey, eLang );
478
0
    if (bOk)
479
0
        nRet = nKey;
480
0
    else if (nCheckPos)
481
0
    {
482
0
        throw util::MalformedNumberFormatException(); // Invalid Format
483
0
    }
484
0
    else if (aFormStr != aFormat)
485
0
    {
486
        // The format exists but with a different format code string, and if it
487
        // was only uppercase vs lowercase keywords; but also syntax extensions
488
        // are possible like resulting embedded LCIDs and what not the client
489
        // doesn't know about. Silently accept instead of throwing an error.
490
0
        nRet = nKey;
491
0
    }
492
0
    else
493
0
        throw uno::RuntimeException(); // Other error (e.g. already added)
494
495
0
    return nRet;
496
0
}
497
498
sal_Int32 SAL_CALL SvNumberFormatsObj::addNewConverted( const OUString& aFormat,
499
                                                        const lang::Locale& nLocale,
500
                                                        const lang::Locale& nNewLocale )
501
45.0k
{
502
45.0k
    ::osl::MutexGuard aGuard( m_aMutex );
503
504
45.0k
    sal_Int32 nRet = 0;
505
45.0k
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
506
45.0k
    if (!pFormatter)
507
0
        throw uno::RuntimeException();
508
509
45.0k
    OUString aFormStr = aFormat;
510
45.0k
    LanguageType eLang = lcl_GetLanguage( nLocale );
511
45.0k
    LanguageType eNewLang = lcl_GetLanguage( nNewLocale );
512
45.0k
    sal_uInt32 nKey = 0;
513
45.0k
    sal_Int32 nCheckPos = 0;
514
45.0k
    SvNumFormatType nType = SvNumFormatType::ALL;
515
    // This is used also when reading OOXML documents, there's no indicator
516
    // whether to convert date particle order as well, so don't. See tdf#119013
517
45.0k
    bool bOk = pFormatter->PutandConvertEntry( aFormStr, nCheckPos, nType, nKey, eLang, eNewLang, false);
518
45.0k
    if (bOk || nKey > 0)
519
43.6k
        nRet = nKey;
520
1.37k
    else if (nCheckPos)
521
61
    {
522
61
        throw util::MalformedNumberFormatException();       // Invalid format
523
61
    }
524
1.31k
    else
525
1.31k
        throw uno::RuntimeException(); // Other error (e.g. already added)
526
527
43.6k
    return nRet;
528
45.0k
}
529
530
void SAL_CALL SvNumberFormatsObj::removeByKey( sal_Int32 nKey )
531
0
{
532
0
    ::osl::MutexGuard aGuard( m_aMutex );
533
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
534
535
0
    if (pFormatter)
536
0
    {
537
0
        pFormatter->DeleteEntry(nKey);
538
0
    }
539
0
}
540
541
OUString SAL_CALL SvNumberFormatsObj::generateFormat( sal_Int32 nBaseKey,
542
                                                      const lang::Locale& nLocale,
543
                                                      sal_Bool bThousands,
544
                                                      sal_Bool bRed, sal_Int16 nDecimals,
545
                                                      sal_Int16 nLeading )
546
0
{
547
0
    ::osl::MutexGuard aGuard( m_aMutex );
548
549
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
550
0
    if (!pFormatter)
551
0
        throw uno::RuntimeException();
552
553
0
    LanguageType eLang = lcl_GetLanguage( nLocale );
554
0
    OUString aRet = pFormatter->GenerateFormat(nBaseKey, eLang, bThousands, bRed, nDecimals, nLeading);
555
0
    return aRet;
556
0
}
557
558
// XNumberFormatTypes
559
560
sal_Int32 SAL_CALL SvNumberFormatsObj::getStandardIndex( const lang::Locale& nLocale )
561
20.2k
{
562
20.2k
    ::osl::MutexGuard aGuard( m_aMutex );
563
564
20.2k
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
565
20.2k
    if (!pFormatter)
566
0
        throw uno::RuntimeException();
567
568
20.2k
    LanguageType eLang = lcl_GetLanguage( nLocale );
569
20.2k
    sal_Int32 nRet = pFormatter->GetStandardIndex(eLang);
570
20.2k
    return nRet;
571
20.2k
}
572
573
sal_Int32 SAL_CALL SvNumberFormatsObj::getStandardFormat( sal_Int16 nType, const lang::Locale& nLocale )
574
0
{
575
0
    ::osl::MutexGuard aGuard( m_aMutex );
576
577
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
578
0
    if (!pFormatter)
579
0
        throw uno::RuntimeException();
580
581
0
    LanguageType eLang = lcl_GetLanguage( nLocale );
582
    // Mask out "defined" bit, so type from an existing number format
583
    // can directly be used for getStandardFormat
584
0
    SvNumFormatType nType2 = static_cast<SvNumFormatType>(nType);
585
0
    nType2 &= ~SvNumFormatType::DEFINED;
586
0
    sal_Int32 nRet = pFormatter->GetStandardFormat(nType2, eLang);
587
0
    return nRet;
588
0
}
589
590
sal_Int32 SAL_CALL SvNumberFormatsObj::getFormatIndex( sal_Int16 nIndex, const lang::Locale& nLocale )
591
176k
{
592
176k
    ::osl::MutexGuard aGuard( m_aMutex );
593
594
176k
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
595
176k
    if (!pFormatter)
596
0
        throw uno::RuntimeException();
597
598
176k
    LanguageType eLang = lcl_GetLanguage( nLocale );
599
176k
    sal_Int32 nRet = pFormatter->GetFormatIndex( static_cast<NfIndexTableOffset>(nIndex), eLang );
600
176k
    return nRet;
601
176k
}
602
603
sal_Bool SAL_CALL SvNumberFormatsObj::isTypeCompatible( sal_Int16 nOldType, sal_Int16 nNewType )
604
0
{
605
0
    ::osl::MutexGuard aGuard( m_aMutex );
606
607
0
    return SvNumberFormatter::IsCompatible( static_cast<SvNumFormatType>(nOldType), static_cast<SvNumFormatType>(nNewType) );
608
0
}
609
610
sal_Int32 SAL_CALL SvNumberFormatsObj::getFormatForLocale( sal_Int32 nKey, const lang::Locale& nLocale )
611
0
{
612
0
    ::osl::MutexGuard aGuard( m_aMutex );
613
614
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
615
0
    if (!pFormatter)
616
0
        throw uno::RuntimeException();
617
618
0
    LanguageType eLang = lcl_GetLanguage( nLocale );
619
0
    sal_Int32 nRet = pFormatter->GetFormatForLanguageIfBuiltIn(nKey, eLang);
620
0
    return nRet;
621
0
}
622
623
// XServiceInfo
624
625
OUString SAL_CALL SvNumberFormatsObj::getImplementationName()
626
0
{
627
0
    return u"SvNumberFormatsObj"_ustr;
628
0
}
629
630
sal_Bool SAL_CALL SvNumberFormatsObj::supportsService( const OUString& ServiceName )
631
0
{
632
0
    return cppu::supportsService( this, ServiceName );
633
0
}
634
635
uno::Sequence<OUString> SAL_CALL SvNumberFormatsObj::getSupportedServiceNames()
636
0
{
637
0
    return { u"com.sun.star.util.NumberFormats"_ustr };
638
0
}
639
640
SvNumberFormatObj::SvNumberFormatObj( SvNumberFormatsSupplierObj& rParent, sal_Int32 nK, ::comphelper::SharedMutex _aMutex )
641
0
    :m_xSupplier( &rParent )
642
0
    ,nKey( nK )
643
0
    ,m_aMutex(std::move( _aMutex ))
644
0
{
645
0
}
646
647
SvNumberFormatObj::~SvNumberFormatObj()
648
0
{
649
0
}
650
651
// XPropertySet
652
653
uno::Reference<beans::XPropertySetInfo> SAL_CALL SvNumberFormatObj::getPropertySetInfo()
654
0
{
655
0
    static uno::Reference<beans::XPropertySetInfo> aRef =
656
0
        new SfxItemPropertySetInfo( lcl_GetNumberFormatPropertyMap() );
657
0
    return aRef;
658
0
}
659
660
void SAL_CALL SvNumberFormatObj::setPropertyValue( const OUString&,
661
                                                   const uno::Any& )
662
0
{
663
0
    throw beans::UnknownPropertyException(); // Everything is read-only
664
0
}
665
666
uno::Any SAL_CALL SvNumberFormatObj::getPropertyValue( const OUString& aPropertyName )
667
0
{
668
0
    ::osl::MutexGuard aGuard( m_aMutex );
669
670
0
    uno::Any aRet;
671
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
672
0
    const SvNumberformat* pFormat = pFormatter ? pFormatter->GetEntry(nKey) : nullptr;
673
0
    if (!pFormat)
674
0
        throw uno::RuntimeException();
675
676
0
    bool bThousand, bRed;
677
0
    sal_uInt16 nDecimals, nLeading;
678
679
0
    if (aPropertyName == PROPERTYNAME_FMTSTR)
680
0
    {
681
0
        aRet <<= pFormat->GetFormatstring();
682
0
    }
683
0
    else if (aPropertyName == PROPERTYNAME_LOCALE)
684
0
    {
685
0
        lang::Locale aLocale( LanguageTag::convertToLocale( pFormat->GetLanguage(), false));
686
0
        aRet <<= aLocale;
687
0
    }
688
0
    else if (aPropertyName == PROPERTYNAME_TYPE)
689
0
    {
690
0
        aRet <<= static_cast<sal_Int16>( pFormat->GetType() );
691
0
    }
692
0
    else if (aPropertyName == PROPERTYNAME_COMMENT)
693
0
    {
694
0
        aRet <<= pFormat->GetComment();
695
0
    }
696
0
    else if (aPropertyName == PROPERTYNAME_STDFORM)
697
0
    {
698
        //! Pass through SvNumberformat Member bStandard?
699
0
        aRet <<= ( ( nKey % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 );
700
0
    }
701
0
    else if (aPropertyName == PROPERTYNAME_USERDEF)
702
0
    {
703
0
        aRet <<= bool( pFormat->GetType() & SvNumFormatType::DEFINED );
704
0
    }
705
0
    else if (aPropertyName == PROPERTYNAME_DECIMALS)
706
0
    {
707
0
        pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
708
0
        aRet <<= static_cast<sal_Int16>(nDecimals);
709
0
    }
710
0
    else if (aPropertyName == PROPERTYNAME_LEADING)
711
0
    {
712
0
        pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
713
0
        aRet <<= static_cast<sal_Int16>(nLeading);
714
0
    }
715
0
    else if (aPropertyName == PROPERTYNAME_NEGRED)
716
0
    {
717
0
        pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
718
0
        aRet <<= bRed;
719
0
    }
720
0
    else if (aPropertyName == PROPERTYNAME_THOUS)
721
0
    {
722
0
        pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
723
0
        aRet <<= bThousand;
724
0
    }
725
0
    else if (aPropertyName == PROPERTYNAME_CURRSYM)
726
0
    {
727
0
        OUString aSymbol, aExt;
728
0
        pFormat->GetNewCurrencySymbol( aSymbol, aExt );
729
0
        aRet <<= aSymbol;
730
0
    }
731
0
    else if (aPropertyName == PROPERTYNAME_CURREXT)
732
0
    {
733
0
        OUString aSymbol, aExt;
734
0
        pFormat->GetNewCurrencySymbol( aSymbol, aExt );
735
0
        aRet <<= aExt;
736
0
    }
737
0
    else if (aPropertyName == PROPERTYNAME_CURRABB)
738
0
    {
739
0
        OUString aSymbol, aExt;
740
0
        bool bBank = false;
741
0
        pFormat->GetNewCurrencySymbol( aSymbol, aExt );
742
0
        const NfCurrencyEntry* pCurr = SvNumberFormatter::GetCurrencyEntry( bBank,
743
0
            aSymbol, aExt, pFormat->GetLanguage() );
744
0
        if ( pCurr )
745
0
            aRet <<= pCurr->GetBankSymbol();
746
0
        else
747
0
            aRet <<= OUString();
748
0
    }
749
0
    else
750
0
        throw beans::UnknownPropertyException(aPropertyName);
751
752
0
    return aRet;
753
0
}
754
755
void SAL_CALL SvNumberFormatObj::addPropertyChangeListener( const OUString&,
756
                                                            const uno::Reference<beans::XPropertyChangeListener>&)
757
0
{
758
0
    OSL_FAIL("not implemented");
759
0
}
760
761
void SAL_CALL SvNumberFormatObj::removePropertyChangeListener( const OUString&,
762
                                                               const uno::Reference<beans::XPropertyChangeListener>&)
763
0
{
764
0
    OSL_FAIL("not implemented");
765
0
}
766
767
void SAL_CALL SvNumberFormatObj::addVetoableChangeListener( const OUString&,
768
                                                            const uno::Reference<beans::XVetoableChangeListener>&)
769
0
{
770
0
    OSL_FAIL("not implemented");
771
0
}
772
773
void SAL_CALL SvNumberFormatObj::removeVetoableChangeListener( const OUString&,
774
                                                               const uno::Reference<beans::XVetoableChangeListener>&)
775
0
{
776
0
    OSL_FAIL("not implemented");
777
0
}
778
779
// XPropertyAccess
780
781
uno::Sequence<beans::PropertyValue> SAL_CALL SvNumberFormatObj::getPropertyValues()
782
0
{
783
0
    ::osl::MutexGuard aGuard( m_aMutex );
784
785
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
786
0
    const SvNumberformat* pFormat = pFormatter ? pFormatter->GetEntry(nKey) : nullptr;
787
0
    if (!pFormat)
788
0
        throw uno::RuntimeException();
789
790
0
    OUString aSymbol, aExt;
791
0
    OUString aAbb;
792
0
    bool bBank = false;
793
0
    pFormat->GetNewCurrencySymbol( aSymbol, aExt );
794
0
    const NfCurrencyEntry* pCurr = SvNumberFormatter::GetCurrencyEntry( bBank,
795
0
        aSymbol, aExt, pFormat->GetLanguage() );
796
0
    if ( pCurr )
797
0
        aAbb = pCurr->GetBankSymbol();
798
799
0
    OUString aFmtStr = pFormat->GetFormatstring();
800
0
    OUString aComment = pFormat->GetComment();
801
0
    bool bStandard = ( ( nKey % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 );
802
    //! Pass through SvNumberformat Member bStandard?
803
0
    bool bUserDef( pFormat->GetType() & SvNumFormatType::DEFINED );
804
0
    bool bThousand, bRed;
805
0
    sal_uInt16 nDecimals, nLeading;
806
0
    pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
807
0
    lang::Locale aLocale( LanguageTag( pFormat->GetLanguage()).getLocale());
808
809
0
    uno::Sequence<beans::PropertyValue> aSeq( comphelper::InitPropertySequence({
810
0
            { PROPERTYNAME_FMTSTR, uno::Any(aFmtStr) },
811
0
            { PROPERTYNAME_LOCALE, uno::Any(aLocale) },
812
0
            { PROPERTYNAME_TYPE, uno::Any(sal_Int16( pFormat->GetType() )) },
813
0
            { PROPERTYNAME_COMMENT, uno::Any(aComment) },
814
0
            { PROPERTYNAME_STDFORM, uno::Any(bStandard) },
815
0
            { PROPERTYNAME_USERDEF, uno::Any(bUserDef) },
816
0
            { PROPERTYNAME_DECIMALS, uno::Any(sal_Int16( nDecimals )) },
817
0
            { PROPERTYNAME_LEADING, uno::Any(sal_Int16( nLeading )) },
818
0
            { PROPERTYNAME_NEGRED, uno::Any(bRed) },
819
0
            { PROPERTYNAME_THOUS, uno::Any(bThousand) },
820
0
            { PROPERTYNAME_CURRSYM, uno::Any(aSymbol) },
821
0
            { PROPERTYNAME_CURREXT, uno::Any(aExt) },
822
0
            { PROPERTYNAME_CURRABB, uno::Any(aAbb) }
823
0
        }));
824
825
0
    return aSeq;
826
0
}
827
828
void SAL_CALL SvNumberFormatObj::setPropertyValues( const uno::Sequence<beans::PropertyValue>& )
829
0
{
830
0
    throw beans::UnknownPropertyException(); // Everything is read-only
831
0
}
832
833
// XServiceInfo
834
835
OUString SAL_CALL SvNumberFormatObj::getImplementationName()
836
0
{
837
0
    return u"SvNumberFormatObj"_ustr;
838
0
}
839
840
sal_Bool SAL_CALL SvNumberFormatObj::supportsService( const OUString& ServiceName )
841
0
{
842
0
    return cppu::supportsService( this, ServiceName );
843
0
}
844
845
uno::Sequence<OUString> SAL_CALL SvNumberFormatObj::getSupportedServiceNames()
846
0
{
847
0
    return { u"com.sun.star.util.NumberFormatProperties"_ustr };
848
0
}
849
850
SvNumberFormatSettingsObj::SvNumberFormatSettingsObj( SvNumberFormatsSupplierObj& rParent, ::comphelper::SharedMutex _aMutex )
851
4.21k
    :m_xSupplier( &rParent )
852
4.21k
    ,m_aMutex(std::move( _aMutex ))
853
4.21k
{
854
4.21k
}
855
856
SvNumberFormatSettingsObj::~SvNumberFormatSettingsObj()
857
4.21k
{
858
4.21k
}
859
860
// XPropertySet
861
862
uno::Reference<beans::XPropertySetInfo> SAL_CALL SvNumberFormatSettingsObj::getPropertySetInfo()
863
4.21k
{
864
4.21k
    static uno::Reference<beans::XPropertySetInfo> aRef =
865
4.21k
        new SfxItemPropertySetInfo( lcl_GetNumberSettingsPropertyMap() );
866
4.21k
    return aRef;
867
4.21k
}
868
869
void SAL_CALL SvNumberFormatSettingsObj::setPropertyValue( const OUString& aPropertyName,
870
                                                           const uno::Any& aValue )
871
4.21k
{
872
4.21k
    ::osl::MutexGuard aGuard( m_aMutex );
873
874
4.21k
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
875
4.21k
    if (!pFormatter)
876
0
        throw uno::RuntimeException();
877
878
4.21k
    if (aPropertyName == PROPERTYNAME_NOZERO)
879
0
    {
880
        //  operator >>= shouldn't be used for bool (?)
881
0
        if ( auto b = o3tl::tryAccess<bool>(aValue) )
882
0
            pFormatter->SetNoZero( *b );
883
0
    }
884
4.21k
    else if (aPropertyName == PROPERTYNAME_NULLDATE)
885
4.21k
    {
886
4.21k
        util::Date aDate;
887
4.21k
        if ( aValue >>= aDate )
888
4.21k
            pFormatter->ChangeNullDate( aDate.Day, aDate.Month, aDate.Year );
889
4.21k
    }
890
0
    else if (aPropertyName == PROPERTYNAME_STDDEC)
891
0
    {
892
0
        sal_Int16 nInt16 = sal_Int16();
893
0
        if ( aValue >>= nInt16 )
894
0
            pFormatter->ChangeStandardPrec( nInt16 );
895
0
    }
896
0
    else if (aPropertyName == PROPERTYNAME_TWODIGIT)
897
0
    {
898
0
        sal_Int16 nInt16 = sal_Int16();
899
0
        if ( aValue >>= nInt16 )
900
0
            pFormatter->SetYear2000( nInt16 );
901
0
    }
902
0
    else
903
0
        throw beans::UnknownPropertyException(aPropertyName);
904
905
4.21k
}
906
907
uno::Any SAL_CALL SvNumberFormatSettingsObj::getPropertyValue( const OUString& aPropertyName )
908
0
{
909
0
    ::osl::MutexGuard aGuard( m_aMutex );
910
911
0
    uno::Any aRet;
912
0
    SvNumberFormatter* pFormatter = m_xSupplier->GetNumberFormatter();
913
0
    if (!pFormatter)
914
0
        throw uno::RuntimeException();
915
916
0
    if (aPropertyName == PROPERTYNAME_NOZERO)
917
0
    {
918
0
        aRet <<= pFormatter->GetNoZero();
919
0
    }
920
0
    else if (aPropertyName == PROPERTYNAME_NULLDATE)
921
0
    {
922
0
        const Date& rDate = pFormatter->GetNullDate();
923
0
        aRet <<= rDate.GetUNODate();
924
0
    }
925
0
    else if (aPropertyName == PROPERTYNAME_STDDEC)
926
0
        aRet <<= static_cast<sal_Int16>( pFormatter->GetStandardPrec() );
927
0
    else if (aPropertyName == PROPERTYNAME_TWODIGIT)
928
0
        aRet <<= static_cast<sal_Int16>( pFormatter->GetYear2000() );
929
0
    else
930
0
        throw beans::UnknownPropertyException(aPropertyName);
931
932
0
    return aRet;
933
0
}
934
935
void SAL_CALL SvNumberFormatSettingsObj::addPropertyChangeListener( const OUString&,
936
                                                                    const uno::Reference<beans::XPropertyChangeListener>&)
937
0
{
938
0
    OSL_FAIL("not implemented");
939
0
}
940
941
void SAL_CALL SvNumberFormatSettingsObj::removePropertyChangeListener( const OUString&,
942
                                                                       const uno::Reference<beans::XPropertyChangeListener>&)
943
0
{
944
0
    OSL_FAIL("not implemented");
945
0
}
946
947
void SAL_CALL SvNumberFormatSettingsObj::addVetoableChangeListener( const OUString&,
948
                                                                    const uno::Reference<beans::XVetoableChangeListener>&)
949
0
{
950
0
    OSL_FAIL("not implemented");
951
0
}
952
953
void SAL_CALL SvNumberFormatSettingsObj::removeVetoableChangeListener( const OUString&,
954
                                                                       const uno::Reference<beans::XVetoableChangeListener>&)
955
0
{
956
0
    OSL_FAIL("not implemented");
957
0
}
958
959
// XServiceInfo
960
961
OUString SAL_CALL SvNumberFormatSettingsObj::getImplementationName()
962
0
{
963
0
    return u"SvNumberFormatSettingsObj"_ustr;
964
0
}
965
966
sal_Bool SAL_CALL SvNumberFormatSettingsObj::supportsService( const OUString& ServiceName )
967
0
{
968
0
    return cppu::supportsService( this, ServiceName );
969
0
}
970
971
uno::Sequence<OUString> SAL_CALL SvNumberFormatSettingsObj::getSupportedServiceNames()
972
0
{
973
0
    return { u"com.sun.star.util.NumberFormatSettings"_ustr };
974
0
}
975
976
977
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
978
com_sun_star_uno_util_numbers_SvNumberFormatterServiceObject_get_implementation(css::uno::XComponentContext*,
979
                                                                                css::uno::Sequence<css::uno::Any> const &)
980
3
{
981
3
    return cppu::acquire(new SvNumberFormatterServiceObj());
982
3
}
983
984
985
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */