xref: /core/cui/source/options/optgdlg.cxx (revision 9b8daf901566eda4eea87acc629621969b999482)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_features.h>
21 #include <svl/numformat.hxx>
22 #include <svl/zforlist.hxx>
23 #include <svl/currencytable.hxx>
24 #include <svtools/langhelp.hxx>
25 #include <unotools/lingucfg.hxx>
26 #if defined(_WIN32)
27 #include <unotools/resmgr.hxx>
28 #endif
29 #include <sfx2/bindings.hxx>
30 #include <sfx2/viewfrm.hxx>
31 #include <i18nlangtag/mslangid.hxx>
32 #include <i18nlangtag/languagetag.hxx>
33 #include <unotools/compatibility.hxx>
34 #include <svl/languageoptions.hxx>
35 #include <svl/cjkoptions.hxx>
36 #include <svl/ctloptions.hxx>
37 #include <unotools/syslocaleoptions.hxx>
38 #include <sfx2/objsh.hxx>
39 #include <comphelper/propertysequence.hxx>
40 #include <svtools/langtab.hxx>
41 #include <editeng/unolingu.hxx>
42 #include <editeng/langitem.hxx>
43 #include <comphelper/processfactory.hxx>
44 #include <comphelper/string.hxx>
45 #include <rtl/ustrbuf.hxx>
46 #include <editeng/editids.hrc>
47 #include <svx/svxids.hrc>
48 #include <svl/intitem.hxx>
49 #include <svl/voiditem.hxx>
50 #include <GraphicsTestsDialog.hxx>
51 #include <unotools/searchopt.hxx>
52 #include <sal/log.hxx>
53 #include <officecfg/Office/Canvas.hxx>
54 #include <officecfg/Office/Common.hxx>
55 #include <officecfg/Setup.hxx>
56 #include <comphelper/configuration.hxx>
57 #include <comphelper/diagnose_ex.hxx>
58 #if HAVE_FEATURE_BREAKPAD
59 #include <desktop/crashreport.hxx>
60 #endif
61 
62 #include <com/sun/star/configuration/theDefaultProvider.hpp>
63 #include <com/sun/star/container/XNameAccess.hpp>
64 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
65 #include <com/sun/star/beans/NamedValue.hpp>
66 #include <com/sun/star/beans/XPropertySet.hpp>
67 #include <com/sun/star/util/XChangesBatch.hpp>
68 #include <com/sun/star/uno/Any.hxx>
69 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
70 #include <com/sun/star/container/XSet.hpp>
71 #include <com/sun/star/i18n/ScriptType.hpp>
72 #include <com/sun/star/office/Quickstart.hpp>
73 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
74 
75 #include <vcl/vclenum.hxx>
76 #include <vcl/svapp.hxx>
77 #include <vcl/settings.hxx>
78 #include <vcl/window.hxx>
79 #include <vcl/skia/SkiaHelper.hxx>
80 #include <bitmaps.hlst>
81 
82 #include "optgdlg.hxx"
83 #include <svtools/apearcfg.hxx>
84 #include <svtools/optionsdrawinglayer.hxx>
85 #include <svtools/restartdialog.hxx>
86 #include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
87 #include <vcl/unohelp2.hxx>
88 
89 #if defined(_WIN32)
90 #include <systools/win32/winstoreutil.hxx>
91 #include <vcl/fileregistration.hxx>
92 #endif
93 using namespace ::com::sun::star::uno;
94 using namespace ::com::sun::star::lang;
95 using namespace ::com::sun::star::beans;
96 using namespace ::com::sun::star::container;
97 using namespace ::com::sun::star::util;
98 using namespace ::utl;
99 
100 // class OfaMiscTabPage --------------------------------------------------
101 
DeactivatePage(SfxItemSet * pSet_)102 DeactivateRC OfaMiscTabPage::DeactivatePage( SfxItemSet* pSet_ )
103 {
104     if ( pSet_ )
105         FillItemSet( pSet_ );
106     return DeactivateRC::LeavePage;
107 }
108 
109 namespace
110 {
impl_SystemFileOpenServiceName()111 const OUString & impl_SystemFileOpenServiceName()
112 {
113 #if defined(_WIN32)
114     static constexpr OUString gPicker = u"com.sun.star.ui.dialogs.SystemFilePicker"_ustr;
115     return gPicker;
116 #elif defined MACOSX
117     static constexpr OUString gPicker = u"com.sun.star.ui.dialogs.AquaFilePicker"_ustr;
118     return gPicker;
119 #else
120     return EMPTY_OUSTRING;
121 #endif
122 }
123 
lcl_HasSystemFilePicker()124 bool lcl_HasSystemFilePicker()
125 {
126     if( Application::hasNativeFileSelection() )
127         return true;
128 
129     // Otherwise fall-back on querying services
130     bool bRet = false;
131     Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
132 
133     Reference< XContentEnumerationAccess > xEnumAccess( xFactory, UNO_QUERY );
134     Reference< XSet > xSet( xFactory, UNO_QUERY );
135 
136     if ( ! xEnumAccess.is() || ! xSet.is() )
137         return bRet;
138 
139     try
140     {
141         const OUString& aFileService = impl_SystemFileOpenServiceName();
142         Reference< XEnumeration > xEnum = xEnumAccess->createContentEnumeration( aFileService );
143         if ( xEnum.is() && xEnum->hasMoreElements() )
144             bRet = true;
145     }
146     catch (const IllegalArgumentException&)
147     {
148     }
149     catch (const ElementExistException&)
150     {
151     }
152     return bRet;
153 }
154 }
155 
OfaMiscTabPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rSet)156 OfaMiscTabPage::OfaMiscTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
157     : SfxTabPage(pPage, pController, u"cui/ui/optgeneralpage.ui"_ustr, u"OptGeneralPage"_ustr, &rSet)
158     , m_xExtHelpCB(m_xBuilder->weld_check_button(u"exthelp"_ustr))
159     , m_xExtHelpImg(m_xBuilder->weld_widget(u"lockexthelp"_ustr))
160     , m_xPopUpNoHelpCB(m_xBuilder->weld_check_button(u"popupnohelp"_ustr))
161     , m_xPopUpNoHelpImg(m_xBuilder->weld_widget(u"lockpopupnohelp"_ustr))
162     , m_xShowTipOfTheDay(m_xBuilder->weld_check_button(u"cbShowTipOfTheDay"_ustr))
163     , m_xShowTipOfTheDayImg(m_xBuilder->weld_widget(u"lockcbShowTipOfTheDay"_ustr))
164     , m_xFileDlgFrame(m_xBuilder->weld_widget(u"filedlgframe"_ustr))
165     , m_xFileDlgROImage(m_xBuilder->weld_widget(u"lockimage"_ustr))
166     , m_xFileDlgCB(m_xBuilder->weld_check_button(u"filedlg"_ustr))
167     , m_xDocStatusCB(m_xBuilder->weld_check_button(u"docstatus"_ustr))
168     , m_xDocStatusImg(m_xBuilder->weld_widget(u"lockdocstatus"_ustr))
169     , m_xYearFrame(m_xBuilder->weld_widget(u"yearframe"_ustr))
170     , m_xYearLabel(m_xBuilder->weld_label(u"yearslabel"_ustr))
171     , m_xYearValueField(m_xBuilder->weld_spin_button(u"year"_ustr))
172     , m_xToYearFT(m_xBuilder->weld_label(u"toyear"_ustr))
173     , m_xYearFrameImg(m_xBuilder->weld_widget(u"lockyears"_ustr))
174 #if HAVE_FEATURE_BREAKPAD
175     , m_xPrivacyFrame(m_xBuilder->weld_widget("privacyframe"))
176     , m_xCrashReport(m_xBuilder->weld_check_button("crashreport"))
177     , m_xCrashReportImg(m_xBuilder->weld_widget("lockcrashreport"))
178 #endif
179 #if defined(_WIN32)
180     , m_xQuickStarterFrame(m_xBuilder->weld_widget("quickstarter"))
181     , m_xQuickLaunchCB(m_xBuilder->weld_check_button("quicklaunch"))
182     , m_xQuickLaunchImg(m_xBuilder->weld_widget("lockquicklaunch"))
183     , m_xFileAssocFrame(m_xBuilder->weld_widget("fileassoc"))
184     , m_xFileAssocBtn(m_xBuilder->weld_button("assocfiles"))
185     , m_xPerformFileExtCheck(m_xBuilder->weld_check_button("cbPerformFileExtCheck"))
186     , m_xPerformFileExtImg(m_xBuilder->weld_widget("lockcbPerformFileExtCheck"))
187 #endif
188 {
189 #if HAVE_FEATURE_BREAKPAD
190     m_xPrivacyFrame->show();
191 #endif
192 
193 #if defined(_WIN32)
194     // Store-packaged apps (located under the protected Program Files\WindowsApps) can't use normal
195     // shell shortcuts to their exe. TODO: show a button to open "Startup Apps" system applet?
196     if (!sal::systools::IsStorePackagedApp())
197         m_xQuickStarterFrame->show();
198 
199     m_xFileAssocFrame->show();
200     m_xFileAssocBtn->connect_clicked(LINK(this, OfaMiscTabPage, FileAssocClick));
201 #endif
202 
203     m_aStrDateInfo = m_xToYearFT->get_label();
204     m_xYearValueField->connect_value_changed( LINK( this, OfaMiscTabPage, TwoFigureHdl ) );
205 
206     SetExchangeSupport();
207 }
208 
~OfaMiscTabPage()209 OfaMiscTabPage::~OfaMiscTabPage()
210 {
211 }
212 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rAttrSet)213 std::unique_ptr<SfxTabPage> OfaMiscTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
214 {
215     return std::make_unique<OfaMiscTabPage>( pPage, pController, *rAttrSet );
216 }
217 
GetAllStrings()218 OUString OfaMiscTabPage::GetAllStrings()
219 {
220     OUString sAllStrings;
221     OUString labels[] = { u"label1"_ustr, u"label2"_ustr, u"label4"_ustr, u"label5"_ustr, u"yearslabel"_ustr,
222                           u"toyear"_ustr, u"label8"_ustr, u"label9"_ustr };
223 
224     for (const auto& label : labels)
225     {
226         if (const auto pString = m_xBuilder->weld_label(label))
227             sAllStrings += pString->get_label() + " ";
228     }
229 
230     OUString checkButton[]
231         = { u"exthelp"_ustr,   u"popupnohelp"_ustr, u"cbShowTipOfTheDay"_ustr, u"filedlg"_ustr,
232             u"docstatus"_ustr, u"crashreport"_ustr, u"quicklaunch"_ustr,       u"cbPerformFileExtCheck"_ustr };
233 
234     for (const auto& check : checkButton)
235     {
236         if (const auto pString = m_xBuilder->weld_check_button(check))
237             sAllStrings += pString->get_label() + " ";
238     }
239 
240     if (const auto pString = m_xBuilder->weld_button(u"assocfiles"_ustr))
241         sAllStrings += pString->get_label() + " ";
242 
243     return sAllStrings.replaceAll("_", "");
244 }
245 
FillItemSet(SfxItemSet * rSet)246 bool OfaMiscTabPage::FillItemSet( SfxItemSet* rSet )
247 {
248     bool bModified = false;
249     std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
250 
251     if ( m_xPopUpNoHelpCB->get_state_changed_from_saved() )
252         officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::set(m_xPopUpNoHelpCB->get_active(), batch);
253 
254     if ( m_xExtHelpCB->get_state_changed_from_saved() )
255         officecfg::Office::Common::Help::ExtendedTip::set(m_xExtHelpCB->get_active(), batch);
256 
257     if ( m_xShowTipOfTheDay->get_state_changed_from_saved() )
258     {
259         officecfg::Office::Common::Misc::ShowTipOfTheDay::set(m_xShowTipOfTheDay->get_active(), batch);
260         bModified = true;
261     }
262 
263     if ( m_xFileDlgCB->get_state_changed_from_saved() )
264     {
265         officecfg::Office::Common::Misc::UseSystemFileDialog::set( !m_xFileDlgCB->get_active(), batch );
266         bModified = true;
267     }
268 
269     if (m_xDocStatusCB->get_state_changed_from_saved())
270     {
271         officecfg::Office::Common::Print::PrintingModifiesDocument::set(m_xDocStatusCB->get_active(), batch);
272         bModified = true;
273     }
274 
275     const SfxUInt16Item* pUInt16Item = GetOldItem( *rSet, SID_ATTR_YEAR2000 );
276     sal_uInt16 nNum = static_cast<sal_uInt16>(m_xYearValueField->get_text().toInt32());
277     if ( pUInt16Item && pUInt16Item->GetValue() != nNum )
278     {
279         bModified = true;
280         rSet->Put( SfxUInt16Item( SID_ATTR_YEAR2000, nNum ) );
281     }
282 
283 #if HAVE_FEATURE_BREAKPAD
284     if (m_xCrashReport->get_state_changed_from_saved())
285     {
286         officecfg::Office::Common::Misc::CrashReport::set(m_xCrashReport->get_active(), batch);
287         bModified = true;
288     }
289 #endif
290 
291 #if defined(_WIN32)
292     if (m_xPerformFileExtCheck->get_state_changed_from_saved())
293     {
294         officecfg::Office::Common::Misc::PerformFileExtCheck::set(
295             m_xPerformFileExtCheck->get_active(), batch);
296         bModified = true;
297     }
298 
299     if( m_xQuickLaunchCB->get_state_changed_from_saved())
300     {
301         rSet->Put(SfxBoolItem(SID_ATTR_QUICKLAUNCHER, m_xQuickLaunchCB->get_active()));
302         bModified = true;
303     }
304 #endif
305 
306     batch->commit();
307 
308     return bModified;
309 }
310 
Reset(const SfxItemSet * rSet)311 void OfaMiscTabPage::Reset( const SfxItemSet* rSet )
312 {
313     bool bEnable = !officecfg::Office::Common::Help::ExtendedTip::isReadOnly();
314     m_xExtHelpCB->set_active( officecfg::Office::Common::Help::Tip::get() &&
315             officecfg::Office::Common::Help::ExtendedTip::get() );
316     m_xExtHelpCB->set_sensitive(bEnable);
317     m_xExtHelpImg->set_visible(!bEnable);
318     m_xExtHelpCB->save_state();
319 
320     bEnable = !officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::isReadOnly();
321     m_xPopUpNoHelpCB->set_active( officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::get() );
322     m_xPopUpNoHelpCB->set_sensitive(bEnable);
323     m_xPopUpNoHelpImg->set_visible(!bEnable);
324     m_xPopUpNoHelpCB->save_state();
325 
326     bEnable = !officecfg::Office::Common::Misc::ShowTipOfTheDay::isReadOnly();
327     m_xShowTipOfTheDay->set_active( officecfg::Office::Common::Misc::ShowTipOfTheDay::get() );
328     m_xShowTipOfTheDay->set_sensitive(bEnable);
329     m_xShowTipOfTheDayImg->set_visible(!bEnable);
330     m_xShowTipOfTheDay->save_state();
331 
332     if (!lcl_HasSystemFilePicker())
333         m_xFileDlgFrame->hide();
334     else
335     {
336         bEnable = !officecfg::Office::Common::Misc::UseSystemFileDialog::isReadOnly();
337         m_xFileDlgCB->set_sensitive(bEnable);
338         m_xFileDlgROImage->set_visible(!bEnable);
339     }
340     m_xFileDlgCB->set_active(!officecfg::Office::Common::Misc::UseSystemFileDialog::get());
341     m_xFileDlgCB->save_state();
342 
343     bEnable = !officecfg::Office::Common::Print::PrintingModifiesDocument::isReadOnly();
344     m_xDocStatusCB->set_active(officecfg::Office::Common::Print::PrintingModifiesDocument::get());
345     m_xDocStatusCB->set_sensitive(bEnable);
346     m_xDocStatusImg->set_visible(!bEnable);
347     m_xDocStatusCB->save_state();
348 
349     bEnable = !officecfg::Office::Common::DateFormat::TwoDigitYear::isReadOnly();
350     m_xYearLabel->set_sensitive(bEnable);
351     m_xYearValueField->set_sensitive(bEnable);
352     m_xToYearFT->set_sensitive(bEnable);
353     m_xYearFrameImg->set_visible(!bEnable);
354 
355     if ( const SfxUInt16Item* pYearItem = rSet->GetItemIfSet( SID_ATTR_YEAR2000, false ) )
356     {
357         m_xYearValueField->set_value( pYearItem->GetValue() );
358         TwoFigureHdl(*m_xYearValueField);
359     }
360     else
361         m_xYearFrame->set_sensitive(false);
362 
363 #if HAVE_FEATURE_BREAKPAD
364     m_xCrashReport->set_active(officecfg::Office::Common::Misc::CrashReport::get() && CrashReporter::IsDumpEnable());
365     m_xCrashReport->set_sensitive(!officecfg::Office::Common::Misc::CrashReport::isReadOnly() && CrashReporter::IsDumpEnable());
366     m_xCrashReportImg->set_visible(officecfg::Office::Common::Misc::CrashReport::isReadOnly() && CrashReporter::IsDumpEnable());
367     m_xCrashReport->save_state();
368 #endif
369 
370 #if defined(_WIN32)
371     if (const SfxBoolItem* pItem = rSet->GetItemIfSet( SID_ATTR_QUICKLAUNCHER, false ))
372     {
373         m_xQuickLaunchCB->set_active( pItem->GetValue() );
374     }
375     else
376     {
377         // quickstart not installed
378         m_xQuickStarterFrame->hide();
379     }
380 
381     m_xQuickLaunchCB->save_state();
382 
383     m_xPerformFileExtCheck->set_active(
384         officecfg::Office::Common::Misc::PerformFileExtCheck::get());
385     m_xPerformFileExtCheck->save_state();
386     m_xPerformFileExtCheck->set_sensitive(!officecfg::Office::Common::Misc::PerformFileExtCheck::isReadOnly());
387     m_xPerformFileExtImg->set_visible(officecfg::Office::Common::Misc::PerformFileExtCheck::isReadOnly());
388 #endif
389 }
390 
IMPL_LINK_NOARG(OfaMiscTabPage,TwoFigureHdl,weld::SpinButton &,void)391 IMPL_LINK_NOARG( OfaMiscTabPage, TwoFigureHdl, weld::SpinButton&, void )
392 {
393     OUString aOutput( m_aStrDateInfo );
394     OUString aStr( m_xYearValueField->get_text() );
395     sal_Int32 nNum = aStr.toInt32();
396     if ( aStr.getLength() != 4 || nNum < m_xYearValueField->get_min() || nNum > m_xYearValueField->get_max() )
397         aOutput += "????";
398     else
399     {
400         nNum += 99;
401         aOutput += OUString::number( nNum );
402     }
403     m_xToYearFT->set_label( aOutput );
404 }
405 
406 #if defined(_WIN32)
IMPL_STATIC_LINK_NOARG(OfaMiscTabPage,FileAssocClick,weld::Button &,void)407 IMPL_STATIC_LINK_NOARG(OfaMiscTabPage, FileAssocClick, weld::Button&, void)
408 {
409     vcl::fileregistration::LaunchRegistrationUI();
410 }
411 #endif
412 
413 class CanvasSettings
414 {
415 public:
416     CanvasSettings();
417 
418     bool    IsHardwareAccelerationAvailable() const;
419 
420 private:
421     typedef std::vector< std::pair<OUString,Sequence<OUString> > > ServiceVector;
422 
423     Reference<XNameAccess> mxForceFlagNameAccess;
424     ServiceVector          maAvailableImplementations;
425     mutable bool           mbHWAccelAvailable;
426     mutable bool           mbHWAccelChecked;
427 };
428 
CanvasSettings()429 CanvasSettings::CanvasSettings() :
430     mbHWAccelAvailable(false),
431     mbHWAccelChecked(false)
432 {
433     try
434     {
435         Reference<XMultiServiceFactory> xConfigProvider(
436             css::configuration::theDefaultProvider::get(
437                 comphelper::getProcessComponentContext()));
438 
439         Sequence<Any> aArgs1(comphelper::InitAnyPropertySequence(
440         {
441             {"nodepath", Any(u"/org.openoffice.Office.Canvas"_ustr)}
442         }));
443         mxForceFlagNameAccess.set(
444             xConfigProvider->createInstanceWithArguments(
445                 u"com.sun.star.configuration.ConfigurationUpdateAccess"_ustr,
446                 aArgs1 ),
447             UNO_QUERY_THROW );
448 
449         Sequence<Any> aArgs2(comphelper::InitAnyPropertySequence(
450         {
451             {"nodepath", Any(u"/org.openoffice.Office.Canvas/CanvasServiceList"_ustr)}
452         }));
453         Reference<XNameAccess> xNameAccess(
454             xConfigProvider->createInstanceWithArguments(
455                 u"com.sun.star.configuration.ConfigurationAccess"_ustr,
456                 aArgs2 ), UNO_QUERY_THROW );
457         Reference<XHierarchicalNameAccess> xHierarchicalNameAccess(
458             xNameAccess, UNO_QUERY_THROW);
459 
460         for (auto& serviceName : xNameAccess->getElementNames())
461         {
462             Reference<XNameAccess> xEntryNameAccess(
463                 xHierarchicalNameAccess->getByHierarchicalName(serviceName),
464                 UNO_QUERY );
465 
466             if( xEntryNameAccess.is() )
467             {
468                 Sequence<OUString> preferredImplementations;
469                 if( xEntryNameAccess->getByName(u"PreferredImplementations"_ustr) >>= preferredImplementations )
470                     maAvailableImplementations.emplace_back(serviceName, preferredImplementations);
471             }
472         }
473     }
474     catch (const Exception&)
475     {
476     }
477 }
478 
IsHardwareAccelerationAvailable() const479 bool CanvasSettings::IsHardwareAccelerationAvailable() const
480 {
481     if( !mbHWAccelChecked )
482     {
483         mbHWAccelChecked = true;
484 
485         Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
486 
487         // check whether any of the service lists has an
488         // implementation that presents the "HardwareAcceleration" property
489         for (auto const& availableImpl : maAvailableImplementations)
490         {
491             for (auto& currImpl : availableImpl.second)
492             {
493                 try
494                 {
495                     Reference<XPropertySet> xPropSet( xFactory->createInstance(
496                                                           currImpl.trim() ),
497                                                       UNO_QUERY_THROW );
498                     bool bHasAccel(false);
499                     if( xPropSet->getPropertyValue(u"HardwareAcceleration"_ustr) >>= bHasAccel )
500                         if( bHasAccel )
501                         {
502                             mbHWAccelAvailable = true;
503                             return mbHWAccelAvailable;
504                         }
505                 }
506                 catch (const Exception&)
507                 {
508                 }
509             }
510         }
511     }
512 
513     return mbHWAccelAvailable;
514 }
515 
516 // class OfaViewTabPage --------------------------------------------------
517 
OfaViewTabPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rSet)518 OfaViewTabPage::OfaViewTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
519     : SfxTabPage(pPage, pController, u"cui/ui/optviewpage.ui"_ustr, u"OptViewPage"_ustr, &rSet)
520     , pCanvasSettings(new CanvasSettings)
521     , m_xFontAntiAliasing(m_xBuilder->weld_check_button(u"aafont"_ustr))
522     , m_xFontAntiAliasingImg(m_xBuilder->weld_widget(u"lockaafont"_ustr))
523     , m_xAAPointLimitLabel(m_xBuilder->weld_label(u"aafrom"_ustr))
524     , m_xAAPointLimitLabelImg(m_xBuilder->weld_widget(u"lockaafrom"_ustr))
525     , m_xAAPointLimit(m_xBuilder->weld_metric_spin_button(u"aanf"_ustr, FieldUnit::PIXEL))
526     , m_xFontShowCB(m_xBuilder->weld_check_button(u"showfontpreview"_ustr))
527     , m_xFontShowImg(m_xBuilder->weld_widget(u"lockshowfontpreview"_ustr))
528     , m_xUseHardwareAccell(m_xBuilder->weld_check_button(u"useaccel"_ustr))
529     , m_xUseHardwareAccellImg(m_xBuilder->weld_widget(u"lockuseaccel"_ustr))
530     , m_xUseAntiAliase(m_xBuilder->weld_check_button(u"useaa"_ustr))
531     , m_xUseAntiAliaseImg(m_xBuilder->weld_widget(u"lockuseaa"_ustr))
532     , m_xUseSkia(m_xBuilder->weld_check_button(u"useskia"_ustr))
533     , m_xUseSkiaImg(m_xBuilder->weld_widget(u"lockuseskia"_ustr))
534     , m_xForceSkiaRaster(m_xBuilder->weld_check_button(u"forceskiaraster"_ustr))
535     , m_xForceSkiaRasterImg(m_xBuilder->weld_widget(u"lockforceskiaraster"_ustr))
536     , m_xSkiaStatusEnabled(m_xBuilder->weld_label(u"skiaenabled"_ustr))
537     , m_xSkiaStatusDisabled(m_xBuilder->weld_label(u"skiadisabled"_ustr))
538     , m_xSkiaLog(m_xBuilder->weld_button(u"btnSkialog"_ustr))
539     , m_xMouseMiddleLabel(m_xBuilder->weld_label(u"label12"_ustr))
540     , m_xMouseMiddleLB(m_xBuilder->weld_combo_box(u"mousemiddle"_ustr))
541     , m_xMouseMiddleImg(m_xBuilder->weld_widget(u"lockmousemiddle"_ustr))
542     , m_xRunGPTests(m_xBuilder->weld_button(u"btn_rungptest"_ustr))
543 {
544     m_xFontAntiAliasing->connect_toggled( LINK( this, OfaViewTabPage, OnAntialiasingToggled ) );
545 
546     m_xUseSkia->connect_toggled(LINK(this, OfaViewTabPage, OnUseSkiaToggled));
547     m_xSkiaLog->connect_clicked(LINK(this, OfaViewTabPage, OnCopySkiaLog));
548 
549     m_xRunGPTests->connect_clicked(LINK(this, OfaViewTabPage, OnRunGPTestClick));
550 
551     // Hide "Run Graphics Test" button if Experimental Mode is off
552     if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
553         m_xRunGPTests->hide();
554 }
555 
~OfaViewTabPage()556 OfaViewTabPage::~OfaViewTabPage()
557 {
558 }
559 
IMPL_LINK_NOARG(OfaViewTabPage,OnRunGPTestClick,weld::Button &,void)560 IMPL_LINK_NOARG(OfaViewTabPage, OnRunGPTestClick, weld::Button&, void)
561 {
562     GraphicsTestsDialog m_xGraphicsTestDialog(m_xContainer.get());
563     m_xGraphicsTestDialog.run();
564 }
565 
IMPL_LINK_NOARG(OfaViewTabPage,OnAntialiasingToggled,weld::Toggleable &,void)566 IMPL_LINK_NOARG( OfaViewTabPage, OnAntialiasingToggled, weld::Toggleable&, void )
567 {
568     bool bAAEnabled = m_xFontAntiAliasing->get_active() && !officecfg::Office::Common::View::FontAntiAliasing::MinPixelHeight::isReadOnly();
569 
570     m_xAAPointLimitLabel->set_sensitive(bAAEnabled);
571     m_xAAPointLimit->set_sensitive(bAAEnabled);
572 }
573 
IMPL_LINK_NOARG(OfaViewTabPage,OnUseSkiaToggled,weld::Toggleable &,void)574 IMPL_LINK_NOARG(OfaViewTabPage, OnUseSkiaToggled, weld::Toggleable&, void)
575 {
576     UpdateSkiaStatus();
577 }
578 
IMPL_LINK_NOARG(OfaViewTabPage,OnCopySkiaLog,weld::Button &,void)579 IMPL_LINK_NOARG(OfaViewTabPage, OnCopySkiaLog, weld::Button&, void)
580 {
581 #if HAVE_FEATURE_SKIA
582     css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard =
583         css::datatransfer::clipboard::SystemClipboard::create(
584             comphelper::getProcessComponentContext());
585     OUString sInfo = SkiaHelper::readLog();
586     vcl::unohelper::TextDataObject::CopyStringTo(sInfo, xClipboard);
587     m_xSkiaLog->set_from_icon_name(RID_SVXBMP_COPY);
588 #endif
589 }
590 
HideSkiaWidgets()591 void OfaViewTabPage::HideSkiaWidgets()
592 {
593     m_xUseSkia->hide();
594     m_xForceSkiaRaster->hide();
595     m_xSkiaStatusEnabled->hide();
596     m_xSkiaStatusDisabled->hide();
597     m_xSkiaLog->hide();
598 }
599 
UpdateSkiaStatus()600 void OfaViewTabPage::UpdateSkiaStatus()
601 {
602 #if HAVE_FEATURE_SKIA
603     bool skiaHidden = true;
604 
605     // For now Skia is used mainly on Windows, enable the controls there.
606     if (Application::GetToolkitName() == "win")
607         skiaHidden = false;
608     // It can also be used on Linux, but only with the rarely used 'gen' backend.
609     if (Application::GetToolkitName() == "x11")
610         skiaHidden = false;
611     // OSX backend has Skia support too.
612     if (Application::GetToolkitName() == "osx")
613         skiaHidden = false;
614 
615     if (skiaHidden)
616     {
617         HideSkiaWidgets();
618         return;
619     }
620 
621     // Easier than a custom translation string.
622     bool bEnabled = SkiaHelper::isVCLSkiaEnabled();
623     m_xSkiaStatusEnabled->set_visible(bEnabled);
624     m_xSkiaStatusDisabled->set_visible(!bEnabled);
625 
626 #if defined(MACOSX) || defined(_WIN32)
627     m_xUseSkia->set_sensitive(false); // macOS/win can __only__ render via skia
628 #else
629     m_xUseSkia->set_sensitive(!officecfg::Office::Common::VCL::UseSkia::isReadOnly());
630 #endif
631     m_xUseSkiaImg->set_visible(officecfg::Office::Common::VCL::UseSkia::isReadOnly());
632     m_xForceSkiaRaster->set_sensitive(m_xUseSkia->get_active() && !officecfg::Office::Common::VCL::ForceSkiaRaster::isReadOnly());
633     m_xForceSkiaRasterImg->set_visible(officecfg::Office::Common::VCL::ForceSkiaRaster::isReadOnly());
634     m_xSkiaLog->set_sensitive(bEnabled);
635 
636     // Technically the 'use hardware acceleration' option could be used to mean !forceSkiaRaster, but the implementation
637     // of the option is so tied to the implementation of the canvas module that it's simpler to ignore it.
638     UpdateHardwareAccelStatus();
639 #else
640     HideSkiaWidgets();
641 #endif
642 }
643 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rAttrSet)644 std::unique_ptr<SfxTabPage> OfaViewTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
645 {
646     return std::make_unique<OfaViewTabPage>(pPage, pController, *rAttrSet);
647 }
648 
GetAllStrings()649 OUString OfaViewTabPage::GetAllStrings()
650 {
651     OUString sAllStrings;
652     OUString labels[] = { u"label16"_ustr, u"label1"_ustr,      u"label6"_ustr,       u"label15"_ustr,
653                           u"label14"_ustr, u"label8"_ustr,      u"label9"_ustr,       u"label4"_ustr, u"label12"_ustr,
654                           u"label2"_ustr,  u"skiaenabled"_ustr, u"skiadisabled"_ustr, u"label5"_ustr, u"aafrom"_ustr };
655 
656     for (const auto& label : labels)
657     {
658         if (const auto pString = m_xBuilder->weld_label(label))
659             sAllStrings += pString->get_label() + " ";
660     }
661 
662     OUString checkButton[]
663         = { u"useaccel"_ustr, u"useaa"_ustr, u"useskia"_ustr, u"forceskiaraster"_ustr, u"showfontpreview"_ustr, u"aafont"_ustr };
664 
665     for (const auto& check : checkButton)
666     {
667         if (const auto pString = m_xBuilder->weld_check_button(check))
668             sAllStrings += pString->get_label() + " ";
669     }
670 
671     sAllStrings += m_xSkiaLog->get_label() + " " + m_xRunGPTests->get_label() + " ";
672 
673     return sAllStrings.replaceAll("_", "");
674 }
675 
FillItemSet(SfxItemSet *)676 bool OfaViewTabPage::FillItemSet( SfxItemSet* )
677 {
678     bool bModified = false;
679     bool bRepaintWindows(false);
680 
681     bool bAppearanceChanged = false;
682     std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
683 
684     // Middle Mouse Button
685     MouseMiddleButtonAction eOldMiddleMouse = static_cast<MouseMiddleButtonAction>(officecfg::Office::Common::View::Dialog::MiddleMouseButton::get());
686     short eNewMiddleMouse = m_xMouseMiddleLB->get_active();
687     if(eNewMiddleMouse > 2)
688         eNewMiddleMouse = 2;
689 
690     if ( eNewMiddleMouse != static_cast<short>(eOldMiddleMouse) )
691     {
692         officecfg::Office::Common::View::Dialog::MiddleMouseButton::set(eNewMiddleMouse, batch);
693         bAppearanceChanged = true;
694     }
695 
696     if (m_xFontAntiAliasing->get_state_changed_from_saved())
697     {
698         bool b = m_xFontAntiAliasing->get_active();
699         officecfg::Office::Common::View::FontAntiAliasing::Enabled::set(b, batch);
700         bAppearanceChanged = true;
701     }
702 
703     if (m_xAAPointLimit->get_value_changed_from_saved())
704     {
705         sal_Int64 i = m_xAAPointLimit->get_value(FieldUnit::PIXEL);
706         officecfg::Office::Common::View::FontAntiAliasing::MinPixelHeight::set(i, batch);
707         bAppearanceChanged = true;
708     }
709 
710     std::shared_ptr<comphelper::ConfigurationChanges> xChanges(comphelper::ConfigurationChanges::create());
711 
712     if (m_xFontShowCB->get_state_changed_from_saved())
713     {
714         officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::set(m_xFontShowCB->get_active(), xChanges);
715         bModified = true;
716     }
717 
718     // #i95644#  if disabled, do not use value, see in ::Reset()
719     if (m_xUseHardwareAccell->get_sensitive())
720     {
721         if(m_xUseHardwareAccell->get_state_changed_from_saved())
722         {
723             officecfg::Office::Canvas::ForceSafeServiceImpl::set(m_xUseHardwareAccell->get_active(), xChanges);
724             bModified = true;
725         }
726     }
727 
728     // #i95644#  if disabled, do not use value, see in ::Reset()
729     if (m_xUseAntiAliase->get_sensitive())
730     {
731         if (m_xUseAntiAliase->get_active() != SvtOptionsDrawinglayer::IsAntiAliasing())
732         {
733             SvtOptionsDrawinglayer::SetAntiAliasing(m_xUseAntiAliase->get_active(), /*bTemporary*/false);
734             bModified = true;
735             bRepaintWindows = true;
736         }
737     }
738 
739     if (m_xUseSkia->get_state_changed_from_saved() ||
740         m_xForceSkiaRaster->get_state_changed_from_saved())
741     {
742         officecfg::Office::Common::VCL::UseSkia::set(m_xUseSkia->get_active(), xChanges);
743         officecfg::Office::Common::VCL::ForceSkiaRaster::set(m_xForceSkiaRaster->get_active(), xChanges);
744         bModified = true;
745     }
746 
747     xChanges->commit();
748 
749     if ( bAppearanceChanged )
750     {
751         batch->commit();
752         SvtTabAppearanceCfg::SetApplicationDefaults ( GetpApp() );
753     }
754 
755     if(bRepaintWindows)
756     {
757         vcl::Window* pAppWindow = Application::GetFirstTopLevelWindow();
758 
759         while(pAppWindow)
760         {
761             pAppWindow->Invalidate();
762             pAppWindow = Application::GetNextTopLevelWindow(pAppWindow);
763         }
764     }
765 
766     if (m_xUseSkia->get_state_changed_from_saved() ||
767         m_xForceSkiaRaster->get_state_changed_from_saved())
768     {
769         SolarMutexGuard aGuard;
770         if( svtools::executeRestartDialog(
771                 comphelper::getProcessComponentContext(), nullptr,
772                 svtools::RESTART_REASON_SKIA))
773             GetDialogController()->response(RET_OK);
774     }
775 
776     return bModified;
777 }
778 
Reset(const SfxItemSet *)779 void OfaViewTabPage::Reset( const SfxItemSet* )
780 {
781     bool bEnable = true;
782 
783     // Middle Mouse Button
784     bEnable = !officecfg::Office::Common::View::Dialog::MiddleMouseButton::isReadOnly();
785     sal_Int16 nMiddleMouseButton = officecfg::Office::Common::View::Dialog::MiddleMouseButton::get();
786     m_xMouseMiddleLB->set_active(static_cast<short>(nMiddleMouseButton));
787     m_xMouseMiddleLabel->set_sensitive(bEnable);
788     m_xMouseMiddleLB->set_sensitive(bEnable);
789     m_xMouseMiddleImg->set_visible(!bEnable);
790     m_xMouseMiddleLB->save_value();
791 
792     bEnable = !officecfg::Office::Common::View::FontAntiAliasing::Enabled::isReadOnly();
793     bool bFontAntiAliasing = officecfg::Office::Common::View::FontAntiAliasing::Enabled::get();
794     m_xFontAntiAliasing->set_active( bFontAntiAliasing );
795     m_xFontAntiAliasing->set_sensitive(bEnable);
796     m_xFontAntiAliasingImg->set_visible(!bEnable);
797 
798     bEnable = !officecfg::Office::Common::View::FontAntiAliasing::MinPixelHeight::isReadOnly();
799     sal_Int16 nFontAntiAliasingMinPixelHeight = officecfg::Office::Common::View::FontAntiAliasing::MinPixelHeight::get();
800     m_xAAPointLimit->set_value(nFontAntiAliasingMinPixelHeight, FieldUnit::PIXEL);
801     m_xAAPointLimit->set_sensitive(bEnable);
802     m_xAAPointLimitLabelImg->set_visible(!bEnable);
803 
804     // WorkingSet
805     bEnable = !officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::isReadOnly();
806     m_xFontShowCB->set_active(officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::get());
807     m_xFontShowCB->set_sensitive(bEnable);
808     m_xFontShowImg->set_visible(!bEnable);
809 
810     UpdateHardwareAccelStatus();
811     m_xUseHardwareAccell->save_state();
812 
813     { // #i95644# AntiAliasing
814         m_xUseAntiAliase->set_active(SvtOptionsDrawinglayer::IsAntiAliasing());
815         bEnable = !officecfg::Office::Common::Drawinglayer::AntiAliasing::isReadOnly();
816         m_xUseAntiAliase->set_sensitive(bEnable);
817         m_xUseAntiAliaseImg->set_visible(!bEnable);
818         m_xUseAntiAliase->save_state();
819     }
820 
821 #if defined(MACOSX) || defined(_WIN32)
822     m_xUseSkia->set_active(true); // macOS/win can __only__ render via skia
823 #else
824     m_xUseSkia->set_active(officecfg::Office::Common::VCL::UseSkia::get());
825 #endif
826     m_xForceSkiaRaster->set_active(officecfg::Office::Common::VCL::ForceSkiaRaster::get());
827     m_xUseSkia->save_state();
828     m_xForceSkiaRaster->save_state();
829 
830     m_xFontAntiAliasing->save_state();
831     m_xAAPointLimit->save_value();
832     m_xFontShowCB->save_state();
833 
834     OnAntialiasingToggled(*m_xFontAntiAliasing);
835     UpdateSkiaStatus();
836 }
837 
UpdateHardwareAccelStatus()838 void OfaViewTabPage::UpdateHardwareAccelStatus()
839 {
840     // #i95644# HW accel (unified to disable mechanism)
841     bool bHardwareAccRO = officecfg::Office::Canvas::ForceSafeServiceImpl::isReadOnly();
842     if(pCanvasSettings->IsHardwareAccelerationAvailable())
843     {
844         m_xUseHardwareAccell->set_active(officecfg::Office::Canvas::ForceSafeServiceImpl::get());
845         m_xUseHardwareAccell->set_sensitive(!bHardwareAccRO);
846         m_xUseHardwareAccellImg->set_visible(bHardwareAccRO);
847     }
848     else
849     {
850         m_xUseHardwareAccell->set_active(false);
851         m_xUseHardwareAccell->set_sensitive(false);
852         m_xUseHardwareAccellImg->set_visible(true);
853     }
854 #if HAVE_FEATURE_SKIA
855     m_xUseHardwareAccell->set_sensitive(!bHardwareAccRO && !m_xUseSkia->get_active());
856 #endif
857 }
858 
859 struct LanguageConfig_Impl
860 {
861     SvtCTLOptions aCTLLanguageOptions;
862     SvtSysLocaleOptions aSysLocaleOptions;
863     SvtLinguConfig aLinguConfig;
864 };
865 
866 static bool bLanguageCurrentDoc_Impl = false;
867 
868 // some things we'll need...
869 constexpr OUString sAccessSrvc = u"com.sun.star.configuration.ConfigurationAccess"_ustr;
870 constexpr OUStringLiteral sAccessUpdSrvc = u"com.sun.star.configuration.ConfigurationUpdateAccess";
871 constexpr OUString sInstalledLocalesPath = u"org.openoffice.Setup/Office/InstalledLocales"_ustr;
872 constexpr OUString sUserLocalePath = u"org.openoffice.Office.Linguistic/General"_ustr;
873 constexpr OUString sUserLocaleKey = u"UILocale"_ustr;
874 static Sequence< OUString > seqInstalledLanguages;
875 
lcl_getDatePatternsConfigString(const LocaleDataWrapper & rLocaleWrapper)876 static OUString lcl_getDatePatternsConfigString( const LocaleDataWrapper& rLocaleWrapper )
877 {
878     const Sequence< OUString >& aDateAcceptancePatterns = rLocaleWrapper.getDateAcceptancePatterns();
879     sal_Int32 nPatterns = aDateAcceptancePatterns.getLength();
880     OUStringBuffer aBuf( nPatterns * 6 );   // 6 := length of Y-M-D;
881     SAL_WARN_IF( !nPatterns, "cui.options", "No date acceptance pattern");
882     if (nPatterns)
883     {
884         aBuf.append(aDateAcceptancePatterns[0]);
885         for (sal_Int32 i=1; i < nPatterns; ++i)
886             aBuf.append(";" + aDateAcceptancePatterns[i]);
887     }
888     return aBuf.makeStringAndClear();
889 }
890 
891 namespace
892 {
893     //what ui language will be selected by default if the user override of General::UILocale is unset ?
GetInstalledLocaleForSystemUILanguage()894     LanguageTag GetInstalledLocaleForSystemUILanguage()
895     {
896         css::uno::Sequence<OUString> inst(officecfg::Setup::Office::InstalledLocales::get()->getElementNames());
897         return LanguageTag(getInstalledLocaleForSystemUILanguage(inst, false)).makeFallback();
898     }
899 }
900 
OfaLanguagesTabPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rSet)901 OfaLanguagesTabPage::OfaLanguagesTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
902     : SfxTabPage(pPage, pController, u"cui/ui/optlanguagespage.ui"_ustr, u"OptLanguagesPage"_ustr, &rSet)
903     , pLangConfig(new LanguageConfig_Impl)
904     , m_bDatePatternsValid(false)
905     , m_xUserInterfaceLB(m_xBuilder->weld_combo_box(u"userinterface"_ustr))
906     , m_xLocaleSettingFT(m_xBuilder->weld_label(u"localesettingFT"_ustr))
907     , m_xLocaleSettingLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"localesetting"_ustr)))
908     , m_xLocaleSettingImg(m_xBuilder->weld_widget(u"locklocalesetting"_ustr))
909     , m_xDecimalSeparatorFT(m_xBuilder->weld_label(u"label6"_ustr))
910     , m_xDecimalSeparatorCB(m_xBuilder->weld_check_button(u"decimalseparator"_ustr))
911     , m_xDecimalSeparatorImg(m_xBuilder->weld_widget(u"lockdecimalseparator"_ustr))
912     , m_xCurrencyFT(m_xBuilder->weld_label(u"defaultcurrency"_ustr))
913     , m_xCurrencyLB(m_xBuilder->weld_combo_box(u"currencylb"_ustr))
914     , m_xCurrencyImg(m_xBuilder->weld_widget(u"lockcurrencylb"_ustr))
915     , m_xDatePatternsFT(m_xBuilder->weld_label(u"dataaccpatterns"_ustr))
916     , m_xDatePatternsED(m_xBuilder->weld_entry(u"datepatterns"_ustr))
917     , m_xDatePatternsImg(m_xBuilder->weld_widget(u"lockdatepatterns"_ustr))
918     , m_xWesternLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"westernlanguage"_ustr)))
919     , m_xWesternLanguageFT(m_xBuilder->weld_label(u"western"_ustr))
920     , m_xWesternLanguageImg(m_xBuilder->weld_widget(u"lockwesternlanguage"_ustr))
921     , m_xAsianLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"asianlanguage"_ustr)))
922     , m_xComplexLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"complexlanguage"_ustr)))
923     , m_xCurrentDocCB(m_xBuilder->weld_check_button(u"currentdoc"_ustr))
924     , m_xAsianSupportCB(m_xBuilder->weld_check_button(u"asiansupport"_ustr))
925     , m_xAsianSupportImg(m_xBuilder->weld_widget(u"lockasiansupport"_ustr))
926     , m_xCTLSupportCB(m_xBuilder->weld_check_button(u"ctlsupport"_ustr))
927     , m_xCTLSupportImg(m_xBuilder->weld_widget(u"lockctlsupport"_ustr))
928     , m_xIgnoreLanguageChangeCB(m_xBuilder->weld_check_button(u"ignorelanguagechange"_ustr))
929     , m_xIgnoreLanguageChangeImg(m_xBuilder->weld_widget(u"lockignorelanguagechange"_ustr))
930 {
931     // tdf#125483 save original default label
932     m_sDecimalSeparatorLabel = m_xDecimalSeparatorCB->get_label();
933 
934     // initialize user interface language selection
935     m_sSystemDefaultString = SvtLanguageTable::GetLanguageString( LANGUAGE_SYSTEM );
936 
937     OUString aUILang = m_sSystemDefaultString +
938                        " - " +
939                        SvtLanguageTable::GetLanguageString(GetInstalledLocaleForSystemUILanguage().getLanguageType());
940 
941     m_xUserInterfaceLB->append(u"0"_ustr, aUILang);
942     m_xUserInterfaceLB->append_separator(u""_ustr);
943     try
944     {
945         Reference< XMultiServiceFactory > theConfigProvider(
946             css::configuration::theDefaultProvider::get(
947                 comphelper::getProcessComponentContext()));
948         // find out which locales are currently installed and add them to the listbox
949         Sequence< Any > theArgs{ Any(NamedValue(u"nodepath"_ustr, Any(sInstalledLocalesPath))) };
950         Reference< XNameAccess > theNameAccess(
951             theConfigProvider->createInstanceWithArguments(sAccessSrvc, theArgs ), UNO_QUERY_THROW );
952         seqInstalledLanguages = theNameAccess->getElementNames();
953         LanguageType aLang = LANGUAGE_DONTKNOW;
954         std::vector< std::pair<sal_Int32, OUString> > aUILanguages;
955         for (sal_Int32 i=0; i<seqInstalledLanguages.getLength(); i++)
956         {
957             aLang = LanguageTag::convertToLanguageTypeWithFallback(seqInstalledLanguages[i]);
958             if (aLang != LANGUAGE_DONTKNOW)
959             {
960                 OUString aLangStr( SvtLanguageTable::GetLanguageString( aLang ) );
961                 aUILanguages.emplace_back(i+1, aLangStr);
962             }
963         }
964 
965         std::sort(aUILanguages.begin(), aUILanguages.end(), [](const auto& l1, const auto& l2) {
966             static const auto aSorter = comphelper::string::NaturalStringSorter(
967                 comphelper::getProcessComponentContext(),
968                 Application::GetSettings().GetUILanguageTag().getLocale());
969             return aSorter.compare(l1.second, l2.second) < 0;
970         });
971 
972         // tdf#114694: append the sorted list after the default entry and separator.
973         for (const auto & [ nGroupID, sGroupName ] : aUILanguages)
974         {
975             m_xUserInterfaceLB->append(OUString::number(nGroupID), sGroupName);
976         }
977 
978         m_xUserInterfaceLB->set_active(0);
979 
980         // find out whether the user has a specific locale specified
981         Sequence< Any > theArgs2{ Any(NamedValue(u"nodepath"_ustr, Any(sUserLocalePath))) };
982         theNameAccess.set(
983             theConfigProvider->createInstanceWithArguments(sAccessSrvc, theArgs2 ), UNO_QUERY_THROW );
984         if (theNameAccess->hasByName(sUserLocaleKey))
985             theNameAccess->getByName(sUserLocaleKey) >>= m_sUserLocaleValue;
986         // select the user specified locale in the listbox
987         if (!m_sUserLocaleValue.isEmpty())
988         {
989             for (sal_Int32 i = 0, nEntryCount = m_xUserInterfaceLB->get_count(); i < nEntryCount; ++i)
990             {
991                 sal_Int32 d = m_xUserInterfaceLB->get_id(i).toInt32();
992                 if ( d > 0 && seqInstalledLanguages.getLength() > d-1 && seqInstalledLanguages[d-1] == m_sUserLocaleValue)
993                     m_xUserInterfaceLB->set_active(i);
994             }
995         }
996 
997     }
998     catch (const Exception &)
999     {
1000         // we'll just leave the box in its default setting and won't
1001         // even give it event handler...
1002         TOOLS_WARN_EXCEPTION("cui.options", "ignoring" );
1003     }
1004 
1005     m_xWesternLanguageLB->SetLanguageList(
1006         SvxLanguageListFlags::WESTERN | SvxLanguageListFlags::ONLY_KNOWN, true, false, true, true,
1007         LANGUAGE_SYSTEM, css::i18n::ScriptType::LATIN);
1008 
1009     m_xAsianLanguageLB->SetLanguageList(
1010         SvxLanguageListFlags::CJK | SvxLanguageListFlags::ONLY_KNOWN, true, false, true, true,
1011         LANGUAGE_SYSTEM, css::i18n::ScriptType::ASIAN);
1012 
1013     m_xComplexLanguageLB->SetLanguageList(
1014         SvxLanguageListFlags::CTL | SvxLanguageListFlags::ONLY_KNOWN, true, false, true, true,
1015         LANGUAGE_SYSTEM, css::i18n::ScriptType::COMPLEX);
1016 
1017     m_xLocaleSettingLB->SetLanguageList(
1018         SvxLanguageListFlags::ALL | SvxLanguageListFlags::ONLY_KNOWN, false, false, false, true,
1019         LANGUAGE_USER_SYSTEM_CONFIG, css::i18n::ScriptType::WEAK);
1020 
1021     const NfCurrencyTable& rCurrTab = SvNumberFormatter::GetTheCurrencyTable();
1022     const NfCurrencyEntry& rCurr = SvNumberFormatter::GetCurrencyEntry( LANGUAGE_SYSTEM );
1023     // insert SYSTEM entry
1024     OUString aDefaultCurr = m_sSystemDefaultString + " - " + rCurr.GetBankSymbol();
1025     m_xCurrencyLB->append(u"default"_ustr, aDefaultCurr);
1026     m_xCurrencyLB->append_separator(u""_ustr);
1027 
1028     assert(m_xCurrencyLB->find_id(u"default"_ustr) != -1);
1029     // all currencies
1030     OUString aTwoSpace( u"  "_ustr );
1031     sal_uInt16 nCurrCount = rCurrTab.size();
1032     std::vector< const NfCurrencyEntry* > aCurrencies;
1033     // first entry is SYSTEM, skip it
1034     for ( sal_uInt16 j=1; j < nCurrCount; ++j )
1035     {
1036         aCurrencies.push_back(&rCurrTab[j]);
1037     }
1038     std::sort(aCurrencies.begin(), aCurrencies.end(),
1039               [](const NfCurrencyEntry* c1, const NfCurrencyEntry* c2) {
1040                   return c1->GetBankSymbol().compareTo(c2->GetBankSymbol()) < 0;
1041               });
1042 
1043     for (auto &v : aCurrencies)
1044     {
1045         OUString aStr_ = v->GetBankSymbol() +
1046                          aTwoSpace +
1047                          v->GetSymbol();
1048         aStr_ = ApplyLreOrRleEmbedding( aStr_ ) +
1049                 aTwoSpace +
1050                 ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString( v->GetLanguage() ) );
1051         m_xCurrencyLB->append(weld::toId(v), aStr_);
1052     }
1053 
1054     m_xCurrencyLB->set_active(0);
1055 
1056     m_xLocaleSettingLB->connect_changed( LINK( this, OfaLanguagesTabPage, LocaleSettingHdl ) );
1057     m_xDatePatternsED->connect_changed( LINK( this, OfaLanguagesTabPage, DatePatternsHdl ) );
1058 
1059     Link<weld::Toggleable&,void> aLink( LINK( this, OfaLanguagesTabPage, SupportHdl ) );
1060     m_xAsianSupportCB->connect_toggled( aLink );
1061     m_xCTLSupportCB->connect_toggled( aLink );
1062 
1063     m_bOldAsian = SvtCJKOptions::IsAnyEnabled();
1064     m_xAsianSupportCB->set_active(m_bOldAsian);
1065     m_xAsianSupportCB->save_state();
1066     bool bReadonly = SvtCJKOptions::IsAnyReadOnly();
1067     m_xAsianSupportCB->set_sensitive(!bReadonly);
1068     m_xAsianSupportImg->set_visible(bReadonly);
1069     SupportHdl(*m_xAsianSupportCB);
1070 
1071     m_bOldCtl = SvtCTLOptions::IsCTLFontEnabled();
1072     m_xCTLSupportCB->set_active(m_bOldCtl);
1073     m_xCTLSupportCB->save_state();
1074     bReadonly = pLangConfig->aCTLLanguageOptions.IsReadOnly(SvtCTLOptions::E_CTLFONT);
1075     m_xCTLSupportCB->set_sensitive(!bReadonly);
1076     m_xCTLSupportImg->set_visible(bReadonly);
1077     SupportHdl(*m_xCTLSupportCB);
1078 
1079     m_xIgnoreLanguageChangeCB->set_active( pLangConfig->aSysLocaleOptions.IsIgnoreLanguageChange() );
1080 }
1081 
~OfaLanguagesTabPage()1082 OfaLanguagesTabPage::~OfaLanguagesTabPage()
1083 {
1084 }
1085 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rAttrSet)1086 std::unique_ptr<SfxTabPage> OfaLanguagesTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
1087 {
1088     return std::make_unique<OfaLanguagesTabPage>(pPage, pController, *rAttrSet);
1089 }
1090 
lcl_Update(std::unique_ptr<SfxVoidItem> pInvalidItems[],std::unique_ptr<SfxBoolItem> pBoolItems[],sal_uInt16 nCount)1091 static void lcl_Update(std::unique_ptr<SfxVoidItem> pInvalidItems[], std::unique_ptr<SfxBoolItem> pBoolItems[], sal_uInt16 nCount)
1092 {
1093     SfxViewFrame* pCurrentFrm = SfxViewFrame::Current();
1094     SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst();
1095     while(pViewFrm)
1096     {
1097         SfxBindings& rBind = pViewFrm->GetBindings();
1098         for(sal_uInt16 i = 0; i < nCount; i++)
1099         {
1100             if(pCurrentFrm == pViewFrm)
1101                 rBind.InvalidateAll(false);
1102             rBind.SetState( *pInvalidItems[i] );
1103             rBind.SetState( *pBoolItems[i] );
1104         }
1105         pViewFrm = SfxViewFrame::GetNext(*pViewFrm);
1106     }
1107 }
1108 
GetAllStrings()1109 OUString OfaLanguagesTabPage::GetAllStrings()
1110 {
1111     OUString sAllStrings;
1112     OUString labels[]
1113         = { u"label1"_ustr, u"label4"_ustr,          u"label7"_ustr, u"localesettingFT"_ustr, u"defaultcurrency"_ustr,
1114             u"label6"_ustr, u"dataaccpatterns"_ustr, u"label2"_ustr, u"western"_ustr,         u"label3"_ustr };
1115 
1116     for (const auto& label : labels)
1117     {
1118         if (const auto pString = m_xBuilder->weld_label(label))
1119             sAllStrings += pString->get_label() + " ";
1120     }
1121 
1122     OUString checkButton[] = { u"decimalseparator"_ustr, u"asiansupport"_ustr, u"ctlsupport"_ustr, u"currentdoc"_ustr,
1123                                u"ignorelanguagechange"_ustr };
1124 
1125     for (const auto& check : checkButton)
1126     {
1127         if (const auto pString = m_xBuilder->weld_check_button(check))
1128             sAllStrings += pString->get_label() + " ";
1129     }
1130 
1131     return sAllStrings.replaceAll("_", "");
1132 }
1133 
FillItemSet(SfxItemSet * rSet)1134 bool OfaLanguagesTabPage::FillItemSet( SfxItemSet* rSet )
1135 {
1136     // lock configuration broadcasters so that we can coordinate the notifications
1137     pLangConfig->aSysLocaleOptions.BlockBroadcasts( true );
1138     pLangConfig->aCTLLanguageOptions.BlockBroadcasts( true );
1139     pLangConfig->aLinguConfig.BlockBroadcasts( true );
1140 
1141     /*
1142      * Sequence checking only matters when CTL support is enabled.
1143      *
1144      * So we only need to check for sequence checking if
1145      * a) previously it was unchecked and is now checked or
1146      * b) it was already checked but the CTL language has changed
1147      */
1148     if (
1149          m_xCTLSupportCB->get_active() &&
1150          (m_xCTLSupportCB->get_saved_state() != TRISTATE_TRUE ||
1151          m_xComplexLanguageLB->get_active_id_changed_from_saved())
1152        )
1153     {
1154         //sequence checking has to be switched on depending on the selected CTL language
1155         LanguageType eCTLLang = m_xComplexLanguageLB->get_active_id();
1156         bool bOn = MsLangId::needsSequenceChecking( eCTLLang);
1157         pLangConfig->aCTLLanguageOptions.SetCTLSequenceCheckingRestricted(bOn);
1158         pLangConfig->aCTLLanguageOptions.SetCTLSequenceChecking(bOn);
1159         pLangConfig->aCTLLanguageOptions.SetCTLSequenceCheckingTypeAndReplace(bOn);
1160     }
1161     try
1162     {
1163         // handle settings for UI Language
1164         // a change of setting needs to bring up a warning message
1165         OUString aLangString;
1166         sal_Int32 d = m_xUserInterfaceLB->get_active_id().toInt32();
1167         if( d > 0 && seqInstalledLanguages.getLength() > d-1)
1168             aLangString = seqInstalledLanguages[d-1];
1169 
1170         /*
1171         if( m_xUserInterfaceLB->GetSelectedEntryPos() > 0)
1172             aLangString = ConvertLanguageToIsoString(m_xUserInterfaceLB->get_active_id());
1173         */
1174         Reference< XMultiServiceFactory > theConfigProvider(
1175             css::configuration::theDefaultProvider::get(
1176                 comphelper::getProcessComponentContext()));
1177         Sequence< Any > theArgs{ Any(NamedValue(u"nodepath"_ustr, Any(sUserLocalePath))) };
1178         Reference< XPropertySet >xProp(
1179             theConfigProvider->createInstanceWithArguments(sAccessUpdSrvc, theArgs ), UNO_QUERY_THROW );
1180         if ( m_sUserLocaleValue != aLangString)
1181         {
1182             // OSL_FAIL("UserInterface language was changed, restart.");
1183             // write new value
1184             xProp->setPropertyValue(sUserLocaleKey, Any(aLangString));
1185             Reference< XChangesBatch >(xProp, UNO_QUERY_THROW)->commitChanges();
1186             // display info
1187             SolarMutexGuard aGuard;
1188             if (svtools::executeRestartDialog(
1189                     comphelper::getProcessComponentContext(), GetFrameWeld(),
1190                     svtools::RESTART_REASON_LANGUAGE_CHANGE))
1191                 GetDialogController()->response(RET_OK);
1192 
1193             // tell quickstarter to stop being a veto listener
1194 
1195             const Reference< XComponentContext >& xContext(
1196                 comphelper::getProcessComponentContext());
1197             css::office::Quickstart::createAndSetVeto(xContext, false, false, false/*DisableVeto*/);
1198         }
1199     }
1200     catch (const Exception&)
1201     {
1202         // we'll just leave the box in its default setting and won't
1203         // even give it event handler...
1204         TOOLS_WARN_EXCEPTION("cui.options", "ignoring");
1205     }
1206 
1207     LanguageTag aLanguageTag( pLangConfig->aSysLocaleOptions.GetLanguageTag());
1208     LanguageType eOldLocale = (aLanguageTag.isSystemLocale() ? LANGUAGE_SYSTEM :
1209             aLanguageTag.makeFallback().getLanguageType());
1210     LanguageType eNewLocale = m_xLocaleSettingLB->get_active_id();
1211 
1212     // If the "Default ..." entry was selected that means SYSTEM, the actual
1213     // eNewLocale value is temporary for the dialog only, do not resolve to
1214     // what system currently is.
1215     if (eNewLocale == LANGUAGE_USER_SYSTEM_CONFIG)
1216         eNewLocale = LANGUAGE_SYSTEM;
1217 
1218     if ( eOldLocale != eNewLocale )
1219     {
1220         // an empty string denotes SYSTEM locale
1221         OUString sNewLang;
1222         if ( eNewLocale != LANGUAGE_SYSTEM )
1223             sNewLang = LanguageTag::convertToBcp47( eNewLocale);
1224 
1225         // locale nowadays get to AppSettings via notification
1226         // this will happen after releasing the lock on the ConfigurationBroadcaster at
1227         // the end of this method
1228         pLangConfig->aSysLocaleOptions.SetLocaleConfigString( sNewLang );
1229         rSet->Put( SfxBoolItem( SID_OPT_LOCALE_CHANGED, true ) );
1230 
1231         SvtScriptType nNewType = SvtLanguageOptions::GetScriptTypeOfLanguage( eNewLocale );
1232         bool bNewCJK = bool( nNewType & SvtScriptType::ASIAN );
1233         auto batch = comphelper::ConfigurationChanges::create();
1234         SvtCompatibilityDefault aCompatOpts(batch);
1235         aCompatOpts.set(u"ExpandWordSpace"_ustr, !bNewCJK);
1236         batch->commit();
1237     }
1238 
1239     if(m_xDecimalSeparatorCB->get_state_changed_from_saved())
1240         pLangConfig->aSysLocaleOptions.SetDecimalSeparatorAsLocale(m_xDecimalSeparatorCB->get_active());
1241 
1242     if(m_xIgnoreLanguageChangeCB->get_state_changed_from_saved())
1243         pLangConfig->aSysLocaleOptions.SetIgnoreLanguageChange(m_xIgnoreLanguageChangeCB->get_active());
1244 
1245     // Configured currency, for example, USD-en-US or EUR-de-DE, or empty for locale default.
1246     OUString sOldCurr = pLangConfig->aSysLocaleOptions.GetCurrencyConfigString();
1247     OUString sId = m_xCurrencyLB->get_active_id();
1248     const NfCurrencyEntry* pCurr = sId == "default" ? nullptr : weld::fromId<const NfCurrencyEntry*>(sId);
1249     OUString sNewCurr;
1250     if ( pCurr )
1251         sNewCurr = SvtSysLocaleOptions::CreateCurrencyConfigString(
1252             pCurr->GetBankSymbol(), pCurr->GetLanguage() );
1253     if ( sOldCurr != sNewCurr )
1254         pLangConfig->aSysLocaleOptions.SetCurrencyConfigString( sNewCurr );
1255 
1256     // Configured date acceptance patterns, for example Y-M-D;M-D or empty for
1257     // locale default.
1258     if (m_bDatePatternsValid && m_xDatePatternsED->get_value_changed_from_saved())
1259         pLangConfig->aSysLocaleOptions.SetDatePatternsConfigString( m_xDatePatternsED->get_text());
1260 
1261     SfxObjectShell* pCurrentDocShell = SfxObjectShell::Current();
1262     Reference< css::linguistic2::XLinguProperties > xLinguProp = LinguMgr::GetLinguPropertySet();
1263     bool bCurrentDocCBChecked = m_xCurrentDocCB->get_active();
1264     if (m_xCurrentDocCB->get_sensitive())
1265         bLanguageCurrentDoc_Impl = bCurrentDocCBChecked;
1266     bool bCurrentDocCBChanged = m_xCurrentDocCB->get_state_changed_from_saved();
1267 
1268     bool bValChanged = m_xWesternLanguageLB->get_active_id_changed_from_saved();
1269     if( (bCurrentDocCBChanged && !bCurrentDocCBChecked) || bValChanged)
1270     {
1271         LanguageType eSelectLang = m_xWesternLanguageLB->get_active_id();
1272         if(!bCurrentDocCBChecked)
1273         {
1274             Any aValue;
1275             Locale aLocale = LanguageTag::convertToLocale( eSelectLang, false);
1276             aValue <<= aLocale;
1277             pLangConfig->aLinguConfig.SetProperty( u"DefaultLocale", aValue );
1278             if (xLinguProp.is())
1279                 xLinguProp->setDefaultLocale( aLocale );
1280         }
1281         if(pCurrentDocShell)
1282         {
1283             rSet->Put(SvxLanguageItem(MsLangId::resolveSystemLanguageByScriptType(eSelectLang, css::i18n::ScriptType::LATIN),
1284                 SID_ATTR_LANGUAGE));
1285         }
1286     }
1287     bValChanged = m_xAsianLanguageLB->get_active_id_changed_from_saved();
1288     if( (bCurrentDocCBChanged && !bCurrentDocCBChecked) || bValChanged)
1289     {
1290         LanguageType eSelectLang = m_xAsianLanguageLB->get_active_id();
1291         if(!bCurrentDocCBChecked)
1292         {
1293             Any aValue;
1294             Locale aLocale = LanguageTag::convertToLocale( eSelectLang, false);
1295             aValue <<= aLocale;
1296             pLangConfig->aLinguConfig.SetProperty( u"DefaultLocale_CJK", aValue );
1297             if (xLinguProp.is())
1298                 xLinguProp->setDefaultLocale_CJK( aLocale );
1299         }
1300         if(pCurrentDocShell)
1301         {
1302             rSet->Put(SvxLanguageItem(MsLangId::resolveSystemLanguageByScriptType(eSelectLang, css::i18n::ScriptType::ASIAN),
1303                 SID_ATTR_CHAR_CJK_LANGUAGE));
1304         }
1305     }
1306     bValChanged = m_xComplexLanguageLB->get_active_id_changed_from_saved();
1307     if( (bCurrentDocCBChanged && !bCurrentDocCBChecked) || bValChanged)
1308     {
1309         LanguageType eSelectLang = m_xComplexLanguageLB->get_active_id();
1310         if(!bCurrentDocCBChecked)
1311         {
1312             Any aValue;
1313             Locale aLocale = LanguageTag::convertToLocale( eSelectLang, false);
1314             aValue <<= aLocale;
1315             pLangConfig->aLinguConfig.SetProperty( u"DefaultLocale_CTL", aValue );
1316             if (xLinguProp.is())
1317                 xLinguProp->setDefaultLocale_CTL( aLocale );
1318         }
1319         if(pCurrentDocShell)
1320         {
1321             rSet->Put(SvxLanguageItem(MsLangId::resolveSystemLanguageByScriptType(eSelectLang, css::i18n::ScriptType::COMPLEX),
1322                 SID_ATTR_CHAR_CTL_LANGUAGE));
1323         }
1324 
1325         // tdf#163228: Mongolian script supports vertical text
1326         pLangConfig->aCTLLanguageOptions.SetCTLVerticalText(
1327             MsLangId::getPrimaryLanguage(eSelectLang)
1328             == MsLangId::getPrimaryLanguage(LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA));
1329     }
1330 
1331     if(m_xAsianSupportCB->get_state_changed_from_saved() )
1332     {
1333         bool bChecked = m_xAsianSupportCB->get_active();
1334         SvtCJKOptions::SetAll(bChecked);
1335 
1336         //iterate over all bindings to invalidate vertical text direction
1337         const sal_uInt16 STATE_COUNT = 2;
1338 
1339         std::unique_ptr<SfxBoolItem> pBoolItems[STATE_COUNT];
1340         pBoolItems[0].reset(new SfxBoolItem(SID_VERTICALTEXT_STATE, false));
1341         pBoolItems[1].reset(new SfxBoolItem(SID_TEXT_FITTOSIZE_VERTICAL, false));
1342 
1343         std::unique_ptr<SfxVoidItem> pInvalidItems[STATE_COUNT];
1344         pInvalidItems[0].reset(new SfxVoidItem(SID_VERTICALTEXT_STATE));
1345         pInvalidItems[1].reset(new SfxVoidItem(SID_TEXT_FITTOSIZE_VERTICAL));
1346 
1347         lcl_Update(pInvalidItems, pBoolItems, STATE_COUNT);
1348     }
1349 
1350     if ( m_xCTLSupportCB->get_state_changed_from_saved() )
1351     {
1352         SvtSearchOptions aOpt;
1353         aOpt.SetIgnoreDiacritics_CTL(true);
1354         aOpt.SetIgnoreKashida_CTL(true);
1355         aOpt.Commit();
1356         pLangConfig->aCTLLanguageOptions.SetCTLFontEnabled( m_xCTLSupportCB->get_active() );
1357 
1358         const sal_uInt16 STATE_COUNT = 1;
1359         std::unique_ptr<SfxBoolItem> pBoolItems[STATE_COUNT];
1360         pBoolItems[0].reset(new SfxBoolItem(SID_CTLFONT_STATE, false));
1361         std::unique_ptr<SfxVoidItem> pInvalidItems[STATE_COUNT];
1362         pInvalidItems[0].reset(new SfxVoidItem(SID_CTLFONT_STATE));
1363         lcl_Update(pInvalidItems, pBoolItems, STATE_COUNT);
1364     }
1365 
1366     if ( pLangConfig->aSysLocaleOptions.IsModified() )
1367         pLangConfig->aSysLocaleOptions.Commit();
1368 
1369     // first release the lock on the ConfigurationBroadcaster for Locale changes
1370     // it seems that our code relies on the fact that before other changes like e.g. currency
1371     // are broadcasted locale changes have been done
1372     pLangConfig->aSysLocaleOptions.BlockBroadcasts( false );
1373     pLangConfig->aCTLLanguageOptions.BlockBroadcasts( false );
1374     pLangConfig->aLinguConfig.BlockBroadcasts( false );
1375 
1376     return false;
1377 }
1378 
Reset(const SfxItemSet * rSet)1379 void OfaLanguagesTabPage::Reset( const SfxItemSet* rSet )
1380 {
1381     LanguageTag aLanguageTag( pLangConfig->aSysLocaleOptions.GetLanguageTag());
1382     if ( aLanguageTag.isSystemLocale() )
1383         m_xLocaleSettingLB->set_active_id( LANGUAGE_USER_SYSTEM_CONFIG );
1384     else
1385         m_xLocaleSettingLB->set_active_id( aLanguageTag.makeFallback().getLanguageType());
1386     bool bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::Locale);
1387     m_xLocaleSettingLB->set_sensitive(!bReadonly);
1388     m_xLocaleSettingFT->set_sensitive(!bReadonly);
1389     m_xLocaleSettingImg->set_visible(bReadonly);
1390 
1391 
1392     m_xDecimalSeparatorCB->set_active( pLangConfig->aSysLocaleOptions.IsDecimalSeparatorAsLocale());
1393     bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::DecimalSeparator);
1394     m_xDecimalSeparatorCB->set_sensitive(!bReadonly);
1395     m_xDecimalSeparatorFT->set_sensitive(!bReadonly);
1396     m_xDecimalSeparatorImg->set_visible(bReadonly);
1397     m_xDecimalSeparatorCB->save_state();
1398 
1399     m_xIgnoreLanguageChangeCB->set_active( pLangConfig->aSysLocaleOptions.IsIgnoreLanguageChange());
1400     bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::IgnoreLanguageChange);
1401     m_xIgnoreLanguageChangeCB->set_sensitive(!bReadonly);
1402     m_xIgnoreLanguageChangeImg->set_visible(bReadonly);
1403     m_xIgnoreLanguageChangeCB->save_state();
1404 
1405     // let LocaleSettingHdl enable/disable checkboxes for CJK/CTL support
1406     // #i15812# must be done *before* the configured currency is set
1407     // and update the decimal separator used for the given locale
1408     LocaleSettingHdl(*m_xLocaleSettingLB->get_widget());
1409 
1410     // configured currency, for example, USD-en-US or EUR-de-DE, or empty for locale default
1411     const NfCurrencyEntry* pCurr = nullptr;
1412     OUString sCurrency = pLangConfig->aSysLocaleOptions.GetCurrencyConfigString();
1413     if ( !sCurrency.isEmpty() )
1414     {
1415         LanguageType eLang;
1416         OUString aAbbrev;
1417         SvtSysLocaleOptions::GetCurrencyAbbrevAndLanguage( aAbbrev, eLang, sCurrency );
1418         pCurr = SvNumberFormatter::GetCurrencyEntry( aAbbrev, eLang );
1419     }
1420     // if pCurr==nullptr the SYSTEM entry is selected
1421     OUString sId = !pCurr ? u"default"_ustr : weld::toId(pCurr);
1422     m_xCurrencyLB->set_active_id(sId);
1423     bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::Currency);
1424     m_xCurrencyLB->set_sensitive(!bReadonly);
1425     m_xCurrencyFT->set_sensitive(!bReadonly);
1426     m_xCurrencyImg->set_visible(bReadonly);
1427 
1428     // date acceptance patterns
1429     OUString aDatePatternsString = pLangConfig->aSysLocaleOptions.GetDatePatternsConfigString();
1430     if (aDatePatternsString.isEmpty())
1431     {
1432         const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
1433         aDatePatternsString = lcl_getDatePatternsConfigString( rLocaleWrapper);
1434         // Let's assume patterns are valid at this point.
1435         m_bDatePatternsValid = true;
1436     }
1437     else
1438     {
1439         bool bModified = false;
1440         m_bDatePatternsValid = validateDatePatterns( bModified, aDatePatternsString);
1441     }
1442     m_xDatePatternsED->set_text(aDatePatternsString);
1443     m_xDatePatternsED->set_message_type( m_bDatePatternsValid ?
1444             weld::EntryMessageType::Normal : weld::EntryMessageType::Error);
1445     bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::DatePatterns);
1446     m_xDatePatternsED->set_sensitive(!bReadonly);
1447     m_xDatePatternsFT->set_sensitive(!bReadonly);
1448     m_xDatePatternsImg->set_visible(bReadonly);
1449     m_xDatePatternsED->save_value();
1450 
1451     //western/CJK/CLK language
1452     LanguageType eCurLang = LANGUAGE_NONE;
1453     LanguageType eCurLangCJK = LANGUAGE_NONE;
1454     LanguageType eCurLangCTL = LANGUAGE_NONE;
1455     SfxObjectShell* pCurrentDocShell = SfxObjectShell::Current();
1456     //collect the configuration values first
1457     m_xCurrentDocCB->set_sensitive(false);
1458 
1459     Any aWestLang;
1460     Any aCJKLang;
1461     Any aCTLLang;
1462     try
1463     {
1464         aWestLang = pLangConfig->aLinguConfig.GetProperty(u"DefaultLocale");
1465         Locale aLocale;
1466         aWestLang >>= aLocale;
1467 
1468         eCurLang = LanguageTag::convertToLanguageType( aLocale, false);
1469 
1470         aCJKLang = pLangConfig->aLinguConfig.GetProperty(u"DefaultLocale_CJK");
1471         aLocale = Locale();
1472         aCJKLang >>= aLocale;
1473         eCurLangCJK = LanguageTag::convertToLanguageType( aLocale, false);
1474 
1475         aCTLLang = pLangConfig->aLinguConfig.GetProperty(u"DefaultLocale_CTL");
1476         aLocale = Locale();
1477         aCTLLang >>= aLocale;
1478         eCurLangCTL = LanguageTag::convertToLanguageType( aLocale, false);
1479     }
1480     catch (const Exception&)
1481     {
1482     }
1483     //overwrite them by the values provided by the DocShell
1484     if(pCurrentDocShell)
1485     {
1486         m_xCurrentDocCB->set_sensitive(true);
1487         m_xCurrentDocCB->set_active(bLanguageCurrentDoc_Impl);
1488         if( const SvxLanguageItem* pLangItem = rSet->GetItemIfSet(SID_ATTR_LANGUAGE, false))
1489         {
1490             LanguageType eTempCurLang = pLangItem->GetValue();
1491             if (MsLangId::resolveSystemLanguageByScriptType(eCurLang, css::i18n::ScriptType::LATIN) != eTempCurLang)
1492                 eCurLang = eTempCurLang;
1493         }
1494 
1495         if( const SvxLanguageItem* pLang = rSet->GetItemIfSet(SID_ATTR_CHAR_CJK_LANGUAGE, false))
1496         {
1497             LanguageType eTempCurLang = pLang->GetValue();
1498             if (MsLangId::resolveSystemLanguageByScriptType(eCurLangCJK, css::i18n::ScriptType::ASIAN) != eTempCurLang)
1499                 eCurLangCJK = eTempCurLang;
1500         }
1501 
1502         if( const SvxLanguageItem* pLang = rSet->GetItemIfSet(SID_ATTR_CHAR_CTL_LANGUAGE, false))
1503         {
1504             LanguageType eTempCurLang = pLang->GetValue();
1505             if (MsLangId::resolveSystemLanguageByScriptType(eCurLangCTL, css::i18n::ScriptType::COMPLEX) != eTempCurLang)
1506                 eCurLangCTL = eTempCurLang;
1507         }
1508     }
1509     if(LANGUAGE_NONE == eCurLang || LANGUAGE_DONTKNOW == eCurLang)
1510         m_xWesternLanguageLB->set_active_id(LANGUAGE_NONE);
1511     else
1512         m_xWesternLanguageLB->set_active_id(eCurLang);
1513 
1514     if(LANGUAGE_NONE == eCurLangCJK || LANGUAGE_DONTKNOW == eCurLangCJK)
1515         m_xAsianLanguageLB->set_active_id(LANGUAGE_NONE);
1516     else
1517         m_xAsianLanguageLB->set_active_id(eCurLangCJK);
1518 
1519     if(LANGUAGE_NONE == eCurLangCTL || LANGUAGE_DONTKNOW == eCurLangCTL)
1520         m_xComplexLanguageLB->set_active_id(LANGUAGE_NONE);
1521     else
1522         m_xComplexLanguageLB->set_active_id(eCurLangCTL);
1523 
1524     m_xWesternLanguageLB->save_active_id();
1525     m_xAsianLanguageLB->save_active_id();
1526     m_xComplexLanguageLB->save_active_id();
1527     m_xIgnoreLanguageChangeCB->save_state();
1528     m_xCurrentDocCB->save_state();
1529 
1530     bool bEnable = !pLangConfig->aLinguConfig.IsReadOnly( u"DefaultLocale" );
1531     m_xWesternLanguageFT->set_sensitive( bEnable );
1532     m_xWesternLanguageLB->set_sensitive( bEnable );
1533     m_xWesternLanguageImg->set_visible( !bEnable );
1534 
1535     // check the box "For the current document only"
1536     // set the focus to the Western Language box
1537     const SfxBoolItem* pLang = rSet->GetItemIfSet(SID_SET_DOCUMENT_LANGUAGE, false );
1538     if ( pLang && pLang->GetValue() )
1539     {
1540         m_xWesternLanguageLB->grab_focus();
1541         m_xCurrentDocCB->set_sensitive(true);
1542         m_xCurrentDocCB->set_active(true);
1543     }
1544 }
1545 
IMPL_LINK(OfaLanguagesTabPage,SupportHdl,weld::Toggleable &,rBox,void)1546 IMPL_LINK(OfaLanguagesTabPage, SupportHdl, weld::Toggleable&, rBox, void)
1547 {
1548     bool bCheck = rBox.get_active();
1549     if ( m_xAsianSupportCB.get() == &rBox )
1550     {
1551         bool bReadonly = pLangConfig->aLinguConfig.IsReadOnly(u"DefaultLocale_CJK");
1552         bCheck = ( bCheck && !bReadonly );
1553         m_xAsianLanguageLB->set_sensitive( bCheck );
1554         if (rBox.get_sensitive())
1555             m_bOldAsian = bCheck;
1556     }
1557     else if ( m_xCTLSupportCB.get() == &rBox )
1558     {
1559         bool bReadonly = pLangConfig->aLinguConfig.IsReadOnly(u"DefaultLocale_CTL");
1560         bCheck = ( bCheck && !bReadonly  );
1561         m_xComplexLanguageLB->set_sensitive( bCheck );
1562         if (rBox.get_sensitive())
1563             m_bOldCtl = bCheck;
1564     }
1565     else
1566         SAL_WARN( "cui.options", "OfaLanguagesTabPage::SupportHdl(): wrong rBox" );
1567 }
1568 
1569 namespace
1570 {
lcl_checkLanguageCheckBox(weld::CheckButton & _rCB,bool _bNewValue,bool _bOldValue)1571     void lcl_checkLanguageCheckBox(weld::CheckButton& _rCB, bool _bNewValue, bool _bOldValue)
1572     {
1573         if ( _bNewValue )
1574             _rCB.set_active(true);
1575         else
1576             _rCB.set_active( _bOldValue );
1577 // #i15082# do not call save_state() in running dialog...
1578 //      _rCB.save_state();
1579         _rCB.set_sensitive( !_bNewValue );
1580     }
1581 }
1582 
IMPL_LINK_NOARG(OfaLanguagesTabPage,LocaleSettingHdl,weld::ComboBox &,void)1583 IMPL_LINK_NOARG(OfaLanguagesTabPage, LocaleSettingHdl, weld::ComboBox&, void)
1584 {
1585     LanguageType eLang = m_xLocaleSettingLB->get_active_id();
1586     SvtScriptType nType = SvtLanguageOptions::GetScriptTypeOfLanguage(eLang);
1587     // first check if CTL must be enabled
1588     // #103299# - if CTL font setting is not readonly
1589     if(!pLangConfig->aCTLLanguageOptions.IsReadOnly(SvtCTLOptions::E_CTLFONT))
1590     {
1591         bool bIsCTLFixed = bool(nType & SvtScriptType::COMPLEX);
1592         lcl_checkLanguageCheckBox(*m_xCTLSupportCB, bIsCTLFixed, m_bOldCtl);
1593         SupportHdl(*m_xCTLSupportCB);
1594     }
1595     // second check if CJK must be enabled
1596     // #103299# - if CJK support is not readonly
1597     if(!SvtCJKOptions::IsAnyReadOnly())
1598     {
1599         bool bIsCJKFixed = bool(nType & SvtScriptType::ASIAN);
1600         lcl_checkLanguageCheckBox(*m_xAsianSupportCB, bIsCJKFixed, m_bOldAsian);
1601         SupportHdl(*m_xAsianSupportCB);
1602     }
1603 
1604     const NfCurrencyEntry& rCurr = SvNumberFormatter::GetCurrencyEntry(
1605             (eLang == LANGUAGE_USER_SYSTEM_CONFIG) ? MsLangId::getConfiguredSystemLanguage() : eLang);
1606     static constexpr OUString aDefaultID = u"default"_ustr;
1607     // Update the "Default ..." currency.
1608     m_xCurrencyLB->remove_id(aDefaultID);
1609     OUString aDefaultCurr = m_sSystemDefaultString + " - " + rCurr.GetBankSymbol();
1610     m_xCurrencyLB->insert(0, aDefaultCurr, &aDefaultID, nullptr, nullptr);
1611     assert(m_xCurrencyLB->find_id(aDefaultID) != -1);
1612     m_xCurrencyLB->set_active_text(aDefaultCurr);
1613 
1614     // obtain corresponding locale data
1615     LocaleDataWrapper aLocaleWrapper(( LanguageTag(eLang) ));
1616 
1617     // update the decimal separator key of the related CheckBox
1618     OUString sTempLabel(m_sDecimalSeparatorLabel);
1619     sTempLabel = sTempLabel.replaceFirst("%1", aLocaleWrapper.getNumDecimalSep() );
1620     m_xDecimalSeparatorCB->set_label(sTempLabel);
1621 
1622     // update the date acceptance patterns
1623     OUString aDatePatternsString = lcl_getDatePatternsConfigString( aLocaleWrapper);
1624     m_bDatePatternsValid = true;
1625     m_xDatePatternsED->set_text( aDatePatternsString);
1626     m_xDatePatternsED->set_message_type(weld::EntryMessageType::Normal);
1627 }
1628 
IMPL_LINK(OfaLanguagesTabPage,DatePatternsHdl,weld::Entry &,rEd,void)1629 IMPL_LINK( OfaLanguagesTabPage, DatePatternsHdl, weld::Entry&, rEd, void )
1630 {
1631     OUString aPatterns(rEd.get_text());
1632     bool bModified = false;
1633     const bool bValid = validateDatePatterns( bModified, aPatterns);
1634     if (bModified)
1635     {
1636         // gtk3 keeps the cursor position on equal length set_text() but at
1637         // least the 'gen' backend does not and resets to 0.
1638         const int nCursorPos = rEd.get_position();
1639         rEd.set_text(aPatterns);
1640         rEd.set_position(nCursorPos);
1641     }
1642     if (bValid)
1643         rEd.set_message_type(weld::EntryMessageType::Normal);
1644     else
1645         rEd.set_message_type(weld::EntryMessageType::Error);
1646     m_bDatePatternsValid = bValid;
1647 }
1648 
validateDatePatterns(bool & rbModified,OUString & rPatterns)1649 bool OfaLanguagesTabPage::validateDatePatterns( bool& rbModified, OUString& rPatterns )
1650 {
1651     bool bValid = true;
1652     if (!rPatterns.isEmpty())
1653     {
1654         OUStringBuffer aBuf( rPatterns);
1655         sal_Int32 nChar = 0;
1656         for (sal_Int32 nIndex=0; nIndex >= 0 && bValid; ++nChar)
1657         {
1658             const OUString aPat( rPatterns.getToken( 0, ';', nIndex));
1659             if (aPat.isEmpty() && nIndex < 0)
1660             {
1661                 // Indicating failure when about to append a pattern is too
1662                 // confusing. Empty patterns are ignored anyway when sequencing
1663                 // to SvtSysLocale.
1664                 continue;   // for
1665             }
1666             else if (aPat.getLength() < 2)
1667                 bValid = false;
1668             else
1669             {
1670                 bool bY, bM, bD;
1671                 bY = bM = bD = false;
1672                 bool bSep = true;
1673                 if (aPat.getLength() == 3)
1674                 {
1675                     // Disallow a pattern that would match a numeric input with
1676                     // decimal separator, like M.D
1677                     const LanguageType eLang = m_xLocaleSettingLB->get_active_id();
1678                     const LocaleDataWrapper aLocaleWrapper(( LanguageTag(eLang)));
1679                     if (    aPat[1] == aLocaleWrapper.getNumDecimalSep().toChar()
1680                          || aPat[1] == aLocaleWrapper.getNumDecimalSepAlt().toChar())
1681                     {
1682                         bValid = false;
1683                     }
1684                 }
1685                 for (sal_Int32 i = 0; i < aPat.getLength() && bValid; /*nop*/)
1686                 {
1687                     const sal_Int32 j = i;
1688                     const sal_uInt32 c = aPat.iterateCodePoints( &i);
1689                     // Only one Y,M,D per pattern, separated by any character(s).
1690                     switch (c)
1691                     {
1692                         case 'y':
1693                         case 'Y':
1694                             if (bY || !bSep)
1695                                 bValid = false;
1696                             else if (c == 'y')
1697                             {
1698                                 aBuf[nChar] = 'Y';
1699                                 rbModified = true;
1700                             }
1701                             bY = true;
1702                             bSep = false;
1703                             break;
1704                         case 'm':
1705                         case 'M':
1706                             if (bM || !bSep)
1707                                 bValid = false;
1708                             else if (c == 'm')
1709                             {
1710                                 aBuf[nChar] = 'M';
1711                                 rbModified = true;
1712                             }
1713                             bM = true;
1714                             bSep = false;
1715                             break;
1716                         case 'd':
1717                         case 'D':
1718                             if (bD || !bSep)
1719                                 bValid = false;
1720                             else if (c == 'd')
1721                             {
1722                                 aBuf[nChar] = 'D';
1723                                 rbModified = true;
1724                             }
1725                             bD = true;
1726                             bSep = false;
1727                             break;
1728                         default:
1729                             // A pattern must not start with a separator (but
1730                             // may end with).
1731                             if (!(bY || bM || bD))
1732                                 bValid = false;
1733                             bSep = true;
1734                     }
1735                     nChar += i-j;
1736                 }
1737                 // At least one of Y,M,D
1738                 bValid &= (bY || bM || bD);
1739             }
1740         }
1741         if (rbModified)
1742             rPatterns = aBuf.makeStringAndClear();
1743     }
1744     return bValid;
1745 }
1746 
1747 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1748