1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/settings.hxx>
21 #include <vcl/weld.hxx>
22 #include <i18nlangtag/languagetag.hxx>
23 #include <i18nlangtag/mslangid.hxx>
24 #include <unotools/lingucfg.hxx>
25 #include <unotools/linguprops.hxx>
26 #include <editeng/unolingu.hxx>
27 #include <linguistic/misc.hxx>
28 #include <sfx2/sfxsids.hrc>
29 #include <tools/debug.hxx>
30 #include <tools/urlobj.hxx>
31 #include <tools/diagnose_ex.h>
32 #include <comphelper/processfactory.hxx>
33 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
34 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
35 #include <com/sun/star/linguistic2/XProofreader.hpp>
36 #include <com/sun/star/linguistic2/XHyphenator.hpp>
37 #include <com/sun/star/linguistic2/XThesaurus.hpp>
38 #include <com/sun/star/linguistic2/XDictionary.hpp>
39 #include <com/sun/star/linguistic2/XDictionaryList.hpp>
40 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
41 #include <com/sun/star/lang/XServiceDisplayName.hpp>
42 #include <com/sun/star/frame/XStorable.hpp>
43 #include <unotools/extendedsecurityoptions.hxx>
44 #include <svl/eitem.hxx>
45 #include <vcl/svapp.hxx>
46 #include <sal/log.hxx>
47 #include <osl/diagnose.h>
48 
49 #include <svx/svxdlg.hxx>
50 #include <editeng/optitems.hxx>
51 #include <optlingu.hxx>
52 #include <dialmgr.hxx>
53 #include <strings.hrc>
54 
55 #include <ucbhelper/content.hxx>
56 
57 #include <vector>
58 #include <map>
59 
60 using namespace ::ucbhelper;
61 using namespace ::com::sun::star;
62 using namespace css::lang;
63 using namespace css::uno;
64 using namespace css::linguistic2;
65 using namespace css::beans;
66 
67 static const sal_Char cSpell[]   = SN_SPELLCHECKER;
68 static const sal_Char cGrammar[] = SN_GRAMMARCHECKER;
69 static const sal_Char cHyph[]    = SN_HYPHENATOR;
70 static const sal_Char cThes[]    = SN_THESAURUS;
71 
72 // static ----------------------------------------------------------------
73 
lcl_SeqGetEntryPos(const Sequence<OUString> & rSeq,const OUString & rEntry)74 static sal_Int32 lcl_SeqGetEntryPos(
75     const Sequence< OUString > &rSeq, const OUString &rEntry )
76 {
77     sal_Int32 i;
78     sal_Int32 nLen = rSeq.getLength();
79     const OUString *pItem = rSeq.getConstArray();
80     for (i = 0;  i < nLen;  ++i)
81     {
82         if (rEntry == pItem[i])
83             break;
84     }
85     return i < nLen ? i : -1;
86 }
87 
KillFile_Impl(const OUString & rURL)88 static bool KillFile_Impl( const OUString& rURL )
89 {
90     bool bRet = true;
91     try
92     {
93         Content aCnt( rURL, uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
94         aCnt.executeCommand( "delete", Any( true ) );
95     }
96     catch( ... )
97     {
98         TOOLS_WARN_EXCEPTION( "cui.options", "KillFile" );
99         bRet = false;
100     }
101 
102     return bRet;
103 }
104 
105 // 0x 0p 0t 0c nn
106 // p: 1 -> parent
107 // t: 1 -> spell, 2 -> hyph, 3 -> thes, 4 -> grammar
108 // c: 1 -> checked 0 -> unchecked
109 // n: index
110 
111 #define TYPE_SPELL      sal_uInt8(1)
112 #define TYPE_GRAMMAR    sal_uInt8(2)
113 #define TYPE_HYPH       sal_uInt8(3)
114 #define TYPE_THES       sal_uInt8(4)
115 
116 class ModuleUserData_Impl
117 {
118     bool bParent;
119     bool bIsChecked;
120     sal_uInt8 nType;
121     sal_uInt8 nIndex;
122     OUString  sImplName;
123 
124 public:
ModuleUserData_Impl(const OUString & sImpName,bool bIsParent,bool bChecked,sal_uInt8 nSetType,sal_uInt8 nSetIndex)125     ModuleUserData_Impl( const OUString& sImpName, bool bIsParent, bool bChecked, sal_uInt8 nSetType, sal_uInt8 nSetIndex ) :
126         bParent(bIsParent),
127         bIsChecked(bChecked),
128         nType(nSetType),
129         nIndex(nSetIndex),
130         sImplName(sImpName)
131         {
132         }
IsParent() const133     bool IsParent() const {return bParent;}
GetType() const134     sal_uInt8 GetType() const {return nType;}
IsChecked() const135     bool IsChecked() const {return bIsChecked;}
GetIndex() const136     sal_uInt8 GetIndex() const {return nIndex;}
GetImplName() const137     const OUString& GetImplName() const {return sImplName;}
138 
139 };
140 
141 
142 // User for user-dictionaries (XDictionary interface)
143 
144 class DicUserData
145 {
146     sal_uInt32 nVal;
147 
148 public:
DicUserData(sal_uInt32 nUserData)149     explicit DicUserData(sal_uInt32 nUserData) : nVal( nUserData ) {}
150     DicUserData( sal_uInt16 nEID,
151                  bool bChecked, bool bEditable, bool bDeletable );
152 
GetUserData() const153     sal_uInt32  GetUserData() const         { return nVal; }
GetEntryId() const154     sal_uInt16  GetEntryId() const          { return static_cast<sal_uInt16>(nVal >> 16); }
IsChecked() const155     bool        IsChecked() const           { return static_cast<bool>((nVal >>  8) & 0x01); }
IsDeletable() const156     bool        IsDeletable() const         { return static_cast<bool>((nVal >> 10) & 0x01); }
157 };
158 
159 
DicUserData(sal_uInt16 nEID,bool bChecked,bool bEditable,bool bDeletable)160 DicUserData::DicUserData(
161         sal_uInt16 nEID,
162         bool bChecked, bool bEditable, bool bDeletable )
163 {
164     DBG_ASSERT( nEID < 65000, "Entry Id out of range" );
165     nVal =  (static_cast<sal_uInt32>(0xFFFF & nEID)         << 16) |
166             (static_cast<sal_uInt32>(bChecked ? 1 : 0)      <<  8) |
167             (static_cast<sal_uInt32>(bEditable ? 1 : 0)     <<  9) |
168             (static_cast<sal_uInt32>(bDeletable ? 1 : 0)    << 10);
169 }
170 
171 /*--------------------------------------------------
172     Entry IDs for options listbox of dialog
173 --------------------------------------------------*/
174 
175 enum EID_OPTIONS
176 {
177     EID_SPELL_AUTO,
178     EID_GRAMMAR_AUTO,
179     EID_CAPITAL_WORDS,
180     EID_WORDS_WITH_DIGITS,
181     EID_SPELL_SPECIAL,
182     EID_NUM_MIN_WORDLEN,
183     EID_NUM_PRE_BREAK,
184     EID_NUM_POST_BREAK,
185     EID_HYPH_AUTO,
186     EID_HYPH_SPECIAL
187 };
188 
189 //! this array must have an entry for every value of EID_OPTIONS.
190 //  It is used to get the respective property name.
191 static const char * aEidToPropName[] =
192 {
193     UPN_IS_SPELL_AUTO,              // EID_SPELL_AUTO
194     UPN_IS_GRAMMAR_AUTO,            // EID_GRAMMAR_AUTO
195     UPN_IS_SPELL_UPPER_CASE,        // EID_CAPITAL_WORDS
196     UPN_IS_SPELL_WITH_DIGITS,       // EID_WORDS_WITH_DIGITS
197     UPN_IS_SPELL_SPECIAL,           // EID_SPELL_SPECIAL
198     UPN_HYPH_MIN_WORD_LENGTH,       // EID_NUM_MIN_WORDLEN,
199     UPN_HYPH_MIN_LEADING,           // EID_NUM_PRE_BREAK
200     UPN_HYPH_MIN_TRAILING,          // EID_NUM_POST_BREAK
201     UPN_IS_HYPH_AUTO,               // EID_HYPH_AUTO
202     UPN_IS_HYPH_SPECIAL             // EID_HYPH_SPECIAL
203 };
204 
lcl_GetPropertyName(EID_OPTIONS eEntryId)205 static OUString lcl_GetPropertyName( EID_OPTIONS eEntryId )
206 {
207     DBG_ASSERT( static_cast<unsigned int>(eEntryId) < SAL_N_ELEMENTS(aEidToPropName), "index out of range" );
208     return OUString::createFromAscii( aEidToPropName[ static_cast<int>(eEntryId) ] );
209 }
210 
211 class OptionsBreakSet : public weld::GenericDialogController
212 {
213     std::unique_ptr<weld::Widget> m_xBeforeFrame;
214     std::unique_ptr<weld::Widget> m_xAfterFrame;
215     std::unique_ptr<weld::Widget> m_xMinimalFrame;
216     std::unique_ptr<weld::SpinButton> m_xBreakNF;
217 
218 public:
OptionsBreakSet(weld::Window * pParent,sal_uInt16 nRID)219     OptionsBreakSet(weld::Window* pParent, sal_uInt16 nRID)
220         : GenericDialogController(pParent, "cui/ui/breaknumberoption.ui", "BreakNumberOption")
221         , m_xBeforeFrame(m_xBuilder->weld_widget("beforeframe"))
222         , m_xAfterFrame(m_xBuilder->weld_widget("afterframe"))
223         , m_xMinimalFrame(m_xBuilder->weld_widget("miniframe"))
224     {
225         assert(EID_NUM_PRE_BREAK == nRID || EID_NUM_POST_BREAK == nRID || EID_NUM_MIN_WORDLEN == nRID); //unexpected ID
226 
227         if (nRID == EID_NUM_PRE_BREAK)
228         {
229             m_xBeforeFrame->show();
230             m_xBreakNF = m_xBuilder->weld_spin_button("beforebreak");
231         }
232         else if(nRID == EID_NUM_POST_BREAK)
233         {
234             m_xAfterFrame->show();
235             m_xBreakNF = m_xBuilder->weld_spin_button("afterbreak");
236         }
237         else if(nRID == EID_NUM_MIN_WORDLEN)
238         {
239             m_xMinimalFrame->show();
240             m_xBreakNF = m_xBuilder->weld_spin_button("wordlength");
241         }
242     }
243 
GetNumericFld()244     weld::SpinButton& GetNumericFld()
245     {
246         return *m_xBreakNF;
247     }
248 };
249 
250 // class OptionsUserData -------------------------------------------------
251 
252 class OptionsUserData
253 {
254     sal_uInt32   nVal;
255 
256 public:
OptionsUserData(sal_uInt32 nUserData)257     explicit OptionsUserData( sal_uInt32 nUserData ) : nVal( nUserData ) {}
258     OptionsUserData( sal_uInt16 nEID,
259                      bool bHasNV, sal_uInt16 nNumVal,
260                      bool bCheckable, bool bChecked );
261 
GetUserData() const262     sal_uInt32  GetUserData() const         { return nVal; }
GetEntryId() const263     sal_uInt16  GetEntryId() const          { return static_cast<sal_uInt16>(nVal >> 16); }
HasNumericValue() const264     bool        HasNumericValue() const     { return static_cast<bool>((nVal >> 10) & 0x01); }
GetNumericValue() const265     sal_uInt16  GetNumericValue() const     { return static_cast<sal_uInt16>(nVal & 0xFF); }
IsCheckable() const266     bool        IsCheckable() const         { return static_cast<bool>((nVal >> 9) & 0x01); }
IsModified() const267     bool        IsModified() const          { return static_cast<bool>((nVal >> 11) & 0x01); }
268 
269     void        SetNumericValue( sal_uInt8 nNumVal );
270 };
271 
OptionsUserData(sal_uInt16 nEID,bool bHasNV,sal_uInt16 nNumVal,bool bCheckable,bool bChecked)272 OptionsUserData::OptionsUserData( sal_uInt16 nEID,
273         bool bHasNV, sal_uInt16 nNumVal,
274         bool bCheckable, bool bChecked )
275 {
276     DBG_ASSERT( nEID < 65000, "Entry Id out of range" );
277     DBG_ASSERT( nNumVal < 256, "value out of range" );
278     nVal =  (static_cast<sal_uInt32>(0xFFFF & nEID)         << 16) |
279             (static_cast<sal_uInt32>(bHasNV ? 1 : 0)        << 10) |
280             (static_cast<sal_uInt32>(bCheckable ? 1 : 0)    <<  9) |
281             (static_cast<sal_uInt32>(bChecked ? 1 : 0)      <<  8) |
282             static_cast<sal_uInt32>(0xFF & nNumVal);
283 }
284 
SetNumericValue(sal_uInt8 nNumVal)285 void OptionsUserData::SetNumericValue( sal_uInt8 nNumVal )
286 {
287     if (HasNumericValue()  &&  (GetNumericValue() != nNumVal))
288     {
289         nVal &= 0xffffff00;
290         nVal |= nNumVal;
291         nVal |= sal_uInt32(1) << 11; // mark as modified
292     }
293 }
294 
295 // ServiceInfo_Impl ----------------------------------------------------
296 
297 struct ServiceInfo_Impl
298 {
299     OUString                    sDisplayName;
300     OUString                    sSpellImplName;
301     OUString                    sHyphImplName;
302     OUString                    sThesImplName;
303     OUString                    sGrammarImplName;
304     uno::Reference< XSpellChecker >     xSpell;
305     uno::Reference< XHyphenator >       xHyph;
306     uno::Reference< XThesaurus >        xThes;
307     uno::Reference< XProofreader >      xGrammar;
308     bool                        bConfigured;
309 
ServiceInfo_ImplServiceInfo_Impl310     ServiceInfo_Impl() : bConfigured(false) {}
311 };
312 
313 typedef std::vector< ServiceInfo_Impl >                   ServiceInfoArr;
314 typedef std::map< LanguageType, Sequence< OUString > >    LangImplNameTable;
315 
316 
317 // SvxLinguData_Impl ----------------------------------------------------
318 
319 class SvxLinguData_Impl
320 {
321     //contains services and implementation names sorted by implementation names
322     ServiceInfoArr                      aDisplayServiceArr;
323     sal_uInt32                          nDisplayServices;
324 
325     Sequence< Locale >                  aAllServiceLocales;
326     LangImplNameTable                   aCfgSpellTable;
327     LangImplNameTable                   aCfgHyphTable;
328     LangImplNameTable                   aCfgThesTable;
329     LangImplNameTable                   aCfgGrammarTable;
330     uno::Reference< XLinguServiceManager2 >  xLinguSrvcMgr;
331 
332 
333     static bool AddRemove( Sequence< OUString > &rConfigured,
334                            const OUString &rImplName, bool bAdd );
335 
336 public:
337     SvxLinguData_Impl();
338 
GetManager()339     uno::Reference<XLinguServiceManager2> &   GetManager() { return xLinguSrvcMgr; }
340 
341     void SetChecked( const Sequence< OUString > &rConfiguredServices );
342     void Reconfigure( const OUString &rDisplayName, bool bEnable );
343 
GetAllSupportedLocales() const344     const Sequence<Locale> &    GetAllSupportedLocales() const { return aAllServiceLocales; }
345 
GetSpellTable()346     LangImplNameTable &         GetSpellTable()         { return aCfgSpellTable; }
GetHyphTable()347     LangImplNameTable &         GetHyphTable()          { return aCfgHyphTable; }
GetThesTable()348     LangImplNameTable &         GetThesTable()          { return aCfgThesTable; }
GetGrammarTable()349     LangImplNameTable &         GetGrammarTable()       { return aCfgGrammarTable; }
350 
GetDisplayServiceArray()351     ServiceInfoArr &            GetDisplayServiceArray()        { return aDisplayServiceArr; }
352 
GetDisplayServiceCount() const353     const sal_uInt32 &   GetDisplayServiceCount() const          { return nDisplayServices; }
SetDisplayServiceCount(sal_uInt32 nVal)354     void            SetDisplayServiceCount( sal_uInt32 nVal )    { nDisplayServices = nVal; }
355 
356     // returns the list of service implementation names for the specified
357     // language and service (TYPE_SPELL, TYPE_HYPH, TYPE_THES) sorted in
358     // the proper order for the SvxEditModulesDlg (the ones from the
359     // configuration (keeping that order!) first and then the other ones.
360     // I.e. the ones available but not configured in arbitrary order).
361     // They available ones may contain names that do not(!) support that
362     // language.
363     Sequence< OUString > GetSortedImplNames( LanguageType nLang, sal_uInt8 nType );
364 
365     ServiceInfo_Impl * GetInfoByImplName( const OUString &rSvcImplName );
366 };
367 
368 
lcl_SeqGetIndex(const Sequence<OUString> & rSeq,const OUString & rTxt)369 static sal_Int32 lcl_SeqGetIndex( const Sequence< OUString > &rSeq, const OUString &rTxt )
370 {
371     sal_Int32 nRes = -1;
372     sal_Int32 nLen = rSeq.getLength();
373     const OUString *pString = rSeq.getConstArray();
374     for (sal_Int32 i = 0;  i < nLen  &&  nRes == -1;  ++i)
375     {
376         if (pString[i] == rTxt)
377             nRes = i;
378     }
379     return nRes;
380 }
381 
382 
GetSortedImplNames(LanguageType nLang,sal_uInt8 nType)383 Sequence< OUString > SvxLinguData_Impl::GetSortedImplNames( LanguageType nLang, sal_uInt8 nType )
384 {
385     LangImplNameTable *pTable = nullptr;
386     switch (nType)
387     {
388         case TYPE_SPELL     : pTable = &aCfgSpellTable; break;
389         case TYPE_HYPH      : pTable = &aCfgHyphTable; break;
390         case TYPE_THES      : pTable = &aCfgThesTable; break;
391         case TYPE_GRAMMAR   : pTable = &aCfgGrammarTable; break;
392     }
393     Sequence< OUString > aRes;
394     if (!pTable)
395     {
396         SAL_WARN( "cui.options", "unknown linguistic type" );
397         return aRes;
398     }
399     if (pTable->count( nLang ))
400         aRes = (*pTable)[ nLang ];      // add configured services
401     sal_Int32 nIdx = aRes.getLength();
402     DBG_ASSERT( static_cast<sal_Int32>(nDisplayServices) >= nIdx, "size mismatch" );
403     aRes.realloc( nDisplayServices );
404     OUString *pRes = aRes.getArray();
405 
406     // add not configured services
407     for (sal_Int32 i = 0;  i < static_cast<sal_Int32>(nDisplayServices);  ++i)
408     {
409         const ServiceInfo_Impl &rInfo = aDisplayServiceArr[ i ];
410         OUString aImplName;
411         switch (nType)
412         {
413             case TYPE_SPELL     : aImplName = rInfo.sSpellImplName; break;
414             case TYPE_HYPH      : aImplName = rInfo.sHyphImplName; break;
415             case TYPE_THES      : aImplName = rInfo.sThesImplName; break;
416             case TYPE_GRAMMAR   : aImplName = rInfo.sGrammarImplName; break;
417         }
418 
419         if (!aImplName.isEmpty()  &&  (lcl_SeqGetIndex( aRes, aImplName) == -1))    // name not yet added
420         {
421             DBG_ASSERT( nIdx < aRes.getLength(), "index out of range" );
422             if (nIdx < aRes.getLength())
423                 pRes[ nIdx++ ] = aImplName;
424         }
425     }
426     // don't forget to put aRes back to its actual size just in case you allocated too much
427     // since all of the names may have already been added
428     // otherwise you get duplicate entries in the edit dialog
429     aRes.realloc( nIdx );
430     return aRes;
431 }
432 
433 
GetInfoByImplName(const OUString & rSvcImplName)434 ServiceInfo_Impl * SvxLinguData_Impl::GetInfoByImplName( const OUString &rSvcImplName )
435 {
436     for (sal_uInt32 i = 0;  i < nDisplayServices;  ++i)
437     {
438         ServiceInfo_Impl &rTmp = aDisplayServiceArr[ i ];
439         if (rTmp.sSpellImplName == rSvcImplName ||
440             rTmp.sHyphImplName  == rSvcImplName ||
441             rTmp.sThesImplName  == rSvcImplName ||
442             rTmp.sGrammarImplName == rSvcImplName)
443         {
444             return &rTmp;
445         }
446     }
447     return nullptr;
448 }
449 
450 
lcl_MergeLocales(Sequence<Locale> & aAllLocales,const Sequence<Locale> & rAdd)451 static void lcl_MergeLocales(Sequence< Locale >& aAllLocales, const Sequence< Locale >& rAdd)
452 {
453     const Locale* pAdd = rAdd.getConstArray();
454     Sequence<Locale> aLocToAdd(rAdd.getLength());
455     const Locale* pAllLocales = aAllLocales.getConstArray();
456     Locale* pLocToAdd = aLocToAdd.getArray();
457     sal_Int32 nFound = 0;
458     sal_Int32 i;
459     for(i = 0; i < rAdd.getLength(); i++)
460     {
461         bool bFound = false;
462         for(sal_Int32 j = 0; j < aAllLocales.getLength() && !bFound; j++)
463         {
464             bFound = pAdd[i].Language == pAllLocales[j].Language &&
465                 pAdd[i].Country == pAllLocales[j].Country &&
466                 pAdd[i].Variant == pAllLocales[j].Variant;
467         }
468         if(!bFound)
469         {
470             pLocToAdd[nFound++] = pAdd[i];
471         }
472     }
473     sal_Int32 nLength = aAllLocales.getLength();
474     aAllLocales.realloc( nLength + nFound);
475     Locale* pAllLocales2 = aAllLocales.getArray();
476     for(i = 0; i < nFound; i++)
477         pAllLocales2[nLength++] = pLocToAdd[i];
478 }
479 
lcl_MergeDisplayArray(SvxLinguData_Impl & rData,const ServiceInfo_Impl & rToAdd)480 static void lcl_MergeDisplayArray(
481         SvxLinguData_Impl &rData,
482         const ServiceInfo_Impl &rToAdd )
483 {
484     sal_uInt32 nCnt = 0;
485 
486     ServiceInfoArr &rSvcInfoArr = rData.GetDisplayServiceArray();
487     sal_uInt32 nEntries = rData.GetDisplayServiceCount();
488 
489     for (sal_uInt32 i = 0;  i < nEntries;  ++i)
490     {
491         ServiceInfo_Impl& rEntry = rSvcInfoArr[i];
492         if (rEntry.sDisplayName == rToAdd.sDisplayName)
493         {
494             if(rToAdd.xSpell.is())
495             {
496                 DBG_ASSERT( !rEntry.xSpell.is() &&
497                             rEntry.sSpellImplName.isEmpty(),
498                             "merge conflict" );
499                 rEntry.sSpellImplName = rToAdd.sSpellImplName;
500                 rEntry.xSpell = rToAdd.xSpell;
501             }
502             if(rToAdd.xGrammar.is())
503             {
504                 DBG_ASSERT( !rEntry.xGrammar.is() &&
505                             rEntry.sGrammarImplName.isEmpty(),
506                             "merge conflict" );
507                 rEntry.sGrammarImplName = rToAdd.sGrammarImplName;
508                 rEntry.xGrammar = rToAdd.xGrammar;
509             }
510             if(rToAdd.xHyph.is())
511             {
512                 DBG_ASSERT( !rEntry.xHyph.is() &&
513                             rEntry.sHyphImplName.isEmpty(),
514                             "merge conflict" );
515                 rEntry.sHyphImplName = rToAdd.sHyphImplName;
516                 rEntry.xHyph = rToAdd.xHyph;
517             }
518             if(rToAdd.xThes.is())
519             {
520                 DBG_ASSERT( !rEntry.xThes.is() &&
521                             rEntry.sThesImplName.isEmpty(),
522                             "merge conflict" );
523                 rEntry.sThesImplName = rToAdd.sThesImplName;
524                 rEntry.xThes = rToAdd.xThes;
525             }
526             return ;
527         }
528         ++nCnt;
529     }
530     rData.GetDisplayServiceArray().push_back( rToAdd );
531     rData.SetDisplayServiceCount( nCnt + 1 );
532 }
533 
SvxLinguData_Impl()534 SvxLinguData_Impl::SvxLinguData_Impl() :
535     nDisplayServices    (0)
536 {
537     uno::Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
538     xLinguSrvcMgr = LinguServiceManager::create(xContext);
539 
540     const Locale& rCurrentLocale = Application::GetSettings().GetLanguageTag().getLocale();
541     Sequence<Any> aArgs(2);//second arguments has to be empty!
542     aArgs.getArray()[0] <<= LinguMgr::GetLinguPropertySet();
543 
544     //read spell checker
545     Sequence< OUString > aSpellNames = xLinguSrvcMgr->getAvailableServices(
546                     cSpell,    Locale() );
547     const OUString* pSpellNames = aSpellNames.getConstArray();
548 
549     sal_Int32 nIdx;
550     for(nIdx = 0; nIdx < aSpellNames.getLength(); nIdx++)
551     {
552         ServiceInfo_Impl aInfo;
553         aInfo.sSpellImplName = pSpellNames[nIdx];
554         aInfo.xSpell.set(
555                         xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sSpellImplName, aArgs, xContext), UNO_QUERY);
556 
557         uno::Reference<XServiceDisplayName> xDispName(aInfo.xSpell, UNO_QUERY);
558         if(xDispName.is())
559             aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
560 
561         const Sequence< Locale > aLocales( aInfo.xSpell->getLocales() );
562         //! suppress display of entries with no supported languages (see feature 110994)
563         if (aLocales.hasElements())
564         {
565             lcl_MergeLocales( aAllServiceLocales, aLocales );
566             lcl_MergeDisplayArray( *this, aInfo );
567         }
568     }
569 
570     //read grammar checker
571     Sequence< OUString > aGrammarNames = xLinguSrvcMgr->getAvailableServices(
572                     cGrammar, Locale() );
573     const OUString* pGrammarNames = aGrammarNames.getConstArray();
574     for(nIdx = 0; nIdx < aGrammarNames.getLength(); nIdx++)
575     {
576         ServiceInfo_Impl aInfo;
577         aInfo.sGrammarImplName = pGrammarNames[nIdx];
578         aInfo.xGrammar.set(
579                         xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sGrammarImplName, aArgs, xContext), UNO_QUERY);
580 
581         uno::Reference<XServiceDisplayName> xDispName(aInfo.xGrammar, UNO_QUERY);
582         if(xDispName.is())
583             aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
584 
585         const Sequence< Locale > aLocales( aInfo.xGrammar->getLocales() );
586         //! suppress display of entries with no supported languages (see feature 110994)
587         if (aLocales.hasElements())
588         {
589             lcl_MergeLocales( aAllServiceLocales, aLocales );
590             lcl_MergeDisplayArray( *this, aInfo );
591         }
592     }
593 
594     //read hyphenator
595     Sequence< OUString > aHyphNames = xLinguSrvcMgr->getAvailableServices(
596                     cHyph, Locale() );
597     const OUString* pHyphNames = aHyphNames.getConstArray();
598     for(nIdx = 0; nIdx < aHyphNames.getLength(); nIdx++)
599     {
600         ServiceInfo_Impl aInfo;
601         aInfo.sHyphImplName = pHyphNames[nIdx];
602         aInfo.xHyph.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sHyphImplName, aArgs, xContext), UNO_QUERY);
603 
604         uno::Reference<XServiceDisplayName> xDispName(aInfo.xHyph, UNO_QUERY);
605         if(xDispName.is())
606             aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
607 
608         const Sequence< Locale > aLocales( aInfo.xHyph->getLocales() );
609         //! suppress display of entries with no supported languages (see feature 110994)
610         if (aLocales.hasElements())
611         {
612             lcl_MergeLocales( aAllServiceLocales, aLocales );
613             lcl_MergeDisplayArray( *this, aInfo );
614         }
615     }
616 
617     //read thesauri
618     Sequence< OUString > aThesNames = xLinguSrvcMgr->getAvailableServices(
619                     cThes,     Locale() );
620     const OUString* pThesNames = aThesNames.getConstArray();
621     for(nIdx = 0; nIdx < aThesNames.getLength(); nIdx++)
622     {
623         ServiceInfo_Impl aInfo;
624         aInfo.sThesImplName = pThesNames[nIdx];
625         aInfo.xThes.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sThesImplName, aArgs, xContext), UNO_QUERY);
626 
627         uno::Reference<XServiceDisplayName> xDispName(aInfo.xThes, UNO_QUERY);
628         if(xDispName.is())
629             aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
630 
631         const Sequence< Locale > aLocales( aInfo.xThes->getLocales() );
632         //! suppress display of entries with no supported languages (see feature 110994)
633         if (aLocales.hasElements())
634         {
635             lcl_MergeLocales( aAllServiceLocales, aLocales );
636             lcl_MergeDisplayArray( *this, aInfo );
637         }
638     }
639 
640     Sequence< OUString > aCfgSvcs;
641     const Locale* pAllLocales = aAllServiceLocales.getConstArray();
642     for(sal_Int32 nLocale = 0; nLocale < aAllServiceLocales.getLength(); nLocale++)
643     {
644         LanguageType nLang = LanguageTag::convertToLanguageType( pAllLocales[nLocale] );
645 
646         aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cSpell, pAllLocales[nLocale]);
647         SetChecked( aCfgSvcs );
648         if (aCfgSvcs.hasElements())
649             aCfgSpellTable[ nLang ] = aCfgSvcs;
650 
651         aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cGrammar, pAllLocales[nLocale]);
652         SetChecked( aCfgSvcs );
653         if (aCfgSvcs.hasElements())
654             aCfgGrammarTable[ nLang ] = aCfgSvcs;
655 
656         aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cHyph, pAllLocales[nLocale]);
657         SetChecked( aCfgSvcs );
658         if (aCfgSvcs.hasElements())
659             aCfgHyphTable[ nLang ] = aCfgSvcs;
660 
661         aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cThes, pAllLocales[nLocale]);
662         SetChecked( aCfgSvcs );
663         if (aCfgSvcs.hasElements())
664             aCfgThesTable[ nLang ] = aCfgSvcs;
665     }
666 }
667 
SetChecked(const Sequence<OUString> & rConfiguredServices)668 void SvxLinguData_Impl::SetChecked(const Sequence<OUString>& rConfiguredServices)
669 {
670     const OUString* pConfiguredServices = rConfiguredServices.getConstArray();
671     for(sal_Int32 n = 0; n < rConfiguredServices.getLength(); n++)
672     {
673         for (sal_uInt32 i = 0;  i < nDisplayServices;  ++i)
674         {
675             ServiceInfo_Impl& rEntry = aDisplayServiceArr[i];
676             if (!rEntry.bConfigured)
677             {
678                 const OUString &rSrvcImplName = pConfiguredServices[n];
679                 if (!rSrvcImplName.isEmpty()  &&
680                     (rEntry.sSpellImplName == rSrvcImplName ||
681                         rEntry.sGrammarImplName == rSrvcImplName ||
682                         rEntry.sHyphImplName == rSrvcImplName ||
683                         rEntry.sThesImplName == rSrvcImplName))
684                 {
685                     rEntry.bConfigured = true;
686                     break;
687                 }
688             }
689         }
690     }
691 }
692 
AddRemove(Sequence<OUString> & rConfigured,const OUString & rImplName,bool bAdd)693 bool SvxLinguData_Impl::AddRemove(
694             Sequence< OUString > &rConfigured,
695             const OUString &rImplName, bool bAdd )
696 {
697     bool bRet = false;  // modified?
698 
699     sal_Int32 nEntries = rConfigured.getLength();
700     sal_Int32 nPos = lcl_SeqGetEntryPos(rConfigured, rImplName);
701     if (bAdd  &&  nPos < 0)         // add new entry
702     {
703         rConfigured.realloc( ++nEntries );
704         OUString *pConfigured = rConfigured.getArray();
705         pConfigured[nEntries - 1] = rImplName;
706         bRet = true;
707     }
708     else if (!bAdd  &&  nPos >= 0)  // remove existing entry
709     {
710         OUString *pConfigured = rConfigured.getArray();
711         for (sal_Int32 i = nPos;  i < nEntries - 1;  ++i)
712             pConfigured[i] = pConfigured[i + 1];
713         rConfigured.realloc(--nEntries);
714         bRet = true;
715     }
716 
717     return bRet;
718 }
719 
720 
Reconfigure(const OUString & rDisplayName,bool bEnable)721 void SvxLinguData_Impl::Reconfigure( const OUString &rDisplayName, bool bEnable )
722 {
723     DBG_ASSERT( !rDisplayName.isEmpty(), "empty DisplayName" );
724 
725     ServiceInfo_Impl *pInfo = nullptr;
726     for (sal_uInt32 i = 0;  i < nDisplayServices;  ++i)
727     {
728         ServiceInfo_Impl& rTmp = aDisplayServiceArr[i];
729         if (rTmp.sDisplayName == rDisplayName)
730         {
731             pInfo = &rTmp;
732             break;
733         }
734     }
735     DBG_ASSERT( pInfo, "DisplayName entry not found" );
736     if (pInfo)
737     {
738         pInfo->bConfigured = bEnable;
739 
740         Sequence< Locale > aLocales;
741         const Locale *pLocale = nullptr;
742         sal_Int32 nLocales = 0;
743         sal_Int32 i;
744 
745         // update configured spellchecker entries
746         if (pInfo->xSpell.is())
747         {
748             aLocales = pInfo->xSpell->getLocales();
749             pLocale = aLocales.getConstArray();
750             nLocales = aLocales.getLength();
751             for (i = 0;  i < nLocales;  ++i)
752             {
753                 LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] );
754                 if (!aCfgSpellTable.count( nLang ) && bEnable)
755                     aCfgSpellTable[ nLang ] = Sequence< OUString >();
756                 if (aCfgSpellTable.count( nLang ))
757                     AddRemove( aCfgSpellTable[ nLang ], pInfo->sSpellImplName, bEnable );
758             }
759         }
760 
761         // update configured grammar checker entries
762         if (pInfo->xGrammar.is())
763         {
764             aLocales = pInfo->xGrammar->getLocales();
765             pLocale = aLocales.getConstArray();
766             nLocales = aLocales.getLength();
767             for (i = 0;  i < nLocales;  ++i)
768             {
769                 LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] );
770                 if (!aCfgGrammarTable.count( nLang ) && bEnable)
771                     aCfgGrammarTable[ nLang ] = Sequence< OUString >();
772                 if (aCfgGrammarTable.count( nLang ))
773                     AddRemove( aCfgGrammarTable[ nLang ], pInfo->sGrammarImplName, bEnable );
774             }
775         }
776 
777         // update configured hyphenator entries
778         if (pInfo->xHyph.is())
779         {
780             aLocales = pInfo->xHyph->getLocales();
781             pLocale = aLocales.getConstArray();
782             nLocales = aLocales.getLength();
783             for (i = 0;  i < nLocales;  ++i)
784             {
785                 LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] );
786                 if (!aCfgHyphTable.count( nLang ) && bEnable)
787                     aCfgHyphTable[ nLang ] = Sequence< OUString >();
788                 if (aCfgHyphTable.count( nLang ))
789                     AddRemove( aCfgHyphTable[ nLang ], pInfo->sHyphImplName, bEnable );
790             }
791         }
792 
793         // update configured spellchecker entries
794         if (pInfo->xThes.is())
795         {
796             aLocales = pInfo->xThes->getLocales();
797             pLocale = aLocales.getConstArray();
798             nLocales = aLocales.getLength();
799             for (i = 0;  i < nLocales;  ++i)
800             {
801                 LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] );
802                 if (!aCfgThesTable.count( nLang ) && bEnable)
803                     aCfgThesTable[ nLang ] = Sequence< OUString >();
804                 if (aCfgThesTable.count( nLang ))
805                     AddRemove( aCfgThesTable[ nLang ], pInfo->sThesImplName, bEnable );
806             }
807         }
808     }
809 }
810 
811 
812 // class SvxLinguTabPage -------------------------------------------------
813 
SvxLinguTabPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rSet)814 SvxLinguTabPage::SvxLinguTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
815     : SfxTabPage(pPage, pController, "cui/ui/optlingupage.ui", "OptLinguPage", &rSet)
816     , sCapitalWords   (CuiResId(RID_SVXSTR_CAPITAL_WORDS))
817     , sWordsWithDigits(CuiResId(RID_SVXSTR_WORDS_WITH_DIGITS))
818     , sSpellSpecial   (CuiResId(RID_SVXSTR_SPELL_SPECIAL))
819     , sSpellAuto      (CuiResId(RID_SVXSTR_SPELL_AUTO))
820     , sGrammarAuto    (CuiResId(RID_SVXSTR_GRAMMAR_AUTO))
821     , sNumMinWordlen  (CuiResId(RID_SVXSTR_NUM_MIN_WORDLEN))
822     , sNumPreBreak    (CuiResId(RID_SVXSTR_NUM_PRE_BREAK))
823     , sNumPostBreak   (CuiResId(RID_SVXSTR_NUM_POST_BREAK))
824     , sHyphAuto       (CuiResId(RID_SVXSTR_HYPH_AUTO))
825     , sHyphSpecial    (CuiResId(RID_SVXSTR_HYPH_SPECIAL))
826     , nUPN_HYPH_MIN_WORD_LENGTH(-1)
827     , nUPN_HYPH_MIN_LEADING(-1)
828     , nUPN_HYPH_MIN_TRAILING(-1)
829     , m_nDlbClickEventId(nullptr)
830     , m_xLinguModulesFT(m_xBuilder->weld_label("lingumodulesft"))
831     , m_xLinguModulesCLB(m_xBuilder->weld_tree_view("lingumodules"))
832     , m_xLinguModulesEditPB(m_xBuilder->weld_button("lingumodulesedit"))
833     , m_xLinguDicsFT(m_xBuilder->weld_label("lingudictsft"))
834     , m_xLinguDicsCLB(m_xBuilder->weld_tree_view("lingudicts"))
835     , m_xLinguDicsNewPB(m_xBuilder->weld_button("lingudictsnew"))
836     , m_xLinguDicsEditPB(m_xBuilder->weld_button("lingudictsedit"))
837     , m_xLinguDicsDelPB(m_xBuilder->weld_button("lingudictsdelete"))
838     , m_xLinguOptionsCLB(m_xBuilder->weld_tree_view("linguoptions"))
839     , m_xLinguOptionsEditPB(m_xBuilder->weld_button("linguoptionsedit"))
840     , m_xMoreDictsLink(m_xBuilder->weld_link_button("moredictslink"))
841 {
842     std::vector<int> aWidths;
843     aWidths.push_back(m_xLinguModulesCLB->get_checkbox_column_width());
844 
845     m_xLinguModulesCLB->set_column_fixed_widths(aWidths);
846     m_xLinguDicsCLB->set_column_fixed_widths(aWidths);
847     m_xLinguOptionsCLB->set_column_fixed_widths(aWidths);
848 
849     m_xLinguModulesCLB->connect_changed( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
850     m_xLinguModulesCLB->connect_row_activated(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
851     m_xLinguModulesCLB->connect_toggled(LINK(this, SvxLinguTabPage, ModulesBoxCheckButtonHdl_Impl));
852 
853     m_xLinguModulesEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
854     m_xLinguOptionsEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
855 
856     m_xLinguDicsCLB->connect_changed( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
857     m_xLinguDicsCLB->connect_toggled(LINK(this, SvxLinguTabPage, DicsBoxCheckButtonHdl_Impl));
858 
859     m_xLinguDicsNewPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
860     m_xLinguDicsEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
861     m_xLinguDicsDelPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
862 
863     m_xLinguOptionsCLB->connect_changed( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
864     m_xLinguOptionsCLB->connect_row_activated(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
865 
866     if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode() == SvtExtendedSecurityOptions::OPEN_NEVER )
867         m_xMoreDictsLink->hide();
868 
869     xProp = LinguMgr::GetLinguPropertySet();
870     xDicList.set( LinguMgr::GetDictionaryList(), UNO_QUERY );
871     if (xDicList.is())
872     {
873         // keep references to all **currently** available dictionaries,
874         // since the diclist may get changed meanwhile (e.g. through the API).
875         // We want the dialog to operate on the same set of dictionaries it
876         // was started with.
877         // Also we have to take care to not lose the last reference when
878         // someone else removes a dictionary from the list.
879         // removed dics will be replaced by NULL new entries be added to the end
880         // Thus we may use indices as consistent references.
881         aDics = xDicList->getDictionaries();
882 
883         UpdateDicBox_Impl();
884     }
885     else
886     {
887         m_xLinguDicsFT->set_sensitive(false);
888         m_xLinguDicsCLB->set_sensitive(false);
889         m_xLinguDicsNewPB->set_sensitive(false);
890         m_xLinguDicsEditPB->set_sensitive(false);
891         m_xLinguDicsDelPB->set_sensitive(false);
892     }
893 }
894 
~SvxLinguTabPage()895 SvxLinguTabPage::~SvxLinguTabPage()
896 {
897     if (m_nDlbClickEventId)
898     {
899         Application::RemoveUserEvent(m_nDlbClickEventId);
900         m_nDlbClickEventId = nullptr;
901     }
902     pLinguData.reset();
903 }
904 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rAttrSet)905 std::unique_ptr<SfxTabPage> SvxLinguTabPage::Create( weld::Container* pPage, weld::DialogController* pController,
906                                             const SfxItemSet* rAttrSet )
907 {
908     return std::make_unique<SvxLinguTabPage>( pPage, pController, *rAttrSet );
909 }
910 
FillItemSet(SfxItemSet * rCoreSet)911 bool SvxLinguTabPage::FillItemSet( SfxItemSet* rCoreSet )
912 {
913     bool bModified = true; // !!!!
914 
915     // if not HideGroups was called with GROUP_MODULES...
916     if (m_xLinguModulesCLB->get_visible())
917     {
918         DBG_ASSERT( pLinguData, "pLinguData not yet initialized" );
919         if (!pLinguData)
920             pLinguData.reset( new SvxLinguData_Impl );
921 
922         // update spellchecker configuration entries
923         const LangImplNameTable *pTable = &pLinguData->GetSpellTable();
924         for (auto const& elem : *pTable)
925         {
926             LanguageType nLang = elem.first;
927             const Sequence< OUString > aImplNames(elem.second);
928             uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
929             Locale aLocale( LanguageTag::convertToLocale(nLang) );
930             if (xMgr.is())
931                 xMgr->setConfiguredServices( cSpell, aLocale, aImplNames );
932         }
933 
934         // update grammar checker configuration entries
935         pTable = &pLinguData->GetGrammarTable();
936         for (auto const& elem : *pTable)
937         {
938             LanguageType nLang = elem.first;
939             const Sequence< OUString > aImplNames(elem.second);
940             uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
941             Locale aLocale( LanguageTag::convertToLocale(nLang) );
942             if (xMgr.is())
943                 xMgr->setConfiguredServices( cGrammar, aLocale, aImplNames );
944         }
945 
946         // update hyphenator configuration entries
947         pTable = &pLinguData->GetHyphTable();
948         for (auto const& elem : *pTable)
949         {
950             LanguageType nLang = elem.first;
951             const Sequence< OUString > aImplNames(elem.second);
952             uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
953             Locale aLocale( LanguageTag::convertToLocale(nLang) );
954             if (xMgr.is())
955                 xMgr->setConfiguredServices( cHyph, aLocale, aImplNames );
956         }
957 
958         // update thesaurus configuration entries
959         pTable = &pLinguData->GetThesTable();
960         for (auto const& elem : *pTable)
961         {
962             LanguageType nLang = elem.first;
963             const Sequence< OUString > aImplNames(elem.second);
964             uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
965             Locale aLocale( LanguageTag::convertToLocale(nLang) );
966             if (xMgr.is())
967                 xMgr->setConfiguredServices( cThes, aLocale, aImplNames );
968         }
969     }
970 
971 
972     // activate dictionaries according to checkbox state
973 
974     Sequence< OUString > aActiveDics;
975     sal_Int32 nActiveDics = 0;
976     int nEntries = m_xLinguDicsCLB->n_children();
977     for (int i = 0; i < nEntries; ++i)
978     {
979         sal_Int32 nDics = aDics.getLength();
980 
981         aActiveDics.realloc( nDics );
982         OUString *pActiveDic = aActiveDics.getArray();
983 
984         DicUserData aData(m_xLinguDicsCLB->get_id(i).toUInt32());
985         if (aData.GetEntryId() < nDics)
986         {
987             bool bChecked = m_xLinguDicsCLB->get_toggle(i, 0) == TRISTATE_TRUE;
988             uno::Reference< XDictionary > xDic( aDics.getConstArray()[ i ] );
989             if (xDic.is())
990             {
991                 if (LinguMgr::GetIgnoreAllList() == xDic)
992                     bChecked = true;
993                 xDic->setActive( bChecked );
994 
995                 if (bChecked)
996                 {
997                     OUString aDicName( xDic->getName() );
998                     pActiveDic[ nActiveDics++ ] = aDicName;
999                 }
1000             }
1001         }
1002     }
1003 
1004     aActiveDics.realloc( nActiveDics );
1005     Any aTmp;
1006     aTmp <<= aActiveDics;
1007     SvtLinguConfig aLngCfg;
1008     aLngCfg.SetProperty( UPH_ACTIVE_DICTIONARIES, aTmp );
1009 
1010 
1011     nEntries = m_xLinguOptionsCLB->n_children();
1012     for (int j = 0; j < nEntries; ++j)
1013     {
1014         OptionsUserData aData(m_xLinguOptionsCLB->get_id(j).toUInt32());
1015         OUString aPropName( lcl_GetPropertyName( static_cast<EID_OPTIONS>(aData.GetEntryId()) ) );
1016 
1017         Any aAny;
1018         if (aData.IsCheckable())
1019         {
1020             bool bChecked = m_xLinguOptionsCLB->get_toggle(j, 0) == TRISTATE_TRUE;
1021             aAny <<= bChecked;
1022         }
1023         else if (aData.HasNumericValue())
1024         {
1025             sal_Int16 nVal = aData.GetNumericValue();
1026             aAny <<= nVal;
1027         }
1028 
1029         if (xProp.is())
1030             xProp->setPropertyValue( aPropName, aAny );
1031         aLngCfg.SetProperty( aPropName, aAny );
1032     }
1033 
1034     OptionsUserData aPreBreakData(m_xLinguOptionsCLB->get_id(EID_NUM_PRE_BREAK).toUInt32());
1035     OptionsUserData aPostBreakData(m_xLinguOptionsCLB->get_id(EID_NUM_POST_BREAK).toUInt32());
1036     if ( aPreBreakData.IsModified() || aPostBreakData.IsModified() )
1037     {
1038         SfxHyphenRegionItem aHyp( GetWhich( SID_ATTR_HYPHENREGION ) );
1039         aHyp.GetMinLead()  = static_cast<sal_uInt8>(aPreBreakData.GetNumericValue());
1040         aHyp.GetMinTrail() = static_cast<sal_uInt8>(aPostBreakData.GetNumericValue());
1041         rCoreSet->Put( aHyp );
1042     }
1043 
1044     // automatic spell checking
1045     bool bNewAutoCheck = m_xLinguOptionsCLB->get_toggle(EID_SPELL_AUTO, 0) == TRISTATE_TRUE;
1046     const SfxPoolItem* pOld = GetOldItem( *rCoreSet, SID_AUTOSPELL_CHECK );
1047     if ( !pOld || static_cast<const SfxBoolItem*>(pOld)->GetValue() != bNewAutoCheck )
1048     {
1049         rCoreSet->Put( SfxBoolItem( GetWhich( SID_AUTOSPELL_CHECK ),
1050                                 bNewAutoCheck ) );
1051         bModified = true;
1052     }
1053 
1054     return bModified;
1055 }
1056 
GetDicUserData(const uno::Reference<XDictionary> & rxDic,sal_uInt16 nIdx)1057 sal_uInt32 SvxLinguTabPage::GetDicUserData( const uno::Reference< XDictionary > &rxDic, sal_uInt16 nIdx )
1058 {
1059     sal_uInt32 nRes = 0;
1060     DBG_ASSERT( rxDic.is(), "dictionary not supplied" );
1061     if (rxDic.is())
1062     {
1063         uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
1064 
1065         bool bChecked = rxDic->isActive();
1066         bool bEditable = !xStor.is() || !xStor->isReadonly();
1067         bool bDeletable = bEditable;
1068 
1069         nRes = DicUserData( nIdx,
1070                 bChecked, bEditable, bDeletable ).GetUserData();
1071     }
1072     return nRes;
1073 }
1074 
1075 
AddDicBoxEntry(const uno::Reference<XDictionary> & rxDic,sal_uInt16 nIdx)1076 void SvxLinguTabPage::AddDicBoxEntry(
1077         const uno::Reference< XDictionary > &rxDic,
1078         sal_uInt16 nIdx )
1079 {
1080     m_xLinguDicsCLB->freeze();
1081 
1082     OUString aTxt( ::GetDicInfoStr( rxDic->getName(),
1083                         LanguageTag( rxDic->getLocale() ).getLanguageType(),
1084                         DictionaryType_NEGATIVE == rxDic->getDictionaryType() ) );
1085     m_xLinguDicsCLB->append();  // append at end
1086     int nEntry = m_xLinguDicsCLB->n_children() - 1;
1087     DicUserData aData( GetDicUserData( rxDic, nIdx ) );
1088     m_xLinguDicsCLB->set_id(nEntry, OUString::number(aData.GetUserData()));
1089     m_xLinguDicsCLB->set_toggle(nEntry, aData.IsChecked() ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1090     m_xLinguDicsCLB->set_text(nEntry, aTxt, 1);  // append at end
1091 
1092     m_xLinguDicsCLB->thaw();
1093 }
1094 
UpdateDicBox_Impl()1095 void SvxLinguTabPage::UpdateDicBox_Impl()
1096 {
1097     m_xLinguDicsCLB->freeze();
1098     m_xLinguDicsCLB->clear();
1099 
1100     sal_Int32 nDics  = aDics.getLength();
1101     const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
1102     for (sal_Int32 i = 0;  i < nDics;  ++i)
1103     {
1104         const uno::Reference< XDictionary > &rDic = pDic[i];
1105         if (rDic.is())
1106             AddDicBoxEntry( rDic, static_cast<sal_uInt16>(i) );
1107     }
1108 
1109     m_xLinguDicsCLB->thaw();
1110     if (m_xLinguDicsCLB->n_children())
1111     {
1112         m_xLinguDicsCLB->select(0);
1113         SelectHdl_Impl(*m_xLinguDicsCLB);
1114     }
1115 }
1116 
UpdateModulesBox_Impl()1117 void SvxLinguTabPage::UpdateModulesBox_Impl()
1118 {
1119     if (pLinguData)
1120     {
1121         const ServiceInfoArr &rAllDispSrvcArr = pLinguData->GetDisplayServiceArray();
1122         const sal_uInt32 nDispSrvcCount = pLinguData->GetDisplayServiceCount();
1123 
1124         m_xLinguModulesCLB->clear();
1125 
1126         for (sal_uInt32 i = 0;  i < nDispSrvcCount;  ++i)
1127         {
1128             const ServiceInfo_Impl &rInfo = rAllDispSrvcArr[i];
1129             m_xLinguModulesCLB->append();
1130             m_xLinguModulesCLB->set_id(i, OUString::number(reinterpret_cast<sal_Int64>(&rInfo)));
1131             m_xLinguModulesCLB->set_toggle(i, rInfo.bConfigured ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1132             m_xLinguModulesCLB->set_text(i, rInfo.sDisplayName, 1);
1133         }
1134         if (nDispSrvcCount)
1135         {
1136             m_xLinguModulesCLB->select(0);
1137             SelectHdl_Impl(*m_xLinguModulesCLB);
1138         }
1139         m_xLinguModulesEditPB->set_sensitive( nDispSrvcCount > 0 );
1140     }
1141 }
1142 
Reset(const SfxItemSet * rSet)1143 void SvxLinguTabPage::Reset( const SfxItemSet* rSet )
1144 {
1145     // if not HideGroups was called with GROUP_MODULES...
1146     if (m_xLinguModulesCLB->get_visible())
1147     {
1148         if (!pLinguData)
1149             pLinguData.reset( new SvxLinguData_Impl );
1150         UpdateModulesBox_Impl();
1151     }
1152 
1153 
1154     //  get data from configuration
1155     SvtLinguConfig aLngCfg;
1156 
1157     m_xLinguOptionsCLB->freeze();
1158     m_xLinguOptionsCLB->clear();
1159 
1160     sal_Int16 nVal = 0;
1161     bool  bVal  = false;
1162     sal_uInt32 nUserData = 0;
1163 
1164     m_xLinguOptionsCLB->append();
1165     int nEntry = 0;
1166 
1167     aLngCfg.GetProperty( UPN_IS_SPELL_AUTO ) >>= bVal;
1168     const SfxPoolItem* pItem = GetItem( *rSet, SID_AUTOSPELL_CHECK );
1169     if (pItem)
1170         bVal = static_cast<const SfxBoolItem *>(pItem)->GetValue();
1171     nUserData = OptionsUserData( EID_SPELL_AUTO, false, 0, true, bVal).GetUserData();
1172     m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1173     m_xLinguOptionsCLB->set_text(nEntry, sSpellAuto, 1);
1174     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1175 
1176     m_xLinguOptionsCLB->append();
1177     ++nEntry;
1178 
1179     aLngCfg.GetProperty( UPN_IS_GRAMMAR_AUTO ) >>= bVal;
1180     nUserData = OptionsUserData( EID_GRAMMAR_AUTO, false, 0, true, bVal).GetUserData();
1181     m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1182     m_xLinguOptionsCLB->set_text(nEntry, sGrammarAuto, 1);
1183     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1184 
1185     m_xLinguOptionsCLB->append();
1186     ++nEntry;
1187 
1188     aLngCfg.GetProperty( UPN_IS_SPELL_UPPER_CASE ) >>= bVal;
1189     nUserData = OptionsUserData( EID_CAPITAL_WORDS, false, 0, true, bVal).GetUserData();
1190     m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1191     m_xLinguOptionsCLB->set_text(nEntry, sCapitalWords, 1);
1192     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1193 
1194     m_xLinguOptionsCLB->append();
1195     ++nEntry;
1196 
1197     aLngCfg.GetProperty( UPN_IS_SPELL_WITH_DIGITS ) >>= bVal;
1198     nUserData = OptionsUserData( EID_WORDS_WITH_DIGITS, false, 0, true, bVal).GetUserData();
1199     m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1200     m_xLinguOptionsCLB->set_text(nEntry, sWordsWithDigits, 1);
1201     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1202 
1203     m_xLinguOptionsCLB->append();
1204     ++nEntry;
1205 
1206     aLngCfg.GetProperty( UPN_IS_SPELL_SPECIAL ) >>= bVal;
1207     nUserData = OptionsUserData( EID_SPELL_SPECIAL, false, 0, true, bVal).GetUserData();
1208     m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1209     m_xLinguOptionsCLB->set_text(nEntry, sSpellSpecial, 1);
1210     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1211 
1212     m_xLinguOptionsCLB->append();
1213     ++nEntry;
1214 
1215     aLngCfg.GetProperty( UPN_HYPH_MIN_WORD_LENGTH ) >>= nVal;
1216     nUserData = OptionsUserData( EID_NUM_MIN_WORDLEN, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
1217     m_xLinguOptionsCLB->set_text(nEntry, sNumMinWordlen + " " + OUString::number(nVal), 1);
1218     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1219     nUPN_HYPH_MIN_WORD_LENGTH = nEntry;
1220 
1221     const SfxHyphenRegionItem *pHyp = nullptr;
1222     sal_uInt16 nWhich = GetWhich( SID_ATTR_HYPHENREGION );
1223     if ( rSet->GetItemState( nWhich, false ) == SfxItemState::SET )
1224         pHyp = &static_cast<const SfxHyphenRegionItem &>( rSet->Get( nWhich ) );
1225 
1226     m_xLinguOptionsCLB->append();
1227     ++nEntry;
1228 
1229     aLngCfg.GetProperty( UPN_HYPH_MIN_LEADING ) >>= nVal;
1230     if (pHyp)
1231         nVal = static_cast<sal_Int16>(pHyp->GetMinLead());
1232     nUserData = OptionsUserData( EID_NUM_PRE_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
1233     m_xLinguOptionsCLB->set_text(nEntry, sNumPreBreak + " " + OUString::number(nVal), 1);
1234     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1235     nUPN_HYPH_MIN_LEADING = nEntry;
1236 
1237     m_xLinguOptionsCLB->append();
1238     ++nEntry;
1239 
1240     aLngCfg.GetProperty( UPN_HYPH_MIN_TRAILING ) >>= nVal;
1241     if (pHyp)
1242         nVal = static_cast<sal_Int16>(pHyp->GetMinTrail());
1243     nUserData = OptionsUserData( EID_NUM_POST_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
1244     m_xLinguOptionsCLB->set_text(nEntry, sNumPostBreak + " " + OUString::number(nVal), 1);
1245     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1246     nUPN_HYPH_MIN_TRAILING = nEntry;
1247 
1248     m_xLinguOptionsCLB->append();
1249     ++nEntry;
1250 
1251     aLngCfg.GetProperty( UPN_IS_HYPH_AUTO ) >>= bVal;
1252     nUserData = OptionsUserData( EID_HYPH_AUTO, false, 0, true, bVal).GetUserData();
1253     m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1254     m_xLinguOptionsCLB->set_text(nEntry, sHyphAuto, 1);
1255     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1256 
1257     m_xLinguOptionsCLB->append();
1258     ++nEntry;
1259 
1260     aLngCfg.GetProperty( UPN_IS_HYPH_SPECIAL ) >>= bVal;
1261     nUserData = OptionsUserData( EID_HYPH_SPECIAL, false, 0, true, bVal).GetUserData();
1262     m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1263     m_xLinguOptionsCLB->set_text(nEntry, sHyphSpecial, 1);
1264     m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1265 
1266     m_xLinguOptionsCLB->thaw();
1267 
1268     m_xLinguOptionsCLB->select(0);
1269     SelectHdl_Impl(*m_xLinguOptionsCLB);
1270 
1271     m_xLinguModulesCLB->set_size_request(m_xLinguModulesCLB->get_preferred_size().Width(),
1272                                          m_xLinguModulesCLB->get_height_rows(3));
1273     m_xLinguDicsCLB->set_size_request(m_xLinguDicsCLB->get_preferred_size().Width(),
1274                                       m_xLinguDicsCLB->get_height_rows(5));
1275     m_xLinguOptionsCLB->set_size_request(m_xLinguOptionsCLB->get_preferred_size().Width(),
1276                                          m_xLinguOptionsCLB->get_height_rows(5));
1277 }
1278 
IMPL_LINK(SvxLinguTabPage,BoxDoubleClickHdl_Impl,weld::TreeView &,rBox,bool)1279 IMPL_LINK(SvxLinguTabPage, BoxDoubleClickHdl_Impl, weld::TreeView&, rBox, bool)
1280 {
1281     if (&rBox == m_xLinguModulesCLB.get() && !m_nDlbClickEventId)
1282     {
1283         //! in order to avoid a bug causing a GPF when double clicking
1284         //! on a module entry and exiting the "Edit Modules" dialog
1285         //! after that.
1286         m_nDlbClickEventId = Application::PostUserEvent(LINK(this, SvxLinguTabPage, PostDblClickHdl_Impl));
1287     }
1288     else if (&rBox == m_xLinguOptionsCLB.get())
1289     {
1290         ClickHdl_Impl(*m_xLinguOptionsEditPB);
1291     }
1292     return true;
1293 }
1294 
IMPL_LINK_NOARG(SvxLinguTabPage,PostDblClickHdl_Impl,void *,void)1295 IMPL_LINK_NOARG(SvxLinguTabPage, PostDblClickHdl_Impl, void*, void)
1296 {
1297     m_nDlbClickEventId = nullptr;
1298     ClickHdl_Impl(*m_xLinguModulesEditPB);
1299 }
1300 
IMPL_LINK(SvxLinguTabPage,ModulesBoxCheckButtonHdl_Impl,const row_col &,rRowCol,void)1301 IMPL_LINK(SvxLinguTabPage, ModulesBoxCheckButtonHdl_Impl, const row_col&, rRowCol, void)
1302 {
1303     if (!pLinguData)
1304         return;
1305     auto nPos = rRowCol.first;
1306     pLinguData->Reconfigure(m_xLinguModulesCLB->get_text(nPos, 1),
1307                             m_xLinguModulesCLB->get_toggle(nPos, 0) == TRISTATE_TRUE);
1308 }
1309 
IMPL_LINK(SvxLinguTabPage,DicsBoxCheckButtonHdl_Impl,const row_col &,rRowCol,void)1310 IMPL_LINK(SvxLinguTabPage, DicsBoxCheckButtonHdl_Impl, const row_col&, rRowCol, void)
1311 {
1312     auto nPos = rRowCol.first;
1313     const uno::Reference<XDictionary> &rDic = aDics.getConstArray()[ nPos ];
1314     if (LinguMgr::GetIgnoreAllList() == rDic)
1315         m_xLinguDicsCLB->set_toggle(nPos, TRISTATE_TRUE, 0);
1316 }
1317 
IMPL_LINK(SvxLinguTabPage,ClickHdl_Impl,weld::Button &,rBtn,void)1318 IMPL_LINK(SvxLinguTabPage, ClickHdl_Impl, weld::Button&, rBtn, void)
1319 {
1320     if (m_xLinguModulesEditPB.get() == &rBtn)
1321     {
1322         if (!pLinguData)
1323             pLinguData.reset( new SvxLinguData_Impl );
1324 
1325         SvxLinguData_Impl   aOldLinguData( *pLinguData );
1326         SvxEditModulesDlg aDlg(GetFrameWeld(), *pLinguData);
1327         if (aDlg.run() != RET_OK)
1328             *pLinguData = aOldLinguData;
1329 
1330         // evaluate new status of 'bConfigured' flag
1331         sal_uInt32 nLen = pLinguData->GetDisplayServiceCount();
1332         for (sal_uInt32 i = 0;  i < nLen;  ++i)
1333             pLinguData->GetDisplayServiceArray()[i].bConfigured = false;
1334         const Locale* pAllLocales = pLinguData->GetAllSupportedLocales().getConstArray();
1335         sal_Int32 nLocales = pLinguData->GetAllSupportedLocales().getLength();
1336         for (sal_Int32 k = 0;  k < nLocales;  ++k)
1337         {
1338             LanguageType nLang = LanguageTag::convertToLanguageType( pAllLocales[k] );
1339             if (pLinguData->GetSpellTable().count( nLang ))
1340                 pLinguData->SetChecked( pLinguData->GetSpellTable()[ nLang ] );
1341             if (pLinguData->GetGrammarTable().count( nLang ))
1342                 pLinguData->SetChecked( pLinguData->GetGrammarTable()[ nLang ] );
1343             if (pLinguData->GetHyphTable().count( nLang ))
1344                 pLinguData->SetChecked( pLinguData->GetHyphTable()[ nLang ] );
1345             if (pLinguData->GetThesTable().count( nLang ))
1346                 pLinguData->SetChecked( pLinguData->GetThesTable()[ nLang ] );
1347         }
1348 
1349         // show new status of modules
1350         UpdateModulesBox_Impl();
1351     }
1352     else if (m_xLinguDicsNewPB.get() == &rBtn)
1353     {
1354         SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1355         ScopedVclPtr<AbstractSvxNewDictionaryDialog> aDlg(pFact->CreateSvxNewDictionaryDialog(GetFrameWeld()));
1356         uno::Reference< XDictionary >  xNewDic;
1357         if ( aDlg->Execute() == RET_OK )
1358             xNewDic = aDlg->GetNewDictionary();
1359         if ( xNewDic.is() )
1360         {
1361             // add new dics to the end
1362             sal_Int32 nLen = aDics.getLength();
1363             aDics.realloc( nLen + 1 );
1364 
1365             aDics.getArray()[ nLen ] = xNewDic;
1366 
1367             AddDicBoxEntry( xNewDic, static_cast<sal_uInt16>(nLen) );
1368         }
1369     }
1370     else if (m_xLinguDicsEditPB.get() == &rBtn)
1371     {
1372         int nEntry = m_xLinguDicsCLB->get_selected_index();
1373         if (nEntry != -1)
1374         {
1375             DicUserData aData(m_xLinguDicsCLB->get_id(nEntry).toUInt32());
1376             sal_uInt16 nDicPos = aData.GetEntryId();
1377             sal_Int32 nDics = aDics.getLength();
1378             if (nDicPos < nDics)
1379             {
1380                 uno::Reference< XDictionary > xDic = aDics.getConstArray()[ nDicPos ];
1381                 if (xDic.is())
1382                 {
1383                     SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1384                     ScopedVclPtr<VclAbstractDialog> aDlg(pFact->CreateSvxEditDictionaryDialog(GetFrameWeld(), xDic->getName()));
1385                     aDlg->Execute();
1386                 }
1387             }
1388         }
1389     }
1390     else if (m_xLinguDicsDelPB.get() == &rBtn)
1391     {
1392         std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "cui/ui/querydeletedictionarydialog.ui"));
1393         std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteDictionaryDialog"));
1394         if (RET_NO == xQuery->run())
1395             return;
1396 
1397         int nEntry = m_xLinguDicsCLB->get_selected_index();
1398         if (nEntry != -1)
1399         {
1400             DicUserData aData(m_xLinguDicsCLB->get_id(nEntry).toUInt32());
1401             sal_uInt16 nDicPos = aData.GetEntryId();
1402             sal_Int32 nDics = aDics.getLength();
1403             if (nDicPos < nDics)
1404             {
1405                 uno::Reference< XDictionary > xDic = aDics.getConstArray()[ nDicPos ];
1406                 if (xDic.is())
1407                 {
1408                     if (LinguMgr::GetIgnoreAllList() == xDic)
1409                         xDic->clear();
1410                     else
1411                     {
1412                         if (xDicList.is())
1413                             xDicList->removeDictionary( xDic );
1414 
1415                         uno::Reference< frame::XStorable > xStor( xDic, UNO_QUERY );
1416                         if ( xStor->hasLocation() && !xStor->isReadonly() )
1417                         {
1418                             OUString sURL = xStor->getLocation();
1419                             INetURLObject aObj(sURL);
1420                             DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File,
1421                                     "non-file URLs cannot be deleted" );
1422                             if ( aObj.GetProtocol() == INetProtocol::File )
1423                             {
1424                                 KillFile_Impl( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1425                             }
1426                         }
1427 
1428                         aDics.getArray()[ nDicPos ] = nullptr;
1429 
1430                         // remove entry from checklistbox
1431                         int nCnt = m_xLinguDicsCLB->n_children();
1432                         for (int i = 0;  i < nCnt;  ++i)
1433                         {
1434                             DicUserData aDicData(m_xLinguDicsCLB->get_id(i).toUInt32());
1435                             if (aDicData.GetEntryId() == nDicPos )
1436                             {
1437                                 m_xLinguDicsCLB->remove(i);
1438                                 break;
1439                             }
1440                         }
1441                         DBG_ASSERT( nCnt > m_xLinguDicsCLB->n_children(),
1442                                 "remove failed ?");
1443                     }
1444                 }
1445             }
1446         }
1447     }
1448     else if (m_xLinguOptionsEditPB.get() == &rBtn)
1449     {
1450         int nEntry = m_xLinguOptionsCLB->get_selected_index();
1451         DBG_ASSERT(nEntry != -1, "no entry selected");
1452         if (nEntry != -1)
1453         {
1454             OptionsUserData aData(m_xLinguOptionsCLB->get_id(nEntry).toUInt32());
1455             if (aData.HasNumericValue())
1456             {
1457                 sal_uInt16 nRID = aData.GetEntryId();
1458                 OptionsBreakSet aDlg(GetFrameWeld(), nRID);
1459                 aDlg.GetNumericFld().set_value(aData.GetNumericValue());
1460                 if (RET_OK == aDlg.run())
1461                 {
1462                     int nVal = aDlg.GetNumericFld().get_value();
1463                     if (-1 != nVal && aData.GetNumericValue() != nVal)
1464                     {
1465                         aData.SetNumericValue( static_cast<sal_uInt8>(nVal) ); //! sets IsModified !
1466                         m_xLinguOptionsCLB->set_id(nEntry, OUString::number(aData.GetUserData()));
1467                         if (nEntry == nUPN_HYPH_MIN_WORD_LENGTH)
1468                             m_xLinguOptionsCLB->set_text(nEntry, sNumMinWordlen + " " + OUString::number(nVal), 1);
1469                         else if (nEntry == nUPN_HYPH_MIN_LEADING)
1470                             m_xLinguOptionsCLB->set_text(nEntry, sNumPreBreak + " " + OUString::number(nVal), 1);
1471                         else if (nEntry == nUPN_HYPH_MIN_TRAILING)
1472                             m_xLinguOptionsCLB->set_text(nEntry, sNumPostBreak + " " + OUString::number(nVal), 1);
1473                         m_xLinguOptionsCLB->set_id(nEntry, OUString::number(aData.GetUserData()));
1474                     }
1475                 }
1476             }
1477         }
1478     }
1479     else
1480     {
1481         OSL_FAIL( "rBtn unexpected value" );
1482     }
1483 }
1484 
IMPL_LINK(SvxLinguTabPage,SelectHdl_Impl,weld::TreeView &,rBox,void)1485 IMPL_LINK(SvxLinguTabPage, SelectHdl_Impl, weld::TreeView&, rBox, void)
1486 {
1487     if (m_xLinguModulesCLB.get() == &rBox)
1488     {
1489     }
1490     else if (m_xLinguDicsCLB.get() == &rBox)
1491     {
1492         int nEntry = rBox.get_selected_index();
1493         if (nEntry != -1)
1494         {
1495             DicUserData aData(rBox.get_id(nEntry).toUInt32());
1496 
1497             // always allow to edit (i.e. at least view the content of the dictionary)
1498             m_xLinguDicsEditPB->set_sensitive( true );
1499             m_xLinguDicsDelPB->set_sensitive( aData.IsDeletable() );
1500         }
1501     }
1502     else if (m_xLinguOptionsCLB.get() == &rBox)
1503     {
1504         int nEntry = rBox.get_selected_index();
1505         if (nEntry != -1)
1506         {
1507             OptionsUserData aData(rBox.get_id(nEntry).toUInt32());
1508             m_xLinguOptionsEditPB->set_sensitive( aData.HasNumericValue() );
1509         }
1510     }
1511     else
1512     {
1513         OSL_FAIL( "rBox unexpected value" );
1514     }
1515 }
1516 
HideGroups(sal_uInt16 nGrp)1517 void SvxLinguTabPage::HideGroups( sal_uInt16 nGrp )
1518 {
1519     if ( 0 != ( GROUP_MODULES & nGrp ) )
1520     {
1521         m_xLinguModulesFT->hide();
1522         m_xLinguModulesCLB->hide();
1523         m_xLinguModulesEditPB->hide();
1524 
1525         if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode()
1526                 != SvtExtendedSecurityOptions::OPEN_NEVER )
1527         {
1528             m_xMoreDictsLink->show();
1529         }
1530     }
1531 }
1532 
SvxEditModulesDlg(weld::Window * pParent,SvxLinguData_Impl & rData)1533 SvxEditModulesDlg::SvxEditModulesDlg(weld::Window* pParent, SvxLinguData_Impl& rData)
1534     : GenericDialogController(pParent, "cui/ui/editmodulesdialog.ui", "EditModulesDialog")
1535     , sSpell(CuiResId(RID_SVXSTR_SPELL))
1536     , sHyph(CuiResId(RID_SVXSTR_HYPH))
1537     , sThes(CuiResId(RID_SVXSTR_THES))
1538     , sGrammar(CuiResId(RID_SVXSTR_GRAMMAR))
1539     , rLinguData(rData)
1540     , m_xModulesCLB(m_xBuilder->weld_tree_view("lingudicts"))
1541     , m_xPrioUpPB(m_xBuilder->weld_button("up"))
1542     , m_xPrioDownPB(m_xBuilder->weld_button("down"))
1543     , m_xBackPB(m_xBuilder->weld_button("back"))
1544     , m_xMoreDictsLink(m_xBuilder->weld_link_button("moredictslink"))
1545     , m_xClosePB(m_xBuilder->weld_button("close"))
1546     , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("language")))
1547 {
1548     m_xModulesCLB->set_size_request(m_xModulesCLB->get_approximate_digit_width() * 40,
1549                                     m_xModulesCLB->get_height_rows(12));
1550 
1551     std::vector<int> aWidths;
1552     aWidths.push_back(m_xModulesCLB->get_checkbox_column_width());
1553     m_xModulesCLB->set_column_fixed_widths(aWidths);
1554 
1555     pDefaultLinguData.reset( new SvxLinguData_Impl( rLinguData ) );
1556 
1557     m_xModulesCLB->connect_changed( LINK( this, SvxEditModulesDlg, SelectHdl_Impl ));
1558     m_xModulesCLB->connect_toggled(LINK(this, SvxEditModulesDlg, BoxCheckButtonHdl_Impl));
1559 
1560     m_xClosePB->connect_clicked( LINK( this, SvxEditModulesDlg, ClickHdl_Impl ));
1561     m_xPrioUpPB->connect_clicked( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
1562     m_xPrioDownPB->connect_clicked( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
1563     m_xBackPB->connect_clicked( LINK( this, SvxEditModulesDlg, BackHdl_Impl ));
1564     // in case of not installed language modules
1565     m_xPrioUpPB->set_sensitive( false );
1566     m_xPrioDownPB->set_sensitive( false );
1567 
1568     if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode() == SvtExtendedSecurityOptions::OPEN_NEVER )
1569         m_xMoreDictsLink->hide();
1570 
1571     // set that we want the checkbox shown if spellchecking is available
1572     m_xLanguageLB->SetLanguageList(SvxLanguageListFlags::EMPTY, false, false, true);
1573 
1574     //fill language box
1575     const Sequence< Locale >& rLoc = rLinguData.GetAllSupportedLocales();
1576     const Locale* pLocales = rLoc.getConstArray();
1577     for (int i = 0; i < rLoc.getLength(); ++i)
1578     {
1579         LanguageType nLang = LanguageTag::convertToLanguageType( pLocales[i] );
1580         m_xLanguageLB->InsertLanguage(nLang);
1581     }
1582     LanguageType eSysLang = MsLangId::getSystemLanguage();
1583     m_xLanguageLB->set_active_id( eSysLang );
1584     if (m_xLanguageLB->get_active_id() != eSysLang)
1585         m_xLanguageLB->set_active(0);
1586 
1587     m_xLanguageLB->connect_changed( LINK( this, SvxEditModulesDlg, LangSelectListBoxHdl_Impl ));
1588     LangSelectHdl_Impl(m_xLanguageLB.get());
1589 }
1590 
~SvxEditModulesDlg()1591 SvxEditModulesDlg::~SvxEditModulesDlg()
1592 {
1593     for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1594         delete reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i).toInt64());
1595 }
1596 
IMPL_LINK(SvxEditModulesDlg,SelectHdl_Impl,weld::TreeView &,rBox,void)1597 IMPL_LINK( SvxEditModulesDlg, SelectHdl_Impl, weld::TreeView&, rBox, void )
1598 {
1599     int nCurPos = rBox.get_selected_index();
1600     if (nCurPos != -1)
1601     {
1602         bool bDisableUp = true;
1603         bool bDisableDown = true;
1604         ModuleUserData_Impl* pData = reinterpret_cast<ModuleUserData_Impl*>(rBox.get_id(nCurPos).toInt64());
1605         if (!pData->IsParent() && pData->GetType() != TYPE_HYPH)
1606         {
1607             if (nCurPos < rBox.n_children() - 1)
1608             {
1609                 bDisableDown = reinterpret_cast<ModuleUserData_Impl*>(rBox.get_id(nCurPos + 1).toInt64())->IsParent();
1610             }
1611             if (nCurPos > 1)
1612             {
1613                 bDisableUp = reinterpret_cast<ModuleUserData_Impl*>(rBox.get_id(nCurPos - 1).toInt64())->IsParent();
1614             }
1615         }
1616         m_xPrioUpPB->set_sensitive(!bDisableUp);
1617         m_xPrioDownPB->set_sensitive(!bDisableDown);
1618     }
1619 }
1620 
IMPL_LINK(SvxEditModulesDlg,BoxCheckButtonHdl_Impl,const row_col &,rRowCol,void)1621 IMPL_LINK( SvxEditModulesDlg, BoxCheckButtonHdl_Impl, const row_col&, rRowCol, void )
1622 {
1623     auto nPos = rRowCol.first;
1624     ModuleUserData_Impl* pData = reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(nPos).toInt64());
1625     if (!pData->IsParent() && pData->GetType() == TYPE_HYPH)
1626     {
1627         // make hyphenator checkboxes function as radio-buttons
1628         // (at most one box may be checked)
1629         for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1630         {
1631             pData = reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i).toInt64());
1632             if (!pData->IsParent() && pData->GetType() == TYPE_HYPH && i != nPos)
1633             {
1634                 m_xModulesCLB->set_toggle(i, TRISTATE_FALSE, 0);
1635             }
1636         }
1637     }
1638 }
1639 
IMPL_LINK_NOARG(SvxEditModulesDlg,LangSelectListBoxHdl_Impl,weld::ComboBox &,void)1640 IMPL_LINK_NOARG(SvxEditModulesDlg, LangSelectListBoxHdl_Impl, weld::ComboBox&, void)
1641 {
1642     LangSelectHdl_Impl(m_xLanguageLB.get());
1643 }
1644 
LangSelectHdl_Impl(const SvxLanguageBox * pBox)1645 void SvxEditModulesDlg::LangSelectHdl_Impl(const SvxLanguageBox* pBox)
1646 {
1647     LanguageType  eCurLanguage = m_xLanguageLB->get_active_id();
1648     static Locale aLastLocale;
1649     Locale aCurLocale( LanguageTag::convertToLocale( eCurLanguage));
1650 
1651     if (pBox)
1652     {
1653         // save old probably changed settings
1654         // before switching to new language entries
1655 
1656         LanguageType nLang = LanguageTag::convertToLanguageType( aLastLocale );
1657 
1658         sal_Int32 nStart = 0, nLocalIndex = 0;
1659         Sequence< OUString > aChange;
1660         bool bChanged = false;
1661         for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1662         {
1663             ModuleUserData_Impl* pData = reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i).toInt64());
1664             if (pData->IsParent())
1665             {
1666                 if (bChanged)
1667                 {
1668                     LangImplNameTable *pTable = nullptr;
1669                     sal_uInt8 nType = pData->GetType();
1670                     switch (nType - 1)
1671                     {
1672                         case  TYPE_SPELL    : pTable = &rLinguData.GetSpellTable(); break;
1673                         case  TYPE_GRAMMAR  : pTable = &rLinguData.GetGrammarTable();  break;
1674                         case  TYPE_HYPH     : pTable = &rLinguData.GetHyphTable();  break;
1675                         case  TYPE_THES     : pTable = &rLinguData.GetThesTable();  break;
1676                     }
1677                     if (pTable)
1678                     {
1679                         aChange.realloc(nStart);
1680                         (*pTable)[ nLang ] = aChange;
1681                     }
1682                 }
1683                 nLocalIndex = nStart = 0;
1684                 aChange.realloc(nEntryCount);
1685                 bChanged = false;
1686             }
1687             else
1688             {
1689                 OUString* pChange = aChange.getArray();
1690                 pChange[nStart] = pData->GetImplName();
1691                 bChanged |= pData->GetIndex() != nLocalIndex ||
1692                     static_cast<TriState>(pData->IsChecked()) != m_xModulesCLB->get_toggle(i, 0);
1693                 if (m_xModulesCLB->get_toggle(i, 0))
1694                     nStart++;
1695                 ++nLocalIndex;
1696             }
1697         }
1698         if(bChanged)
1699         {
1700             aChange.realloc(nStart);
1701             rLinguData.GetThesTable()[ nLang ] = aChange;
1702         }
1703     }
1704 
1705     for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1706         delete reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i).toInt64());
1707     m_xModulesCLB->clear();
1708 
1709     // display entries for new selected language
1710 
1711     if (LANGUAGE_DONTKNOW != eCurLanguage)
1712     {
1713         sal_uLong n;
1714         ServiceInfo_Impl* pInfo;
1715 
1716         int nRow = 0;
1717         // spellchecker entries
1718 
1719         ModuleUserData_Impl* pUserData = new ModuleUserData_Impl(
1720                                          OUString(), true, false, TYPE_SPELL, 0 );
1721         OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pUserData)));
1722         m_xModulesCLB->append(nullptr);
1723         m_xModulesCLB->set_id(nRow, sId);
1724         m_xModulesCLB->set_text(nRow, sSpell, 1);
1725         m_xModulesCLB->set_text_emphasis(nRow, true, 1);
1726         ++nRow;
1727 
1728         Sequence< OUString > aNames( rLinguData.GetSortedImplNames( eCurLanguage, TYPE_SPELL ) );
1729         const OUString *pName = aNames.getConstArray();
1730         sal_uLong nNames = static_cast<sal_uLong>(aNames.getLength());
1731         sal_Int32 nLocalIndex = 0;  // index relative to parent
1732         for (n = 0;  n < nNames;  ++n)
1733         {
1734             OUString aImplName;
1735             bool     bIsSuppLang = false;
1736 
1737             pInfo = rLinguData.GetInfoByImplName( pName[n] );
1738             if (pInfo)
1739             {
1740                 bIsSuppLang = pInfo->xSpell.is()  &&
1741                               pInfo->xSpell->hasLocale( aCurLocale );
1742                 aImplName = pInfo->sSpellImplName;
1743             }
1744             if (!aImplName.isEmpty() && bIsSuppLang)
1745             {
1746                 OUString aTxt( pInfo->sDisplayName );
1747 
1748                 LangImplNameTable &rTable = rLinguData.GetSpellTable();
1749                 const bool bHasLang = rTable.count( eCurLanguage );
1750                 if (!bHasLang)
1751                 {
1752                     SAL_INFO( "cui.options", "language entry missing" );    // only relevant if all languages found should be supported
1753                 }
1754                 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1755                 pUserData = new ModuleUserData_Impl( aImplName, false,
1756                                         bCheck, TYPE_SPELL, static_cast<sal_uInt8>(nLocalIndex++) );
1757                 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1758 
1759                 m_xModulesCLB->append(nullptr);
1760                 m_xModulesCLB->set_id(nRow, sId);
1761                 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1762                 m_xModulesCLB->set_text(nRow, aTxt, 1);
1763                 ++nRow;
1764             }
1765         }
1766 
1767         // grammar checker entries
1768 
1769         pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_GRAMMAR, 0 );
1770         sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1771         m_xModulesCLB->append(nullptr);
1772         m_xModulesCLB->set_id(nRow, sId);
1773         m_xModulesCLB->set_text(nRow, sGrammar, 1);
1774         m_xModulesCLB->set_text_emphasis(nRow, true, 1);
1775         ++nRow;
1776 
1777         aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_GRAMMAR );
1778         pName = aNames.getConstArray();
1779         nNames = static_cast<sal_uLong>(aNames.getLength());
1780         nLocalIndex = 0;
1781         for (n = 0;  n < nNames;  ++n)
1782         {
1783             OUString aImplName;
1784             bool     bIsSuppLang = false;
1785 
1786             pInfo = rLinguData.GetInfoByImplName( pName[n] );
1787             if (pInfo)
1788             {
1789                 bIsSuppLang = pInfo->xGrammar.is()  &&
1790                               pInfo->xGrammar->hasLocale( aCurLocale );
1791                 aImplName = pInfo->sGrammarImplName;
1792             }
1793             if (!aImplName.isEmpty() && bIsSuppLang)
1794             {
1795                 OUString aTxt( pInfo->sDisplayName );
1796 
1797                 LangImplNameTable &rTable = rLinguData.GetGrammarTable();
1798                 const bool bHasLang = rTable.count( eCurLanguage );
1799                 if (!bHasLang)
1800                 {
1801                     SAL_INFO( "cui.options", "language entry missing" );    // only relevant if all languages found should be supported
1802                 }
1803                 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1804                 pUserData = new ModuleUserData_Impl( aImplName, false,
1805                                         bCheck, TYPE_GRAMMAR, static_cast<sal_uInt8>(nLocalIndex++) );
1806 
1807                 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1808 
1809                 m_xModulesCLB->append(nullptr);
1810                 m_xModulesCLB->set_id(nRow, sId);
1811                 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1812                 m_xModulesCLB->set_text(nRow, aTxt, 1);
1813                 ++nRow;
1814             }
1815         }
1816 
1817         // hyphenator entries
1818 
1819         pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_HYPH, 0 );
1820         sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1821         m_xModulesCLB->append(nullptr);
1822         m_xModulesCLB->set_id(nRow, sId);
1823         m_xModulesCLB->set_text(nRow, sHyph, 1);
1824         m_xModulesCLB->set_text_emphasis(nRow, true, 1);
1825         ++nRow;
1826 
1827         aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_HYPH );
1828         pName = aNames.getConstArray();
1829         nNames = static_cast<sal_uLong>(aNames.getLength());
1830         nLocalIndex = 0;
1831         for (n = 0;  n < nNames;  ++n)
1832         {
1833             OUString aImplName;
1834             bool     bIsSuppLang = false;
1835 
1836             pInfo = rLinguData.GetInfoByImplName( pName[n] );
1837             if (pInfo)
1838             {
1839                 bIsSuppLang = pInfo->xHyph.is()  &&
1840                               pInfo->xHyph->hasLocale( aCurLocale );
1841                 aImplName = pInfo->sHyphImplName;
1842             }
1843             if (!aImplName.isEmpty() && bIsSuppLang)
1844             {
1845                 OUString aTxt( pInfo->sDisplayName );
1846 
1847                 LangImplNameTable &rTable = rLinguData.GetHyphTable();
1848                 const bool bHasLang = rTable.count( eCurLanguage );
1849                 if (!bHasLang)
1850                 {
1851                     SAL_INFO( "cui.options", "language entry missing" );    // only relevant if all languages found should be supported
1852                 }
1853                 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1854                 pUserData = new ModuleUserData_Impl( aImplName, false,
1855                                         bCheck, TYPE_HYPH, static_cast<sal_uInt8>(nLocalIndex++) );
1856                 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1857 
1858                 m_xModulesCLB->append(nullptr);
1859                 m_xModulesCLB->set_id(nRow, sId);
1860                 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1861                 m_xModulesCLB->set_text(nRow, aTxt, 1);
1862                 ++nRow;
1863             }
1864         }
1865 
1866         // thesaurus entries
1867 
1868         pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_THES, 0 );
1869         sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1870         m_xModulesCLB->append(nullptr);
1871         m_xModulesCLB->set_id(nRow, sId);
1872         m_xModulesCLB->set_text(nRow, sThes, 1);
1873         m_xModulesCLB->set_text_emphasis(nRow, true, 1);
1874         ++nRow;
1875 
1876         aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_THES );
1877         pName = aNames.getConstArray();
1878         nNames = static_cast<sal_uLong>(aNames.getLength());
1879         nLocalIndex = 0;
1880         for (n = 0;  n < nNames;  ++n)
1881         {
1882             OUString aImplName;
1883             bool     bIsSuppLang = false;
1884 
1885             pInfo = rLinguData.GetInfoByImplName( pName[n] );
1886             if (pInfo)
1887             {
1888                 bIsSuppLang = pInfo->xThes.is()  &&
1889                               pInfo->xThes->hasLocale( aCurLocale );
1890                 aImplName = pInfo->sThesImplName;
1891             }
1892             if (!aImplName.isEmpty() && bIsSuppLang)
1893             {
1894                 OUString aTxt( pInfo->sDisplayName );
1895 
1896                 LangImplNameTable &rTable = rLinguData.GetThesTable();
1897                 const bool bHasLang = rTable.count( eCurLanguage );
1898                 if (!bHasLang)
1899                 {
1900                     SAL_INFO( "cui.options", "language entry missing" );    // only relevant if all languages found should be supported
1901                 }
1902                 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1903                 pUserData = new ModuleUserData_Impl( aImplName, false,
1904                                         bCheck, TYPE_THES, static_cast<sal_uInt8>(nLocalIndex++) );
1905                 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1906 
1907                 m_xModulesCLB->append(nullptr);
1908                 m_xModulesCLB->set_id(nRow, sId);
1909                 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1910                 m_xModulesCLB->set_text(nRow, aTxt, 1);
1911                 ++nRow;
1912             }
1913         }
1914     }
1915     aLastLocale = aCurLocale;
1916 }
1917 
IMPL_LINK(SvxEditModulesDlg,UpDownHdl_Impl,weld::Button &,rBtn,void)1918 IMPL_LINK( SvxEditModulesDlg, UpDownHdl_Impl, weld::Button&, rBtn, void )
1919 {
1920     bool bUp = m_xPrioUpPB.get() == &rBtn;
1921     int nCurPos = m_xModulesCLB->get_selected_index();
1922     if (nCurPos != -1)
1923     {
1924         m_xModulesCLB->freeze();
1925 
1926         OUString sId(m_xModulesCLB->get_id(nCurPos));
1927         OUString sStr(m_xModulesCLB->get_text(nCurPos));
1928         bool bIsChecked = m_xModulesCLB->get_toggle(nCurPos, nCurPos);
1929 
1930         m_xModulesCLB->remove(nCurPos);
1931 
1932         int nDestPos = bUp ? nCurPos - 1 : nCurPos + 1;
1933 
1934         m_xModulesCLB->insert_text(nDestPos, sStr);
1935         m_xModulesCLB->set_id(nDestPos, sId);
1936         m_xModulesCLB->set_toggle(nDestPos, bIsChecked ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1937 
1938         m_xModulesCLB->thaw();
1939 
1940         m_xModulesCLB->select(nDestPos);
1941         SelectHdl_Impl(*m_xModulesCLB);
1942     }
1943 }
1944 
IMPL_LINK_NOARG(SvxEditModulesDlg,ClickHdl_Impl,weld::Button &,void)1945 IMPL_LINK_NOARG(SvxEditModulesDlg, ClickHdl_Impl, weld::Button&, void)
1946 {
1947     // store language config
1948     LangSelectHdl_Impl(m_xLanguageLB.get());
1949     m_xDialog->response(RET_OK);
1950 }
1951 
IMPL_LINK_NOARG(SvxEditModulesDlg,BackHdl_Impl,weld::Button &,void)1952 IMPL_LINK_NOARG(SvxEditModulesDlg, BackHdl_Impl, weld::Button&, void)
1953 {
1954     rLinguData = *pDefaultLinguData;
1955     LangSelectHdl_Impl(nullptr);
1956 }
1957 
1958 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1959