Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/linguistic/source/dlistimp.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 <cppuhelper/factory.hxx>
22
#include <osl/file.hxx>
23
#include <tools/debug.hxx>
24
#include <tools/stream.hxx>
25
#include <tools/urlobj.hxx>
26
#include <unotools/useroptions.hxx>
27
#include <cppuhelper/supportsservice.hxx>
28
#include <cppuhelper/weak.hxx>
29
#include <unotools/localfilehelper.hxx>
30
#include <comphelper/lok.hxx>
31
#include <comphelper/processfactory.hxx>
32
#include <comphelper/sequence.hxx>
33
#include <unotools/ucbstreamhelper.hxx>
34
#include <com/sun/star/frame/XStorable.hpp>
35
#include <com/sun/star/uno/Reference.h>
36
#include <com/sun/star/linguistic2/DictionaryEventFlags.hpp>
37
#include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
38
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
39
#include <svtools/strings.hrc>
40
#include <unotools/resmgr.hxx>
41
#include <unotools/charclass.hxx>
42
#include <sal/log.hxx>
43
#include <utility>
44
45
#include "dlistimp.hxx"
46
#include "dicimp.hxx"
47
#include "lngopt.hxx"
48
49
using namespace osl;
50
using namespace com::sun::star;
51
using namespace com::sun::star::lang;
52
using namespace com::sun::star::uno;
53
using namespace com::sun::star::linguistic2;
54
using namespace linguistic;
55
56
57
static bool IsVers2OrNewer( const OUString& rFileURL, LanguageType& nLng, bool& bNeg, OUString& aDicName );
58
59
static void AddInternal( const uno::Reference< XDictionary > &rDic,
60
                         const OUString& rNew );
61
static void AddUserData( const uno::Reference< XDictionary > &rDic );
62
63
64
class DicEvtListenerHelper :
65
    public cppu::WeakImplHelper
66
    <
67
        XDictionaryEventListener
68
    >
69
{
70
    comphelper::OInterfaceContainerHelper3<XDictionaryListEventListener> aDicListEvtListeners;
71
    uno::Reference< XDictionaryList >       xMyDicList;
72
73
    sal_Int16                               nCondensedEvt;
74
    sal_Int16                               nNumCollectEvtListeners;
75
76
public:
77
    explicit DicEvtListenerHelper( uno::Reference< XDictionaryList > xDicList );
78
    virtual ~DicEvtListenerHelper() override;
79
80
    // XEventListener
81
    virtual void SAL_CALL
82
        disposing( const EventObject& rSource ) override;
83
84
    // XDictionaryEventListener
85
    virtual void SAL_CALL
86
        processDictionaryEvent( const DictionaryEvent& rDicEvent ) override;
87
88
    // non-UNO functions
89
    void    DisposeAndClear( const EventObject &rEvtObj );
90
91
    bool    AddDicListEvtListener(
92
                const uno::Reference< XDictionaryListEventListener >& rxListener );
93
    bool    RemoveDicListEvtListener(
94
                const uno::Reference< XDictionaryListEventListener >& rxListener );
95
0
    sal_Int16   BeginCollectEvents() { return ++nNumCollectEvtListeners;}
96
    sal_Int16   EndCollectEvents();
97
    sal_Int16   FlushEvents();
98
0
    void    ClearEvents()   { nCondensedEvt = 0; }
99
};
100
101
102
DicEvtListenerHelper::DicEvtListenerHelper(
103
        uno::Reference< XDictionaryList > xDicList ) :
104
0
    aDicListEvtListeners    ( GetLinguMutex() ),
105
0
    xMyDicList              (std::move( xDicList )),
106
0
    nCondensedEvt(0), nNumCollectEvtListeners(0)
107
0
{
108
0
}
109
110
111
DicEvtListenerHelper::~DicEvtListenerHelper()
112
0
{
113
0
    DBG_ASSERT(aDicListEvtListeners.getLength() == 0,
114
0
        "lng : event listeners are still existing");
115
0
}
116
117
118
void DicEvtListenerHelper::DisposeAndClear( const EventObject &rEvtObj )
119
0
{
120
0
    aDicListEvtListeners.disposeAndClear( rEvtObj );
121
0
}
122
123
124
void SAL_CALL DicEvtListenerHelper::disposing( const EventObject& rSource )
125
0
{
126
0
    osl::MutexGuard aGuard( GetLinguMutex() );
127
128
0
    uno::Reference< XDictionaryListEventListener > xSrc( rSource.Source, UNO_QUERY );
129
130
    // remove event object from EventListener list
131
0
    if (xSrc.is())
132
0
        aDicListEvtListeners.removeInterface( xSrc );
133
134
    // if object is a dictionary then remove it from the dictionary list
135
    // Note: this will probably happen only if someone makes a XDictionary
136
    // implementation of his own that is also a XComponent.
137
0
    uno::Reference< XDictionary > xDic( rSource.Source, UNO_QUERY );
138
0
    if (xDic.is())
139
0
    {
140
0
        xMyDicList->removeDictionary( xDic );
141
0
    }
142
0
}
143
144
145
void SAL_CALL DicEvtListenerHelper::processDictionaryEvent(
146
            const DictionaryEvent& rDicEvent )
147
0
{
148
0
    osl::MutexGuard aGuard( GetLinguMutex() );
149
150
0
    uno::Reference< XDictionary > xDic( rDicEvent.Source, UNO_QUERY );
151
0
    DBG_ASSERT(xDic.is(), "lng : missing event source");
152
153
    // assert that there is a corresponding dictionary entry if one was
154
    // added or deleted
155
0
    DBG_ASSERT( !(rDicEvent.nEvent &
156
0
                    (DictionaryEventFlags::ADD_ENTRY | DictionaryEventFlags::DEL_ENTRY))
157
0
                || rDicEvent.xDictionaryEntry.is(),
158
0
                "lng : missing dictionary entry" );
159
160
    // evaluate DictionaryEvents and update data for next DictionaryListEvent
161
0
    DictionaryType eDicType = xDic->getDictionaryType();
162
0
    DBG_ASSERT(eDicType != DictionaryType_MIXED,
163
0
        "lng : unexpected dictionary type");
164
0
    if ((rDicEvent.nEvent & DictionaryEventFlags::ADD_ENTRY) && xDic->isActive())
165
0
        nCondensedEvt |= rDicEvent.xDictionaryEntry->isNegative() ?
166
0
            DictionaryListEventFlags::ADD_NEG_ENTRY :
167
0
            DictionaryListEventFlags::ADD_POS_ENTRY;
168
0
    if ((rDicEvent.nEvent & DictionaryEventFlags::DEL_ENTRY) && xDic->isActive())
169
0
        nCondensedEvt |= rDicEvent.xDictionaryEntry->isNegative() ?
170
0
            DictionaryListEventFlags::DEL_NEG_ENTRY :
171
0
            DictionaryListEventFlags::DEL_POS_ENTRY;
172
0
    if ((rDicEvent.nEvent & DictionaryEventFlags::ENTRIES_CLEARED) && xDic->isActive())
173
0
        nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
174
0
            DictionaryListEventFlags::DEL_NEG_ENTRY :
175
0
            DictionaryListEventFlags::DEL_POS_ENTRY;
176
0
    if ((rDicEvent.nEvent & DictionaryEventFlags::CHG_LANGUAGE) && xDic->isActive())
177
0
        nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
178
0
            DictionaryListEventFlags::DEACTIVATE_NEG_DIC
179
0
                | DictionaryListEventFlags::ACTIVATE_NEG_DIC :
180
0
            DictionaryListEventFlags::DEACTIVATE_POS_DIC
181
0
                | DictionaryListEventFlags::ACTIVATE_POS_DIC;
182
0
    if (rDicEvent.nEvent & DictionaryEventFlags::ACTIVATE_DIC)
183
0
        nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
184
0
            DictionaryListEventFlags::ACTIVATE_NEG_DIC :
185
0
            DictionaryListEventFlags::ACTIVATE_POS_DIC;
186
0
    if (rDicEvent.nEvent & DictionaryEventFlags::DEACTIVATE_DIC)
187
0
        nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
188
0
            DictionaryListEventFlags::DEACTIVATE_NEG_DIC :
189
0
            DictionaryListEventFlags::DEACTIVATE_POS_DIC;
190
191
0
    if (nNumCollectEvtListeners == 0 && nCondensedEvt != 0)
192
0
        FlushEvents();
193
0
}
194
195
196
bool DicEvtListenerHelper::AddDicListEvtListener(
197
            const uno::Reference< XDictionaryListEventListener >& xListener )
198
0
{
199
0
    DBG_ASSERT( xListener.is(), "empty reference" );
200
0
    sal_Int32   nCount = aDicListEvtListeners.getLength();
201
0
    return aDicListEvtListeners.addInterface( xListener ) != nCount;
202
0
}
203
204
205
bool DicEvtListenerHelper::RemoveDicListEvtListener(
206
            const uno::Reference< XDictionaryListEventListener >& xListener )
207
0
{
208
0
    DBG_ASSERT( xListener.is(), "empty reference" );
209
0
    sal_Int32   nCount = aDicListEvtListeners.getLength();
210
0
    return aDicListEvtListeners.removeInterface( xListener ) != nCount;
211
0
}
212
213
214
sal_Int16 DicEvtListenerHelper::EndCollectEvents()
215
0
{
216
0
    DBG_ASSERT(nNumCollectEvtListeners > 0, "lng: mismatched function call");
217
0
    if (nNumCollectEvtListeners > 0)
218
0
    {
219
0
        FlushEvents();
220
0
        nNumCollectEvtListeners--;
221
0
    }
222
223
0
    return nNumCollectEvtListeners;
224
0
}
225
226
227
sal_Int16 DicEvtListenerHelper::FlushEvents()
228
0
{
229
0
    if (0 != nCondensedEvt)
230
0
    {
231
        // build DictionaryListEvent to pass on to listeners
232
0
        uno::Sequence< DictionaryEvent > aDicEvents;
233
0
        DictionaryListEvent aEvent( xMyDicList, nCondensedEvt, aDicEvents );
234
235
        // pass on event
236
0
        aDicListEvtListeners.notifyEach( &XDictionaryListEventListener::processDictionaryListEvent, aEvent );
237
238
        // clear "list" of events
239
0
        nCondensedEvt = 0;
240
0
    }
241
242
0
    return nNumCollectEvtListeners;
243
0
}
244
245
246
void DicList::MyAppExitListener::AtExit()
247
0
{
248
0
    rMyDicList.SaveDics();
249
0
}
250
251
252
DicList::DicList() :
253
0
    aEvtListeners   ( GetLinguMutex() )
254
0
{
255
0
    mxDicEvtLstnrHelper  = new DicEvtListenerHelper( this );
256
0
    bDisposing = false;
257
0
    bInCreation = false;
258
259
0
    mxExitListener = new MyAppExitListener( *this );
260
0
    mxExitListener->Activate();
261
0
}
262
263
DicList::~DicList()
264
0
{
265
0
    mxExitListener->Deactivate();
266
0
}
267
268
269
void DicList::SearchForDictionaries(
270
    DictionaryVec_t&rDicList,
271
    const OUString &rDicDirURL,
272
    bool bIsWriteablePath )
273
0
{
274
0
    osl::MutexGuard aGuard( GetLinguMutex() );
275
276
0
    const uno::Sequence< OUString > aDirCnt( utl::LocalFileHelper::
277
0
                                        GetFolderContents( rDicDirURL, false ) );
278
0
    SvtSysLocale aSysLocale;
279
280
0
    for (const OUString& aURL : aDirCnt)
281
0
    {
282
0
        LanguageType nLang = LANGUAGE_NONE;
283
0
        bool         bNeg  = false;
284
0
        OUString     aDicTitle = u""_ustr;
285
286
0
        if(!::IsVers2OrNewer( aURL, nLang, bNeg, aDicTitle ))
287
0
        {
288
            // When not
289
0
            sal_Int32 nPos  = aURL.indexOf('.');
290
0
            OUString aExt( aURL.copy(nPos + 1).toAsciiLowerCase() );
291
292
0
            if ("dcn" == aExt)       // negative
293
0
                bNeg = true;
294
0
            else if ("dcp" == aExt)  // positive
295
0
                bNeg = false;
296
0
            else
297
0
                continue;          // other files
298
0
        }
299
300
        // Record in the list of Dictionaries
301
        // When it already exists don't record
302
0
        OUString aTmp1 = aSysLocale.GetCharClass().lowercase( aURL);
303
0
        sal_Int32 nPos = aTmp1.lastIndexOf( '/' );
304
0
        if (-1 != nPos)
305
0
            aTmp1 = aTmp1.copy( nPos + 1 );
306
0
        OUString aTmp2;
307
0
        size_t j;
308
0
        size_t nCount = rDicList.size();
309
0
        for(j = 0;  j < nCount;  j++)
310
0
        {
311
0
            aTmp2 = rDicList[j]->getName();
312
0
            aTmp2 = aSysLocale.GetCharClass().lowercase( aTmp2);
313
0
            if(aTmp1 == aTmp2)
314
0
                break;
315
0
        }
316
0
        if(j >= nCount)     // dictionary not yet in DicList
317
0
        {
318
            // get decoded dictionary file name
319
0
            INetURLObject aURLObj( aURL );
320
0
            OUString aDicName = aURLObj.getName( INetURLObject::LAST_SEGMENT,
321
0
                        true, INetURLObject::DecodeMechanism::WithCharset );
322
323
0
            DictionaryType eType = bNeg ? DictionaryType_NEGATIVE : DictionaryType_POSITIVE;
324
0
            uno::Reference< XDictionary > xDic =
325
0
                        new DictionaryNeo( aDicTitle.isEmpty() ? aDicName : aDicTitle, nLang, eType, aURL, bIsWriteablePath );
326
327
            // when using libreofficekit we don't have "options" dialog to make user-dictionaries active
328
            // so when we add user-dictionary, we make them active as well
329
0
            if (comphelper::LibreOfficeKit::isActive())
330
0
                xDic->setActive(true);
331
332
0
            addDictionary( xDic );
333
0
            nCount++;
334
0
        }
335
0
    }
336
0
}
337
338
339
sal_Int32 DicList::GetDicPos(const uno::Reference< XDictionary > &xDic)
340
0
{
341
0
    osl::MutexGuard aGuard( GetLinguMutex() );
342
343
0
    DictionaryVec_t& rDicList = GetOrCreateDicList();
344
0
    size_t n = rDicList.size();
345
0
    for (size_t i = 0;  i < n;  i++)
346
0
    {
347
0
        if ( rDicList[i] == xDic )
348
0
            return i;
349
0
    }
350
0
    return -1;
351
0
}
352
353
sal_Int16 SAL_CALL DicList::getCount()
354
0
{
355
0
    osl::MutexGuard aGuard( GetLinguMutex() );
356
0
    return static_cast< sal_Int16 >(GetOrCreateDicList().size());
357
0
}
358
359
uno::Sequence< uno::Reference< XDictionary > > SAL_CALL
360
        DicList::getDictionaries()
361
0
{
362
0
    osl::MutexGuard aGuard( GetLinguMutex() );
363
364
0
    DictionaryVec_t& rDicList = GetOrCreateDicList();
365
366
0
    return comphelper::containerToSequence(rDicList);
367
0
}
368
369
uno::Reference< XDictionary > SAL_CALL
370
        DicList::getDictionaryByName( const OUString& aDictionaryName )
371
0
{
372
0
    osl::MutexGuard aGuard( GetLinguMutex() );
373
374
0
    uno::Reference< XDictionary > xDic;
375
0
    DictionaryVec_t& rDicList = GetOrCreateDicList();
376
0
    size_t nCount = rDicList.size();
377
0
    for (size_t i = 0;  i < nCount;  i++)
378
0
    {
379
0
        const uno::Reference< XDictionary > &rDic = rDicList[i];
380
0
        if (rDic.is()  &&  rDic->getName() == aDictionaryName)
381
0
        {
382
0
            xDic = rDic;
383
0
            break;
384
0
        }
385
0
    }
386
387
0
    return xDic;
388
0
}
389
390
sal_Bool SAL_CALL DicList::addDictionary(
391
            const uno::Reference< XDictionary >& xDictionary )
392
0
{
393
0
    osl::MutexGuard aGuard( GetLinguMutex() );
394
395
0
    if (bDisposing)
396
0
        return false;
397
398
0
    bool bRes = false;
399
0
    if (xDictionary.is())
400
0
    {
401
0
        DictionaryVec_t& rDicList = GetOrCreateDicList();
402
0
        rDicList.push_back( xDictionary );
403
0
        bRes = true;
404
405
        // add listener helper to the dictionaries listener lists
406
0
        xDictionary->addDictionaryEventListener( mxDicEvtLstnrHelper );
407
0
    }
408
0
    return bRes;
409
0
}
410
411
sal_Bool SAL_CALL
412
    DicList::removeDictionary( const uno::Reference< XDictionary >& xDictionary )
413
0
{
414
0
    osl::MutexGuard aGuard( GetLinguMutex() );
415
416
0
    if (bDisposing)
417
0
        return false;
418
419
0
    bool  bRes = false;
420
0
    sal_Int32 nPos = GetDicPos( xDictionary );
421
0
    if (nPos >= 0)
422
0
    {
423
        // remove dictionary list from the dictionaries listener lists
424
0
        DictionaryVec_t& rDicList = GetOrCreateDicList();
425
0
        uno::Reference< XDictionary > xDic( rDicList[ nPos ] );
426
0
        DBG_ASSERT(xDic.is(), "lng : empty reference");
427
0
        if (xDic.is())
428
0
        {
429
            // deactivate dictionary if not already done
430
0
            xDic->setActive( false );
431
432
0
            xDic->removeDictionaryEventListener( mxDicEvtLstnrHelper );
433
0
        }
434
435
        // remove element at nPos
436
0
        rDicList.erase( rDicList.begin() + nPos );
437
0
        bRes = true;
438
0
    }
439
0
    return bRes;
440
0
}
441
442
sal_Bool SAL_CALL DicList::addDictionaryListEventListener(
443
            const uno::Reference< XDictionaryListEventListener >& xListener,
444
            sal_Bool bReceiveVerbose )
445
0
{
446
0
    osl::MutexGuard aGuard( GetLinguMutex() );
447
448
0
    if (bDisposing)
449
0
        return false;
450
451
0
    DBG_ASSERT(!bReceiveVerbose, "lng : not yet supported");
452
453
0
    bool bRes = false;
454
0
    if (xListener.is()) //! don't add empty references
455
0
    {
456
0
        bRes = mxDicEvtLstnrHelper->AddDicListEvtListener( xListener );
457
0
    }
458
0
    return bRes;
459
0
}
460
461
sal_Bool SAL_CALL DicList::removeDictionaryListEventListener(
462
            const uno::Reference< XDictionaryListEventListener >& xListener )
463
0
{
464
0
    osl::MutexGuard aGuard( GetLinguMutex() );
465
466
0
    if (bDisposing)
467
0
        return false;
468
469
0
    bool bRes = false;
470
0
    if(xListener.is())
471
0
    {
472
0
        bRes = mxDicEvtLstnrHelper->RemoveDicListEvtListener( xListener );
473
0
    }
474
0
    return bRes;
475
0
}
476
477
sal_Int16 SAL_CALL DicList::beginCollectEvents()
478
0
{
479
0
    osl::MutexGuard aGuard( GetLinguMutex() );
480
0
    return mxDicEvtLstnrHelper->BeginCollectEvents();
481
0
}
482
483
sal_Int16 SAL_CALL DicList::endCollectEvents()
484
0
{
485
0
    osl::MutexGuard aGuard( GetLinguMutex() );
486
0
    return mxDicEvtLstnrHelper->EndCollectEvents();
487
0
}
488
489
sal_Int16 SAL_CALL DicList::flushEvents()
490
0
{
491
0
    osl::MutexGuard aGuard( GetLinguMutex() );
492
0
    return mxDicEvtLstnrHelper->FlushEvents();
493
0
}
494
495
uno::Reference< XDictionary > SAL_CALL
496
    DicList::createDictionary( const OUString& rName, const Locale& rLocale,
497
            DictionaryType eDicType, const OUString& rURL )
498
0
{
499
0
    osl::MutexGuard aGuard( GetLinguMutex() );
500
501
0
    LanguageType nLanguage = LinguLocaleToLanguage( rLocale );
502
0
    bool bIsWriteablePath = rURL.match( GetDictionaryWriteablePath() );
503
0
    return new DictionaryNeo( rName, nLanguage, eDicType, rURL, bIsWriteablePath );
504
0
}
505
506
507
uno::Reference< XDictionaryEntry > SAL_CALL
508
    DicList::queryDictionaryEntry( const OUString& rWord, const Locale& rLocale,
509
            sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry )
510
0
{
511
0
    osl::MutexGuard aGuard( GetLinguMutex() );
512
0
    return SearchDicList( this, rWord, LinguLocaleToLanguage( rLocale ),
513
0
                            bSearchPosDics, bSearchSpellEntry );
514
0
}
515
516
517
void SAL_CALL
518
    DicList::dispose()
519
0
{
520
0
    osl::MutexGuard aGuard( GetLinguMutex() );
521
522
0
    if (bDisposing)
523
0
        return;
524
525
0
    bDisposing = true;
526
0
    EventObject aEvtObj( static_cast<XDictionaryList *>(this) );
527
528
0
    aEvtListeners.disposeAndClear( aEvtObj );
529
0
    if (mxDicEvtLstnrHelper.is())
530
0
        mxDicEvtLstnrHelper->DisposeAndClear( aEvtObj );
531
532
    //! avoid creation of dictionaries if not already done
533
0
    if ( !aDicList.empty() )
534
0
    {
535
0
        DictionaryVec_t& rDicList = GetOrCreateDicList();
536
0
        size_t nCount = rDicList.size();
537
0
        for (size_t i = 0;  i < nCount;  i++)
538
0
        {
539
            // save (modified) dictionaries
540
0
            uno::Reference< frame::XStorable >  xStor( rDicList[i] , UNO_QUERY );
541
0
            if (xStor.is())
542
0
            {
543
0
                try
544
0
                {
545
0
                    if (!xStor->isReadonly() && xStor->hasLocation())
546
0
                        xStor->store();
547
0
                }
548
0
                catch(Exception &)
549
0
                {
550
0
                }
551
0
            }
552
553
            // release references to (members of) this object hold by
554
            // dictionaries
555
0
            if (rDicList[i].is())
556
0
                rDicList[i]->removeDictionaryEventListener( mxDicEvtLstnrHelper );
557
0
        }
558
0
    }
559
0
    mxDicEvtLstnrHelper.clear();
560
0
}
561
562
void SAL_CALL
563
    DicList::addEventListener( const uno::Reference< XEventListener >& rxListener )
564
0
{
565
0
    osl::MutexGuard aGuard( GetLinguMutex() );
566
567
0
    if (!bDisposing && rxListener.is())
568
0
        aEvtListeners.addInterface( rxListener );
569
0
}
570
571
void SAL_CALL
572
    DicList::removeEventListener( const uno::Reference< XEventListener >& rxListener )
573
0
{
574
0
    osl::MutexGuard aGuard( GetLinguMutex() );
575
576
0
    if (!bDisposing && rxListener.is())
577
0
        aEvtListeners.removeInterface( rxListener );
578
0
}
579
580
void SAL_CALL DicList::initialize(const css::uno::Sequence<css::uno::Any>& /*rArguments*/)
581
0
{
582
0
    osl::MutexGuard aGuard(GetLinguMutex());
583
584
0
    if (!bInCreation && !bDisposing)
585
0
    {
586
0
        CreateDicList();
587
0
    }
588
0
}
589
590
void DicList::CreateDicList()
591
0
{
592
0
    bInCreation = true;
593
594
    // look for dictionaries
595
0
    const OUString aWriteablePath( GetDictionaryWriteablePath() );
596
0
    std::vector< OUString > aPaths( GetDictionaryPaths() );
597
0
    for (const OUString & aPath : aPaths)
598
0
    {
599
0
        const bool bIsWriteablePath = (aPath == aWriteablePath);
600
0
        SearchForDictionaries( aDicList, aPath, bIsWriteablePath );
601
0
    }
602
603
    // create IgnoreAllList dictionary with empty URL (non persistent)
604
    // and add it to list
605
0
    const LanguageTag tag = comphelper::LibreOfficeKit::isActive()
606
0
                                ? LanguageTag(u"en-US"_ustr)
607
0
                                : SvtSysLocale().GetUILanguageTag();
608
0
    std::locale loc(Translate::Create("svt", tag));
609
0
    uno::Reference< XDictionary > xIgnAll(
610
0
            createDictionary( Translate::get(STR_DESCRIPTION_IGNOREALLLIST, loc), LinguLanguageToLocale( LANGUAGE_NONE ),
611
0
                              DictionaryType_POSITIVE, OUString() ) );
612
0
    if (xIgnAll.is())
613
0
    {
614
0
        AddUserData( xIgnAll );
615
0
        xIgnAll->setActive( true );
616
0
        addDictionary( xIgnAll );
617
0
    }
618
619
620
    // evaluate list of dictionaries to be activated from configuration
621
    //! to suppress overwriting the list of active dictionaries in the
622
    //! configuration with incorrect arguments during the following
623
    //! activation of the dictionaries
624
0
    mxDicEvtLstnrHelper->BeginCollectEvents();
625
0
    const uno::Sequence< OUString > aActiveDics( aOpt.GetActiveDics() );
626
0
    for (const OUString& rActiveDic : aActiveDics)
627
0
    {
628
0
        if (!rActiveDic.isEmpty())
629
0
        {
630
0
            uno::Reference< XDictionary > xDic( getDictionaryByName( rActiveDic ) );
631
0
            if (xDic.is())
632
0
                xDic->setActive( true );
633
0
        }
634
0
    }
635
636
    // suppress collected events during creation of the dictionary list.
637
    // there should be no events during creation.
638
0
    mxDicEvtLstnrHelper->ClearEvents();
639
640
0
    mxDicEvtLstnrHelper->EndCollectEvents();
641
642
0
    bInCreation = false;
643
0
}
644
645
646
void DicList::SaveDics()
647
0
{
648
    // save dics only if they have already been used/created.
649
    //! don't create them just for the purpose of saving them !
650
0
    if ( aDicList.empty() )
651
0
        return;
652
653
    // save (modified) dictionaries
654
0
    DictionaryVec_t& rDicList = GetOrCreateDicList();
655
0
    size_t nCount = rDicList.size();
656
0
    for (size_t i = 0;  i < nCount;  i++)
657
0
    {
658
        // save (modified) dictionaries
659
0
        uno::Reference< frame::XStorable >  xStor( rDicList[i], UNO_QUERY );
660
0
        if (xStor.is())
661
0
        {
662
0
            try
663
0
            {
664
0
                if (!xStor->isReadonly() && xStor->hasLocation())
665
0
                    xStor->store();
666
0
            }
667
0
            catch(Exception &)
668
0
            {
669
0
            }
670
0
        }
671
0
    }
672
0
}
673
674
675
// Service specific part
676
677
OUString SAL_CALL DicList::getImplementationName(  )
678
0
{
679
0
    return u"com.sun.star.lingu2.DicList"_ustr;
680
0
}
681
682
683
sal_Bool SAL_CALL DicList::supportsService( const OUString& ServiceName )
684
0
{
685
0
    return cppu::supportsService(this, ServiceName);
686
0
}
687
688
uno::Sequence< OUString > SAL_CALL DicList::getSupportedServiceNames(  )
689
0
{
690
0
    return { u"com.sun.star.linguistic2.DictionaryList"_ustr };
691
0
}
692
693
694
695
static sal_Int32 lcl_GetToken( OUString &rToken,
696
            const OUString &rText, sal_Int32 nPos, std::u16string_view rDelim )
697
0
{
698
0
    sal_Int32 nRes = -1;
699
700
0
    if (rText.isEmpty() ||  nPos >= rText.getLength())
701
0
        rToken.clear();
702
0
    else if (rDelim.empty())
703
0
    {
704
0
        rToken = rText;
705
0
        if (!rToken.isEmpty())
706
0
            nRes = rText.getLength();
707
0
    }
708
0
    else
709
0
    {
710
0
        sal_Int32 i;
711
0
        for (i = nPos; i < rText.getLength(); ++i)
712
0
        {
713
0
            if (std::string_view::npos != rDelim.find( rText[i] ))
714
0
                break;
715
0
        }
716
717
0
        if (i >= rText.getLength())   // delimiter not found
718
0
            rToken  = rText.copy( nPos );
719
0
        else
720
0
            rToken  = rText.copy( nPos, i - nPos );
721
0
        nRes    = i + 1;    // continue after found delimiter
722
0
    }
723
724
0
    return nRes;
725
0
}
726
727
728
static void AddInternal(
729
        const uno::Reference<XDictionary> &rDic,
730
        const OUString& rNew )
731
0
{
732
0
    if (!rDic.is())
733
0
        return;
734
735
    //! TL TODO: word iterator should be used to break up the text
736
0
    OUString aDelim(u"!\"#$%&'()*+,-/:;<=>?[]\\_^`{|}~\t \n"_ustr);
737
0
    OSL_ENSURE(aDelim.indexOf(u'.') == -1,
738
0
        "ensure no '.'");
739
740
0
    OUString      aToken;
741
0
    sal_Int32 nPos = 0;
742
0
    while (-1 != (nPos = lcl_GetToken( aToken, rNew, nPos, aDelim )))
743
0
    {
744
0
        if( !aToken.isEmpty()  &&  !IsNumeric( aToken ) )
745
0
        {
746
0
            rDic->add( aToken, false, OUString() );
747
0
        }
748
0
    }
749
0
}
750
751
static void AddUserData( const uno::Reference< XDictionary > &rDic )
752
0
{
753
0
    if (rDic.is())
754
0
    {
755
0
        SvtUserOptions aUserOpt;
756
0
        AddInternal( rDic, aUserOpt.GetFullName() );
757
0
        AddInternal( rDic, aUserOpt.GetCompany() );
758
0
        AddInternal( rDic, aUserOpt.GetStreet() );
759
0
        AddInternal( rDic, aUserOpt.GetCity() );
760
0
        AddInternal( rDic, aUserOpt.GetTitle() );
761
0
        AddInternal( rDic, aUserOpt.GetPosition() );
762
0
        AddInternal( rDic, aUserOpt.GetEmail() );
763
0
    }
764
0
}
765
766
static bool IsVers2OrNewer( const OUString& rFileURL, LanguageType& nLng, bool& bNeg, OUString& aDicName )
767
0
{
768
0
    if (rFileURL.isEmpty())
769
0
        return false;
770
0
    OUString aExt;
771
0
    sal_Int32 nPos = rFileURL.lastIndexOf( '.' );
772
0
    if (-1 != nPos)
773
0
        aExt = rFileURL.copy( nPos + 1 ).toAsciiLowerCase();
774
775
0
    if (aExt != "dic")
776
0
        return false;
777
778
    // get stream to be used
779
0
    const uno::Reference< uno::XComponentContext >& xContext( comphelper::getProcessComponentContext() );
780
781
    // get XInputStream stream
782
0
    uno::Reference< io::XInputStream > xStream;
783
0
    try
784
0
    {
785
0
        uno::Reference< ucb::XSimpleFileAccess3 > xAccess( ucb::SimpleFileAccess::create(xContext) );
786
0
        xStream = xAccess->openFileRead( rFileURL );
787
0
    }
788
0
    catch (const uno::Exception &)
789
0
    {
790
0
        SAL_WARN( "linguistic", "failed to get input stream" );
791
0
    }
792
0
    DBG_ASSERT( xStream.is(), "failed to get stream for read" );
793
0
    if (!xStream.is())
794
0
        return false;
795
796
0
    std::unique_ptr<SvStream> pStream( utl::UcbStreamHelper::CreateStream( xStream ) );
797
798
0
    int nDicVersion = ReadDicVersion(*pStream, nLng, bNeg, aDicName);
799
0
    return 2 == nDicVersion || nDicVersion >= 5;
800
0
}
801
802
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
803
linguistic_DicList_get_implementation(
804
    css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
805
0
{
806
0
    return cppu::acquire(new DicList());
807
0
}
808
809
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */