Use correct object
[LibreOffice.git] / cui / source / options / optlingu.cxx
blob2d6e77ffed078f0b1d678060ae1585d9e0773698
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 <utility>
21 #include <vcl/settings.hxx>
22 #include <vcl/weld.hxx>
23 #include <i18nlangtag/languagetag.hxx>
24 #include <i18nlangtag/mslangid.hxx>
25 #include <o3tl/safeint.hxx>
26 #include <officecfg/Office/Security.hxx>
27 #include <officecfg/Office/Linguistic.hxx>
28 #include <unotools/lingucfg.hxx>
29 #include <unotools/linguprops.hxx>
30 #include <editeng/unolingu.hxx>
31 #include <linguistic/misc.hxx>
32 #include <sfx2/sfxsids.hrc>
33 #include <tools/debug.hxx>
34 #include <tools/urlobj.hxx>
35 #include <comphelper/diagnose_ex.hxx>
36 #include <comphelper/dispatchcommand.hxx>
37 #include <comphelper/lok.hxx>
38 #include <comphelper/processfactory.hxx>
39 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
40 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
41 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
42 #include <com/sun/star/linguistic2/XProofreader.hpp>
43 #include <com/sun/star/linguistic2/XHyphenator.hpp>
44 #include <com/sun/star/linguistic2/XThesaurus.hpp>
45 #include <com/sun/star/linguistic2/XDictionary.hpp>
46 #include <com/sun/star/linguistic2/XDictionaryList.hpp>
47 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
48 #include <com/sun/star/lang/XServiceDisplayName.hpp>
49 #include <com/sun/star/frame/XStorable.hpp>
50 #include <com/sun/star/container/XNameAccess.hpp>
51 #include <com/sun/star/beans/PropertyAttribute.hpp>
52 #include <unotools/extendedsecurityoptions.hxx>
53 #include <svl/eitem.hxx>
54 #include <vcl/svapp.hxx>
55 #include <sal/log.hxx>
56 #include <osl/diagnose.h>
58 #include <svx/svxdlg.hxx>
59 #include <editeng/optitems.hxx>
60 #include <optlingu.hxx>
61 #include <dialmgr.hxx>
62 #include <strings.hrc>
64 #include <ucbhelper/content.hxx>
66 #include <set>
67 #include <vector>
68 #include <map>
70 using namespace ::ucbhelper;
71 using namespace ::com::sun::star;
72 using namespace css::lang;
73 using namespace css::uno;
74 using namespace css::linguistic2;
75 using namespace css::beans;
77 constexpr OUString cSpell(SN_SPELLCHECKER);
78 constexpr OUString cGrammar(SN_GRAMMARCHECKER);
79 constexpr OUString cHyph(SN_HYPHENATOR);
80 constexpr OUString cThes(SN_THESAURUS);
82 // static ----------------------------------------------------------------
84 static sal_Int32 lcl_SeqGetEntryPos(
85 const Sequence< OUString > &rSeq, std::u16string_view rEntry )
87 auto it = std::find(rSeq.begin(), rSeq.end(), rEntry);
88 return it == rSeq.end() ? -1 : std::distance(rSeq.begin(), it);
91 static bool KillFile_Impl( const OUString& rURL )
93 bool bRet = true;
94 try
96 Content aCnt( rURL, uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
97 aCnt.executeCommand( u"delete"_ustr, Any( true ) );
99 catch( ... )
101 TOOLS_WARN_EXCEPTION( "cui.options", "KillFile" );
102 bRet = false;
105 return bRet;
108 // 0x 0p 0t 0c nn
109 // p: 1 -> parent
110 // t: 1 -> spell, 2 -> hyph, 3 -> thes, 4 -> grammar
111 // c: 1 -> checked 0 -> unchecked
112 // n: index
114 #define TYPE_SPELL sal_uInt8(1)
115 #define TYPE_GRAMMAR sal_uInt8(2)
116 #define TYPE_HYPH sal_uInt8(3)
117 #define TYPE_THES sal_uInt8(4)
119 namespace {
121 class ModuleUserData_Impl
123 bool bParent;
124 bool bIsChecked;
125 sal_uInt8 nType;
126 sal_uInt8 nIndex;
127 OUString sImplName;
129 public:
130 ModuleUserData_Impl( OUString sImpName, bool bIsParent, bool bChecked, sal_uInt8 nSetType, sal_uInt8 nSetIndex ) :
131 bParent(bIsParent),
132 bIsChecked(bChecked),
133 nType(nSetType),
134 nIndex(nSetIndex),
135 sImplName(std::move(sImpName))
138 bool IsParent() const {return bParent;}
139 sal_uInt8 GetType() const {return nType;}
140 bool IsChecked() const {return bIsChecked;}
141 sal_uInt8 GetIndex() const {return nIndex;}
142 const OUString& GetImplName() const {return sImplName;}
147 // User for user-dictionaries (XDictionary interface)
149 class DicUserData
151 sal_uInt32 nVal;
153 public:
154 explicit DicUserData(sal_uInt32 nUserData) : nVal( nUserData ) {}
155 DicUserData( sal_uInt16 nEID,
156 bool bChecked, bool bEditable, bool bDeletable );
158 sal_uInt32 GetUserData() const { return nVal; }
159 sal_uInt16 GetEntryId() const { return static_cast<sal_uInt16>(nVal >> 16); }
160 bool IsChecked() const { return static_cast<bool>((nVal >> 8) & 0x01); }
161 bool IsDeletable() const { return static_cast<bool>((nVal >> 10) & 0x01); }
166 DicUserData::DicUserData(
167 sal_uInt16 nEID,
168 bool bChecked, bool bEditable, bool bDeletable )
170 DBG_ASSERT( nEID < 65000, "Entry Id out of range" );
171 nVal = (static_cast<sal_uInt32>(0xFFFF & nEID) << 16) |
172 (static_cast<sal_uInt32>(bChecked ? 1 : 0) << 8) |
173 (static_cast<sal_uInt32>(bEditable ? 1 : 0) << 9) |
174 (static_cast<sal_uInt32>(bDeletable ? 1 : 0) << 10);
177 /*--------------------------------------------------
178 Entry IDs for options listbox of dialog
179 --------------------------------------------------*/
181 namespace {
183 enum EID_OPTIONS
185 EID_SPELL_AUTO,
186 EID_GRAMMAR_AUTO,
187 EID_CAPITAL_WORDS,
188 EID_WORDS_WITH_DIGITS,
189 EID_SPELL_SPECIAL,
190 EID_NUM_MIN_WORDLEN,
191 EID_NUM_PRE_BREAK,
192 EID_NUM_POST_BREAK,
193 EID_HYPH_AUTO,
194 EID_HYPH_SPECIAL,
195 EID_SPELL_CLOSED_COMPOUND,
196 EID_SPELL_HYPHENATED_COMPOUND
201 static const OUString & lcl_GetPropertyName( EID_OPTIONS eEntryId )
203 switch (eEntryId)
205 case EID_SPELL_AUTO: return UPN_IS_SPELL_AUTO;
206 case EID_GRAMMAR_AUTO: return UPN_IS_GRAMMAR_AUTO;
207 case EID_CAPITAL_WORDS: return UPN_IS_SPELL_UPPER_CASE;
208 case EID_SPELL_CLOSED_COMPOUND: return UPN_IS_SPELL_CLOSED_COMPOUND;
209 case EID_SPELL_HYPHENATED_COMPOUND: return UPN_IS_SPELL_HYPHENATED_COMPOUND;
210 case EID_WORDS_WITH_DIGITS: return UPN_IS_SPELL_WITH_DIGITS;
211 case EID_SPELL_SPECIAL: return UPN_IS_SPELL_SPECIAL;
212 case EID_NUM_MIN_WORDLEN: return UPN_HYPH_MIN_WORD_LENGTH;
213 case EID_NUM_PRE_BREAK: return UPN_HYPH_MIN_LEADING;
214 case EID_NUM_POST_BREAK: return UPN_HYPH_MIN_TRAILING;
215 case EID_HYPH_AUTO: return UPN_IS_HYPH_AUTO;
216 case EID_HYPH_SPECIAL: return UPN_IS_HYPH_SPECIAL;
217 default: assert (false); abort();
221 namespace {
223 class OptionsBreakSet : public weld::GenericDialogController
225 std::unique_ptr<weld::Widget> m_xBeforeFrame;
226 std::unique_ptr<weld::Widget> m_xAfterFrame;
227 std::unique_ptr<weld::Widget> m_xMinimalFrame;
228 std::unique_ptr<weld::SpinButton> m_xBreakNF;
230 public:
231 OptionsBreakSet(weld::Window* pParent, sal_uInt16 nRID)
232 : GenericDialogController(pParent, u"cui/ui/breaknumberoption.ui"_ustr, u"BreakNumberOption"_ustr)
233 , m_xBeforeFrame(m_xBuilder->weld_widget(u"beforeframe"_ustr))
234 , m_xAfterFrame(m_xBuilder->weld_widget(u"afterframe"_ustr))
235 , m_xMinimalFrame(m_xBuilder->weld_widget(u"miniframe"_ustr))
237 assert(EID_NUM_PRE_BREAK == nRID || EID_NUM_POST_BREAK == nRID || EID_NUM_MIN_WORDLEN == nRID); //unexpected ID
239 if (nRID == EID_NUM_PRE_BREAK)
241 m_xBeforeFrame->show();
242 m_xBreakNF = m_xBuilder->weld_spin_button(u"beforebreak"_ustr);
244 else if(nRID == EID_NUM_POST_BREAK)
246 m_xAfterFrame->show();
247 m_xBreakNF = m_xBuilder->weld_spin_button(u"afterbreak"_ustr);
249 else if(nRID == EID_NUM_MIN_WORDLEN)
251 m_xMinimalFrame->show();
252 m_xBreakNF = m_xBuilder->weld_spin_button(u"wordlength"_ustr);
256 weld::SpinButton& GetNumericFld()
258 return *m_xBreakNF;
262 // class OptionsUserData -------------------------------------------------
264 class OptionsUserData
266 sal_uInt32 nVal;
268 public:
269 explicit OptionsUserData( sal_uInt32 nUserData ) : nVal( nUserData ) {}
270 OptionsUserData( sal_uInt16 nEID,
271 bool bHasNV, sal_uInt16 nNumVal,
272 bool bCheckable, bool bChecked );
274 sal_uInt32 GetUserData() const { return nVal; }
275 sal_uInt16 GetEntryId() const { return static_cast<sal_uInt16>(nVal >> 16); }
276 bool HasNumericValue() const { return static_cast<bool>((nVal >> 10) & 0x01); }
277 sal_uInt16 GetNumericValue() const { return static_cast<sal_uInt16>(nVal & 0xFF); }
278 bool IsCheckable() const { return static_cast<bool>((nVal >> 9) & 0x01); }
279 bool IsModified() const { return static_cast<bool>((nVal >> 11) & 0x01); }
281 void SetNumericValue( sal_uInt8 nNumVal );
286 OptionsUserData::OptionsUserData( sal_uInt16 nEID,
287 bool bHasNV, sal_uInt16 nNumVal,
288 bool bCheckable, bool bChecked )
290 DBG_ASSERT( nEID < 65000, "Entry Id out of range" );
291 DBG_ASSERT( nNumVal < 256, "value out of range" );
292 nVal = (static_cast<sal_uInt32>(0xFFFF & nEID) << 16) |
293 (static_cast<sal_uInt32>(bHasNV ? 1 : 0) << 10) |
294 (static_cast<sal_uInt32>(bCheckable ? 1 : 0) << 9) |
295 (static_cast<sal_uInt32>(bChecked ? 1 : 0) << 8) |
296 static_cast<sal_uInt32>(0xFF & nNumVal);
299 void OptionsUserData::SetNumericValue( sal_uInt8 nNumVal )
301 if (HasNumericValue() && (GetNumericValue() != nNumVal))
303 nVal &= 0xffffff00;
304 nVal |= nNumVal;
305 nVal |= sal_uInt32(1) << 11; // mark as modified
309 // ServiceInfo_Impl ----------------------------------------------------
311 namespace {
313 struct ServiceInfo_Impl
315 OUString sDisplayName;
316 OUString sSpellImplName;
317 OUString sHyphImplName;
318 OUString sThesImplName;
319 OUString sGrammarImplName;
320 uno::Reference< XSpellChecker > xSpell;
321 uno::Reference< XHyphenator > xHyph;
322 uno::Reference< XThesaurus > xThes;
323 uno::Reference< XProofreader > xGrammar;
324 bool bConfigured;
326 ServiceInfo_Impl() : bConfigured(false) {}
329 struct Locale_less
331 bool operator()(const css::lang::Locale& lhs, const css::lang::Locale& rhs) const
333 if (lhs.Language < rhs.Language)
334 return true;
335 if (lhs.Language > rhs.Language)
336 return false;
337 if (lhs.Country < rhs.Country)
338 return true;
339 if (lhs.Country > rhs.Country)
340 return false;
341 return lhs.Variant < rhs.Variant;
347 typedef std::vector< ServiceInfo_Impl > ServiceInfoArr;
348 typedef std::map< LanguageType, Sequence< OUString > > LangImplNameTable;
351 // SvxLinguData_Impl ----------------------------------------------------
353 class SvxLinguData_Impl
355 //contains services and implementation names sorted by implementation names
356 ServiceInfoArr aDisplayServiceArr;
357 sal_uInt32 nDisplayServices;
359 std::set<Locale, Locale_less> aAllServiceLocales;
360 LangImplNameTable aCfgSpellTable;
361 LangImplNameTable aCfgHyphTable;
362 LangImplNameTable aCfgThesTable;
363 LangImplNameTable aCfgGrammarTable;
364 uno::Reference< XLinguServiceManager2 > xLinguSrvcMgr;
367 static bool AddRemove( Sequence< OUString > &rConfigured,
368 const OUString &rImplName, bool bAdd );
370 public:
371 SvxLinguData_Impl();
373 uno::Reference<XLinguServiceManager2> & GetManager() { return xLinguSrvcMgr; }
375 void SetChecked( const Sequence< OUString > &rConfiguredServices );
376 void Reconfigure( std::u16string_view rDisplayName, bool bEnable );
378 const auto& GetAllSupportedLocales() const { return aAllServiceLocales; }
380 LangImplNameTable & GetSpellTable() { return aCfgSpellTable; }
381 LangImplNameTable & GetHyphTable() { return aCfgHyphTable; }
382 LangImplNameTable & GetThesTable() { return aCfgThesTable; }
383 LangImplNameTable & GetGrammarTable() { return aCfgGrammarTable; }
385 ServiceInfoArr & GetDisplayServiceArray() { return aDisplayServiceArr; }
387 const sal_uInt32 & GetDisplayServiceCount() const { return nDisplayServices; }
388 void SetDisplayServiceCount( sal_uInt32 nVal ) { nDisplayServices = nVal; }
390 // returns the list of service implementation names for the specified
391 // language and service (TYPE_SPELL, TYPE_HYPH, TYPE_THES) sorted in
392 // the proper order for the SvxEditModulesDlg (the ones from the
393 // configuration (keeping that order!) first and then the other ones.
394 // I.e. the ones available but not configured in arbitrary order).
395 // They available ones may contain names that do not(!) support that
396 // language.
397 Sequence< OUString > GetSortedImplNames( LanguageType nLang, sal_uInt8 nType );
399 ServiceInfo_Impl * GetInfoByImplName( std::u16string_view rSvcImplName );
403 Sequence< OUString > SvxLinguData_Impl::GetSortedImplNames( LanguageType nLang, sal_uInt8 nType )
405 LangImplNameTable *pTable = nullptr;
406 switch (nType)
408 case TYPE_SPELL : pTable = &aCfgSpellTable; break;
409 case TYPE_HYPH : pTable = &aCfgHyphTable; break;
410 case TYPE_THES : pTable = &aCfgThesTable; break;
411 case TYPE_GRAMMAR : pTable = &aCfgGrammarTable; break;
413 Sequence< OUString > aRes;
414 if (!pTable)
416 SAL_WARN( "cui.options", "unknown linguistic type" );
417 return aRes;
419 if (pTable->count( nLang ))
420 aRes = (*pTable)[ nLang ]; // add configured services
421 sal_Int32 nIdx = aRes.getLength();
422 DBG_ASSERT( nDisplayServices >= o3tl::make_unsigned(nIdx), "size mismatch" );
423 aRes.realloc( nDisplayServices );
424 OUString *pRes = aRes.getArray();
426 // add not configured services
427 for (sal_uInt32 i = 0; i < nDisplayServices; ++i)
429 const ServiceInfo_Impl &rInfo = aDisplayServiceArr[ i ];
430 OUString aImplName;
431 switch (nType)
433 case TYPE_SPELL : aImplName = rInfo.sSpellImplName; break;
434 case TYPE_HYPH : aImplName = rInfo.sHyphImplName; break;
435 case TYPE_THES : aImplName = rInfo.sThesImplName; break;
436 case TYPE_GRAMMAR : aImplName = rInfo.sGrammarImplName; break;
439 if (!aImplName.isEmpty() && (lcl_SeqGetEntryPos( aRes, aImplName) == -1)) // name not yet added
441 DBG_ASSERT( nIdx < aRes.getLength(), "index out of range" );
442 if (nIdx < aRes.getLength())
443 pRes[ nIdx++ ] = aImplName;
446 // don't forget to put aRes back to its actual size just in case you allocated too much
447 // since all of the names may have already been added
448 // otherwise you get duplicate entries in the edit dialog
449 aRes.realloc( nIdx );
450 return aRes;
454 ServiceInfo_Impl * SvxLinguData_Impl::GetInfoByImplName( std::u16string_view rSvcImplName )
456 for (sal_uInt32 i = 0; i < nDisplayServices; ++i)
458 ServiceInfo_Impl &rTmp = aDisplayServiceArr[ i ];
459 if (rTmp.sSpellImplName == rSvcImplName ||
460 rTmp.sHyphImplName == rSvcImplName ||
461 rTmp.sThesImplName == rSvcImplName ||
462 rTmp.sGrammarImplName == rSvcImplName)
464 return &rTmp;
467 return nullptr;
470 static void lcl_MergeDisplayArray(
471 SvxLinguData_Impl &rData,
472 const ServiceInfo_Impl &rToAdd )
474 sal_uInt32 nCnt = 0;
476 ServiceInfoArr &rSvcInfoArr = rData.GetDisplayServiceArray();
477 sal_uInt32 nEntries = rData.GetDisplayServiceCount();
479 for (sal_uInt32 i = 0; i < nEntries; ++i)
481 ServiceInfo_Impl& rEntry = rSvcInfoArr[i];
482 if (rEntry.sDisplayName == rToAdd.sDisplayName)
484 if(rToAdd.xSpell.is())
486 DBG_ASSERT( !rEntry.xSpell.is() &&
487 rEntry.sSpellImplName.isEmpty(),
488 "merge conflict" );
489 rEntry.sSpellImplName = rToAdd.sSpellImplName;
490 rEntry.xSpell = rToAdd.xSpell;
492 if(rToAdd.xGrammar.is())
494 DBG_ASSERT( !rEntry.xGrammar.is() &&
495 rEntry.sGrammarImplName.isEmpty(),
496 "merge conflict" );
497 rEntry.sGrammarImplName = rToAdd.sGrammarImplName;
498 rEntry.xGrammar = rToAdd.xGrammar;
500 if(rToAdd.xHyph.is())
502 DBG_ASSERT( !rEntry.xHyph.is() &&
503 rEntry.sHyphImplName.isEmpty(),
504 "merge conflict" );
505 rEntry.sHyphImplName = rToAdd.sHyphImplName;
506 rEntry.xHyph = rToAdd.xHyph;
508 if(rToAdd.xThes.is())
510 DBG_ASSERT( !rEntry.xThes.is() &&
511 rEntry.sThesImplName.isEmpty(),
512 "merge conflict" );
513 rEntry.sThesImplName = rToAdd.sThesImplName;
514 rEntry.xThes = rToAdd.xThes;
516 return ;
518 ++nCnt;
520 rData.GetDisplayServiceArray().push_back( rToAdd );
521 rData.SetDisplayServiceCount( nCnt + 1 );
524 SvxLinguData_Impl::SvxLinguData_Impl() :
525 nDisplayServices (0)
527 const uno::Reference< XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
528 xLinguSrvcMgr = LinguServiceManager::create(xContext);
530 const Locale& rCurrentLocale = Application::GetSettings().GetUILanguageTag().getLocale();
531 Sequence<Any> aArgs
533 Any(LinguMgr::GetLinguPropertySet()),
534 Any() // second argument has to be empty!
537 //read spell checker
538 const Sequence< OUString > aSpellNames = xLinguSrvcMgr->getAvailableServices(
539 cSpell, Locale() );
541 for(const OUString& spellName : aSpellNames)
543 ServiceInfo_Impl aInfo;
544 aInfo.sSpellImplName = spellName;
545 aInfo.xSpell.set(
546 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sSpellImplName, aArgs, xContext), UNO_QUERY);
548 uno::Reference<XServiceDisplayName> xDispName(aInfo.xSpell, UNO_QUERY);
549 if(xDispName.is())
550 aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
552 const Sequence< Locale > aLocales( aInfo.xSpell->getLocales() );
553 //! suppress display of entries with no supported languages (see feature 110994)
554 if (aLocales.hasElements())
556 aAllServiceLocales.insert(aLocales.begin(), aLocales.end());
557 lcl_MergeDisplayArray( *this, aInfo );
561 //read grammar checker
562 const Sequence< OUString > aGrammarNames = xLinguSrvcMgr->getAvailableServices(
563 cGrammar, Locale() );
564 for(const OUString& grammarName : aGrammarNames)
566 ServiceInfo_Impl aInfo;
567 aInfo.sGrammarImplName = grammarName;
568 aInfo.xGrammar.set(
569 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sGrammarImplName, aArgs, xContext), UNO_QUERY);
571 uno::Reference<XServiceDisplayName> xDispName(aInfo.xGrammar, UNO_QUERY);
572 if(xDispName.is())
573 aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
575 const Sequence< Locale > aLocales( aInfo.xGrammar->getLocales() );
576 //! suppress display of entries with no supported languages (see feature 110994)
577 if (aLocales.hasElements())
579 aAllServiceLocales.insert(aLocales.begin(), aLocales.end());
580 lcl_MergeDisplayArray( *this, aInfo );
584 //read hyphenator
585 const Sequence< OUString > aHyphNames = xLinguSrvcMgr->getAvailableServices(
586 cHyph, Locale() );
587 for(const OUString& hyphName : aHyphNames)
589 ServiceInfo_Impl aInfo;
590 aInfo.sHyphImplName = hyphName;
591 aInfo.xHyph.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sHyphImplName, aArgs, xContext), UNO_QUERY);
593 uno::Reference<XServiceDisplayName> xDispName(aInfo.xHyph, UNO_QUERY);
594 if(xDispName.is())
595 aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
597 const Sequence< Locale > aLocales( aInfo.xHyph->getLocales() );
598 //! suppress display of entries with no supported languages (see feature 110994)
599 if (aLocales.hasElements())
601 aAllServiceLocales.insert(aLocales.begin(), aLocales.end());
602 lcl_MergeDisplayArray( *this, aInfo );
606 //read thesauri
607 const Sequence< OUString > aThesNames = xLinguSrvcMgr->getAvailableServices(
608 cThes, Locale() );
609 for(const OUString& thesName : aThesNames)
611 ServiceInfo_Impl aInfo;
612 aInfo.sThesImplName = thesName;
613 aInfo.xThes.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sThesImplName, aArgs, xContext), UNO_QUERY);
615 uno::Reference<XServiceDisplayName> xDispName(aInfo.xThes, UNO_QUERY);
616 if(xDispName.is())
617 aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
619 const Sequence< Locale > aLocales( aInfo.xThes->getLocales() );
620 //! suppress display of entries with no supported languages (see feature 110994)
621 if (aLocales.hasElements())
623 aAllServiceLocales.insert(aLocales.begin(), aLocales.end());
624 lcl_MergeDisplayArray( *this, aInfo );
628 Sequence< OUString > aCfgSvcs;
629 for (auto const& locale : aAllServiceLocales)
631 LanguageType nLang = LanguageTag::convertToLanguageType( locale );
633 aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cSpell, locale);
634 SetChecked( aCfgSvcs );
635 if (aCfgSvcs.hasElements())
636 aCfgSpellTable[ nLang ] = aCfgSvcs;
638 aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cGrammar, locale);
639 SetChecked( aCfgSvcs );
640 if (aCfgSvcs.hasElements())
641 aCfgGrammarTable[ nLang ] = aCfgSvcs;
643 aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cHyph, locale);
644 SetChecked( aCfgSvcs );
645 if (aCfgSvcs.hasElements())
646 aCfgHyphTable[ nLang ] = aCfgSvcs;
648 aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cThes, locale);
649 SetChecked( aCfgSvcs );
650 if (aCfgSvcs.hasElements())
651 aCfgThesTable[ nLang ] = aCfgSvcs;
655 void SvxLinguData_Impl::SetChecked(const Sequence<OUString>& rConfiguredServices)
657 for(OUString const & configService : rConfiguredServices)
659 for (sal_uInt32 i = 0; i < nDisplayServices; ++i)
661 ServiceInfo_Impl& rEntry = aDisplayServiceArr[i];
662 if (!rEntry.bConfigured)
664 const OUString &rSrvcImplName = configService;
665 if (!rSrvcImplName.isEmpty() &&
666 (rEntry.sSpellImplName == rSrvcImplName ||
667 rEntry.sGrammarImplName == rSrvcImplName ||
668 rEntry.sHyphImplName == rSrvcImplName ||
669 rEntry.sThesImplName == rSrvcImplName))
671 rEntry.bConfigured = true;
672 break;
679 bool SvxLinguData_Impl::AddRemove(
680 Sequence< OUString > &rConfigured,
681 const OUString &rImplName, bool bAdd )
683 bool bRet = false; // modified?
685 sal_Int32 nEntries = rConfigured.getLength();
686 sal_Int32 nPos = lcl_SeqGetEntryPos(rConfigured, rImplName);
687 if (bAdd && nPos < 0) // add new entry
689 rConfigured.realloc( ++nEntries );
690 OUString *pConfigured = rConfigured.getArray();
691 pConfigured[nEntries - 1] = rImplName;
692 bRet = true;
694 else if (!bAdd && nPos >= 0) // remove existing entry
696 OUString *pConfigured = rConfigured.getArray();
697 for (sal_Int32 i = nPos; i < nEntries - 1; ++i)
698 pConfigured[i] = pConfigured[i + 1];
699 rConfigured.realloc(--nEntries);
700 bRet = true;
703 return bRet;
707 void SvxLinguData_Impl::Reconfigure( std::u16string_view rDisplayName, bool bEnable )
709 DBG_ASSERT( !rDisplayName.empty(), "empty DisplayName" );
711 ServiceInfo_Impl *pInfo = nullptr;
712 for (sal_uInt32 i = 0; i < nDisplayServices; ++i)
714 ServiceInfo_Impl& rTmp = aDisplayServiceArr[i];
715 if (rTmp.sDisplayName == rDisplayName)
717 pInfo = &rTmp;
718 break;
721 DBG_ASSERT( pInfo, "DisplayName entry not found" );
722 if (!pInfo)
723 return;
725 pInfo->bConfigured = bEnable;
727 // update configured spellchecker entries
728 if (pInfo->xSpell.is())
730 for (auto& locale : pInfo->xSpell->getLocales())
732 LanguageType nLang = LanguageTag::convertToLanguageType(locale);
733 if (!aCfgSpellTable.count( nLang ) && bEnable)
734 aCfgSpellTable[ nLang ] = Sequence< OUString >();
735 if (aCfgSpellTable.count( nLang ))
736 AddRemove( aCfgSpellTable[ nLang ], pInfo->sSpellImplName, bEnable );
740 // update configured grammar checker entries
741 if (pInfo->xGrammar.is())
743 for (auto& locale : pInfo->xGrammar->getLocales())
745 LanguageType nLang = LanguageTag::convertToLanguageType(locale);
746 if (!aCfgGrammarTable.count( nLang ) && bEnable)
747 aCfgGrammarTable[ nLang ] = Sequence< OUString >();
748 if (aCfgGrammarTable.count( nLang ))
749 AddRemove( aCfgGrammarTable[ nLang ], pInfo->sGrammarImplName, bEnable );
753 // update configured hyphenator entries
754 if (pInfo->xHyph.is())
756 for (auto& locale : pInfo->xHyph->getLocales())
758 LanguageType nLang = LanguageTag::convertToLanguageType(locale);
759 if (!aCfgHyphTable.count( nLang ) && bEnable)
760 aCfgHyphTable[ nLang ] = Sequence< OUString >();
761 if (aCfgHyphTable.count( nLang ))
762 AddRemove( aCfgHyphTable[ nLang ], pInfo->sHyphImplName, bEnable );
766 // update configured spellchecker entries
767 if (!pInfo->xThes.is())
768 return;
770 for (auto& locale : pInfo->xThes->getLocales())
772 LanguageType nLang = LanguageTag::convertToLanguageType(locale);
773 if (!aCfgThesTable.count( nLang ) && bEnable)
774 aCfgThesTable[ nLang ] = Sequence< OUString >();
775 if (aCfgThesTable.count( nLang ))
776 AddRemove( aCfgThesTable[ nLang ], pInfo->sThesImplName, bEnable );
781 // class SvxLinguTabPage -------------------------------------------------
783 SvxLinguTabPage::SvxLinguTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
784 : SfxTabPage(pPage, pController, u"cui/ui/optlingupage.ui"_ustr, u"OptLinguPage"_ustr, &rSet)
785 , sCapitalWords (CuiResId(RID_CUISTR_CAPITAL_WORDS))
786 , sWordsWithDigits(CuiResId(RID_CUISTR_WORDS_WITH_DIGITS))
787 , sSpellSpecial (CuiResId(RID_CUISTR_SPELL_SPECIAL))
788 , sSpellAuto (CuiResId(RID_CUISTR_SPELL_AUTO))
789 , sSpellClosedCompound (CuiResId(RID_CUISTR_SPELL_CLOSED_COMPOUND))
790 , sSpellHyphenatedCompound (CuiResId(RID_CUISTR_SPELL_HYPHENATED_COMPOUND))
791 , sGrammarAuto (CuiResId(RID_CUISTR_GRAMMAR_AUTO))
792 , sNumMinWordlen (CuiResId(RID_CUISTR_NUM_MIN_WORDLEN))
793 , sNumPreBreak (CuiResId(RID_CUISTR_NUM_PRE_BREAK))
794 , sNumPostBreak (CuiResId(RID_CUISTR_NUM_POST_BREAK))
795 , sHyphAuto (CuiResId(RID_CUISTR_HYPH_AUTO))
796 , sHyphSpecial (CuiResId(RID_CUISTR_HYPH_SPECIAL))
797 , nUPN_HYPH_MIN_WORD_LENGTH(-1)
798 , nUPN_HYPH_MIN_LEADING(-1)
799 , nUPN_HYPH_MIN_TRAILING(-1)
800 , m_nDlbClickEventId(nullptr)
801 , m_xLinguModulesFT(m_xBuilder->weld_label(u"lingumodulesft"_ustr))
802 , m_xLinguModulesCLB(m_xBuilder->weld_tree_view(u"lingumodules"_ustr))
803 , m_xLinguModulesEditPB(m_xBuilder->weld_button(u"lingumodulesedit"_ustr))
804 , m_xLinguDicsFT(m_xBuilder->weld_label(u"lingudictsft"_ustr))
805 , m_xLinguDicsCLB(m_xBuilder->weld_tree_view(u"lingudicts"_ustr))
806 , m_xLinguDicsNewPB(m_xBuilder->weld_button(u"lingudictsnew"_ustr))
807 , m_xLinguDicsEditPB(m_xBuilder->weld_button(u"lingudictsedit"_ustr))
808 , m_xLinguDicsDelPB(m_xBuilder->weld_button(u"lingudictsdelete"_ustr))
809 , m_xLinguOptionsCLB(m_xBuilder->weld_tree_view(u"linguoptions"_ustr))
810 , m_xLinguOptionsEditPB(m_xBuilder->weld_button(u"linguoptionsedit"_ustr))
811 , m_xMoreDictsBox(m_xBuilder->weld_box(u"moredictsbox"_ustr))
812 , m_xMoreDictsLink(m_xBuilder->weld_link_button(u"moredictslink"_ustr))
814 m_xLinguModulesCLB->enable_toggle_buttons(weld::ColumnToggleType::Check);
815 m_xLinguDicsCLB->enable_toggle_buttons(weld::ColumnToggleType::Check);
816 m_xLinguOptionsCLB->enable_toggle_buttons(weld::ColumnToggleType::Check);
818 m_xLinguModulesCLB->connect_selection_changed(LINK(this, SvxLinguTabPage, SelectHdl_Impl));
819 m_xLinguModulesCLB->connect_row_activated(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
820 m_xLinguModulesCLB->connect_toggled(LINK(this, SvxLinguTabPage, ModulesBoxCheckButtonHdl_Impl));
822 m_xLinguModulesEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
823 m_xLinguOptionsEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
825 m_xLinguDicsCLB->connect_selection_changed(LINK(this, SvxLinguTabPage, SelectHdl_Impl));
826 m_xLinguDicsCLB->connect_toggled(LINK(this, SvxLinguTabPage, DicsBoxCheckButtonHdl_Impl));
828 m_xLinguDicsNewPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
829 m_xLinguDicsEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
830 m_xLinguDicsDelPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
832 m_xLinguOptionsCLB->connect_selection_changed(LINK(this, SvxLinguTabPage, SelectHdl_Impl));
833 m_xLinguOptionsCLB->connect_row_activated(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
835 m_xMoreDictsLink->connect_activate_link(LINK(this, SvxLinguTabPage, OnLinkClick));
836 if (officecfg::Office::Security::Hyperlinks::Open::get() == SvtExtendedSecurityOptions::OPEN_NEVER)
837 m_xMoreDictsBox->hide();
839 if (comphelper::LibreOfficeKit::isActive())
841 // hide User-defined Dictionaries part
842 m_xBuilder->weld_frame(u"dictsframe"_ustr)->hide();
843 // hide Get more dictionaries URL + icon
844 m_xMoreDictsBox->hide();
847 xProp = LinguMgr::GetLinguPropertySet();
848 xDicList.set( LinguMgr::GetDictionaryList() );
849 if (xDicList.is())
851 // keep references to all **currently** available dictionaries,
852 // since the diclist may get changed meanwhile (e.g. through the API).
853 // We want the dialog to operate on the same set of dictionaries it
854 // was started with.
855 // Also we have to take care to not lose the last reference when
856 // someone else removes a dictionary from the list.
857 // removed dics will be replaced by NULL new entries be added to the end
858 // Thus we may use indices as consistent references.
859 aDics = xDicList->getDictionaries();
861 UpdateDicBox_Impl();
863 else
865 m_xLinguDicsFT->set_sensitive(false);
866 m_xLinguDicsCLB->set_sensitive(false);
867 m_xLinguDicsNewPB->set_sensitive(false);
868 m_xLinguDicsEditPB->set_sensitive(false);
869 m_xLinguDicsDelPB->set_sensitive(false);
873 SvxLinguTabPage::~SvxLinguTabPage()
875 if (m_nDlbClickEventId)
877 Application::RemoveUserEvent(m_nDlbClickEventId);
878 m_nDlbClickEventId = nullptr;
880 pLinguData.reset();
883 std::unique_ptr<SfxTabPage> SvxLinguTabPage::Create( weld::Container* pPage, weld::DialogController* pController,
884 const SfxItemSet* rAttrSet )
886 return std::make_unique<SvxLinguTabPage>( pPage, pController, *rAttrSet );
889 OUString SvxLinguTabPage::GetAllStrings()
891 OUString sAllStrings;
892 OUString labels[] = { u"lingumodulesft"_ustr, u"lingudictsft"_ustr, u"label4"_ustr };
894 for (const auto& label : labels)
896 if (const auto pString = m_xBuilder->weld_label(label))
897 sAllStrings += pString->get_label() + " ";
900 sAllStrings += m_xMoreDictsLink->get_label() + " ";
902 return sAllStrings.replaceAll("_", "");
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) == TRISTATE_TRUE;
982 uno::Reference<XDictionary> xDic(aDics[i]);
983 if (xDic.is())
985 if (LinguMgr::GetIgnoreAllList() == xDic)
986 bChecked = true;
987 xDic->setActive( bChecked );
988 if (bChecked)
989 pActiveDic[nActiveDics++] = xDic->getName();
994 aActiveDics.realloc( nActiveDics );
995 Any aTmp;
996 aTmp <<= aActiveDics;
997 SvtLinguConfig aLngCfg;
998 aLngCfg.SetProperty( UPH_ACTIVE_DICTIONARIES, aTmp );
1001 nEntries = m_xLinguOptionsCLB->n_children();
1002 for (int j = 0; j < nEntries; ++j)
1004 OptionsUserData aData(m_xLinguOptionsCLB->get_id(j).toUInt32());
1005 OUString aPropName( lcl_GetPropertyName( static_cast<EID_OPTIONS>(aData.GetEntryId()) ) );
1007 Any aAny;
1008 if (aData.IsCheckable())
1010 bool bChecked = m_xLinguOptionsCLB->get_toggle(j) == TRISTATE_TRUE;
1011 aAny <<= bChecked;
1013 else if (aData.HasNumericValue())
1015 sal_Int16 nVal = aData.GetNumericValue();
1016 aAny <<= nVal;
1019 if (xProp.is())
1020 xProp->setPropertyValue( aPropName, aAny );
1021 aLngCfg.SetProperty( aPropName, aAny );
1024 OptionsUserData aPreBreakData(m_xLinguOptionsCLB->get_id(EID_NUM_PRE_BREAK).toUInt32());
1025 OptionsUserData aPostBreakData(m_xLinguOptionsCLB->get_id(EID_NUM_POST_BREAK).toUInt32());
1026 if ( aPreBreakData.IsModified() || aPostBreakData.IsModified() )
1028 SfxHyphenRegionItem aHyp( SID_ATTR_HYPHENREGION );
1029 aHyp.GetMinLead() = static_cast<sal_uInt8>(aPreBreakData.GetNumericValue());
1030 aHyp.GetMinTrail() = static_cast<sal_uInt8>(aPostBreakData.GetNumericValue());
1031 rCoreSet->Put( aHyp );
1034 // automatic spell checking
1035 bool bNewAutoCheck = m_xLinguOptionsCLB->get_toggle(EID_SPELL_AUTO) == TRISTATE_TRUE;
1036 const SfxPoolItem* pOld = GetOldItem( *rCoreSet, SID_AUTOSPELL_CHECK );
1037 if ( !pOld || static_cast<const SfxBoolItem*>(pOld)->GetValue() != bNewAutoCheck )
1039 rCoreSet->Put( SfxBoolItem( SID_AUTOSPELL_CHECK, bNewAutoCheck ) );
1040 bModified = true;
1043 return bModified;
1046 sal_uInt32 SvxLinguTabPage::GetDicUserData( const uno::Reference< XDictionary > &rxDic, sal_uInt16 nIdx )
1048 sal_uInt32 nRes = 0;
1049 DBG_ASSERT( rxDic.is(), "dictionary not supplied" );
1050 if (rxDic.is())
1052 uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
1054 bool bChecked = rxDic->isActive();
1055 bool bEditable = !xStor.is() || !xStor->isReadonly();
1056 bool bDeletable = bEditable;
1058 nRes = DicUserData( nIdx,
1059 bChecked, bEditable, bDeletable ).GetUserData();
1061 return nRes;
1065 void SvxLinguTabPage::AddDicBoxEntry(
1066 const uno::Reference< XDictionary > &rxDic,
1067 sal_uInt16 nIdx )
1069 m_xLinguDicsCLB->freeze();
1071 OUString aTxt( ::GetDicInfoStr( rxDic->getName(),
1072 LanguageTag( rxDic->getLocale() ).getLanguageType(),
1073 DictionaryType_NEGATIVE == rxDic->getDictionaryType() ) );
1074 m_xLinguDicsCLB->append(); // append at end
1075 int nEntry = m_xLinguDicsCLB->n_children() - 1;
1076 DicUserData aData( GetDicUserData( rxDic, nIdx ) );
1077 m_xLinguDicsCLB->set_id(nEntry, OUString::number(aData.GetUserData()));
1078 m_xLinguDicsCLB->set_toggle(nEntry, aData.IsChecked() ? TRISTATE_TRUE : TRISTATE_FALSE);
1079 m_xLinguDicsCLB->set_text(nEntry, aTxt, 0); // append at end
1081 m_xLinguDicsCLB->thaw();
1084 void SvxLinguTabPage::UpdateDicBox_Impl()
1086 m_xLinguDicsCLB->freeze();
1087 m_xLinguDicsCLB->clear();
1089 for (sal_Int32 i = 0; i < aDics.getLength(); ++i)
1091 const uno::Reference<XDictionary>& rDic = aDics[i];
1092 if (rDic.is())
1093 AddDicBoxEntry( rDic, static_cast<sal_uInt16>(i) );
1096 m_xLinguDicsCLB->thaw();
1097 if (m_xLinguDicsCLB->n_children())
1099 m_xLinguDicsCLB->select(0);
1100 SelectHdl_Impl(*m_xLinguDicsCLB);
1104 void SvxLinguTabPage::UpdateModulesBox_Impl()
1106 if (!pLinguData)
1107 return;
1109 const ServiceInfoArr &rAllDispSrvcArr = pLinguData->GetDisplayServiceArray();
1110 const sal_uInt32 nDispSrvcCount = pLinguData->GetDisplayServiceCount();
1112 m_xLinguModulesCLB->clear();
1114 for (sal_uInt32 i = 0; i < nDispSrvcCount; ++i)
1116 const ServiceInfo_Impl &rInfo = rAllDispSrvcArr[i];
1117 m_xLinguModulesCLB->append();
1118 m_xLinguModulesCLB->set_id(i, weld::toId(&rInfo));
1119 m_xLinguModulesCLB->set_toggle(i, rInfo.bConfigured ? TRISTATE_TRUE : TRISTATE_FALSE);
1120 m_xLinguModulesCLB->set_text(i, rInfo.sDisplayName, 0);
1122 if (nDispSrvcCount)
1124 m_xLinguModulesCLB->select(0);
1125 SelectHdl_Impl(*m_xLinguModulesCLB);
1127 m_xLinguModulesEditPB->set_sensitive( nDispSrvcCount > 0 );
1130 void SvxLinguTabPage::Reset( const SfxItemSet* rSet )
1132 // if not HideGroups was called with GROUP_MODULES...
1133 if (m_xLinguModulesCLB->get_visible())
1135 if (!pLinguData)
1136 pLinguData.reset( new SvxLinguData_Impl );
1137 UpdateModulesBox_Impl();
1141 // get data from configuration
1142 SvtLinguConfig aLngCfg;
1144 m_xLinguOptionsCLB->freeze();
1145 m_xLinguOptionsCLB->clear();
1147 sal_Int16 nVal = 0;
1148 bool bVal = false;
1149 sal_uInt32 nUserData = 0;
1151 m_xLinguOptionsCLB->append();
1152 int nEntry = 0;
1154 aLngCfg.GetProperty( UPN_IS_SPELL_AUTO ) >>= bVal;
1155 const SfxPoolItem* pItem = GetItem( *rSet, SID_AUTOSPELL_CHECK );
1156 if (pItem)
1157 bVal = static_cast<const SfxBoolItem *>(pItem)->GetValue();
1158 nUserData = OptionsUserData( EID_SPELL_AUTO, false, 0, true, bVal).GetUserData();
1159 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE);
1160 m_xLinguOptionsCLB->set_text(nEntry, sSpellAuto, 0);
1161 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1162 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_AUTO));
1164 m_xLinguOptionsCLB->append();
1165 ++nEntry;
1167 aLngCfg.GetProperty( UPN_IS_GRAMMAR_AUTO ) >>= bVal;
1168 nUserData = OptionsUserData( EID_GRAMMAR_AUTO, false, 0, true, bVal).GetUserData();
1169 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE);
1170 m_xLinguOptionsCLB->set_text(nEntry, sGrammarAuto, 0);
1171 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1172 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_GRAMMAR_AUTO));
1174 m_xLinguOptionsCLB->append();
1175 ++nEntry;
1177 aLngCfg.GetProperty( UPN_IS_SPELL_UPPER_CASE ) >>= bVal;
1178 nUserData = OptionsUserData( EID_CAPITAL_WORDS, false, 0, true, bVal).GetUserData();
1179 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE);
1180 m_xLinguOptionsCLB->set_text(nEntry, sCapitalWords, 0);
1181 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1182 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_UPPER_CASE));
1184 m_xLinguOptionsCLB->append();
1185 ++nEntry;
1187 aLngCfg.GetProperty( UPN_IS_SPELL_WITH_DIGITS ) >>= bVal;
1188 nUserData = OptionsUserData( EID_WORDS_WITH_DIGITS, false, 0, true, bVal).GetUserData();
1189 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE);
1190 m_xLinguOptionsCLB->set_text(nEntry, sWordsWithDigits, 0);
1191 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1192 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_WITH_DIGITS));
1194 m_xLinguOptionsCLB->append();
1195 ++nEntry;
1197 aLngCfg.GetProperty( UPN_IS_SPELL_CLOSED_COMPOUND ) >>= bVal;
1198 nUserData = OptionsUserData( EID_SPELL_CLOSED_COMPOUND, false, 0, true, bVal).GetUserData();
1199 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE);
1200 m_xLinguOptionsCLB->set_text(nEntry, sSpellClosedCompound, 0);
1201 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1202 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_CLOSED_COMPOUND));
1204 m_xLinguOptionsCLB->append();
1205 ++nEntry;
1207 aLngCfg.GetProperty( UPN_IS_SPELL_HYPHENATED_COMPOUND ) >>= bVal;
1208 nUserData = OptionsUserData( EID_SPELL_HYPHENATED_COMPOUND, false, 0, true, bVal).GetUserData();
1209 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE);
1210 m_xLinguOptionsCLB->set_text(nEntry, sSpellHyphenatedCompound, 0);
1211 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1212 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_HYPHENATED_COMPOUND));
1214 m_xLinguOptionsCLB->append();
1215 ++nEntry;
1217 aLngCfg.GetProperty( UPN_IS_SPELL_SPECIAL ) >>= bVal;
1218 nUserData = OptionsUserData( EID_SPELL_SPECIAL, false, 0, true, bVal).GetUserData();
1219 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE);
1220 m_xLinguOptionsCLB->set_text(nEntry, sSpellSpecial, 0);
1221 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1222 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_SPECIAL));
1224 m_xLinguOptionsCLB->append();
1225 ++nEntry;
1227 aLngCfg.GetProperty( UPN_HYPH_MIN_WORD_LENGTH ) >>= nVal;
1228 nUserData = OptionsUserData( EID_NUM_MIN_WORDLEN, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
1229 m_xLinguOptionsCLB->set_text(nEntry, sNumMinWordlen + " " + OUString::number(nVal), 0);
1230 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1231 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_HYPH_MIN_WORD_LENGTH));
1232 nUPN_HYPH_MIN_WORD_LENGTH = nEntry;
1234 const SfxHyphenRegionItem *pHyp = nullptr;
1235 if ( rSet->GetItemState( SID_ATTR_HYPHENREGION, false ) == SfxItemState::SET )
1236 pHyp = & rSet->Get( SID_ATTR_HYPHENREGION );
1238 m_xLinguOptionsCLB->append();
1239 ++nEntry;
1241 aLngCfg.GetProperty( UPN_HYPH_MIN_LEADING ) >>= nVal;
1242 if (pHyp)
1243 nVal = static_cast<sal_Int16>(pHyp->GetMinLead());
1244 nUserData = OptionsUserData( EID_NUM_PRE_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
1245 m_xLinguOptionsCLB->set_text(nEntry, sNumPreBreak + " " + OUString::number(nVal), 0);
1246 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1247 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_HYPH_MIN_LEADING));
1248 nUPN_HYPH_MIN_LEADING = nEntry;
1250 m_xLinguOptionsCLB->append();
1251 ++nEntry;
1253 aLngCfg.GetProperty( UPN_HYPH_MIN_TRAILING ) >>= nVal;
1254 if (pHyp)
1255 nVal = static_cast<sal_Int16>(pHyp->GetMinTrail());
1256 nUserData = OptionsUserData( EID_NUM_POST_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
1257 m_xLinguOptionsCLB->set_text(nEntry, sNumPostBreak + " " + OUString::number(nVal), 0);
1258 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1259 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_HYPH_MIN_TRAILING));
1260 nUPN_HYPH_MIN_TRAILING = nEntry;
1262 m_xLinguOptionsCLB->append();
1263 ++nEntry;
1265 aLngCfg.GetProperty( UPN_IS_HYPH_AUTO ) >>= bVal;
1266 nUserData = OptionsUserData( EID_HYPH_AUTO, false, 0, true, bVal).GetUserData();
1267 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE);
1268 m_xLinguOptionsCLB->set_text(nEntry, sHyphAuto, 0);
1269 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1270 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_HYPH_AUTO));
1272 m_xLinguOptionsCLB->append();
1273 ++nEntry;
1275 aLngCfg.GetProperty( UPN_IS_HYPH_SPECIAL ) >>= bVal;
1276 nUserData = OptionsUserData( EID_HYPH_SPECIAL, false, 0, true, bVal).GetUserData();
1277 m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE);
1278 m_xLinguOptionsCLB->set_text(nEntry, sHyphSpecial, 0);
1279 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData));
1280 m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_HYPH_SPECIAL));
1282 m_xLinguOptionsCLB->thaw();
1284 m_xLinguOptionsCLB->select(0);
1285 SelectHdl_Impl(*m_xLinguOptionsCLB);
1287 m_xLinguModulesCLB->set_size_request(m_xLinguModulesCLB->get_preferred_size().Width(),
1288 m_xLinguModulesCLB->get_height_rows(3));
1289 m_xLinguDicsCLB->set_size_request(m_xLinguDicsCLB->get_preferred_size().Width(),
1290 m_xLinguDicsCLB->get_height_rows(5));
1291 m_xLinguOptionsCLB->set_size_request(m_xLinguOptionsCLB->get_preferred_size().Width(),
1292 m_xLinguOptionsCLB->get_height_rows(5));
1294 if (officecfg::Office::Linguistic::General::DictionaryList::ActiveDictionaries::isReadOnly())
1296 m_xLinguDicsFT->set_sensitive(false);
1297 m_xLinguDicsCLB->set_sensitive(false);
1298 m_xLinguDicsNewPB->set_sensitive(false);
1299 m_xLinguDicsEditPB->set_sensitive(false);
1300 m_xLinguDicsDelPB->set_sensitive(false);
1304 IMPL_LINK(SvxLinguTabPage, BoxDoubleClickHdl_Impl, weld::TreeView&, rBox, bool)
1306 if (&rBox == m_xLinguModulesCLB.get() && !m_nDlbClickEventId)
1308 //! in order to avoid a bug causing a GPF when double clicking
1309 //! on a module entry and exiting the "Edit Modules" dialog
1310 //! after that.
1311 m_nDlbClickEventId = Application::PostUserEvent(LINK(this, SvxLinguTabPage, PostDblClickHdl_Impl));
1313 else if (&rBox == m_xLinguOptionsCLB.get())
1315 ClickHdl_Impl(*m_xLinguOptionsEditPB);
1317 return true;
1320 IMPL_LINK_NOARG(SvxLinguTabPage, PostDblClickHdl_Impl, void*, void)
1322 m_nDlbClickEventId = nullptr;
1323 ClickHdl_Impl(*m_xLinguModulesEditPB);
1326 IMPL_LINK(SvxLinguTabPage, ModulesBoxCheckButtonHdl_Impl, const weld::TreeView::iter_col&, rRowCol, void)
1328 if (!pLinguData)
1329 return;
1330 pLinguData->Reconfigure(m_xLinguModulesCLB->get_text(rRowCol.first),
1331 m_xLinguModulesCLB->get_toggle(rRowCol.first) == TRISTATE_TRUE);
1334 IMPL_LINK(SvxLinguTabPage, DicsBoxCheckButtonHdl_Impl, const weld::TreeView::iter_col&, rRowCol, void)
1336 const uno::Reference<XDictionary> &rDic = aDics[m_xLinguDicsCLB->get_iter_index_in_parent(rRowCol.first)];
1337 if (LinguMgr::GetIgnoreAllList() == rDic)
1338 m_xLinguDicsCLB->set_toggle(rRowCol.first, TRISTATE_TRUE);
1341 IMPL_LINK(SvxLinguTabPage, ClickHdl_Impl, weld::Button&, rBtn, void)
1343 if (m_xLinguModulesEditPB.get() == &rBtn)
1345 if (!pLinguData)
1346 pLinguData.reset( new SvxLinguData_Impl );
1348 SvxLinguData_Impl aOldLinguData(*pLinguData);
1349 SvxEditModulesDlg aDlg(GetFrameWeld(), *pLinguData);
1350 if (aDlg.run() != RET_OK)
1351 *pLinguData = std::move(aOldLinguData);
1353 // evaluate new status of 'bConfigured' flag
1354 sal_uInt32 nLen = pLinguData->GetDisplayServiceCount();
1355 for (sal_uInt32 i = 0; i < nLen; ++i)
1356 pLinguData->GetDisplayServiceArray()[i].bConfigured = false;
1357 for (const auto& locale : pLinguData->GetAllSupportedLocales())
1359 LanguageType nLang = LanguageTag::convertToLanguageType(locale);
1360 if (pLinguData->GetSpellTable().count( nLang ))
1361 pLinguData->SetChecked( pLinguData->GetSpellTable()[ nLang ] );
1362 if (pLinguData->GetGrammarTable().count( nLang ))
1363 pLinguData->SetChecked( pLinguData->GetGrammarTable()[ nLang ] );
1364 if (pLinguData->GetHyphTable().count( nLang ))
1365 pLinguData->SetChecked( pLinguData->GetHyphTable()[ nLang ] );
1366 if (pLinguData->GetThesTable().count( nLang ))
1367 pLinguData->SetChecked( pLinguData->GetThesTable()[ nLang ] );
1370 // show new status of modules
1371 UpdateModulesBox_Impl();
1373 else if (m_xLinguDicsNewPB.get() == &rBtn)
1375 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1376 ScopedVclPtr<AbstractSvxNewDictionaryDialog> aDlg(pFact->CreateSvxNewDictionaryDialog(GetFrameWeld()));
1377 uno::Reference< XDictionary > xNewDic;
1378 if ( aDlg->Execute() == RET_OK )
1379 xNewDic = aDlg->GetNewDictionary();
1380 if ( xNewDic.is() )
1382 // add new dics to the end
1383 sal_Int32 nLen = aDics.getLength();
1384 aDics.realloc( nLen + 1 );
1386 aDics.getArray()[ nLen ] = xNewDic;
1388 AddDicBoxEntry( xNewDic, static_cast<sal_uInt16>(nLen) );
1391 else if (m_xLinguDicsEditPB.get() == &rBtn)
1393 int nEntry = m_xLinguDicsCLB->get_selected_index();
1394 if (nEntry != -1)
1396 DicUserData aData(m_xLinguDicsCLB->get_id(nEntry).toUInt32());
1397 sal_uInt16 nDicPos = aData.GetEntryId();
1398 sal_Int32 nDics = aDics.getLength();
1399 if (nDicPos < nDics)
1401 uno::Reference<XDictionary> xDic = aDics[nDicPos];
1402 if (xDic.is())
1404 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1405 ScopedVclPtr<VclAbstractDialog> aDlg(pFact->CreateSvxEditDictionaryDialog(GetFrameWeld(), xDic->getName()));
1406 aDlg->Execute();
1411 else if (m_xLinguDicsDelPB.get() == &rBtn)
1413 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), u"cui/ui/querydeletedictionarydialog.ui"_ustr));
1414 std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog(u"QueryDeleteDictionaryDialog"_ustr));
1415 if (RET_NO == xQuery->run())
1416 return;
1418 int nEntry = m_xLinguDicsCLB->get_selected_index();
1419 if (nEntry != -1)
1421 DicUserData aData(m_xLinguDicsCLB->get_id(nEntry).toUInt32());
1422 sal_uInt16 nDicPos = aData.GetEntryId();
1423 sal_Int32 nDics = aDics.getLength();
1424 if (nDicPos < nDics)
1426 uno::Reference<XDictionary> xDic = aDics[nDicPos];
1427 if (xDic.is())
1429 if (LinguMgr::GetIgnoreAllList() == xDic)
1430 xDic->clear();
1431 else
1433 if (xDicList.is())
1434 xDicList->removeDictionary( xDic );
1436 uno::Reference< frame::XStorable > xStor( xDic, UNO_QUERY );
1437 if ( xStor->hasLocation() && !xStor->isReadonly() )
1439 OUString sURL = xStor->getLocation();
1440 INetURLObject aObj(sURL);
1441 DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File,
1442 "non-file URLs cannot be deleted" );
1443 if ( aObj.GetProtocol() == INetProtocol::File )
1445 KillFile_Impl( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1449 aDics.getArray()[ nDicPos ] = nullptr;
1451 // remove entry from checklistbox
1452 int nCnt = m_xLinguDicsCLB->n_children();
1453 for (int i = 0; i < nCnt; ++i)
1455 DicUserData aDicData(m_xLinguDicsCLB->get_id(i).toUInt32());
1456 if (aDicData.GetEntryId() == nDicPos )
1458 m_xLinguDicsCLB->remove(i);
1459 break;
1462 DBG_ASSERT( nCnt > m_xLinguDicsCLB->n_children(),
1463 "remove failed ?");
1469 else if (m_xLinguOptionsEditPB.get() == &rBtn)
1471 int nEntry = m_xLinguOptionsCLB->get_selected_index();
1472 DBG_ASSERT(nEntry != -1, "no entry selected");
1473 if (nEntry != -1)
1475 OptionsUserData aData(m_xLinguOptionsCLB->get_id(nEntry).toUInt32());
1476 if (aData.HasNumericValue())
1478 sal_uInt16 nRID = aData.GetEntryId();
1479 OptionsBreakSet aDlg(GetFrameWeld(), nRID);
1480 aDlg.GetNumericFld().set_value(aData.GetNumericValue());
1481 if (RET_OK == aDlg.run())
1483 int nVal = aDlg.GetNumericFld().get_value();
1484 if (-1 != nVal && aData.GetNumericValue() != nVal)
1486 aData.SetNumericValue( static_cast<sal_uInt8>(nVal) ); //! sets IsModified !
1487 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(aData.GetUserData()));
1488 if (nEntry == nUPN_HYPH_MIN_WORD_LENGTH)
1489 m_xLinguOptionsCLB->set_text(nEntry, sNumMinWordlen + " " + OUString::number(nVal), 0);
1490 else if (nEntry == nUPN_HYPH_MIN_LEADING)
1491 m_xLinguOptionsCLB->set_text(nEntry, sNumPreBreak + " " + OUString::number(nVal), 0);
1492 else if (nEntry == nUPN_HYPH_MIN_TRAILING)
1493 m_xLinguOptionsCLB->set_text(nEntry, sNumPostBreak + " " + OUString::number(nVal), 0);
1494 m_xLinguOptionsCLB->set_id(nEntry, OUString::number(aData.GetUserData()));
1500 else
1502 SAL_WARN("cui.options", "rBtn unexpected value");
1506 IMPL_LINK(SvxLinguTabPage, SelectHdl_Impl, weld::TreeView&, rBox, void)
1508 if (m_xLinguModulesCLB.get() == &rBox)
1511 else if (m_xLinguDicsCLB.get() == &rBox)
1513 int nEntry = rBox.get_selected_index();
1514 if (nEntry != -1)
1516 DicUserData aData(rBox.get_id(nEntry).toUInt32());
1518 // always allow to edit (i.e. at least view the content of the dictionary)
1519 m_xLinguDicsEditPB->set_sensitive( true );
1520 m_xLinguDicsDelPB->set_sensitive( aData.IsDeletable() );
1523 else if (m_xLinguOptionsCLB.get() == &rBox)
1525 int nEntry = rBox.get_selected_index();
1526 if (nEntry != -1)
1528 OptionsUserData aData(rBox.get_id(nEntry).toUInt32());
1529 m_xLinguOptionsEditPB->set_sensitive( aData.HasNumericValue() );
1532 else
1534 SAL_WARN("cui.options", "rBtn unexpected value");
1538 void SvxLinguTabPage::HideGroups( sal_uInt16 nGrp )
1540 if ( 0 != ( GROUP_MODULES & nGrp ) )
1542 m_xLinguModulesFT->hide();
1543 m_xLinguModulesCLB->hide();
1544 m_xLinguModulesEditPB->hide();
1546 if (officecfg::Office::Security::Hyperlinks::Open::get() != SvtExtendedSecurityOptions::OPEN_NEVER &&
1547 !comphelper::LibreOfficeKit::isActive())
1549 m_xMoreDictsBox->show();
1554 IMPL_STATIC_LINK_NOARG(SvxLinguTabPage, OnLinkClick, weld::LinkButton&, bool)
1556 comphelper::dispatchCommand(u".uno:MoreDictionaries"_ustr, {});
1557 return true;
1560 SvxEditModulesDlg::SvxEditModulesDlg(weld::Window* pParent, SvxLinguData_Impl& rData)
1561 : GenericDialogController(pParent, u"cui/ui/editmodulesdialog.ui"_ustr, u"EditModulesDialog"_ustr)
1562 , sSpell(CuiResId(RID_CUISTR_SPELL))
1563 , sHyph(CuiResId(RID_CUISTR_HYPH))
1564 , sThes(CuiResId(RID_CUISTR_THES))
1565 , sGrammar(CuiResId(RID_CUISTR_GRAMMAR))
1566 , rLinguData(rData)
1567 , m_xModulesCLB(m_xBuilder->weld_tree_view(u"lingudicts"_ustr))
1568 , m_xPrioUpPB(m_xBuilder->weld_button(u"up"_ustr))
1569 , m_xPrioDownPB(m_xBuilder->weld_button(u"down"_ustr))
1570 , m_xBackPB(m_xBuilder->weld_button(u"back"_ustr))
1571 , m_xMoreDictsLink(m_xBuilder->weld_link_button(u"moredictslink"_ustr))
1572 , m_xClosePB(m_xBuilder->weld_button(u"close"_ustr))
1573 , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"language"_ustr)))
1575 m_xModulesCLB->set_size_request(m_xModulesCLB->get_approximate_digit_width() * 40,
1576 m_xModulesCLB->get_height_rows(12));
1578 m_xModulesCLB->enable_toggle_buttons(weld::ColumnToggleType::Check);
1580 pDefaultLinguData.reset( new SvxLinguData_Impl( rLinguData ) );
1582 m_xModulesCLB->connect_selection_changed(LINK(this, SvxEditModulesDlg, SelectHdl_Impl));
1583 m_xModulesCLB->connect_toggled(LINK(this, SvxEditModulesDlg, BoxCheckButtonHdl_Impl));
1585 m_xClosePB->connect_clicked( LINK( this, SvxEditModulesDlg, ClickHdl_Impl ));
1586 m_xPrioUpPB->connect_clicked( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
1587 m_xPrioDownPB->connect_clicked( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
1588 m_xBackPB->connect_clicked( LINK( this, SvxEditModulesDlg, BackHdl_Impl ));
1589 // in case of not installed language modules
1590 m_xPrioUpPB->set_sensitive( false );
1591 m_xPrioDownPB->set_sensitive( false );
1593 m_xMoreDictsLink->connect_activate_link(LINK(this, SvxEditModulesDlg, OnLinkClick));
1594 if (officecfg::Office::Security::Hyperlinks::Open::get() == SvtExtendedSecurityOptions::OPEN_NEVER)
1595 m_xMoreDictsLink->hide();
1597 // set that we want the checkbox shown if spellchecking is available
1598 m_xLanguageLB->SetLanguageList(SvxLanguageListFlags::EMPTY, false, false, true);
1600 //fill language box
1601 const auto& rLoc = rLinguData.GetAllSupportedLocales();
1602 std::vector<LanguageType> aLanguages;
1603 aLanguages.reserve(rLoc.size());
1604 std::transform(rLoc.begin(), rLoc.end(), std::back_inserter(aLanguages),
1605 [](Locale const& locale) { return LanguageTag::convertToLanguageType(locale); });
1606 m_xLanguageLB->InsertLanguages(aLanguages);
1607 LanguageType eSysLang = MsLangId::getConfiguredSystemLanguage();
1608 m_xLanguageLB->set_active_id( eSysLang );
1609 if (m_xLanguageLB->get_active_id() != eSysLang)
1610 m_xLanguageLB->set_active(0);
1612 const css::uno::Reference < css::uno::XComponentContext >& xContext(::comphelper::getProcessComponentContext());
1613 m_xReadWriteAccess = css::configuration::ReadWriteAccess::create(xContext, u"*"_ustr);
1615 m_xLanguageLB->connect_changed( LINK( this, SvxEditModulesDlg, LangSelectListBoxHdl_Impl ));
1616 LangSelectHdl_Impl(m_xLanguageLB.get());
1619 SvxEditModulesDlg::~SvxEditModulesDlg()
1621 for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1622 delete weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i));
1625 IMPL_LINK( SvxEditModulesDlg, SelectHdl_Impl, weld::TreeView&, rBox, void )
1627 int nCurPos = rBox.get_selected_index();
1628 if (nCurPos == -1)
1629 return;
1631 bool bDisableUp = true;
1632 bool bDisableDown = true;
1633 ModuleUserData_Impl* pData = weld::fromId<ModuleUserData_Impl*>(rBox.get_id(nCurPos));
1634 if (!pData->IsParent() && pData->GetType() != TYPE_HYPH)
1636 if (nCurPos < rBox.n_children() - 1)
1638 bDisableDown = weld::fromId<ModuleUserData_Impl*>(rBox.get_id(nCurPos + 1))->IsParent();
1640 if (nCurPos > 1)
1642 bDisableUp = weld::fromId<ModuleUserData_Impl*>(rBox.get_id(nCurPos - 1))->IsParent();
1645 m_xPrioUpPB->set_sensitive(!bDisableUp);
1646 m_xPrioDownPB->set_sensitive(!bDisableDown);
1649 IMPL_LINK( SvxEditModulesDlg, BoxCheckButtonHdl_Impl, const weld::TreeView::iter_col&, rRowCol, void )
1651 ModuleUserData_Impl* pData = weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(rRowCol.first));
1652 if (pData->IsParent() || pData->GetType() != TYPE_HYPH)
1653 return;
1655 // make hyphenator checkboxes function as radio-buttons
1656 // (at most one box may be checked)
1657 auto nPos = m_xModulesCLB->get_iter_index_in_parent(rRowCol.first);
1658 for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1660 pData = weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i));
1661 if (!pData->IsParent() && pData->GetType() == TYPE_HYPH && i != nPos)
1663 m_xModulesCLB->set_toggle(i, TRISTATE_FALSE);
1668 IMPL_LINK_NOARG(SvxEditModulesDlg, LangSelectListBoxHdl_Impl, weld::ComboBox&, void)
1670 LangSelectHdl_Impl(m_xLanguageLB.get());
1673 void SvxEditModulesDlg::LangSelectHdl_Impl(const SvxLanguageBox* pBox)
1675 LanguageType eCurLanguage = m_xLanguageLB->get_active_id();
1676 static Locale aLastLocale;
1677 Locale aCurLocale( LanguageTag::convertToLocale( eCurLanguage));
1679 if (pBox)
1681 // save old probably changed settings
1682 // before switching to new language entries
1684 LanguageType nLang = LanguageTag::convertToLanguageType( aLastLocale );
1686 sal_Int32 nStart = 0, nLocalIndex = 0;
1687 Sequence< OUString > aChange;
1688 bool bChanged = false;
1689 for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1691 ModuleUserData_Impl* pData = weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i));
1692 if (pData->IsParent())
1694 if (bChanged)
1696 LangImplNameTable *pTable = nullptr;
1697 sal_uInt8 nType = pData->GetType();
1698 switch (nType - 1)
1700 case TYPE_SPELL : pTable = &rLinguData.GetSpellTable(); break;
1701 case TYPE_GRAMMAR : pTable = &rLinguData.GetGrammarTable(); break;
1702 case TYPE_HYPH : pTable = &rLinguData.GetHyphTable(); break;
1703 case TYPE_THES : pTable = &rLinguData.GetThesTable(); break;
1705 if (pTable)
1707 aChange.realloc(nStart);
1708 (*pTable)[ nLang ] = aChange;
1711 nLocalIndex = nStart = 0;
1712 aChange.realloc(nEntryCount);
1713 bChanged = false;
1715 else
1717 OUString* pChange = aChange.getArray();
1718 pChange[nStart] = pData->GetImplName();
1719 bChanged |= pData->GetIndex() != nLocalIndex ||
1720 static_cast<TriState>(pData->IsChecked()) != m_xModulesCLB->get_toggle(i);
1721 if (m_xModulesCLB->get_toggle(i))
1722 nStart++;
1723 ++nLocalIndex;
1726 if(bChanged)
1728 aChange.realloc(nStart);
1729 rLinguData.GetThesTable()[ nLang ] = std::move(aChange);
1733 for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i)
1734 delete weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i));
1735 m_xModulesCLB->clear();
1737 // display entries for new selected language
1739 if (LANGUAGE_DONTKNOW != eCurLanguage)
1741 bool bReadOnly = false;
1743 int nRow = 0;
1744 // spellchecker entries
1746 ModuleUserData_Impl* pUserData = new ModuleUserData_Impl(
1747 OUString(), true, false, TYPE_SPELL, 0 );
1748 OUString sId(weld::toId(pUserData));
1749 m_xModulesCLB->append(nullptr);
1750 m_xModulesCLB->set_id(nRow, sId);
1751 m_xModulesCLB->set_text(nRow, sSpell, 0);
1752 m_xModulesCLB->set_text_emphasis(nRow, true, 0);
1753 ++nRow;
1755 OUString aLangNodeName = LanguageTag::convertToBcp47(aCurLocale);
1756 OUString aConfigPath = officecfg::Office::Linguistic::ServiceManager::path() + "/SpellCheckerList/" + aLangNodeName;
1757 if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath))
1759 css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath);
1760 bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0;
1763 sal_Int32 nLocalIndex = 0; // index relative to parent
1764 for (auto& name : rLinguData.GetSortedImplNames(eCurLanguage, TYPE_SPELL))
1766 OUString aImplName;
1767 bool bIsSuppLang = false;
1769 ServiceInfo_Impl* pInfo = rLinguData.GetInfoByImplName(name);
1770 if (pInfo)
1772 bIsSuppLang = pInfo->xSpell.is() &&
1773 pInfo->xSpell->hasLocale( aCurLocale );
1774 aImplName = pInfo->sSpellImplName;
1776 if (!aImplName.isEmpty() && bIsSuppLang)
1778 OUString aTxt( pInfo->sDisplayName );
1780 LangImplNameTable &rTable = rLinguData.GetSpellTable();
1781 const bool bHasLang = rTable.count( eCurLanguage );
1782 if (!bHasLang)
1784 SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
1786 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1787 pUserData = new ModuleUserData_Impl( aImplName, false,
1788 bCheck, TYPE_SPELL, static_cast<sal_uInt8>(nLocalIndex++) );
1789 sId = weld::toId(pUserData);
1791 m_xModulesCLB->append(nullptr);
1792 m_xModulesCLB->set_id(nRow, sId);
1793 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
1794 m_xModulesCLB->set_text(nRow, aTxt, 0);
1795 m_xModulesCLB->set_text_emphasis(nRow, false, 0);
1796 m_xModulesCLB->set_sensitive(nRow, !bReadOnly);
1797 ++nRow;
1801 // grammar checker entries
1803 pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_GRAMMAR, 0 );
1804 sId = weld::toId(pUserData);
1805 m_xModulesCLB->append(nullptr);
1806 m_xModulesCLB->set_id(nRow, sId);
1807 m_xModulesCLB->set_text(nRow, sGrammar, 0);
1808 m_xModulesCLB->set_text_emphasis(nRow, true, 0);
1809 ++nRow;
1811 aConfigPath = officecfg::Office::Linguistic::ServiceManager::path() + "/GrammarCheckerList/" + aLangNodeName;
1812 if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath))
1814 css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath);
1815 bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0;
1818 nLocalIndex = 0;
1819 for (auto& name : rLinguData.GetSortedImplNames(eCurLanguage, TYPE_GRAMMAR))
1821 OUString aImplName;
1822 bool bIsSuppLang = false;
1824 ServiceInfo_Impl* pInfo = rLinguData.GetInfoByImplName(name);
1825 if (pInfo)
1827 bIsSuppLang = pInfo->xGrammar.is() &&
1828 pInfo->xGrammar->hasLocale( aCurLocale );
1829 aImplName = pInfo->sGrammarImplName;
1831 if (!aImplName.isEmpty() && bIsSuppLang)
1833 OUString aTxt( pInfo->sDisplayName );
1835 LangImplNameTable &rTable = rLinguData.GetGrammarTable();
1836 const bool bHasLang = rTable.count( eCurLanguage );
1837 if (!bHasLang)
1839 SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
1841 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1842 pUserData = new ModuleUserData_Impl( aImplName, false,
1843 bCheck, TYPE_GRAMMAR, static_cast<sal_uInt8>(nLocalIndex++) );
1845 sId = weld::toId(pUserData);
1847 m_xModulesCLB->append(nullptr);
1848 m_xModulesCLB->set_id(nRow, sId);
1849 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
1850 m_xModulesCLB->set_text(nRow, aTxt, 0);
1851 m_xModulesCLB->set_text_emphasis(nRow, false, 0);
1852 m_xModulesCLB->set_sensitive(nRow, !bReadOnly);
1853 ++nRow;
1857 // hyphenator entries
1859 pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_HYPH, 0 );
1860 sId = weld::toId(pUserData);
1861 m_xModulesCLB->append(nullptr);
1862 m_xModulesCLB->set_id(nRow, sId);
1863 m_xModulesCLB->set_text(nRow, sHyph, 0);
1864 m_xModulesCLB->set_text_emphasis(nRow, true, 0);
1865 ++nRow;
1867 aConfigPath = officecfg::Office::Linguistic::ServiceManager::path() + "/HyphenatorList/" + aLangNodeName;
1868 if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath))
1870 css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath);
1871 bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0;
1874 nLocalIndex = 0;
1875 for (auto& name : rLinguData.GetSortedImplNames(eCurLanguage, TYPE_HYPH))
1877 OUString aImplName;
1878 bool bIsSuppLang = false;
1880 ServiceInfo_Impl* pInfo = rLinguData.GetInfoByImplName(name);
1881 if (pInfo)
1883 bIsSuppLang = pInfo->xHyph.is() &&
1884 pInfo->xHyph->hasLocale( aCurLocale );
1885 aImplName = pInfo->sHyphImplName;
1887 if (!aImplName.isEmpty() && bIsSuppLang)
1889 OUString aTxt( pInfo->sDisplayName );
1891 LangImplNameTable &rTable = rLinguData.GetHyphTable();
1892 const bool bHasLang = rTable.count( eCurLanguage );
1893 if (!bHasLang)
1895 SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
1897 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1898 pUserData = new ModuleUserData_Impl( aImplName, false,
1899 bCheck, TYPE_HYPH, static_cast<sal_uInt8>(nLocalIndex++) );
1900 sId = weld::toId(pUserData);
1902 m_xModulesCLB->append(nullptr);
1903 m_xModulesCLB->set_id(nRow, sId);
1904 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
1905 m_xModulesCLB->set_text(nRow, aTxt, 0);
1906 m_xModulesCLB->set_text_emphasis(nRow, false, 0);
1907 m_xModulesCLB->set_sensitive(nRow, !bReadOnly);
1908 ++nRow;
1912 // thesaurus entries
1914 pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_THES, 0 );
1915 sId = weld::toId(pUserData);
1916 m_xModulesCLB->append(nullptr);
1917 m_xModulesCLB->set_id(nRow, sId);
1918 m_xModulesCLB->set_text(nRow, sThes, 0);
1919 m_xModulesCLB->set_text_emphasis(nRow, true, 0);
1920 ++nRow;
1922 aConfigPath = officecfg::Office::Linguistic::ServiceManager::path() + "/ThesaurusList/" + aLangNodeName;
1923 if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath))
1925 css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath);
1926 bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0;
1929 nLocalIndex = 0;
1930 for (auto& name : rLinguData.GetSortedImplNames(eCurLanguage, TYPE_THES))
1932 OUString aImplName;
1933 bool bIsSuppLang = false;
1935 ServiceInfo_Impl* pInfo = rLinguData.GetInfoByImplName(name);
1936 if (pInfo)
1938 bIsSuppLang = pInfo->xThes.is() &&
1939 pInfo->xThes->hasLocale( aCurLocale );
1940 aImplName = pInfo->sThesImplName;
1942 if (!aImplName.isEmpty() && bIsSuppLang)
1944 OUString aTxt( pInfo->sDisplayName );
1946 LangImplNameTable &rTable = rLinguData.GetThesTable();
1947 const bool bHasLang = rTable.count( eCurLanguage );
1948 if (!bHasLang)
1950 SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
1952 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
1953 pUserData = new ModuleUserData_Impl( aImplName, false,
1954 bCheck, TYPE_THES, static_cast<sal_uInt8>(nLocalIndex++) );
1955 sId = weld::toId(pUserData);
1957 m_xModulesCLB->append(nullptr);
1958 m_xModulesCLB->set_id(nRow, sId);
1959 m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
1960 m_xModulesCLB->set_text(nRow, aTxt, 0);
1961 m_xModulesCLB->set_text_emphasis(nRow, false, 0);
1962 m_xModulesCLB->set_sensitive(nRow, !bReadOnly);
1963 ++nRow;
1967 aLastLocale = std::move(aCurLocale);
1970 IMPL_LINK( SvxEditModulesDlg, UpDownHdl_Impl, weld::Button&, rBtn, void )
1972 bool bUp = m_xPrioUpPB.get() == &rBtn;
1973 int nCurPos = m_xModulesCLB->get_selected_index();
1974 if (nCurPos == -1)
1975 return;
1977 m_xModulesCLB->freeze();
1979 OUString sId(m_xModulesCLB->get_id(nCurPos));
1980 OUString sStr(m_xModulesCLB->get_text(nCurPos));
1981 bool bIsChecked = m_xModulesCLB->get_toggle(nCurPos);
1983 m_xModulesCLB->remove(nCurPos);
1985 int nDestPos = bUp ? nCurPos - 1 : nCurPos + 1;
1987 m_xModulesCLB->insert_text(nDestPos, sStr);
1988 m_xModulesCLB->set_id(nDestPos, sId);
1989 m_xModulesCLB->set_toggle(nDestPos, bIsChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
1991 m_xModulesCLB->thaw();
1993 m_xModulesCLB->select(nDestPos);
1994 SelectHdl_Impl(*m_xModulesCLB);
1997 IMPL_LINK_NOARG(SvxEditModulesDlg, ClickHdl_Impl, weld::Button&, void)
1999 // store language config
2000 LangSelectHdl_Impl(m_xLanguageLB.get());
2001 m_xDialog->response(RET_OK);
2004 IMPL_LINK_NOARG(SvxEditModulesDlg, BackHdl_Impl, weld::Button&, void)
2006 rLinguData = *pDefaultLinguData;
2007 LangSelectHdl_Impl(nullptr);
2010 IMPL_STATIC_LINK_NOARG(SvxEditModulesDlg, OnLinkClick, weld::LinkButton&, bool)
2012 comphelper::dispatchCommand(u".uno:MoreDictionaries"_ustr, {});
2013 return true;
2016 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */