Coverage Report

Created: 2026-05-16 09:25

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