Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/editeng/source/misc/unolingu.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 <memory>
22
#include <editeng/unolingu.hxx>
23
#include <com/sun/star/frame/Desktop.hpp>
24
#include <com/sun/star/frame/XStorable.hpp>
25
#include <com/sun/star/lang/XEventListener.hpp>
26
#include <com/sun/star/linguistic2/XHyphenatedWord.hpp>
27
#include <com/sun/star/linguistic2/DictionaryList.hpp>
28
#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
29
#include <com/sun/star/linguistic2/LinguProperties.hpp>
30
#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
31
32
#include <comphelper/lok.hxx>
33
#include <comphelper/processfactory.hxx>
34
#include <cppuhelper/implbase.hxx>
35
#include <i18nlangtag/languagetag.hxx>
36
#include <unotools/lingucfg.hxx>
37
#include <utility>
38
#include <vcl/svapp.hxx>
39
#include <vcl/vclenum.hxx>
40
#include <vcl/weld/MessageDialog.hxx>
41
#include <linguistic/misc.hxx>
42
#include <editeng/eerdll.hxx>
43
#include <editeng/editrids.hrc>
44
#include <svtools/strings.hrc>
45
#include <unotools/resmgr.hxx>
46
#include <sal/log.hxx>
47
#include <osl/diagnose.h>
48
49
using namespace ::comphelper;
50
using namespace ::linguistic;
51
using namespace ::com::sun::star;
52
using namespace ::com::sun::star::uno;
53
using namespace ::com::sun::star::lang;
54
using namespace ::com::sun::star::frame;
55
using namespace ::com::sun::star::linguistic2;
56
57
static uno::Reference< XLinguServiceManager2 > GetLngSvcMgr_Impl()
58
0
{
59
0
    const uno::Reference< XComponentContext >& xContext = comphelper::getProcessComponentContext();
60
0
    uno::Reference< XLinguServiceManager2 > xRes = LinguServiceManager::create(xContext);
61
0
    return xRes;
62
0
}
63
64
namespace {
65
66
//! Dummy implementation in order to avoid loading of lingu DLL
67
//! when only the XSupportedLocales interface is used.
68
//! The dummy accesses the real implementation (and thus loading the DLL)
69
//! when "real" work needs to be done only.
70
class ThesDummy_Impl :
71
    public cppu::WeakImplHelper< XThesaurus >
72
{
73
    uno::Reference< XThesaurus >              xThes;      // the real one...
74
    std::unique_ptr<Sequence< lang::Locale >> pLocaleSeq;
75
76
    void GetCfgLocales();
77
78
    void GetThes_Impl();
79
80
public:
81
0
    ThesDummy_Impl() {}
82
83
    // XSupportedLocales
84
    virtual css::uno::Sequence< css::lang::Locale > SAL_CALL
85
        getLocales() override;
86
    virtual sal_Bool SAL_CALL
87
        hasLocale( const css::lang::Locale& rLocale ) override;
88
89
    // XThesaurus
90
    virtual css::uno::Sequence<
91
            css::uno::Reference< css::linguistic2::XMeaning > > SAL_CALL
92
        queryMeanings( const OUString& rTerm,
93
                const css::lang::Locale& rLocale,
94
                const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override;
95
};
96
97
}
98
99
void ThesDummy_Impl::GetCfgLocales()
100
0
{
101
0
    if (pLocaleSeq)
102
0
        return;
103
104
0
    SvtLinguConfig aCfg;
105
0
    Sequence < OUString > aNodeNames( aCfg.GetNodeNames( u"ServiceManager/ThesaurusList"_ustr ) );
106
0
    sal_Int32 nLen = aNodeNames.getLength();
107
0
    pLocaleSeq.reset( new Sequence< lang::Locale >( nLen ) );
108
0
    lang::Locale *pLocale = pLocaleSeq->getArray();
109
0
    for (sal_Int32 i = 0;  i < nLen;  ++i)
110
0
    {
111
0
        pLocale[i] = LanguageTag::convertToLocaleWithFallback(aNodeNames[i]);
112
0
    }
113
0
}
114
115
116
void ThesDummy_Impl::GetThes_Impl()
117
0
{
118
0
    if (!xThes.is())
119
0
    {
120
0
        uno::Reference< XLinguServiceManager2 > xLngSvcMgr( GetLngSvcMgr_Impl() );
121
0
        xThes = xLngSvcMgr->getThesaurus();
122
123
0
        if (xThes.is())
124
0
        {
125
            // no longer needed...
126
0
            pLocaleSeq.reset();
127
0
        }
128
0
    }
129
0
}
130
131
132
uno::Sequence< lang::Locale > SAL_CALL
133
        ThesDummy_Impl::getLocales()
134
0
{
135
0
    GetThes_Impl();
136
0
    if (xThes.is())
137
0
        return xThes->getLocales();
138
0
    else if (!pLocaleSeq)       // if not already loaded save startup time by avoiding loading them now
139
0
        GetCfgLocales();
140
0
    return *pLocaleSeq;
141
0
}
142
143
144
sal_Bool SAL_CALL
145
        ThesDummy_Impl::hasLocale( const lang::Locale& rLocale )
146
0
{
147
0
    GetThes_Impl();
148
0
    if (xThes.is())
149
0
        return xThes->hasLocale( rLocale );
150
0
    else if (!pLocaleSeq)       // if not already loaded save startup time by avoiding loading them now
151
0
        GetCfgLocales();
152
0
    return std::find(pLocaleSeq->begin(), pLocaleSeq->end(), rLocale) != pLocaleSeq->end();
153
0
}
154
155
156
uno::Sequence< uno::Reference< linguistic2::XMeaning > > SAL_CALL
157
        ThesDummy_Impl::queryMeanings(
158
                const OUString& rTerm,
159
                const lang::Locale& rLocale,
160
                const css::uno::Sequence< css::beans::PropertyValue >& rProperties )
161
0
{
162
0
    GetThes_Impl();
163
0
    uno::Sequence< uno::Reference< linguistic2::XMeaning > > aRes;
164
0
    OSL_ENSURE( xThes.is(), "Thesaurus missing" );
165
0
    if (xThes.is())
166
0
        aRes = xThes->queryMeanings( rTerm, rLocale, rProperties );
167
0
    return aRes;
168
0
}
169
170
namespace {
171
172
//! Dummy implementation in order to avoid loading of lingu DLL.
173
//! The dummy accesses the real implementation (and thus loading the DLL)
174
//! when it needs to be done only.
175
class SpellDummy_Impl :
176
    public cppu::WeakImplHelper< XSpellChecker1 >
177
{
178
    uno::Reference< XSpellChecker1 >     xSpell;      // the real one...
179
180
    void    GetSpell_Impl();
181
182
public:
183
184
    // XSupportedLanguages (for XSpellChecker1)
185
    virtual css::uno::Sequence< sal_Int16 > SAL_CALL
186
        getLanguages() override;
187
    virtual sal_Bool SAL_CALL
188
        hasLanguage( sal_Int16 nLanguage ) override;
189
190
    // XSpellChecker1 (same as XSpellChecker but sal_Int16 for language)
191
    virtual sal_Bool SAL_CALL
192
        isValid( const OUString& rWord, sal_Int16 nLanguage,
193
                const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override;
194
    virtual css::uno::Reference< css::linguistic2::XSpellAlternatives > SAL_CALL
195
        spell( const OUString& rWord, sal_Int16 nLanguage,
196
                const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override;
197
};
198
199
}
200
201
void SpellDummy_Impl::GetSpell_Impl()
202
0
{
203
0
    if (!xSpell.is())
204
0
    {
205
0
        uno::Reference< XLinguServiceManager2 > xLngSvcMgr( GetLngSvcMgr_Impl() );
206
0
        xSpell.set( xLngSvcMgr->getSpellChecker(), UNO_QUERY );
207
0
    }
208
0
}
209
210
211
uno::Sequence< sal_Int16 > SAL_CALL
212
    SpellDummy_Impl::getLanguages()
213
0
{
214
0
    GetSpell_Impl();
215
0
    if (xSpell.is())
216
0
        return xSpell->getLanguages();
217
0
    else
218
0
        return uno::Sequence< sal_Int16 >();
219
0
}
220
221
222
sal_Bool SAL_CALL
223
    SpellDummy_Impl::hasLanguage( sal_Int16 nLanguage )
224
0
{
225
0
    GetSpell_Impl();
226
0
    bool bRes = false;
227
0
    if (xSpell.is())
228
0
        bRes = xSpell->hasLanguage( nLanguage );
229
0
    return bRes;
230
0
}
231
232
233
sal_Bool SAL_CALL
234
    SpellDummy_Impl::isValid( const OUString& rWord, sal_Int16 nLanguage,
235
            const css::uno::Sequence< css::beans::PropertyValue >& rProperties )
236
0
{
237
0
    GetSpell_Impl();
238
0
    bool bRes = true;
239
0
    if (xSpell.is())
240
0
        bRes = xSpell->isValid( rWord, nLanguage, rProperties );
241
0
    return bRes;
242
0
}
243
244
245
uno::Reference< linguistic2::XSpellAlternatives > SAL_CALL
246
    SpellDummy_Impl::spell( const OUString& rWord, sal_Int16 nLanguage,
247
            const css::uno::Sequence< css::beans::PropertyValue >& rProperties )
248
0
{
249
0
    GetSpell_Impl();
250
0
    uno::Reference< linguistic2::XSpellAlternatives > xRes;
251
0
    if (xSpell.is())
252
0
        xRes = xSpell->spell( rWord, nLanguage, rProperties );
253
0
    return xRes;
254
0
}
255
256
namespace {
257
258
//! Dummy implementation in order to avoid loading of lingu DLL.
259
//! The dummy accesses the real implementation (and thus loading the DLL)
260
//! when it needs to be done only.
261
class HyphDummy_Impl :
262
    public cppu::WeakImplHelper< XHyphenator >
263
{
264
    uno::Reference< XHyphenator >     xHyph;      // the real one...
265
266
    void    GetHyph_Impl();
267
268
public:
269
270
    // XSupportedLocales
271
    virtual css::uno::Sequence<
272
            css::lang::Locale > SAL_CALL
273
        getLocales() override;
274
    virtual sal_Bool SAL_CALL
275
        hasLocale( const css::lang::Locale& rLocale ) override;
276
277
    // XHyphenator
278
    virtual css::uno::Reference<
279
            css::linguistic2::XHyphenatedWord > SAL_CALL
280
        hyphenate( const OUString& rWord,
281
                const css::lang::Locale& rLocale,
282
                sal_Int16 nMaxLeading,
283
                const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override;
284
    virtual css::uno::Reference<
285
            css::linguistic2::XHyphenatedWord > SAL_CALL
286
        queryAlternativeSpelling( const OUString& rWord,
287
                const css::lang::Locale& rLocale,
288
                sal_Int16 nIndex,
289
                const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override;
290
    virtual css::uno::Reference<
291
            css::linguistic2::XPossibleHyphens > SAL_CALL
292
        createPossibleHyphens(
293
                const OUString& rWord,
294
                const css::lang::Locale& rLocale,
295
                const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override;
296
};
297
298
}
299
300
void HyphDummy_Impl::GetHyph_Impl()
301
0
{
302
0
    if (!xHyph.is())
303
0
    {
304
0
        uno::Reference< XLinguServiceManager2 > xLngSvcMgr( GetLngSvcMgr_Impl() );
305
0
        xHyph = xLngSvcMgr->getHyphenator();
306
0
    }
307
0
}
308
309
310
uno::Sequence< lang::Locale > SAL_CALL
311
    HyphDummy_Impl::getLocales()
312
0
{
313
0
    GetHyph_Impl();
314
0
    if (xHyph.is())
315
0
        return xHyph->getLocales();
316
0
    else
317
0
        return uno::Sequence< lang::Locale >();
318
0
}
319
320
321
sal_Bool SAL_CALL
322
    HyphDummy_Impl::hasLocale( const lang::Locale& rLocale )
323
0
{
324
0
    GetHyph_Impl();
325
0
    bool bRes = false;
326
0
    if (xHyph.is())
327
0
        bRes = xHyph->hasLocale( rLocale );
328
0
    return bRes;
329
0
}
330
331
332
uno::Reference< linguistic2::XHyphenatedWord > SAL_CALL
333
    HyphDummy_Impl::hyphenate(
334
            const OUString& rWord,
335
            const lang::Locale& rLocale,
336
            sal_Int16 nMaxLeading,
337
            const css::uno::Sequence< css::beans::PropertyValue >& rProperties )
338
0
{
339
0
    GetHyph_Impl();
340
0
    uno::Reference< linguistic2::XHyphenatedWord > xRes;
341
0
    if (xHyph.is())
342
0
        xRes = xHyph->hyphenate( rWord, rLocale, nMaxLeading, rProperties );
343
0
    return xRes;
344
0
}
345
346
347
uno::Reference< linguistic2::XHyphenatedWord > SAL_CALL
348
    HyphDummy_Impl::queryAlternativeSpelling(
349
            const OUString& rWord,
350
            const lang::Locale& rLocale,
351
            sal_Int16 nIndex,
352
            const css::uno::Sequence< css::beans::PropertyValue >& rProperties )
353
0
{
354
0
    GetHyph_Impl();
355
0
    uno::Reference< linguistic2::XHyphenatedWord > xRes;
356
0
    if (xHyph.is())
357
0
        xRes = xHyph->queryAlternativeSpelling( rWord, rLocale, nIndex, rProperties );
358
0
    return xRes;
359
0
}
360
361
362
uno::Reference< linguistic2::XPossibleHyphens > SAL_CALL
363
    HyphDummy_Impl::createPossibleHyphens(
364
            const OUString& rWord,
365
            const lang::Locale& rLocale,
366
            const css::uno::Sequence< css::beans::PropertyValue >& rProperties )
367
0
{
368
0
    GetHyph_Impl();
369
0
    uno::Reference< linguistic2::XPossibleHyphens > xRes;
370
0
    if (xHyph.is())
371
0
        xRes = xHyph->createPossibleHyphens( rWord, rLocale, rProperties );
372
0
    return xRes;
373
0
}
374
375
class LinguMgrExitLstnr : public cppu::WeakImplHelper<XEventListener>
376
{
377
    uno::Reference< XDesktop2 >        xDesktop;
378
379
    static void AtExit();
380
381
public:
382
    LinguMgrExitLstnr();
383
    virtual ~LinguMgrExitLstnr() override;
384
385
    // lang::XEventListener
386
    virtual void    SAL_CALL disposing(const EventObject& rSource) override;
387
};
388
389
LinguMgrExitLstnr::LinguMgrExitLstnr()
390
14
{
391
    // add object to frame::Desktop EventListeners in order to properly call
392
    // the AtExit function at application exit.
393
394
14
    const uno::Reference< XComponentContext >&  xContext = getProcessComponentContext();
395
14
    xDesktop = Desktop::create( xContext );
396
14
    xDesktop->addEventListener( this );
397
14
}
398
399
LinguMgrExitLstnr::~LinguMgrExitLstnr()
400
0
{
401
0
    if (xDesktop.is())
402
0
    {
403
0
        xDesktop->removeEventListener( this );
404
0
        xDesktop = nullptr;    //! release reference to desktop
405
0
    }
406
0
    OSL_ENSURE(!xDesktop.is(), "reference to desktop should be released");
407
0
}
408
409
void LinguMgrExitLstnr::disposing(const EventObject& rSource)
410
0
{
411
0
    if (xDesktop.is()  &&  rSource.Source == xDesktop)
412
0
    {
413
0
        xDesktop->removeEventListener( this );
414
0
        xDesktop = nullptr;    //! release reference to desktop
415
416
0
        AtExit();
417
0
    }
418
0
}
419
420
void LinguMgrExitLstnr::AtExit()
421
0
{
422
0
    SolarMutexGuard g;
423
424
    // release references
425
0
    LinguMgr::xLngSvcMgr    = nullptr;
426
0
    LinguMgr::xSpell        = nullptr;
427
0
    LinguMgr::xHyph         = nullptr;
428
0
    LinguMgr::xThes         = nullptr;
429
0
    LinguMgr::xDicList      = nullptr;
430
0
    LinguMgr::xProp         = nullptr;
431
0
    LinguMgr::xIgnoreAll    = nullptr;
432
0
    LinguMgr::xChangeAll    = nullptr;
433
434
0
    LinguMgr::bExiting      = true;
435
436
0
    LinguMgr::pExitLstnr    = nullptr;
437
0
}
438
439
440
rtl::Reference<LinguMgrExitLstnr> LinguMgr::pExitLstnr;
441
bool                            LinguMgr::bExiting      = false;
442
uno::Reference< XLinguServiceManager2 >  LinguMgr::xLngSvcMgr;
443
uno::Reference< XSpellChecker1 >    LinguMgr::xSpell;
444
uno::Reference< XHyphenator >       LinguMgr::xHyph;
445
uno::Reference< XThesaurus >        LinguMgr::xThes;
446
uno::Reference< XSearchableDictionaryList >   LinguMgr::xDicList;
447
uno::Reference< XLinguProperties >  LinguMgr::xProp;
448
uno::Reference< XDictionary >       LinguMgr::xIgnoreAll;
449
uno::Reference< XDictionary >       LinguMgr::xChangeAll;
450
451
452
uno::Reference< XLinguServiceManager2 > LinguMgr::GetLngSvcMgr()
453
0
{
454
0
    if (bExiting)
455
0
        return nullptr;
456
457
0
    if (!pExitLstnr)
458
0
        pExitLstnr = new LinguMgrExitLstnr;
459
460
0
    if (!xLngSvcMgr.is())
461
0
        xLngSvcMgr = GetLngSvcMgr_Impl();
462
463
0
    return xLngSvcMgr;
464
0
}
465
466
467
uno::Reference< XSpellChecker1 > LinguMgr::GetSpellChecker()
468
40.0k
{
469
40.0k
    return xSpell.is() ? xSpell : GetSpell();
470
40.0k
}
471
472
uno::Reference< XHyphenator > LinguMgr::GetHyphenator()
473
177k
{
474
177k
    return xHyph.is() ? xHyph : GetHyph();
475
177k
}
476
477
uno::Reference< XThesaurus > LinguMgr::GetThesaurus()
478
0
{
479
0
    return xThes.is() ? xThes : GetThes();
480
0
}
481
482
uno::Reference< XSearchableDictionaryList > LinguMgr::GetDictionaryList()
483
0
{
484
0
    return xDicList.is() ? xDicList : GetDicList();
485
0
}
486
487
uno::Reference< linguistic2::XLinguProperties > LinguMgr::GetLinguPropertySet()
488
0
{
489
0
    return xProp.is() ? xProp : GetProp();
490
0
}
491
492
uno::Reference< XDictionary > LinguMgr::GetStandardDic()
493
0
{
494
    //! don't hold reference to this
495
    //! (it may be removed from dictionary list and needs to be
496
    //! created empty if accessed again)
497
0
    return GetStandard();
498
0
}
499
500
uno::Reference< XDictionary > LinguMgr::GetIgnoreAllList()
501
0
{
502
0
    return xIgnoreAll.is() ? xIgnoreAll : GetIgnoreAll();
503
0
}
504
505
uno::Reference< XDictionary > LinguMgr::GetChangeAllList()
506
0
{
507
0
    return xChangeAll.is() ? xChangeAll : GetChangeAll();
508
0
}
509
510
uno::Reference< XSpellChecker1 > LinguMgr::GetSpell()
511
5
{
512
5
    if (bExiting)
513
0
        return nullptr;
514
515
5
    if (!pExitLstnr)
516
5
        pExitLstnr = new LinguMgrExitLstnr;
517
518
    //! use dummy implementation in order to avoid loading of lingu DLL
519
5
    xSpell = new SpellDummy_Impl;
520
5
    return xSpell;
521
5
}
522
523
uno::Reference< XHyphenator > LinguMgr::GetHyph()
524
14
{
525
14
    if (bExiting)
526
0
        return nullptr;
527
528
14
    if (!pExitLstnr)
529
9
        pExitLstnr = new LinguMgrExitLstnr;
530
531
    //! use dummy implementation in order to avoid loading of lingu DLL
532
14
    xHyph = new HyphDummy_Impl;
533
14
    return xHyph;
534
14
}
535
536
uno::Reference< XThesaurus > LinguMgr::GetThes()
537
0
{
538
0
    if (bExiting)
539
0
        return nullptr;
540
541
0
    if (!pExitLstnr)
542
0
        pExitLstnr = new LinguMgrExitLstnr;
543
544
    //! use dummy implementation in order to avoid loading of lingu DLL
545
    //! when only the XSupportedLocales interface is used.
546
    //! The dummy accesses the real implementation (and thus loading the DLL)
547
    //! when "real" work needs to be done only.
548
0
    xThes = new ThesDummy_Impl;
549
0
    return xThes;
550
0
}
551
552
uno::Reference< XSearchableDictionaryList > LinguMgr::GetDicList()
553
0
{
554
0
    if (bExiting)
555
0
        return nullptr;
556
557
0
    if (!pExitLstnr)
558
0
        pExitLstnr = new LinguMgrExitLstnr;
559
560
0
    xDicList = linguistic2::DictionaryList::create( getProcessComponentContext() );
561
0
    return xDicList;
562
0
}
563
564
uno::Reference< linguistic2::XLinguProperties > LinguMgr::GetProp()
565
0
{
566
0
    if (bExiting)
567
0
        return nullptr;
568
569
0
    if (!pExitLstnr)
570
0
        pExitLstnr = new LinguMgrExitLstnr;
571
572
0
    xProp = linguistic2::LinguProperties::create( getProcessComponentContext()  );
573
0
    return xProp;
574
0
}
575
576
uno::Reference< XDictionary > LinguMgr::GetIgnoreAll()
577
0
{
578
0
    if (bExiting)
579
0
        return nullptr;
580
581
0
    if (!pExitLstnr)
582
0
        pExitLstnr = new LinguMgrExitLstnr;
583
584
0
    uno::Reference< XSearchableDictionaryList >  xTmpDicList( GetDictionaryList() );
585
0
    if (xTmpDicList.is())
586
0
    {
587
0
        const LanguageTag tag = comphelper::LibreOfficeKit::isActive()
588
0
                                    ? LanguageTag(u"en-US"_ustr)
589
0
                                    : SvtSysLocale().GetUILanguageTag();
590
0
        std::locale loc(Translate::Create("svt", tag));
591
0
        xIgnoreAll = xTmpDicList->getDictionaryByName(
592
0
                                    Translate::get(STR_DESCRIPTION_IGNOREALLLIST, loc) );
593
0
    }
594
0
    return xIgnoreAll;
595
0
}
596
597
uno::Reference< XDictionary > LinguMgr::GetChangeAll()
598
0
{
599
0
    if (bExiting)
600
0
        return nullptr;
601
602
0
    if (!pExitLstnr)
603
0
        pExitLstnr = new LinguMgrExitLstnr;
604
605
0
    uno::Reference< XSearchableDictionaryList > _xDicList = GetDictionaryList();
606
0
    if (_xDicList.is())
607
0
    {
608
0
        xChangeAll = _xDicList->createDictionary(
609
0
                            u"ChangeAllList"_ustr,
610
0
                            LanguageTag::convertToLocale( LANGUAGE_NONE ),
611
0
                            DictionaryType_NEGATIVE, OUString() );
612
0
    }
613
0
    return xChangeAll;
614
0
}
615
616
uno::Reference< XDictionary > LinguMgr::GetStandard()
617
0
{
618
    // Tries to return a dictionary which may hold positive entries is
619
    // persistent and not read-only.
620
621
0
    if (bExiting)
622
0
        return nullptr;
623
624
0
    uno::Reference< XSearchableDictionaryList >  xTmpDicList( GetDictionaryList() );
625
0
    if (!xTmpDicList.is())
626
0
        return nullptr;
627
628
0
    static constexpr OUString aDicName( u"standard.dic"_ustr );
629
0
    uno::Reference< XDictionary > xDic = xTmpDicList->getDictionaryByName( aDicName );
630
0
    if (!xDic.is())
631
0
    {
632
        // try to create standard dictionary
633
0
        uno::Reference< XDictionary >    xTmp;
634
0
        try
635
0
        {
636
0
            xTmp =  xTmpDicList->createDictionary( aDicName,
637
0
                        LanguageTag::convertToLocale( LANGUAGE_NONE ),
638
0
                        DictionaryType_POSITIVE,
639
0
                        linguistic::GetWritableDictionaryURL( aDicName ) );
640
0
        }
641
0
        catch(const css::uno::Exception &)
642
0
        {
643
0
        }
644
645
        // add new dictionary to list
646
0
        if (xTmp.is())
647
0
        {
648
0
            xTmpDicList->addDictionary( xTmp );
649
0
            xTmp->setActive( true );
650
0
        }
651
0
        xDic = std::move(xTmp);
652
0
    }
653
#if OSL_DEBUG_LEVEL > 1
654
    uno::Reference< XStorable >      xStor( xDic, UNO_QUERY );
655
    OSL_ENSURE( xDic.is() && xDic->getDictionaryType() == DictionaryType_POSITIVE,
656
            "wrong dictionary type");
657
    OSL_ENSURE( xDic.is() && LanguageTag( xDic->getLocale() ).getLanguageType() == LANGUAGE_NONE,
658
            "wrong dictionary language");
659
    OSL_ENSURE( !xStor.is() || (xStor->hasLocation() && !xStor->isReadonly()),
660
            "dictionary not editable" );
661
#endif
662
663
0
    return xDic;
664
0
}
665
666
SvxAlternativeSpelling SvxGetAltSpelling(
667
        const css::uno::Reference< css::linguistic2::XHyphenatedWord > & rHyphWord )
668
0
{
669
0
    SvxAlternativeSpelling aRes;
670
0
    if (rHyphWord.is() && rHyphWord->isAlternativeSpelling())
671
0
    {
672
0
        OUString aWord( rHyphWord->getWord() ),
673
0
                 aAltWord( rHyphWord->getHyphenatedWord() );
674
0
        sal_Int16   nHyphenationPos     = rHyphWord->getHyphenationPos(),
675
0
                nHyphenPos          = rHyphWord->getHyphenPos();
676
0
        sal_Int16   nLen    = static_cast<sal_Int16>(aWord.getLength());
677
0
        sal_Int16   nAltLen = static_cast<sal_Int16>(aAltWord.getLength());
678
0
        const sal_Unicode *pWord    = aWord.getStr(),
679
0
                          *pAltWord = aAltWord.getStr();
680
681
        // count number of chars from the left to the
682
        // hyphenation pos / hyphen pos that are equal
683
0
        sal_Int16 nL = 0;
684
0
        while (nL <= nHyphenationPos && nL <= nHyphenPos
685
0
               && pWord[ nL ] == pAltWord[ nL ])
686
0
            ++nL;
687
        // count number of chars from the right to the
688
        // hyphenation pos / hyphen pos that are equal
689
0
        sal_Int16 nR = 0;
690
0
        sal_Int32 nIdx    = nLen - 1;
691
0
        sal_Int32 nAltIdx = nAltLen - 1;
692
0
        while (nIdx > nHyphenationPos && nAltIdx > nHyphenPos
693
0
               && pWord[ nIdx-- ] == pAltWord[ nAltIdx-- ])
694
0
            ++nR;
695
696
0
        aRes.aReplacement       = aAltWord.copy( nL, nAltLen - nL - nR );
697
0
        aRes.nChangedPos        = nL;
698
0
        aRes.nChangedLength     = nLen - nL - nR;
699
0
        aRes.bIsAltSpelling     = true;
700
0
    }
701
0
    return aRes;
702
0
}
703
704
705
SvxDicListChgClamp::SvxDicListChgClamp( uno::Reference< XSearchableDictionaryList > _xDicList ) :
706
0
    xDicList    (std::move( _xDicList ))
707
0
{
708
0
    if (xDicList.is())
709
0
    {
710
0
        xDicList->beginCollectEvents();
711
0
    }
712
0
}
713
714
SvxDicListChgClamp::~SvxDicListChgClamp()
715
0
{
716
0
    if (xDicList.is())
717
0
    {
718
0
        xDicList->endCollectEvents();
719
0
    }
720
0
}
721
722
short SvxDicError(weld::Window *pParent, linguistic::DictionaryError nError)
723
0
{
724
0
    short nRes = 0;
725
0
    if (linguistic::DictionaryError::NONE != nError)
726
0
    {
727
0
        TranslateId pRid;
728
0
        switch (nError)
729
0
        {
730
0
            case linguistic::DictionaryError::FULL     : pRid = RID_SVXSTR_DIC_ERR_FULL;  break;
731
0
            case linguistic::DictionaryError::READONLY : pRid = RID_SVXSTR_DIC_ERR_READONLY;  break;
732
0
            default:
733
0
                pRid = RID_SVXSTR_DIC_ERR_UNKNOWN;
734
0
                SAL_WARN("editeng", "unexpected case");
735
0
        }
736
0
        std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
737
0
                                                      VclMessageType::Info, VclButtonsType::Ok,
738
0
                                                      EditResId(pRid)));
739
0
        nRes = xInfoBox->run();
740
741
0
    }
742
0
    return nRes;
743
0
}
744
745
746
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */