Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svl/source/config/ctloptions.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 <svl/ctloptions.hxx>
22
23
#include <svl/languageoptions.hxx>
24
#include <unotools/configitem.hxx>
25
#include <unotools/configmgr.hxx>
26
#include <unotools/syslocale.hxx>
27
#include <com/sun/star/uno/Any.h>
28
#include <com/sun/star/uno/Sequence.hxx>
29
#include <i18nlangtag/lang.h>
30
#include <i18nlangtag/languagetag.hxx>
31
#include <i18nlangtag/mslangid.hxx>
32
#include <osl/mutex.hxx>
33
#include "itemholder2.hxx"
34
#include <officecfg/System.hxx>
35
#include <officecfg/Office/Common.hxx>
36
37
using namespace ::com::sun::star;
38
using namespace ::com::sun::star::uno;
39
40
0
#define CFG_READONLY_DEFAULT false
41
42
class SvtCTLOptions_Impl : public utl::ConfigItem
43
{
44
private:
45
    bool                        m_bIsLoaded;
46
    bool                        m_bCTLFontEnabled;
47
    bool m_bCTLVerticalText;
48
    bool                        m_bCTLSequenceChecking;
49
    bool                        m_bCTLRestricted;
50
    bool                        m_bCTLTypeAndReplace;
51
    SvtCTLOptions::CursorMovement   m_eCTLCursorMovement;
52
    SvtCTLOptions::TextNumerals     m_eCTLTextNumerals;
53
54
    bool                        m_bROCTLFontEnabled;
55
    bool m_bROCTLVerticalText;
56
    bool                        m_bROCTLSequenceChecking;
57
    bool                        m_bROCTLRestricted;
58
    bool                        m_bROCTLTypeAndReplace;
59
    bool                        m_bROCTLCursorMovement;
60
    bool                        m_bROCTLTextNumerals;
61
62
    virtual void    ImplCommit() override;
63
64
public:
65
    SvtCTLOptions_Impl();
66
    virtual ~SvtCTLOptions_Impl() override;
67
68
    virtual void    Notify( const Sequence< OUString >& _aPropertyNames ) override;
69
    void            Load();
70
71
0
    bool            IsLoaded() const { return m_bIsLoaded; }
72
73
    void SetCTLVerticalText(bool bVertical);
74
75
    void            SetCTLSequenceChecking( bool _bEnabled );
76
77
    void            SetCTLSequenceCheckingRestricted( bool _bEnable );
78
79
    void            SetCTLSequenceCheckingTypeAndReplace( bool _bEnable );
80
81
    void            SetCTLCursorMovement( SvtCTLOptions::CursorMovement _eMovement );
82
83
    void            SetCTLTextNumerals( SvtCTLOptions::TextNumerals _eNumerals );
84
85
};
86
namespace
87
{
88
    Sequence<OUString> & PropertyNames()
89
0
    {
90
0
        static Sequence<OUString> SINGLETON;
91
0
        return SINGLETON;
92
0
    }
93
}
94
95
SvtCTLOptions_Impl::SvtCTLOptions_Impl() :
96
97
0
    utl::ConfigItem(u"Office.Common/I18N/CTL"_ustr),
98
99
0
    m_bIsLoaded             ( false ),
100
0
    m_bCTLFontEnabled       ( true ),
101
0
    m_bCTLVerticalText      ( true ),
102
0
    m_bCTLSequenceChecking  ( false ),
103
0
    m_bCTLRestricted        ( false ),
104
0
    m_bCTLTypeAndReplace    ( false ),
105
0
    m_eCTLCursorMovement    ( SvtCTLOptions::MOVEMENT_LOGICAL ),
106
0
    m_eCTLTextNumerals      ( SvtCTLOptions::NUMERALS_ARABIC ),
107
108
0
    m_bROCTLFontEnabled     ( CFG_READONLY_DEFAULT ),
109
0
    m_bROCTLVerticalText    ( CFG_READONLY_DEFAULT ),
110
0
    m_bROCTLSequenceChecking( CFG_READONLY_DEFAULT ),
111
0
    m_bROCTLRestricted      ( CFG_READONLY_DEFAULT ),
112
0
    m_bROCTLTypeAndReplace  ( CFG_READONLY_DEFAULT ),
113
0
    m_bROCTLCursorMovement  ( CFG_READONLY_DEFAULT ),
114
0
    m_bROCTLTextNumerals    ( CFG_READONLY_DEFAULT )
115
0
{
116
0
}
117
SvtCTLOptions_Impl::~SvtCTLOptions_Impl()
118
0
{
119
0
    assert(!IsModified()); // should have been committed
120
0
}
121
122
void SvtCTLOptions_Impl::Notify( const Sequence< OUString >& )
123
0
{
124
0
    Load();
125
0
    NotifyListeners(ConfigurationHints::CtlSettingsChanged);
126
0
}
127
128
void SvtCTLOptions_Impl::ImplCommit()
129
0
{
130
0
    Sequence< OUString > &rPropertyNames = PropertyNames();
131
0
    OUString* pOrgNames = rPropertyNames.getArray();
132
0
    sal_Int32 nOrgCount = rPropertyNames.getLength();
133
134
0
    Sequence< OUString > aNames( nOrgCount );
135
0
    Sequence< Any > aValues( nOrgCount );
136
137
0
    OUString* pNames = aNames.getArray();
138
0
    Any* pValues = aValues.getArray();
139
0
    sal_Int32 nRealCount = 0;
140
141
0
    for ( int nProp = 0; nProp < nOrgCount; nProp++ )
142
0
    {
143
0
        switch ( nProp )
144
0
        {
145
0
            case  0:
146
0
            {
147
0
                if (!m_bROCTLFontEnabled)
148
0
                {
149
0
                    pNames[nRealCount] = pOrgNames[nProp];
150
0
                    pValues[nRealCount] <<= m_bCTLFontEnabled;
151
0
                    ++nRealCount;
152
0
                }
153
0
            }
154
0
            break;
155
156
0
            case  1:
157
0
            {
158
0
                if (!m_bROCTLSequenceChecking)
159
0
                {
160
0
                    pNames[nRealCount] = pOrgNames[nProp];
161
0
                    pValues[nRealCount] <<= m_bCTLSequenceChecking;
162
0
                    ++nRealCount;
163
0
                }
164
0
            }
165
0
            break;
166
167
0
            case  2:
168
0
            {
169
0
                if (!m_bROCTLCursorMovement)
170
0
                {
171
0
                    pNames[nRealCount] = pOrgNames[nProp];
172
0
                    pValues[nRealCount] <<= static_cast<sal_Int32>(m_eCTLCursorMovement);
173
0
                    ++nRealCount;
174
0
                }
175
0
            }
176
0
            break;
177
178
0
            case  3:
179
0
            {
180
0
                if (!m_bROCTLTextNumerals)
181
0
                {
182
0
                    pNames[nRealCount] = pOrgNames[nProp];
183
0
                    pValues[nRealCount] <<= static_cast<sal_Int32>(m_eCTLTextNumerals);
184
0
                    ++nRealCount;
185
0
                }
186
0
            }
187
0
            break;
188
189
0
            case  4:
190
0
            {
191
0
                if (!m_bROCTLRestricted)
192
0
                {
193
0
                    pNames[nRealCount] = pOrgNames[nProp];
194
0
                    pValues[nRealCount] <<= m_bCTLRestricted;
195
0
                    ++nRealCount;
196
0
                }
197
0
            }
198
0
            break;
199
0
            case 5:
200
0
            {
201
0
                if(!m_bROCTLTypeAndReplace)
202
0
                {
203
0
                    pNames[nRealCount] = pOrgNames[nProp];
204
0
                    pValues[nRealCount] <<= m_bCTLTypeAndReplace;
205
0
                    ++nRealCount;
206
0
                }
207
0
            }
208
0
            break;
209
0
            case 6:
210
0
            {
211
0
                if (!m_bROCTLVerticalText)
212
0
                {
213
0
                    pNames[nRealCount] = pOrgNames[nProp];
214
0
                    pValues[nRealCount] <<= m_bCTLVerticalText;
215
0
                    ++nRealCount;
216
0
                }
217
0
            }
218
0
            break;
219
0
        }
220
0
    }
221
0
    aNames.realloc(nRealCount);
222
0
    aValues.realloc(nRealCount);
223
0
    PutProperties( aNames, aValues );
224
    //broadcast changes
225
0
    NotifyListeners(ConfigurationHints::CtlSettingsChanged);
226
0
}
227
228
void SvtCTLOptions_Impl::Load()
229
0
{
230
0
    Sequence< OUString >& rPropertyNames = PropertyNames();
231
0
    if ( !rPropertyNames.hasElements() )
232
0
    {
233
0
        rPropertyNames = {
234
0
            u"CTLFont"_ustr,
235
0
            u"CTLSequenceChecking"_ustr,
236
0
            u"CTLCursorMovement"_ustr,
237
0
            u"CTLTextNumerals"_ustr,
238
0
            u"CTLSequenceCheckingRestricted"_ustr,
239
0
            u"CTLSequenceCheckingTypeAndReplace"_ustr,
240
0
            u"CTLVerticalText"_ustr};
241
0
        EnableNotification( rPropertyNames );
242
0
    }
243
0
    Sequence< Any > aValues = GetProperties( rPropertyNames );
244
0
    Sequence< sal_Bool > aROStates = GetReadOnlyStates( rPropertyNames );
245
0
    const Any* pValues = aValues.getConstArray();
246
0
    const sal_Bool* pROStates = aROStates.getConstArray();
247
0
    assert(aValues.getLength() == rPropertyNames.getLength() && "GetProperties failed");
248
0
    assert(aROStates.getLength() == rPropertyNames.getLength() && "GetReadOnlyStates failed");
249
0
    if ( aValues.getLength() == rPropertyNames.getLength() && aROStates.getLength() == rPropertyNames.getLength() )
250
0
    {
251
0
        bool bValue = false;
252
0
        sal_Int32 nValue = 0;
253
254
0
        for ( int nProp = 0; nProp < rPropertyNames.getLength(); nProp++ )
255
0
        {
256
0
            if ( pValues[nProp].hasValue() )
257
0
            {
258
0
                if ( pValues[nProp] >>= bValue )
259
0
                {
260
0
                    switch ( nProp )
261
0
                    {
262
0
                        case 0: { m_bCTLFontEnabled = bValue; m_bROCTLFontEnabled = pROStates[nProp]; } break;
263
0
                        case 1: { m_bCTLSequenceChecking = bValue; m_bROCTLSequenceChecking = pROStates[nProp]; } break;
264
0
                        case 4: { m_bCTLRestricted = bValue; m_bROCTLRestricted = pROStates[nProp]; } break;
265
0
                        case 5: { m_bCTLTypeAndReplace = bValue; m_bROCTLTypeAndReplace = pROStates[nProp]; } break;
266
0
                        case 6: { m_bCTLVerticalText = bValue; m_bROCTLVerticalText = pROStates[nProp]; } break;
267
0
                    }
268
0
                }
269
0
                else if ( pValues[nProp] >>= nValue )
270
0
                {
271
0
                    switch ( nProp )
272
0
                    {
273
0
                        case 2: { m_eCTLCursorMovement = static_cast<SvtCTLOptions::CursorMovement>(nValue); m_bROCTLCursorMovement = pROStates[nProp]; } break;
274
0
                        case 3: { m_eCTLTextNumerals = static_cast<SvtCTLOptions::TextNumerals>(nValue); m_bROCTLTextNumerals = pROStates[nProp]; } break;
275
0
                    }
276
0
                }
277
0
            }
278
0
        }
279
0
    }
280
281
0
    if (!m_bCTLFontEnabled)
282
0
    {
283
0
        SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage(LANGUAGE_SYSTEM);
284
        //system locale is CTL
285
0
        bool bAutoEnableCTL = bool(nScriptType & SvtScriptType::COMPLEX);
286
287
0
        if (!bAutoEnableCTL)
288
0
        {
289
            //windows secondary system locale is CTL
290
0
            OUString sWin16SystemLocale = officecfg::System::L10N::SystemLocale::get();
291
0
            LanguageType eSystemLanguage = LANGUAGE_NONE;
292
0
            if (!sWin16SystemLocale.isEmpty())
293
0
            {
294
0
                eSystemLanguage
295
0
                    = LanguageTag::convertToLanguageTypeWithFallback(sWin16SystemLocale);
296
0
            }
297
298
0
            if (eSystemLanguage != LANGUAGE_SYSTEM)
299
0
            {
300
0
                SvtScriptType nWinScript
301
0
                    = SvtLanguageOptions::GetScriptTypeOfLanguage(eSystemLanguage);
302
0
                bAutoEnableCTL = bool(nWinScript & SvtScriptType::COMPLEX);
303
0
            }
304
305
            //CTL keyboard is installed
306
0
            if (!bAutoEnableCTL)
307
0
            {
308
0
                bAutoEnableCTL = SvtSystemLanguageOptions::isCTLKeyboardLayoutInstalled();
309
0
            }
310
0
        }
311
312
0
        if (bAutoEnableCTL)
313
0
        {
314
0
            m_bCTLFontEnabled = true;
315
0
            LanguageType nLanguage = SvtSysLocale().GetLanguageTag().getLanguageType();
316
            //enable sequence checking for the appropriate languages
317
0
            m_bCTLSequenceChecking = m_bCTLRestricted = m_bCTLTypeAndReplace
318
0
                = (MsLangId::needsSequenceChecking(nLanguage)
319
0
                   || MsLangId::needsSequenceChecking(LANGUAGE_SYSTEM));
320
0
            Commit();
321
0
        }
322
0
    }
323
324
0
    m_bIsLoaded = true;
325
0
}
326
void SvtCTLOptions_Impl::SetCTLVerticalText(bool bVertical)
327
0
{
328
0
    if (!m_bROCTLVerticalText && m_bCTLVerticalText != bVertical)
329
0
    {
330
0
        m_bCTLVerticalText = bVertical;
331
0
        SetModified();
332
0
        NotifyListeners(ConfigurationHints::NONE);
333
0
    }
334
0
}
335
void SvtCTLOptions_Impl::SetCTLSequenceChecking( bool _bEnabled )
336
0
{
337
0
    if(!m_bROCTLSequenceChecking && m_bCTLSequenceChecking != _bEnabled)
338
0
    {
339
0
        SetModified();
340
0
        m_bCTLSequenceChecking = _bEnabled;
341
0
        NotifyListeners(ConfigurationHints::NONE);
342
0
    }
343
0
}
344
void SvtCTLOptions_Impl::SetCTLSequenceCheckingRestricted( bool _bEnabled )
345
0
{
346
0
    if(!m_bROCTLRestricted && m_bCTLRestricted != _bEnabled)
347
0
    {
348
0
        SetModified();
349
0
        m_bCTLRestricted = _bEnabled;
350
0
        NotifyListeners(ConfigurationHints::NONE);
351
0
    }
352
0
}
353
void  SvtCTLOptions_Impl::SetCTLSequenceCheckingTypeAndReplace( bool _bEnabled )
354
0
{
355
0
    if(!m_bROCTLTypeAndReplace && m_bCTLTypeAndReplace != _bEnabled)
356
0
    {
357
0
        SetModified();
358
0
        m_bCTLTypeAndReplace = _bEnabled;
359
0
        NotifyListeners(ConfigurationHints::NONE);
360
0
    }
361
0
}
362
void SvtCTLOptions_Impl::SetCTLCursorMovement( SvtCTLOptions::CursorMovement _eMovement )
363
0
{
364
0
    if (!m_bROCTLCursorMovement && m_eCTLCursorMovement != _eMovement )
365
0
    {
366
0
        SetModified();
367
0
        m_eCTLCursorMovement = _eMovement;
368
0
        NotifyListeners(ConfigurationHints::NONE);
369
0
    }
370
0
}
371
void SvtCTLOptions_Impl::SetCTLTextNumerals( SvtCTLOptions::TextNumerals _eNumerals )
372
0
{
373
0
    if (!m_bROCTLTextNumerals && m_eCTLTextNumerals != _eNumerals )
374
0
    {
375
0
        SetModified();
376
0
        m_eCTLTextNumerals = _eNumerals;
377
0
        NotifyListeners(ConfigurationHints::NONE);
378
0
    }
379
0
}
380
381
namespace {
382
383
    // global
384
    std::weak_ptr<SvtCTLOptions_Impl> g_pCTLOptions;
385
386
    osl::Mutex& CTLMutex()
387
0
    {
388
0
        static osl::Mutex aMutex;
389
0
        return aMutex;
390
0
    }
391
}
392
393
SvtCTLOptions::SvtCTLOptions( bool bDontLoad )
394
0
{
395
    // Global access, must be guarded (multithreading)
396
0
    ::osl::MutexGuard aGuard( CTLMutex() );
397
398
0
    m_pImpl = g_pCTLOptions.lock();
399
0
    if ( !m_pImpl )
400
0
    {
401
0
        m_pImpl = std::make_shared<SvtCTLOptions_Impl>();
402
0
        g_pCTLOptions = m_pImpl;
403
0
        ItemHolder2::holdConfigItem(EItem::CTLOptions);
404
0
    }
405
406
0
    if( !bDontLoad && !m_pImpl->IsLoaded() )
407
0
        m_pImpl->Load();
408
409
0
    m_pImpl->AddListener(this);
410
0
}
411
412
413
SvtCTLOptions::~SvtCTLOptions()
414
0
{
415
    // Global access, must be guarded (multithreading)
416
0
    ::osl::MutexGuard aGuard( CTLMutex() );
417
418
0
    m_pImpl->RemoveListener(this);
419
0
    m_pImpl.reset();
420
0
}
421
422
bool SvtCTLOptions::IsCTLFontEnabled()
423
0
{
424
    // tdf#168719: The CTL font can no longer be disabled
425
0
    return true;
426
0
}
427
428
void SvtCTLOptions::SetCTLVerticalText(bool bVertical)
429
0
{
430
0
    assert(m_pImpl->IsLoaded());
431
0
    m_pImpl->SetCTLVerticalText(bVertical);
432
0
}
433
434
bool SvtCTLOptions::IsCTLVerticalText()
435
0
{
436
    // tdf#168719: The CTL font can no longer be disabled
437
0
    return true;
438
0
}
439
440
void SvtCTLOptions::SetCTLSequenceChecking( bool _bEnabled )
441
0
{
442
0
    assert(m_pImpl->IsLoaded());
443
0
    m_pImpl->SetCTLSequenceChecking(_bEnabled);
444
0
}
445
446
bool SvtCTLOptions::IsCTLSequenceChecking()
447
0
{
448
0
    return officecfg::Office::Common::I18N::CTL::CTLSequenceChecking::get();
449
0
}
450
451
void SvtCTLOptions::SetCTLSequenceCheckingRestricted( bool _bEnable )
452
0
{
453
0
    assert(m_pImpl->IsLoaded());
454
0
    m_pImpl->SetCTLSequenceCheckingRestricted(_bEnable);
455
0
}
456
457
bool SvtCTLOptions::IsCTLSequenceCheckingRestricted()
458
0
{
459
0
    return officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingRestricted::get();
460
0
}
461
462
void SvtCTLOptions::SetCTLSequenceCheckingTypeAndReplace( bool _bEnable )
463
0
{
464
0
    assert(m_pImpl->IsLoaded());
465
0
    m_pImpl->SetCTLSequenceCheckingTypeAndReplace(_bEnable);
466
0
}
467
468
bool SvtCTLOptions::IsCTLSequenceCheckingTypeAndReplace()
469
0
{
470
0
    return officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingTypeAndReplace::get();
471
0
}
472
473
void SvtCTLOptions::SetCTLCursorMovement( SvtCTLOptions::CursorMovement _eMovement )
474
0
{
475
0
    assert(m_pImpl->IsLoaded());
476
0
    m_pImpl->SetCTLCursorMovement( _eMovement );
477
0
}
478
479
SvtCTLOptions::CursorMovement SvtCTLOptions::GetCTLCursorMovement()
480
0
{
481
0
    return static_cast<SvtCTLOptions::CursorMovement>(officecfg::Office::Common::I18N::CTL::CTLCursorMovement::get());
482
0
}
483
484
void SvtCTLOptions::SetCTLTextNumerals( SvtCTLOptions::TextNumerals _eNumerals )
485
0
{
486
0
    assert(m_pImpl->IsLoaded());
487
0
    m_pImpl->SetCTLTextNumerals( _eNumerals );
488
0
}
489
490
SvtCTLOptions::TextNumerals SvtCTLOptions::GetCTLTextNumerals()
491
108k
{
492
108k
    if (comphelper::IsFuzzing())
493
108k
        return SvtCTLOptions::NUMERALS_ARABIC;
494
0
    return static_cast<SvtCTLOptions::TextNumerals>(officecfg::Office::Common::I18N::CTL::CTLTextNumerals::get());
495
108k
}
496
497
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */