Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / cui / source / options / optlingu.cxx
blob2026c73826a916150565445106bf8b997222047c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
49 #include <svx/svxdlg.hxx>
50 #include <editeng/optitems.hxx>
51 #include <optlingu.hxx>
52 #include <dialmgr.hxx>
53 #include <strings.hrc>
55 #include <ucbhelper/content.hxx>
57 #include <vector>
58 #include <map>
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;
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;
72 // static ----------------------------------------------------------------
74 static sal_Int32 lcl_SeqGetEntryPos(
75 const Sequence< OUString > &rSeq, const OUString &rEntry )
77 sal_Int32 i;
78 sal_Int32 nLen = rSeq.getLength();
79 const OUString *pItem = rSeq.getConstArray();
80 for (i = 0; i < nLen; ++i)
82 if (rEntry == pItem[i])
83 break;
85 return i < nLen ? i : -1;
88 static bool KillFile_Impl( const OUString& rURL )
90 bool bRet = true;
91 try
93 Content aCnt( rURL, uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
94 aCnt.executeCommand( "delete", Any( true ) );
96 catch( ... )
98 TOOLS_WARN_EXCEPTION( "cui.options", "KillFile" );
99 bRet = false;
102 return bRet;
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
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)
116 class ModuleUserData_Impl
118 bool bParent;
119 bool bIsChecked;
120 sal_uInt8 nType;
121 sal_uInt8 nIndex;
122 OUString sImplName;
124 public:
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)
133 bool IsParent() const {return bParent;}
134 sal_uInt8 GetType() const {return nType;}
135 bool IsChecked() const {return bIsChecked;}
136 sal_uInt8 GetIndex() const {return nIndex;}
137 const OUString& GetImplName() const {return sImplName;}
142 // User for user-dictionaries (XDictionary interface)
144 class DicUserData
146 sal_uInt32 nVal;
148 public:
149 explicit DicUserData(sal_uInt32 nUserData) : nVal( nUserData ) {}
150 DicUserData( sal_uInt16 nEID,
151 bool bChecked, bool bEditable, bool bDeletable );
153 sal_uInt32 GetUserData() const { return nVal; }
154 sal_uInt16 GetEntryId() const { return static_cast<sal_uInt16>(nVal >> 16); }
155 bool IsChecked() const { return static_cast<bool>((nVal >> 8) & 0x01); }
156 bool IsDeletable() const { return static_cast<bool>((nVal >> 10) & 0x01); }
160 DicUserData::DicUserData(
161 sal_uInt16 nEID,
162 bool bChecked, bool bEditable, bool bDeletable )
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);
171 /*--------------------------------------------------
172 Entry IDs for options listbox of dialog
173 --------------------------------------------------*/
175 enum EID_OPTIONS
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
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[] =
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
205 static OUString lcl_GetPropertyName( EID_OPTIONS eEntryId )
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) ] );
211 class OptionsBreakSet : public weld::GenericDialogController
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;
218 public:
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"))
225 assert(EID_NUM_PRE_BREAK == nRID || EID_NUM_POST_BREAK == nRID || EID_NUM_MIN_WORDLEN == nRID); //unexpected ID
227 if (nRID == EID_NUM_PRE_BREAK)
229 m_xBeforeFrame->show();
230 m_xBreakNF = m_xBuilder->weld_spin_button("beforebreak");
232 else if(nRID == EID_NUM_POST_BREAK)
234 m_xAfterFrame->show();
235 m_xBreakNF = m_xBuilder->weld_spin_button("afterbreak");
237 else if(nRID == EID_NUM_MIN_WORDLEN)
239 m_xMinimalFrame->show();
240 m_xBreakNF = m_xBuilder->weld_spin_button("wordlength");
244 weld::SpinButton& GetNumericFld()
246 return *m_xBreakNF;
250 // class OptionsUserData -------------------------------------------------
252 class OptionsUserData
254 sal_uInt32 nVal;
256 public:
257 explicit OptionsUserData( sal_uInt32 nUserData ) : nVal( nUserData ) {}
258 OptionsUserData( sal_uInt16 nEID,
259 bool bHasNV, sal_uInt16 nNumVal,
260 bool bCheckable, bool bChecked );
262 sal_uInt32 GetUserData() const { return nVal; }
263 sal_uInt16 GetEntryId() const { return static_cast<sal_uInt16>(nVal >> 16); }
264 bool HasNumericValue() const { return static_cast<bool>((nVal >> 10) & 0x01); }
265 sal_uInt16 GetNumericValue() const { return static_cast<sal_uInt16>(nVal & 0xFF); }
266 bool IsCheckable() const { return static_cast<bool>((nVal >> 9) & 0x01); }
267 bool IsModified() const { return static_cast<bool>((nVal >> 11) & 0x01); }
269 void SetNumericValue( sal_uInt8 nNumVal );
272 OptionsUserData::OptionsUserData( sal_uInt16 nEID,
273 bool bHasNV, sal_uInt16 nNumVal,
274 bool bCheckable, bool bChecked )
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);
285 void OptionsUserData::SetNumericValue( sal_uInt8 nNumVal )
287 if (HasNumericValue() && (GetNumericValue() != nNumVal))
289 nVal &= 0xffffff00;
290 nVal |= nNumVal;
291 nVal |= sal_uInt32(1) << 11; // mark as modified
295 // ServiceInfo_Impl ----------------------------------------------------
297 struct ServiceInfo_Impl
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;
310 ServiceInfo_Impl() : bConfigured(false) {}
313 typedef std::vector< ServiceInfo_Impl > ServiceInfoArr;
314 typedef std::map< LanguageType, Sequence< OUString > > LangImplNameTable;
317 // SvxLinguData_Impl ----------------------------------------------------
319 class SvxLinguData_Impl
321 //contains services and implementation names sorted by implementation names
322 ServiceInfoArr aDisplayServiceArr;
323 sal_uInt32 nDisplayServices;
325 Sequence< Locale > aAllServiceLocales;
326 LangImplNameTable aCfgSpellTable;
327 LangImplNameTable aCfgHyphTable;
328 LangImplNameTable aCfgThesTable;
329 LangImplNameTable aCfgGrammarTable;
330 uno::Reference< XLinguServiceManager2 > xLinguSrvcMgr;
333 static bool AddRemove( Sequence< OUString > &rConfigured,
334 const OUString &rImplName, bool bAdd );
336 public:
337 SvxLinguData_Impl();
339 uno::Reference<XLinguServiceManager2> & GetManager() { return xLinguSrvcMgr; }
341 void SetChecked( const Sequence< OUString > &rConfiguredServices );
342 void Reconfigure( const OUString &rDisplayName, bool bEnable );
344 const Sequence<Locale> & GetAllSupportedLocales() const { return aAllServiceLocales; }
346 LangImplNameTable & GetSpellTable() { return aCfgSpellTable; }
347 LangImplNameTable & GetHyphTable() { return aCfgHyphTable; }
348 LangImplNameTable & GetThesTable() { return aCfgThesTable; }
349 LangImplNameTable & GetGrammarTable() { return aCfgGrammarTable; }
351 ServiceInfoArr & GetDisplayServiceArray() { return aDisplayServiceArr; }
353 const sal_uInt32 & GetDisplayServiceCount() const { return nDisplayServices; }
354 void SetDisplayServiceCount( sal_uInt32 nVal ) { nDisplayServices = nVal; }
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 );
365 ServiceInfo_Impl * GetInfoByImplName( const OUString &rSvcImplName );
369 static sal_Int32 lcl_SeqGetIndex( const Sequence< OUString > &rSeq, const OUString &rTxt )
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)
376 if (pString[i] == rTxt)
377 nRes = i;
379 return nRes;
383 Sequence< OUString > SvxLinguData_Impl::GetSortedImplNames( LanguageType nLang, sal_uInt8 nType )
385 LangImplNameTable *pTable = nullptr;
386 switch (nType)
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;
393 Sequence< OUString > aRes;
394 if (!pTable)
396 SAL_WARN( "cui.options", "unknown linguistic type" );
397 return aRes;
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();
406 // add not configured services
407 for (sal_Int32 i = 0; i < static_cast<sal_Int32>(nDisplayServices); ++i)
409 const ServiceInfo_Impl &rInfo = aDisplayServiceArr[ i ];
410 OUString aImplName;
411 switch (nType)
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;
419 if (!aImplName.isEmpty() && (lcl_SeqGetIndex( aRes, aImplName) == -1)) // name not yet added
421 DBG_ASSERT( nIdx < aRes.getLength(), "index out of range" );
422 if (nIdx < aRes.getLength())
423 pRes[ nIdx++ ] = aImplName;
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;
434 ServiceInfo_Impl * SvxLinguData_Impl::GetInfoByImplName( const OUString &rSvcImplName )
436 for (sal_uInt32 i = 0; i < nDisplayServices; ++i)
438 ServiceInfo_Impl &rTmp = aDisplayServiceArr[ i ];
439 if (rTmp.sSpellImplName == rSvcImplName ||
440 rTmp.sHyphImplName == rSvcImplName ||
441 rTmp.sThesImplName == rSvcImplName ||
442 rTmp.sGrammarImplName == rSvcImplName)
444 return &rTmp;
447 return nullptr;
451 static void lcl_MergeLocales(Sequence< Locale >& aAllLocales, const Sequence< Locale >& rAdd)
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++)
461 bool bFound = false;
462 for(sal_Int32 j = 0; j < aAllLocales.getLength() && !bFound; j++)
464 bFound = pAdd[i].Language == pAllLocales[j].Language &&
465 pAdd[i].Country == pAllLocales[j].Country &&
466 pAdd[i].Variant == pAllLocales[j].Variant;
468 if(!bFound)
470 pLocToAdd[nFound++] = pAdd[i];
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];
480 static void lcl_MergeDisplayArray(
481 SvxLinguData_Impl &rData,
482 const ServiceInfo_Impl &rToAdd )
484 sal_uInt32 nCnt = 0;
486 ServiceInfoArr &rSvcInfoArr = rData.GetDisplayServiceArray();
487 sal_uInt32 nEntries = rData.GetDisplayServiceCount();
489 for (sal_uInt32 i = 0; i < nEntries; ++i)
491 ServiceInfo_Impl& rEntry = rSvcInfoArr[i];
492 if (rEntry.sDisplayName == rToAdd.sDisplayName)
494 if(rToAdd.xSpell.is())
496 DBG_ASSERT( !rEntry.xSpell.is() &&
497 rEntry.sSpellImplName.isEmpty(),
498 "merge conflict" );
499 rEntry.sSpellImplName = rToAdd.sSpellImplName;
500 rEntry.xSpell = rToAdd.xSpell;
502 if(rToAdd.xGrammar.is())
504 DBG_ASSERT( !rEntry.xGrammar.is() &&
505 rEntry.sGrammarImplName.isEmpty(),
506 "merge conflict" );
507 rEntry.sGrammarImplName = rToAdd.sGrammarImplName;
508 rEntry.xGrammar = rToAdd.xGrammar;
510 if(rToAdd.xHyph.is())
512 DBG_ASSERT( !rEntry.xHyph.is() &&
513 rEntry.sHyphImplName.isEmpty(),
514 "merge conflict" );
515 rEntry.sHyphImplName = rToAdd.sHyphImplName;
516 rEntry.xHyph = rToAdd.xHyph;
518 if(rToAdd.xThes.is())
520 DBG_ASSERT( !rEntry.xThes.is() &&
521 rEntry.sThesImplName.isEmpty(),
522 "merge conflict" );
523 rEntry.sThesImplName = rToAdd.sThesImplName;
524 rEntry.xThes = rToAdd.xThes;
526 return ;
528 ++nCnt;
530 rData.GetDisplayServiceArray().push_back( rToAdd );
531 rData.SetDisplayServiceCount( nCnt + 1 );
534 SvxLinguData_Impl::SvxLinguData_Impl() :
535 nDisplayServices (0)
537 uno::Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
538 xLinguSrvcMgr = LinguServiceManager::create(xContext);
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();
544 //read spell checker
545 Sequence< OUString > aSpellNames = xLinguSrvcMgr->getAvailableServices(
546 cSpell, Locale() );
547 const OUString* pSpellNames = aSpellNames.getConstArray();
549 sal_Int32 nIdx;
550 for(nIdx = 0; nIdx < aSpellNames.getLength(); nIdx++)
552 ServiceInfo_Impl aInfo;
553 aInfo.sSpellImplName = pSpellNames[nIdx];
554 aInfo.xSpell.set(
555 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sSpellImplName, aArgs, xContext), UNO_QUERY);
557 uno::Reference<XServiceDisplayName> xDispName(aInfo.xSpell, UNO_QUERY);
558 if(xDispName.is())
559 aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
561 const Sequence< Locale > aLocales( aInfo.xSpell->getLocales() );
562 //! suppress display of entries with no supported languages (see feature 110994)
563 if (aLocales.hasElements())
565 lcl_MergeLocales( aAllServiceLocales, aLocales );
566 lcl_MergeDisplayArray( *this, aInfo );
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++)
576 ServiceInfo_Impl aInfo;
577 aInfo.sGrammarImplName = pGrammarNames[nIdx];
578 aInfo.xGrammar.set(
579 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sGrammarImplName, aArgs, xContext), UNO_QUERY);
581 uno::Reference<XServiceDisplayName> xDispName(aInfo.xGrammar, UNO_QUERY);
582 if(xDispName.is())
583 aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
585 const Sequence< Locale > aLocales( aInfo.xGrammar->getLocales() );
586 //! suppress display of entries with no supported languages (see feature 110994)
587 if (aLocales.hasElements())
589 lcl_MergeLocales( aAllServiceLocales, aLocales );
590 lcl_MergeDisplayArray( *this, aInfo );
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++)
600 ServiceInfo_Impl aInfo;
601 aInfo.sHyphImplName = pHyphNames[nIdx];
602 aInfo.xHyph.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sHyphImplName, aArgs, xContext), UNO_QUERY);
604 uno::Reference<XServiceDisplayName> xDispName(aInfo.xHyph, UNO_QUERY);
605 if(xDispName.is())
606 aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
608 const Sequence< Locale > aLocales( aInfo.xHyph->getLocales() );
609 //! suppress display of entries with no supported languages (see feature 110994)
610 if (aLocales.hasElements())
612 lcl_MergeLocales( aAllServiceLocales, aLocales );
613 lcl_MergeDisplayArray( *this, aInfo );
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++)
623 ServiceInfo_Impl aInfo;
624 aInfo.sThesImplName = pThesNames[nIdx];
625 aInfo.xThes.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sThesImplName, aArgs, xContext), UNO_QUERY);
627 uno::Reference<XServiceDisplayName> xDispName(aInfo.xThes, UNO_QUERY);
628 if(xDispName.is())
629 aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
631 const Sequence< Locale > aLocales( aInfo.xThes->getLocales() );
632 //! suppress display of entries with no supported languages (see feature 110994)
633 if (aLocales.hasElements())
635 lcl_MergeLocales( aAllServiceLocales, aLocales );
636 lcl_MergeDisplayArray( *this, aInfo );
640 Sequence< OUString > aCfgSvcs;
641 const Locale* pAllLocales = aAllServiceLocales.getConstArray();
642 for(sal_Int32 nLocale = 0; nLocale < aAllServiceLocales.getLength(); nLocale++)
644 LanguageType nLang = LanguageTag::convertToLanguageType( pAllLocales[nLocale] );
646 aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cSpell, pAllLocales[nLocale]);
647 SetChecked( aCfgSvcs );
648 if (aCfgSvcs.hasElements())
649 aCfgSpellTable[ nLang ] = aCfgSvcs;
651 aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cGrammar, pAllLocales[nLocale]);
652 SetChecked( aCfgSvcs );
653 if (aCfgSvcs.hasElements())
654 aCfgGrammarTable[ nLang ] = aCfgSvcs;
656 aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cHyph, pAllLocales[nLocale]);
657 SetChecked( aCfgSvcs );
658 if (aCfgSvcs.hasElements())
659 aCfgHyphTable[ nLang ] = aCfgSvcs;
661 aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cThes, pAllLocales[nLocale]);
662 SetChecked( aCfgSvcs );
663 if (aCfgSvcs.hasElements())
664 aCfgThesTable[ nLang ] = aCfgSvcs;
668 void SvxLinguData_Impl::SetChecked(const Sequence<OUString>& rConfiguredServices)
670 const OUString* pConfiguredServices = rConfiguredServices.getConstArray();
671 for(sal_Int32 n = 0; n < rConfiguredServices.getLength(); n++)
673 for (sal_uInt32 i = 0; i < nDisplayServices; ++i)
675 ServiceInfo_Impl& rEntry = aDisplayServiceArr[i];
676 if (!rEntry.bConfigured)
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))
685 rEntry.bConfigured = true;
686 break;
693 bool SvxLinguData_Impl::AddRemove(
694 Sequence< OUString > &rConfigured,
695 const OUString &rImplName, bool bAdd )
697 bool bRet = false; // modified?
699 sal_Int32 nEntries = rConfigured.getLength();
700 sal_Int32 nPos = lcl_SeqGetEntryPos(rConfigured, rImplName);
701 if (bAdd && nPos < 0) // add new entry
703 rConfigured.realloc( ++nEntries );
704 OUString *pConfigured = rConfigured.getArray();
705 pConfigured[nEntries - 1] = rImplName;
706 bRet = true;
708 else if (!bAdd && nPos >= 0) // remove existing entry
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;
717 return bRet;
721 void SvxLinguData_Impl::Reconfigure( const OUString &rDisplayName, bool bEnable )
723 DBG_ASSERT( !rDisplayName.isEmpty(), "empty DisplayName" );
725 ServiceInfo_Impl *pInfo = nullptr;
726 for (sal_uInt32 i = 0; i < nDisplayServices; ++i)
728 ServiceInfo_Impl& rTmp = aDisplayServiceArr[i];
729 if (rTmp.sDisplayName == rDisplayName)
731 pInfo = &rTmp;
732 break;
735 DBG_ASSERT( pInfo, "DisplayName entry not found" );
736 if (pInfo)
738 pInfo->bConfigured = bEnable;
740 Sequence< Locale > aLocales;
741 const Locale *pLocale = nullptr;
742 sal_Int32 nLocales = 0;
743 sal_Int32 i;
745 // update configured spellchecker entries
746 if (pInfo->xSpell.is())
748 aLocales = pInfo->xSpell->getLocales();
749 pLocale = aLocales.getConstArray();
750 nLocales = aLocales.getLength();
751 for (i = 0; i < nLocales; ++i)
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 );
761 // update configured grammar checker entries
762 if (pInfo->xGrammar.is())
764 aLocales = pInfo->xGrammar->getLocales();
765 pLocale = aLocales.getConstArray();
766 nLocales = aLocales.getLength();
767 for (i = 0; i < nLocales; ++i)
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 );
777 // update configured hyphenator entries
778 if (pInfo->xHyph.is())
780 aLocales = pInfo->xHyph->getLocales();
781 pLocale = aLocales.getConstArray();
782 nLocales = aLocales.getLength();
783 for (i = 0; i < nLocales; ++i)
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 );
793 // update configured spellchecker entries
794 if (pInfo->xThes.is())
796 aLocales = pInfo->xThes->getLocales();
797 pLocale = aLocales.getConstArray();
798 nLocales = aLocales.getLength();
799 for (i = 0; i < nLocales; ++i)
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 );
812 // class SvxLinguTabPage -------------------------------------------------
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_xLinguModulesFT(m_xBuilder->weld_label("lingumodulesft"))
830 , m_xLinguModulesCLB(m_xBuilder->weld_tree_view("lingumodules"))
831 , m_xLinguModulesEditPB(m_xBuilder->weld_button("lingumodulesedit"))
832 , m_xLinguDicsFT(m_xBuilder->weld_label("lingudictsft"))
833 , m_xLinguDicsCLB(m_xBuilder->weld_tree_view("lingudicts"))
834 , m_xLinguDicsNewPB(m_xBuilder->weld_button("lingudictsnew"))
835 , m_xLinguDicsEditPB(m_xBuilder->weld_button("lingudictsedit"))
836 , m_xLinguDicsDelPB(m_xBuilder->weld_button("lingudictsdelete"))
837 , m_xLinguOptionsCLB(m_xBuilder->weld_tree_view("linguoptions"))
838 , m_xLinguOptionsEditPB(m_xBuilder->weld_button("linguoptionsedit"))
839 , m_xMoreDictsLink(m_xBuilder->weld_link_button("moredictslink"))
841 std::vector<int> aWidths;
842 aWidths.push_back(m_xLinguModulesCLB->get_checkbox_column_width());
844 m_xLinguModulesCLB->set_column_fixed_widths(aWidths);
845 m_xLinguDicsCLB->set_column_fixed_widths(aWidths);
846 m_xLinguOptionsCLB->set_column_fixed_widths(aWidths);
848 m_xLinguModulesCLB->connect_changed( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
849 m_xLinguModulesCLB->connect_row_activated(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
850 m_xLinguModulesCLB->connect_toggled(LINK(this, SvxLinguTabPage, ModulesBoxCheckButtonHdl_Impl));
852 m_xLinguModulesEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
853 m_xLinguOptionsEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
855 m_xLinguDicsCLB->connect_changed( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
856 m_xLinguDicsCLB->connect_toggled(LINK(this, SvxLinguTabPage, DicsBoxCheckButtonHdl_Impl));
858 m_xLinguDicsNewPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
859 m_xLinguDicsEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
860 m_xLinguDicsDelPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
862 m_xLinguOptionsCLB->connect_changed( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
863 m_xLinguOptionsCLB->connect_row_activated(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
865 if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode() == SvtExtendedSecurityOptions::OPEN_NEVER )
866 m_xMoreDictsLink->hide();
868 xProp = LinguMgr::GetLinguPropertySet();
869 xDicList.set( LinguMgr::GetDictionaryList(), UNO_QUERY );
870 if (xDicList.is())
872 // keep references to all **currently** available dictionaries,
873 // since the diclist may get changed meanwhile (e.g. through the API).
874 // We want the dialog to operate on the same set of dictionaries it
875 // was started with.
876 // Also we have to take care to not lose the last reference when
877 // someone else removes a dictionary from the list.
878 // removed dics will be replaced by NULL new entries be added to the end
879 // Thus we may use indices as consistent references.
880 aDics = xDicList->getDictionaries();
882 UpdateDicBox_Impl();
884 else
886 m_xLinguDicsFT->set_sensitive(false);
887 m_xLinguDicsCLB->set_sensitive(false);
888 m_xLinguDicsNewPB->set_sensitive(false);
889 m_xLinguDicsEditPB->set_sensitive(false);
890 m_xLinguDicsDelPB->set_sensitive(false);
894 SvxLinguTabPage::~SvxLinguTabPage()
896 pLinguData.reset();
899 std::unique_ptr<SfxTabPage> SvxLinguTabPage::Create( weld::Container* pPage, weld::DialogController* pController,
900 const SfxItemSet* rAttrSet )
902 return std::make_unique<SvxLinguTabPage>( pPage, pController, *rAttrSet );
905 bool SvxLinguTabPage::FillItemSet( SfxItemSet* rCoreSet )
907 bool bModified = true; // !!!!
909 // if not HideGroups was called with GROUP_MODULES...
910 if (m_xLinguModulesCLB->get_visible())
912 DBG_ASSERT( pLinguData, "pLinguData not yet initialized" );
913 if (!pLinguData)
914 pLinguData.reset( new SvxLinguData_Impl );
916 // update spellchecker configuration entries
917 const LangImplNameTable *pTable = &pLinguData->GetSpellTable();
918 for (auto const& elem : *pTable)
920 LanguageType nLang = elem.first;
921 const Sequence< OUString > aImplNames(elem.second);
922 uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
923 Locale aLocale( LanguageTag::convertToLocale(nLang) );
924 if (xMgr.is())
925 xMgr->setConfiguredServices( cSpell, aLocale, aImplNames );
928 // update grammar checker configuration entries
929 pTable = &pLinguData->GetGrammarTable();
930 for (auto const& elem : *pTable)
932 LanguageType nLang = elem.first;
933 const Sequence< OUString > aImplNames(elem.second);
934 uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
935 Locale aLocale( LanguageTag::convertToLocale(nLang) );
936 if (xMgr.is())
937 xMgr->setConfiguredServices( cGrammar, aLocale, aImplNames );
940 // update hyphenator configuration entries
941 pTable = &pLinguData->GetHyphTable();
942 for (auto const& elem : *pTable)
944 LanguageType nLang = elem.first;
945 const Sequence< OUString > aImplNames(elem.second);
946 uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
947 Locale aLocale( LanguageTag::convertToLocale(nLang) );
948 if (xMgr.is())
949 xMgr->setConfiguredServices( cHyph, aLocale, aImplNames );
952 // update thesaurus configuration entries
953 pTable = &pLinguData->GetThesTable();
954 for (auto const& elem : *pTable)
956 LanguageType nLang = elem.first;
957 const Sequence< OUString > aImplNames(elem.second);
958 uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
959 Locale aLocale( LanguageTag::convertToLocale(nLang) );
960 if (xMgr.is())
961 xMgr->setConfiguredServices( cThes, aLocale, aImplNames );
966 // activate dictionaries according to checkbox state
968 Sequence< OUString > aActiveDics;
969 sal_Int32 nActiveDics = 0;
970 int nEntries = m_xLinguDicsCLB->n_children();
971 for (int i = 0; i < nEntries; ++i)
973 sal_Int32 nDics = aDics.getLength();
975 aActiveDics.realloc( nDics );
976 OUString *pActiveDic = aActiveDics.getArray();
978 DicUserData aData(m_xLinguDicsCLB->get_id(i).toUInt32());
979 if (aData.GetEntryId() < nDics)
981 bool bChecked = m_xLinguDicsCLB->get_toggle(i, 0) == TRISTATE_TRUE;
982 uno::Reference< XDictionary > xDic( aDics.getConstArray()[ i ] );
983 if (xDic.is())
985 if (LinguMgr::GetIgnoreAllList() == xDic)
986 bChecked = true;
987 xDic->setActive( bChecked );
989 if (bChecked)
991 OUString aDicName( xDic->getName() );
992 pActiveDic[ nActiveDics++ ] = aDicName;
998 aActiveDics.realloc( nActiveDics );
999 Any aTmp;
1000 aTmp <<= aActiveDics;
1001 SvtLinguConfig aLngCfg;
1002 aLngCfg.SetProperty( UPH_ACTIVE_DICTIONARIES, aTmp );
1005 nEntries = m_xLinguOptionsCLB->n_children();
1006 for (int j = 0; j < nEntries; ++j)
1008 OptionsUserData aData(m_xLinguOptionsCLB->get_id(j).toUInt32());
1009 OUString aPropName( lcl_GetPropertyName( static_cast<EID_OPTIONS>(aData.GetEntryId()) ) );
1011 Any aAny;
1012 if (aData.IsCheckable())
1014 bool bChecked = m_xLinguOptionsCLB->get_toggle(j, 0) == TRISTATE_TRUE;
1015 aAny <<= bChecked;
1017 else if (aData.HasNumericValue())
1019 sal_Int16 nVal = aData.GetNumericValue();
1020 aAny <<= nVal;
1023 if (xProp.is())
1024 xProp->setPropertyValue( aPropName, aAny );
1025 aLngCfg.SetProperty( aPropName, aAny );
1028 OptionsUserData aPreBreakData(m_xLinguOptionsCLB->get_id(EID_NUM_PRE_BREAK).toUInt32());
1029 OptionsUserData aPostBreakData(m_xLinguOptionsCLB->get_id(EID_NUM_POST_BREAK).toUInt32());
1030 if ( aPreBreakData.IsModified() || aPostBreakData.IsModified() )
1032 SfxHyphenRegionItem aHyp( GetWhich( SID_ATTR_HYPHENREGION ) );
1033 aHyp.GetMinLead() = static_cast<sal_uInt8>(aPreBreakData.GetNumericValue());
1034 aHyp.GetMinTrail() = static_cast<sal_uInt8>(aPostBreakData.GetNumericValue());
1035 rCoreSet->Put( aHyp );
1038 // automatic spell checking
1039 bool bNewAutoCheck = m_xLinguOptionsCLB->get_toggle(EID_SPELL_AUTO, 0) == TRISTATE_TRUE;
1040 const SfxPoolItem* pOld = GetOldItem( *rCoreSet, SID_AUTOSPELL_CHECK );
1041 if ( !pOld || static_cast<const SfxBoolItem*>(pOld)->GetValue() != bNewAutoCheck )
1043 rCoreSet->Put( SfxBoolItem( GetWhich( SID_AUTOSPELL_CHECK ),
1044 bNewAutoCheck ) );
1045 bModified = true;
1048 return bModified;
1051 sal_uInt32 SvxLinguTabPage::GetDicUserData( const uno::Reference< XDictionary > &rxDic, sal_uInt16 nIdx )
1053 sal_uInt32 nRes = 0;
1054 DBG_ASSERT( rxDic.is(), "dictionary not supplied" );
1055 if (rxDic.is())
1057 uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
1059 bool bChecked = rxDic->isActive();
1060 bool bEditable = !xStor.is() || !xStor->isReadonly();
1061 bool bDeletable = bEditable;
1063 nRes = DicUserData( nIdx,
1064 bChecked, bEditable, bDeletable ).GetUserData();
1066 return nRes;
1070 void SvxLinguTabPage::AddDicBoxEntry(
1071 const uno::Reference< XDictionary > &rxDic,
1072 sal_uInt16 nIdx )
1074 m_xLinguDicsCLB->freeze();
1076 OUString aTxt( ::GetDicInfoStr( rxDic->getName(),
1077 LanguageTag( rxDic->getLocale() ).getLanguageType(),
1078 DictionaryType_NEGATIVE == rxDic->getDictionaryType() ) );
1079 m_xLinguDicsCLB->append(); // append at end
1080 int nEntry = m_xLinguDicsCLB->n_children() - 1;
1081 DicUserData aData( GetDicUserData( rxDic, nIdx ) );
1082 m_xLinguDicsCLB->set_id(nEntry, OUString::number(aData.GetUserData()));
1083 m_xLinguDicsCLB->set_toggle(nEntry, aData.IsChecked() ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1084 m_xLinguDicsCLB->set_text(nEntry, aTxt, 1); // append at end
1086 m_xLinguDicsCLB->thaw();
1089 void SvxLinguTabPage::UpdateDicBox_Impl()
1091 m_xLinguDicsCLB->freeze();
1092 m_xLinguDicsCLB->clear();
1094 sal_Int32 nDics = aDics.getLength();
1095 const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
1096 for (sal_Int32 i = 0; i < nDics; ++i)
1098 const uno::Reference< XDictionary > &rDic = pDic[i];
1099 if (rDic.is())
1100 AddDicBoxEntry( rDic, static_cast<sal_uInt16>(i) );
1103 m_xLinguDicsCLB->thaw();
1104 if (m_xLinguDicsCLB->n_children())
1106 m_xLinguDicsCLB->select(0);
1107 SelectHdl_Impl(*m_xLinguDicsCLB);
1111 void SvxLinguTabPage::UpdateModulesBox_Impl()
1113 if (pLinguData)
1115 const ServiceInfoArr &rAllDispSrvcArr = pLinguData->GetDisplayServiceArray();
1116 const sal_uInt32 nDispSrvcCount = pLinguData->GetDisplayServiceCount();
1118 m_xLinguModulesCLB->clear();
1120 for (sal_uInt32 i = 0; i < nDispSrvcCount; ++i)
1122 const ServiceInfo_Impl &rInfo = rAllDispSrvcArr[i];
1123 m_xLinguModulesCLB->append();
1124 m_xLinguModulesCLB->set_id(i, OUString::number(reinterpret_cast<sal_Int64>(&rInfo)));
1125 m_xLinguModulesCLB->set_toggle(i, rInfo.bConfigured ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1126 m_xLinguModulesCLB->set_text(i, rInfo.sDisplayName, 1);
1128 if (nDispSrvcCount)
1130 m_xLinguModulesCLB->select(0);
1131 SelectHdl_Impl(*m_xLinguModulesCLB);
1133 m_xLinguModulesEditPB->set_sensitive( nDispSrvcCount > 0 );
1137 void SvxLinguTabPage::Reset( const SfxItemSet* rSet )
1139 // if not HideGroups was called with GROUP_MODULES...
1140 if (m_xLinguModulesCLB->get_visible())
1142 if (!pLinguData)
1143 pLinguData.reset( new SvxLinguData_Impl );
1144 UpdateModulesBox_Impl();
1148 // get data from configuration
1149 SvtLinguConfig aLngCfg;
1151 m_xLinguOptionsCLB->freeze();
1152 m_xLinguOptionsCLB->clear();
1154 sal_Int16 nVal = 0;
1155 bool bVal = false;
1156 sal_uInt32 nUserData = 0;
1158 m_xLinguOptionsCLB->append();
1159 int nEntry = 0;
1161 aLngCfg.GetProperty( UPN_IS_SPELL_AUTO ) >>= bVal;
1162 const SfxPoolItem* pItem = GetItem( *rSet, SID_AUTOSPELL_CHECK );
1163 if (pItem)
1164 bVal = static_cast<const SfxBoolItem *>(pItem)->GetValue();
1165 nUserData = OptionsUserData( EID_SPELL_AUTO, false, 0, true, bVal).GetUserData();
1166 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1167 m_xLinguOptionsCLB->set_text(nEntry, sSpellAuto, 1);
1168 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1170 m_xLinguOptionsCLB->append();
1171 ++nEntry;
1173 aLngCfg.GetProperty( UPN_IS_GRAMMAR_AUTO ) >>= bVal;
1174 nUserData = OptionsUserData( EID_GRAMMAR_AUTO, false, 0, true, bVal).GetUserData();
1175 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1176 m_xLinguOptionsCLB->set_text(nEntry, sGrammarAuto, 1);
1177 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1179 m_xLinguOptionsCLB->append();
1180 ++nEntry;
1182 aLngCfg.GetProperty( UPN_IS_SPELL_UPPER_CASE ) >>= bVal;
1183 nUserData = OptionsUserData( EID_CAPITAL_WORDS, false, 0, true, bVal).GetUserData();
1184 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1185 m_xLinguOptionsCLB->set_text(nEntry, sCapitalWords, 1);
1186 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1188 m_xLinguOptionsCLB->append();
1189 ++nEntry;
1191 aLngCfg.GetProperty( UPN_IS_SPELL_WITH_DIGITS ) >>= bVal;
1192 nUserData = OptionsUserData( EID_WORDS_WITH_DIGITS, false, 0, true, bVal).GetUserData();
1193 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1194 m_xLinguOptionsCLB->set_text(nEntry, sWordsWithDigits, 1);
1195 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1197 m_xLinguOptionsCLB->append();
1198 ++nEntry;
1200 aLngCfg.GetProperty( UPN_IS_SPELL_SPECIAL ) >>= bVal;
1201 nUserData = OptionsUserData( EID_SPELL_SPECIAL, false, 0, true, bVal).GetUserData();
1202 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1203 m_xLinguOptionsCLB->set_text(nEntry, sSpellSpecial, 1);
1204 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1206 m_xLinguOptionsCLB->append();
1207 ++nEntry;
1209 aLngCfg.GetProperty( UPN_HYPH_MIN_WORD_LENGTH ) >>= nVal;
1210 nUserData = OptionsUserData( EID_NUM_MIN_WORDLEN, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
1211 m_xLinguOptionsCLB->set_text(nEntry, sNumMinWordlen + " " + OUString::number(nVal), 1);
1212 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1213 nUPN_HYPH_MIN_WORD_LENGTH = nEntry;
1215 const SfxHyphenRegionItem *pHyp = nullptr;
1216 sal_uInt16 nWhich = GetWhich( SID_ATTR_HYPHENREGION );
1217 if ( rSet->GetItemState( nWhich, false ) == SfxItemState::SET )
1218 pHyp = &static_cast<const SfxHyphenRegionItem &>( rSet->Get( nWhich ) );
1220 m_xLinguOptionsCLB->append();
1221 ++nEntry;
1223 aLngCfg.GetProperty( UPN_HYPH_MIN_LEADING ) >>= nVal;
1224 if (pHyp)
1225 nVal = static_cast<sal_Int16>(pHyp->GetMinLead());
1226 nUserData = OptionsUserData( EID_NUM_PRE_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
1227 m_xLinguOptionsCLB->set_text(nEntry, sNumPreBreak + " " + OUString::number(nVal), 1);
1228 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1229 nUPN_HYPH_MIN_LEADING = nEntry;
1231 m_xLinguOptionsCLB->append();
1232 ++nEntry;
1234 aLngCfg.GetProperty( UPN_HYPH_MIN_TRAILING ) >>= nVal;
1235 if (pHyp)
1236 nVal = static_cast<sal_Int16>(pHyp->GetMinTrail());
1237 nUserData = OptionsUserData( EID_NUM_POST_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
1238 m_xLinguOptionsCLB->set_text(nEntry, sNumPostBreak + " " + OUString::number(nVal), 1);
1239 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1240 nUPN_HYPH_MIN_TRAILING = nEntry;
1242 m_xLinguOptionsCLB->append();
1243 ++nEntry;
1245 aLngCfg.GetProperty( UPN_IS_HYPH_AUTO ) >>= bVal;
1246 nUserData = OptionsUserData( EID_HYPH_AUTO, false, 0, true, bVal).GetUserData();
1247 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1248 m_xLinguOptionsCLB->set_text(nEntry, sHyphAuto, 1);
1249 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1251 m_xLinguOptionsCLB->append();
1252 ++nEntry;
1254 aLngCfg.GetProperty( UPN_IS_HYPH_SPECIAL ) >>= bVal;
1255 nUserData = OptionsUserData( EID_HYPH_SPECIAL, false, 0, true, bVal).GetUserData();
1256 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1257 m_xLinguOptionsCLB->set_text(nEntry, sHyphSpecial, 1);
1258 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1260 m_xLinguOptionsCLB->thaw();
1262 m_xLinguOptionsCLB->select(0);
1263 SelectHdl_Impl(*m_xLinguOptionsCLB);
1265 m_xLinguModulesCLB->set_size_request(m_xLinguModulesCLB->get_preferred_size().Width(),
1266 m_xLinguModulesCLB->get_height_rows(3));
1267 m_xLinguDicsCLB->set_size_request(m_xLinguDicsCLB->get_preferred_size().Width(),
1268 m_xLinguDicsCLB->get_height_rows(5));
1269 m_xLinguOptionsCLB->set_size_request(m_xLinguOptionsCLB->get_preferred_size().Width(),
1270 m_xLinguOptionsCLB->get_height_rows(5));
1273 IMPL_LINK(SvxLinguTabPage, BoxDoubleClickHdl_Impl, weld::TreeView&, rBox, bool)
1275 if (&rBox == m_xLinguModulesCLB.get())
1277 //! in order to avoid a bug causing a GPF when double clicking
1278 //! on a module entry and exiting the "Edit Modules" dialog
1279 //! after that.
1280 Application::PostUserEvent( LINK(
1281 this, SvxLinguTabPage, PostDblClickHdl_Impl ), nullptr, true);
1283 else if (&rBox == m_xLinguOptionsCLB.get())
1285 ClickHdl_Impl(*m_xLinguOptionsEditPB);
1287 return true;
1290 IMPL_LINK_NOARG(SvxLinguTabPage, PostDblClickHdl_Impl, void*, void)
1292 ClickHdl_Impl(*m_xLinguModulesEditPB);
1295 IMPL_LINK(SvxLinguTabPage, ModulesBoxCheckButtonHdl_Impl, const row_col&, rRowCol, void)
1297 if (!pLinguData)
1298 return;
1299 auto nPos = rRowCol.first;
1300 pLinguData->Reconfigure(m_xLinguModulesCLB->get_text(nPos, 1),
1301 m_xLinguModulesCLB->get_toggle(nPos, 0) == TRISTATE_TRUE);
1304 IMPL_LINK(SvxLinguTabPage, DicsBoxCheckButtonHdl_Impl, const row_col&, rRowCol, void)
1306 auto nPos = rRowCol.first;
1307 const uno::Reference<XDictionary> &rDic = aDics.getConstArray()[ nPos ];
1308 if (LinguMgr::GetIgnoreAllList() == rDic)
1309 m_xLinguDicsCLB->set_toggle(nPos, TRISTATE_TRUE, 0);
1312 IMPL_LINK(SvxLinguTabPage, ClickHdl_Impl, weld::Button&, rBtn, void)
1314 if (m_xLinguModulesEditPB.get() == &rBtn)
1316 if (!pLinguData)
1317 pLinguData.reset( new SvxLinguData_Impl );
1319 SvxLinguData_Impl aOldLinguData( *pLinguData );
1320 SvxEditModulesDlg aDlg(GetFrameWeld(), *pLinguData);
1321 if (aDlg.run() != RET_OK)
1322 *pLinguData = aOldLinguData;
1324 // evaluate new status of 'bConfigured' flag
1325 sal_uInt32 nLen = pLinguData->GetDisplayServiceCount();
1326 for (sal_uInt32 i = 0; i < nLen; ++i)
1327 pLinguData->GetDisplayServiceArray()[i].bConfigured = false;
1328 const Locale* pAllLocales = pLinguData->GetAllSupportedLocales().getConstArray();
1329 sal_Int32 nLocales = pLinguData->GetAllSupportedLocales().getLength();
1330 for (sal_Int32 k = 0; k < nLocales; ++k)
1332 LanguageType nLang = LanguageTag::convertToLanguageType( pAllLocales[k] );
1333 if (pLinguData->GetSpellTable().count( nLang ))
1334 pLinguData->SetChecked( pLinguData->GetSpellTable()[ nLang ] );
1335 if (pLinguData->GetGrammarTable().count( nLang ))
1336 pLinguData->SetChecked( pLinguData->GetGrammarTable()[ nLang ] );
1337 if (pLinguData->GetHyphTable().count( nLang ))
1338 pLinguData->SetChecked( pLinguData->GetHyphTable()[ nLang ] );
1339 if (pLinguData->GetThesTable().count( nLang ))
1340 pLinguData->SetChecked( pLinguData->GetThesTable()[ nLang ] );
1343 // show new status of modules
1344 UpdateModulesBox_Impl();
1346 else if (m_xLinguDicsNewPB.get() == &rBtn)
1348 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1349 ScopedVclPtr<AbstractSvxNewDictionaryDialog> aDlg(pFact->CreateSvxNewDictionaryDialog(GetFrameWeld()));
1350 uno::Reference< XDictionary > xNewDic;
1351 if ( aDlg->Execute() == RET_OK )
1352 xNewDic = aDlg->GetNewDictionary();
1353 if ( xNewDic.is() )
1355 // add new dics to the end
1356 sal_Int32 nLen = aDics.getLength();
1357 aDics.realloc( nLen + 1 );
1359 aDics.getArray()[ nLen ] = xNewDic;
1361 AddDicBoxEntry( xNewDic, static_cast<sal_uInt16>(nLen) );
1364 else if (m_xLinguDicsEditPB.get() == &rBtn)
1366 int nEntry = m_xLinguDicsCLB->get_selected_index();
1367 if (nEntry != -1)
1369 DicUserData aData(m_xLinguDicsCLB->get_id(nEntry).toUInt32());
1370 sal_uInt16 nDicPos = aData.GetEntryId();
1371 sal_Int32 nDics = aDics.getLength();
1372 if (nDicPos < nDics)
1374 uno::Reference< XDictionary > xDic = aDics.getConstArray()[ nDicPos ];
1375 if (xDic.is())
1377 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1378 ScopedVclPtr<VclAbstractDialog> aDlg(pFact->CreateSvxEditDictionaryDialog(GetFrameWeld(), xDic->getName()));
1379 aDlg->Execute();
1384 else if (m_xLinguDicsDelPB.get() == &rBtn)
1386 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "cui/ui/querydeletedictionarydialog.ui"));
1387 std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteDictionaryDialog"));
1388 if (RET_NO == xQuery->run())
1389 return;
1391 int nEntry = m_xLinguDicsCLB->get_selected_index();
1392 if (nEntry != -1)
1394 DicUserData aData(m_xLinguDicsCLB->get_id(nEntry).toUInt32());
1395 sal_uInt16 nDicPos = aData.GetEntryId();
1396 sal_Int32 nDics = aDics.getLength();
1397 if (nDicPos < nDics)
1399 uno::Reference< XDictionary > xDic = aDics.getConstArray()[ nDicPos ];
1400 if (xDic.is())
1402 if (LinguMgr::GetIgnoreAllList() == xDic)
1403 xDic->clear();
1404 else
1406 if (xDicList.is())
1407 xDicList->removeDictionary( xDic );
1409 uno::Reference< frame::XStorable > xStor( xDic, UNO_QUERY );
1410 if ( xStor->hasLocation() && !xStor->isReadonly() )
1412 OUString sURL = xStor->getLocation();
1413 INetURLObject aObj(sURL);
1414 DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File,
1415 "non-file URLs cannot be deleted" );
1416 if ( aObj.GetProtocol() == INetProtocol::File )
1418 KillFile_Impl( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1422 aDics.getArray()[ nDicPos ] = nullptr;
1424 // remove entry from checklistbox
1425 int nCnt = m_xLinguDicsCLB->n_children();
1426 for (int i = 0; i < nCnt; ++i)
1428 DicUserData aDicData(m_xLinguDicsCLB->get_id(i).toUInt32());
1429 if (aDicData.GetEntryId() == nDicPos )
1431 m_xLinguDicsCLB->remove(i);
1432 break;
1435 DBG_ASSERT( nCnt > m_xLinguDicsCLB->n_children(),
1436 "remove failed ?");
1442 else if (m_xLinguOptionsEditPB.get() == &rBtn)
1444 int nEntry = m_xLinguOptionsCLB->get_selected_index();
1445 DBG_ASSERT(nEntry != -1, "no entry selected");
1446 if (nEntry != -1)
1448 OptionsUserData aData(m_xLinguOptionsCLB->get_id(nEntry).toUInt32());
1449 if (aData.HasNumericValue())
1451 sal_uInt16 nRID = aData.GetEntryId();
1452 OptionsBreakSet aDlg(GetFrameWeld(), nRID);
1453 aDlg.GetNumericFld().set_value(aData.GetNumericValue());
1454 if (RET_OK == aDlg.run())
1456 int nVal = aDlg.GetNumericFld().get_value();
1457 if (-1 != nVal && aData.GetNumericValue() != nVal)
1459 aData.SetNumericValue( static_cast<sal_uInt8>(nVal) ); //! sets IsModified !
1460 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(aData.GetUserData()));
1461 if (nEntry == nUPN_HYPH_MIN_WORD_LENGTH)
1462 m_xLinguOptionsCLB->set_text(nEntry, sNumMinWordlen + " " + OUString::number(nVal), 1);
1463 else if (nEntry == nUPN_HYPH_MIN_LEADING)
1464 m_xLinguOptionsCLB->set_text(nEntry, sNumPreBreak + " " + OUString::number(nVal), 1);
1465 else if (nEntry == nUPN_HYPH_MIN_TRAILING)
1466 m_xLinguOptionsCLB->set_text(nEntry, sNumPostBreak + " " + OUString::number(nVal), 1);
1467 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(aData.GetUserData()));
1473 else
1475 OSL_FAIL( "rBtn unexpected value" );
1479 IMPL_LINK(SvxLinguTabPage, SelectHdl_Impl, weld::TreeView&, rBox, void)
1481 if (m_xLinguModulesCLB.get() == &rBox)
1484 else if (m_xLinguDicsCLB.get() == &rBox)
1486 int nEntry = rBox.get_selected_index();
1487 if (nEntry != -1)
1489 DicUserData aData(rBox.get_id(nEntry).toUInt32());
1491 // always allow to edit (i.e. at least view the content of the dictionary)
1492 m_xLinguDicsEditPB->set_sensitive( true );
1493 m_xLinguDicsDelPB->set_sensitive( aData.IsDeletable() );
1496 else if (m_xLinguOptionsCLB.get() == &rBox)
1498 int nEntry = rBox.get_selected_index();
1499 if (nEntry != -1)
1501 OptionsUserData aData(rBox.get_id(nEntry).toUInt32());
1502 m_xLinguOptionsEditPB->set_sensitive( aData.HasNumericValue() );
1505 else
1507 OSL_FAIL( "rBox unexpected value" );
1511 void SvxLinguTabPage::HideGroups( sal_uInt16 nGrp )
1513 if ( 0 != ( GROUP_MODULES & nGrp ) )
1515 m_xLinguModulesFT->hide();
1516 m_xLinguModulesCLB->hide();
1517 m_xLinguModulesEditPB->hide();
1519 if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode()
1520 != SvtExtendedSecurityOptions::OPEN_NEVER )
1522 m_xMoreDictsLink->show();
1527 SvxEditModulesDlg::SvxEditModulesDlg(weld::Window* pParent, SvxLinguData_Impl& rData)
1528 : GenericDialogController(pParent, "cui/ui/editmodulesdialog.ui", "EditModulesDialog")
1529 , sSpell(CuiResId(RID_SVXSTR_SPELL))
1530 , sHyph(CuiResId(RID_SVXSTR_HYPH))
1531 , sThes(CuiResId(RID_SVXSTR_THES))
1532 , sGrammar(CuiResId(RID_SVXSTR_GRAMMAR))
1533 , rLinguData(rData)
1534 , m_xModulesCLB(m_xBuilder->weld_tree_view("lingudicts"))
1535 , m_xPrioUpPB(m_xBuilder->weld_button("up"))
1536 , m_xPrioDownPB(m_xBuilder->weld_button("down"))
1537 , m_xBackPB(m_xBuilder->weld_button("back"))
1538 , m_xMoreDictsLink(m_xBuilder->weld_link_button("moredictslink"))
1539 , m_xClosePB(m_xBuilder->weld_button("close"))
1540 , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("language")))
1542 m_xModulesCLB->set_size_request(m_xModulesCLB->get_approximate_digit_width() * 40,
1543 m_xModulesCLB->get_height_rows(12));
1545 std::vector<int> aWidths;
1546 aWidths.push_back(m_xModulesCLB->get_checkbox_column_width());
1547 m_xModulesCLB->set_column_fixed_widths(aWidths);
1549 pDefaultLinguData.reset( new SvxLinguData_Impl( rLinguData ) );
1551 m_xModulesCLB->connect_changed( LINK( this, SvxEditModulesDlg, SelectHdl_Impl ));
1552 m_xModulesCLB->connect_toggled(LINK(this, SvxEditModulesDlg, BoxCheckButtonHdl_Impl));
1554 m_xClosePB->connect_clicked( LINK( this, SvxEditModulesDlg, ClickHdl_Impl ));
1555 m_xPrioUpPB->connect_clicked( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
1556 m_xPrioDownPB->connect_clicked( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
1557 m_xBackPB->connect_clicked( LINK( this, SvxEditModulesDlg, BackHdl_Impl ));
1558 // in case of not installed language modules
1559 m_xPrioUpPB->set_sensitive( false );
1560 m_xPrioDownPB->set_sensitive( false );
1562 if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode() == SvtExtendedSecurityOptions::OPEN_NEVER )
1563 m_xMoreDictsLink->hide();
1565 // set that we want the checkbox shown if spellchecking is available
1566 m_xLanguageLB->SetLanguageList(SvxLanguageListFlags::EMPTY, false, false, true);
1568 //fill language box
1569 const Sequence< Locale >& rLoc = rLinguData.GetAllSupportedLocales();
1570 const Locale* pLocales = rLoc.getConstArray();
1571 for (int i = 0; i < rLoc.getLength(); ++i)
1573 LanguageType nLang = LanguageTag::convertToLanguageType( pLocales[i] );
1574 m_xLanguageLB->InsertLanguage(nLang);
1576 LanguageType eSysLang = MsLangId::getSystemLanguage();
1577 m_xLanguageLB->set_active_id( eSysLang );
1578 if (m_xLanguageLB->get_active_id() != eSysLang)
1579 m_xLanguageLB->set_active(0);
1581 m_xLanguageLB->connect_changed( LINK( this, SvxEditModulesDlg, LangSelectListBoxHdl_Impl ));
1582 LangSelectHdl_Impl(m_xLanguageLB.get());
1585 SvxEditModulesDlg::~SvxEditModulesDlg()
1587 for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1588 delete reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i).toInt64());
1591 IMPL_LINK( SvxEditModulesDlg, SelectHdl_Impl, weld::TreeView&, rBox, void )
1593 int nCurPos = rBox.get_selected_index();
1594 if (nCurPos != -1)
1596 bool bDisableUp = true;
1597 bool bDisableDown = true;
1598 ModuleUserData_Impl* pData = reinterpret_cast<ModuleUserData_Impl*>(rBox.get_id(nCurPos).toInt64());
1599 if (!pData->IsParent() && pData->GetType() != TYPE_HYPH)
1601 if (nCurPos < rBox.n_children() - 1)
1603 bDisableDown = reinterpret_cast<ModuleUserData_Impl*>(rBox.get_id(nCurPos + 1).toInt64())->IsParent();
1605 if (nCurPos > 1)
1607 bDisableUp = reinterpret_cast<ModuleUserData_Impl*>(rBox.get_id(nCurPos - 1).toInt64())->IsParent();
1610 m_xPrioUpPB->set_sensitive(!bDisableUp);
1611 m_xPrioDownPB->set_sensitive(!bDisableDown);
1615 IMPL_LINK( SvxEditModulesDlg, BoxCheckButtonHdl_Impl, const row_col&, rRowCol, void )
1617 auto nPos = rRowCol.first;
1618 ModuleUserData_Impl* pData = reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(nPos).toInt64());
1619 if (!pData->IsParent() && pData->GetType() == TYPE_HYPH)
1621 // make hyphenator checkboxes function as radio-buttons
1622 // (at most one box may be checked)
1623 for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1625 pData = reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i).toInt64());
1626 if (!pData->IsParent() && pData->GetType() == TYPE_HYPH && i != nPos)
1628 m_xModulesCLB->set_toggle(i, TRISTATE_FALSE, 0);
1634 IMPL_LINK_NOARG(SvxEditModulesDlg, LangSelectListBoxHdl_Impl, weld::ComboBox&, void)
1636 LangSelectHdl_Impl(m_xLanguageLB.get());
1639 void SvxEditModulesDlg::LangSelectHdl_Impl(const SvxLanguageBox* pBox)
1641 LanguageType eCurLanguage = m_xLanguageLB->get_active_id();
1642 static Locale aLastLocale;
1643 Locale aCurLocale( LanguageTag::convertToLocale( eCurLanguage));
1645 if (pBox)
1647 // save old probably changed settings
1648 // before switching to new language entries
1650 LanguageType nLang = LanguageTag::convertToLanguageType( aLastLocale );
1652 sal_Int32 nStart = 0, nLocalIndex = 0;
1653 Sequence< OUString > aChange;
1654 bool bChanged = false;
1655 for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1657 ModuleUserData_Impl* pData = reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i).toInt64());
1658 if (pData->IsParent())
1660 if (bChanged)
1662 LangImplNameTable *pTable = nullptr;
1663 sal_uInt8 nType = pData->GetType();
1664 switch (nType - 1)
1666 case TYPE_SPELL : pTable = &rLinguData.GetSpellTable(); break;
1667 case TYPE_GRAMMAR : pTable = &rLinguData.GetGrammarTable(); break;
1668 case TYPE_HYPH : pTable = &rLinguData.GetHyphTable(); break;
1669 case TYPE_THES : pTable = &rLinguData.GetThesTable(); break;
1671 if (pTable)
1673 aChange.realloc(nStart);
1674 (*pTable)[ nLang ] = aChange;
1677 nLocalIndex = nStart = 0;
1678 aChange.realloc(nEntryCount);
1679 bChanged = false;
1681 else
1683 OUString* pChange = aChange.getArray();
1684 pChange[nStart] = pData->GetImplName();
1685 bChanged |= pData->GetIndex() != nLocalIndex ||
1686 static_cast<TriState>(pData->IsChecked()) != m_xModulesCLB->get_toggle(i, 0);
1687 if (m_xModulesCLB->get_toggle(i, 0))
1688 nStart++;
1689 ++nLocalIndex;
1692 if(bChanged)
1694 aChange.realloc(nStart);
1695 rLinguData.GetThesTable()[ nLang ] = aChange;
1699 for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1700 delete reinterpret_cast<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i).toInt64());
1701 m_xModulesCLB->clear();
1703 // display entries for new selected language
1705 if (LANGUAGE_DONTKNOW != eCurLanguage)
1707 sal_uLong n;
1708 ServiceInfo_Impl* pInfo;
1710 int nRow = 0;
1711 // spellchecker entries
1713 ModuleUserData_Impl* pUserData = new ModuleUserData_Impl(
1714 OUString(), true, false, TYPE_SPELL, 0 );
1715 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pUserData)));
1716 m_xModulesCLB->append(nullptr);
1717 m_xModulesCLB->set_id(nRow, sId);
1718 m_xModulesCLB->set_text(nRow, sSpell, 1);
1719 m_xModulesCLB->set_text_emphasis(nRow, true, 1);
1720 ++nRow;
1722 Sequence< OUString > aNames( rLinguData.GetSortedImplNames( eCurLanguage, TYPE_SPELL ) );
1723 const OUString *pName = aNames.getConstArray();
1724 sal_uLong nNames = static_cast<sal_uLong>(aNames.getLength());
1725 sal_Int32 nLocalIndex = 0; // index relative to parent
1726 for (n = 0; n < nNames; ++n)
1728 OUString aImplName;
1729 bool bIsSuppLang = false;
1731 pInfo = rLinguData.GetInfoByImplName( pName[n] );
1732 if (pInfo)
1734 bIsSuppLang = pInfo->xSpell.is() &&
1735 pInfo->xSpell->hasLocale( aCurLocale );
1736 aImplName = pInfo->sSpellImplName;
1738 if (!aImplName.isEmpty() && bIsSuppLang)
1740 OUString aTxt( pInfo->sDisplayName );
1742 LangImplNameTable &rTable = rLinguData.GetSpellTable();
1743 const bool bHasLang = rTable.count( eCurLanguage );
1744 if (!bHasLang)
1746 SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
1748 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1749 pUserData = new ModuleUserData_Impl( aImplName, false,
1750 bCheck, TYPE_SPELL, static_cast<sal_uInt8>(nLocalIndex++) );
1751 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1753 m_xModulesCLB->append(nullptr);
1754 m_xModulesCLB->set_id(nRow, sId);
1755 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1756 m_xModulesCLB->set_text(nRow, aTxt, 1);
1757 ++nRow;
1761 // grammar checker entries
1763 pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_GRAMMAR, 0 );
1764 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1765 m_xModulesCLB->append(nullptr);
1766 m_xModulesCLB->set_id(nRow, sId);
1767 m_xModulesCLB->set_text(nRow, sGrammar, 1);
1768 m_xModulesCLB->set_text_emphasis(nRow, true, 1);
1769 ++nRow;
1771 aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_GRAMMAR );
1772 pName = aNames.getConstArray();
1773 nNames = static_cast<sal_uLong>(aNames.getLength());
1774 nLocalIndex = 0;
1775 for (n = 0; n < nNames; ++n)
1777 OUString aImplName;
1778 bool bIsSuppLang = false;
1780 pInfo = rLinguData.GetInfoByImplName( pName[n] );
1781 if (pInfo)
1783 bIsSuppLang = pInfo->xGrammar.is() &&
1784 pInfo->xGrammar->hasLocale( aCurLocale );
1785 aImplName = pInfo->sGrammarImplName;
1787 if (!aImplName.isEmpty() && bIsSuppLang)
1789 OUString aTxt( pInfo->sDisplayName );
1791 LangImplNameTable &rTable = rLinguData.GetGrammarTable();
1792 const bool bHasLang = rTable.count( eCurLanguage );
1793 if (!bHasLang)
1795 SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
1797 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1798 pUserData = new ModuleUserData_Impl( aImplName, false,
1799 bCheck, TYPE_GRAMMAR, static_cast<sal_uInt8>(nLocalIndex++) );
1801 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1803 m_xModulesCLB->append(nullptr);
1804 m_xModulesCLB->set_id(nRow, sId);
1805 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1806 m_xModulesCLB->set_text(nRow, aTxt, 1);
1807 ++nRow;
1811 // hyphenator entries
1813 pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_HYPH, 0 );
1814 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1815 m_xModulesCLB->append(nullptr);
1816 m_xModulesCLB->set_id(nRow, sId);
1817 m_xModulesCLB->set_text(nRow, sHyph, 1);
1818 m_xModulesCLB->set_text_emphasis(nRow, true, 1);
1819 ++nRow;
1821 aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_HYPH );
1822 pName = aNames.getConstArray();
1823 nNames = static_cast<sal_uLong>(aNames.getLength());
1824 nLocalIndex = 0;
1825 for (n = 0; n < nNames; ++n)
1827 OUString aImplName;
1828 bool bIsSuppLang = false;
1830 pInfo = rLinguData.GetInfoByImplName( pName[n] );
1831 if (pInfo)
1833 bIsSuppLang = pInfo->xHyph.is() &&
1834 pInfo->xHyph->hasLocale( aCurLocale );
1835 aImplName = pInfo->sHyphImplName;
1837 if (!aImplName.isEmpty() && bIsSuppLang)
1839 OUString aTxt( pInfo->sDisplayName );
1841 LangImplNameTable &rTable = rLinguData.GetHyphTable();
1842 const bool bHasLang = rTable.count( eCurLanguage );
1843 if (!bHasLang)
1845 SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
1847 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1848 pUserData = new ModuleUserData_Impl( aImplName, false,
1849 bCheck, TYPE_HYPH, static_cast<sal_uInt8>(nLocalIndex++) );
1850 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1852 m_xModulesCLB->append(nullptr);
1853 m_xModulesCLB->set_id(nRow, sId);
1854 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1855 m_xModulesCLB->set_text(nRow, aTxt, 1);
1856 ++nRow;
1860 // thesaurus entries
1862 pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_THES, 0 );
1863 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1864 m_xModulesCLB->append(nullptr);
1865 m_xModulesCLB->set_id(nRow, sId);
1866 m_xModulesCLB->set_text(nRow, sThes, 1);
1867 m_xModulesCLB->set_text_emphasis(nRow, true, 1);
1868 ++nRow;
1870 aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_THES );
1871 pName = aNames.getConstArray();
1872 nNames = static_cast<sal_uLong>(aNames.getLength());
1873 nLocalIndex = 0;
1874 for (n = 0; n < nNames; ++n)
1876 OUString aImplName;
1877 bool bIsSuppLang = false;
1879 pInfo = rLinguData.GetInfoByImplName( pName[n] );
1880 if (pInfo)
1882 bIsSuppLang = pInfo->xThes.is() &&
1883 pInfo->xThes->hasLocale( aCurLocale );
1884 aImplName = pInfo->sThesImplName;
1886 if (!aImplName.isEmpty() && bIsSuppLang)
1888 OUString aTxt( pInfo->sDisplayName );
1890 LangImplNameTable &rTable = rLinguData.GetThesTable();
1891 const bool bHasLang = rTable.count( eCurLanguage );
1892 if (!bHasLang)
1894 SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
1896 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1897 pUserData = new ModuleUserData_Impl( aImplName, false,
1898 bCheck, TYPE_THES, static_cast<sal_uInt8>(nLocalIndex++) );
1899 sId = OUString::number(reinterpret_cast<sal_Int64>(pUserData));
1901 m_xModulesCLB->append(nullptr);
1902 m_xModulesCLB->set_id(nRow, sId);
1903 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1904 m_xModulesCLB->set_text(nRow, aTxt, 1);
1905 ++nRow;
1909 aLastLocale = aCurLocale;
1912 IMPL_LINK( SvxEditModulesDlg, UpDownHdl_Impl, weld::Button&, rBtn, void )
1914 bool bUp = m_xPrioUpPB.get() == &rBtn;
1915 int nCurPos = m_xModulesCLB->get_selected_index();
1916 if (nCurPos != -1)
1918 m_xModulesCLB->freeze();
1920 OUString sId(m_xModulesCLB->get_id(nCurPos));
1921 OUString sStr(m_xModulesCLB->get_text(nCurPos));
1922 bool bIsChecked = m_xModulesCLB->get_toggle(nCurPos, nCurPos);
1924 m_xModulesCLB->remove(nCurPos);
1926 int nDestPos = bUp ? nCurPos - 1 : nCurPos + 1;
1928 m_xModulesCLB->insert_text(nDestPos, sStr);
1929 m_xModulesCLB->set_id(nDestPos, sId);
1930 m_xModulesCLB->set_toggle(nDestPos, bIsChecked ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
1932 m_xModulesCLB->thaw();
1934 m_xModulesCLB->select(nDestPos);
1935 SelectHdl_Impl(*m_xModulesCLB);
1939 IMPL_LINK_NOARG(SvxEditModulesDlg, ClickHdl_Impl, weld::Button&, void)
1941 // store language config
1942 LangSelectHdl_Impl(m_xLanguageLB.get());
1943 m_xDialog->response(RET_OK);
1946 IMPL_LINK_NOARG(SvxEditModulesDlg, BackHdl_Impl, weld::Button&, void)
1948 rLinguData = *pDefaultLinguData;
1949 LangSelectHdl_Impl(nullptr);
1952 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */