/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <config_features.h>
#include <o3tl/untaint.hxx>
#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <svl/currencytable.hxx>
#include <svtools/langhelp.hxx>
#include <unotools/lingucfg.hxx>
#if defined(_WIN32)
#include <unotools/resmgr.hxx>
#endif
#include <sfx2/bindings.hxx>
#include <sfx2/viewfrm.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <i18nlangtag/languagetag.hxx>
#include <unotools/compatibility.hxx>
#include <svl/languageoptions.hxx>
#include <svl/cjkoptions.hxx>
#include <svl/ctloptions.hxx>
#include <unotools/syslocaleoptions.hxx>
#include <sfx2/objsh.hxx>
#include <comphelper/propertysequence.hxx>
#include <svtools/langtab.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/langitem.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <rtl/ustrbuf.hxx>
#include <editeng/editids.hrc>
#include <svx/svxids.hrc>
#include <svl/intitem.hxx>
#include <svl/voiditem.hxx>
#include <GraphicsTestsDialog.hxx>
#include <unotools/searchopt.hxx>
#include <sal/log.hxx>
#include <officecfg/Office/Canvas.hxx>
#include <officecfg/Office/Common.hxx>
#include <officecfg/Setup.hxx>
#include <comphelper/configuration.hxx>
#include <comphelper/diagnose_ex.hxx>
#if HAVE_FEATURE_BREAKPAD
#include <desktop/crashreport.hxx>
#endif
#include <com/sun/star/configuration/theDefaultProvider.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/util/XChangesBatch.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/container/XContentEnumerationAccess.hpp>
#include <com/sun/star/container/XSet.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <com/sun/star/office/Quickstart.hpp>
#include <com/sun/star/linguistic2/XLinguProperties.hpp>
#include <vcl/vclenum.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/window.hxx>
#include <vcl/skia/SkiaHelper.hxx>
#include <bitmaps.hlst>
#include "optgdlg.hxx"
#include <svtools/apearcfg.hxx>
#include <svtools/optionsdrawinglayer.hxx>
#include <svtools/restartdialog.hxx>
#include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
#include <vcl/unohelp2.hxx>
#if defined(_WIN32)
#include <systools/win32/winstoreutil.hxx>
#include <vcl/fileregistration.hxx>
#endif
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::util;
using namespace ::utl;
// class OfaMiscTabPage --------------------------------------------------
DeactivateRC OfaMiscTabPage::DeactivatePage( SfxItemSet* pSet_ )
{
if ( pSet_ )
FillItemSet( pSet_ );
return DeactivateRC::LeavePage;
}
namespace
{
const OUString & impl_SystemFileOpenServiceName()
{
#if defined(_WIN32)
static constexpr OUString gPicker = u"com.sun.star.ui.dialogs.SystemFilePicker"_ustr;
return gPicker;
#elif defined MACOSX
static constexpr OUString gPicker = u"com.sun.star.ui.dialogs.AquaFilePicker"_ustr;
return gPicker;
#else
return EMPTY_OUSTRING;
#endif
}
bool lcl_HasSystemFilePicker()
{
if( Application::hasNativeFileSelection() )
return true;
// Otherwise fall-back on querying services
bool bRet = false;
Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
Reference< XContentEnumerationAccess > xEnumAccess( xFactory, UNO_QUERY );
Reference< XSet > xSet( xFactory, UNO_QUERY );
if ( ! xEnumAccess.is() || ! xSet.is() )
return bRet;
try
{
const OUString& aFileService = impl_SystemFileOpenServiceName();
Reference< XEnumeration > xEnum = xEnumAccess->createContentEnumeration( aFileService );
if ( xEnum.is() && xEnum->hasMoreElements() )
bRet = true;
}
catch (const IllegalArgumentException&)
{
}
catch (const ElementExistException&)
{
}
return bRet;
}
}
OfaMiscTabPage::OfaMiscTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
: SfxTabPage(pPage, pController, u"cui/ui/optgeneralpage.ui"_ustr, u"OptGeneralPage"_ustr, &rSet)
, m_xExtHelpCB(m_xBuilder->weld_check_button(u"exthelp"_ustr))
, m_xExtHelpImg(m_xBuilder->weld_widget(u"lockexthelp"_ustr))
, m_xPopUpNoHelpCB(m_xBuilder->weld_check_button(u"popupnohelp"_ustr))
, m_xPopUpNoHelpImg(m_xBuilder->weld_widget(u"lockpopupnohelp"_ustr))
, m_xShowTipOfTheDay(m_xBuilder->weld_check_button(u"cbShowTipOfTheDay"_ustr))
, m_xShowTipOfTheDayImg(m_xBuilder->weld_widget(u"lockcbShowTipOfTheDay"_ustr))
, m_xFileDlgROImage(m_xBuilder->weld_widget(u"lockimage"_ustr))
, m_xFileDlgCB(m_xBuilder->weld_check_button(u"filedlg"_ustr))
, m_xColorDlgROImage(m_xBuilder->weld_widget(u"locksystemcolordialogs"_ustr))
, m_xColorDlgCB(m_xBuilder->weld_check_button(u"systemcolordialogs"_ustr))
, m_xDocStatusCB(m_xBuilder->weld_check_button(u"docstatus"_ustr))
, m_xDocStatusImg(m_xBuilder->weld_widget(u"lockdocstatus"_ustr))
, m_xYearFrame(m_xBuilder->weld_widget(u"yearframe"_ustr))
, m_xYearLabel(m_xBuilder->weld_label(u"yearslabel"_ustr))
, m_xYearValueField(m_xBuilder->weld_spin_button(u"year"_ustr))
, m_xToYearFT(m_xBuilder->weld_label(u"toyear"_ustr))
, m_xYearFrameImg(m_xBuilder->weld_widget(u"lockyears"_ustr))
#if HAVE_FEATURE_BREAKPAD
, m_xPrivacyFrame(m_xBuilder->weld_widget("privacyframe"))
, m_xCrashReport(m_xBuilder->weld_check_button("crashreport"))
, m_xCrashReportImg(m_xBuilder->weld_widget("lockcrashreport"))
#endif
#if defined(_WIN32)
, m_xQuickStarterFrame(m_xBuilder->weld_widget("quickstarter"))
, m_xQuickLaunchCB(m_xBuilder->weld_check_button("quicklaunch"))
, m_xQuickLaunchImg(m_xBuilder->weld_widget("lockquicklaunch"))
, m_xFileAssocFrame(m_xBuilder->weld_widget("fileassoc"))
, m_xFileAssocBtn(m_xBuilder->weld_button("assocfiles"))
, m_xPerformFileExtCheck(m_xBuilder->weld_check_button("cbPerformFileExtCheck"))
, m_xPerformFileExtImg(m_xBuilder->weld_widget("lockcbPerformFileExtCheck"))
#endif
{
#if HAVE_FEATURE_BREAKPAD
m_xPrivacyFrame->show();
#endif
#if defined(_WIN32)
// Store-packaged apps (located under the protected Program Files\WindowsApps) can't use normal
// shell shortcuts to their exe. TODO: show a button to open "Startup Apps" system applet?
if (!sal::systools::IsStorePackagedApp())
m_xQuickStarterFrame->show();
m_xFileAssocFrame->show();
m_xFileAssocBtn->connect_clicked(LINK(this, OfaMiscTabPage, FileAssocClick));
#endif
m_aStrDateInfo = m_xToYearFT->get_label();
m_xYearValueField->connect_value_changed( LINK( this, OfaMiscTabPage, TwoFigureHdl ) );
SetExchangeSupport();
}
OfaMiscTabPage::~OfaMiscTabPage()
{
}
std::unique_ptr<SfxTabPage> OfaMiscTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
{
return std::make_unique<OfaMiscTabPage>( pPage, pController, *rAttrSet );
}
OUString OfaMiscTabPage::GetAllStrings()
{
OUStringBuffer sAllStrings;
OUString labels[] = { u"label1"_ustr, u"label2"_ustr, u"label4"_ustr, u"label5"_ustr, u"yearslabel"_ustr,
u"toyear"_ustr, u"label8"_ustr, u"label9"_ustr };
for (const auto& label : labels)
{
if (const auto pString = m_xBuilder->weld_label(label))
sAllStrings.append(pString->get_label() + " ");
}
OUString checkButton[]
= { u"exthelp"_ustr, u"popupnohelp"_ustr, u"cbShowTipOfTheDay"_ustr, u"filedlg"_ustr,
u"docstatus"_ustr, u"crashreport"_ustr, u"quicklaunch"_ustr, u"cbPerformFileExtCheck"_ustr };
for (const auto& check : checkButton)
{
if (const auto pString = m_xBuilder->weld_check_button(check))
sAllStrings.append(pString->get_label() + " ");
}
if (const auto pString = m_xBuilder->weld_button(u"assocfiles"_ustr))
sAllStrings.append(pString->get_label() + " ");
return sAllStrings.toString().replaceAll("_", "");
}
bool OfaMiscTabPage::FillItemSet( SfxItemSet* rSet )
{
bool bModified = false;
std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
if ( m_xPopUpNoHelpCB->get_state_changed_from_saved() )
officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::set(m_xPopUpNoHelpCB->get_active(), batch);
if ( m_xExtHelpCB->get_state_changed_from_saved() )
officecfg::Office::Common::Help::ExtendedTip::set(m_xExtHelpCB->get_active(), batch);
if ( m_xShowTipOfTheDay->get_state_changed_from_saved() )
{
officecfg::Office::Common::Misc::ShowTipOfTheDay::set(m_xShowTipOfTheDay->get_active(), batch);
bModified = true;
}
if (m_xColorDlgCB->get_state_changed_from_saved())
{
officecfg::Office::Common::Misc::UseSystemColorDialog::set(!m_xColorDlgCB->get_active(), batch);
bModified = true;
}
if ( m_xFileDlgCB->get_state_changed_from_saved() )
{
officecfg::Office::Common::Misc::UseSystemFileDialog::set( !m_xFileDlgCB->get_active(), batch );
bModified = true;
}
if (m_xDocStatusCB->get_state_changed_from_saved())
{
officecfg::Office::Common::Print::PrintingModifiesDocument::set(m_xDocStatusCB->get_active(), batch);
bModified = true;
}
const SfxUInt16Item* pUInt16Item = GetOldItem( *rSet, SID_ATTR_YEAR2000 );
sal_uInt16 nNum = static_cast<sal_uInt16>(m_xYearValueField->get_text().toInt32());
if ( pUInt16Item && pUInt16Item->GetValue() != nNum )
{
bModified = true;
rSet->Put( SfxUInt16Item( SID_ATTR_YEAR2000, nNum ) );
}
#if HAVE_FEATURE_BREAKPAD
if (m_xCrashReport->get_state_changed_from_saved())
{
officecfg::Office::Common::Misc::CrashReport::set(m_xCrashReport->get_active(), batch);
bModified = true;
}
#endif
#if defined(_WIN32)
if (m_xPerformFileExtCheck->get_state_changed_from_saved())
{
officecfg::Office::Common::Misc::PerformFileExtCheck::set(
m_xPerformFileExtCheck->get_active(), batch);
bModified = true;
}
if( m_xQuickLaunchCB->get_state_changed_from_saved())
{
rSet->Put(SfxBoolItem(SID_ATTR_QUICKLAUNCHER, m_xQuickLaunchCB->get_active()));
bModified = true;
}
#endif
batch->commit();
return bModified;
}
void OfaMiscTabPage::Reset( const SfxItemSet* rSet )
{
bool bEnable = !officecfg::Office::Common::Help::ExtendedTip::isReadOnly();
m_xExtHelpCB->set_active( officecfg::Office::Common::Help::Tip::get() &&
officecfg::Office::Common::Help::ExtendedTip::get() );
m_xExtHelpCB->set_sensitive(bEnable);
m_xExtHelpImg->set_visible(!bEnable);
m_xExtHelpCB->save_state();
bEnable = !officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::isReadOnly();
m_xPopUpNoHelpCB->set_active( officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::get() );
m_xPopUpNoHelpCB->set_sensitive(bEnable);
m_xPopUpNoHelpImg->set_visible(!bEnable);
m_xPopUpNoHelpCB->save_state();
bEnable = !officecfg::Office::Common::Misc::ShowTipOfTheDay::isReadOnly();
m_xShowTipOfTheDay->set_active( officecfg::Office::Common::Misc::ShowTipOfTheDay::get() );
m_xShowTipOfTheDay->set_sensitive(bEnable);
m_xShowTipOfTheDayImg->set_visible(!bEnable);
m_xShowTipOfTheDay->save_state();
bEnable = !officecfg::Office::Common::Misc::UseSystemColorDialog::isReadOnly();
m_xColorDlgCB->set_sensitive(bEnable);
m_xColorDlgROImage->set_visible(!bEnable);
m_xColorDlgCB->set_active(!officecfg::Office::Common::Misc::UseSystemColorDialog::get());
m_xColorDlgCB->save_state();
const bool bReadOnly = officecfg::Office::Common::Misc::UseSystemFileDialog::isReadOnly();
bEnable = !bReadOnly && lcl_HasSystemFilePicker();
m_xFileDlgCB->set_sensitive(bEnable);
m_xFileDlgROImage->set_visible(bReadOnly);
m_xFileDlgCB->set_active(!lcl_HasSystemFilePicker() || !officecfg::Office::Common::Misc::UseSystemFileDialog::get());
m_xFileDlgCB->save_state();
bEnable = !officecfg::Office::Common::Print::PrintingModifiesDocument::isReadOnly();
m_xDocStatusCB->set_active(officecfg::Office::Common::Print::PrintingModifiesDocument::get());
m_xDocStatusCB->set_sensitive(bEnable);
m_xDocStatusImg->set_visible(!bEnable);
m_xDocStatusCB->save_state();
bEnable = !officecfg::Office::Common::DateFormat::TwoDigitYear::isReadOnly();
m_xYearLabel->set_sensitive(bEnable);
m_xYearValueField->set_sensitive(bEnable);
m_xToYearFT->set_sensitive(bEnable);
m_xYearFrameImg->set_visible(!bEnable);
if ( const SfxUInt16Item* pYearItem = rSet->GetItemIfSet( SID_ATTR_YEAR2000, false ) )
{
m_xYearValueField->set_value( pYearItem->GetValue() );
TwoFigureHdl(*m_xYearValueField);
}
else
m_xYearFrame->set_sensitive(false);
#if HAVE_FEATURE_BREAKPAD
m_xCrashReport->set_active(officecfg::Office::Common::Misc::CrashReport::get() && CrashReporter::IsDumpEnable());
m_xCrashReport->set_sensitive(!officecfg::Office::Common::Misc::CrashReport::isReadOnly() && CrashReporter::IsDumpEnable());
m_xCrashReportImg->set_visible(officecfg::Office::Common::Misc::CrashReport::isReadOnly() && CrashReporter::IsDumpEnable());
m_xCrashReport->save_state();
#endif
#if defined(_WIN32)
if (const SfxBoolItem* pItem = rSet->GetItemIfSet( SID_ATTR_QUICKLAUNCHER, false ))
{
m_xQuickLaunchCB->set_active( pItem->GetValue() );
}
else
{
// quickstart not installed
m_xQuickStarterFrame->hide();
}
m_xQuickLaunchCB->save_state();
m_xPerformFileExtCheck->set_active(
officecfg::Office::Common::Misc::PerformFileExtCheck::get());
m_xPerformFileExtCheck->save_state();
m_xPerformFileExtCheck->set_sensitive(!officecfg::Office::Common::Misc::PerformFileExtCheck::isReadOnly());
m_xPerformFileExtImg->set_visible(officecfg::Office::Common::Misc::PerformFileExtCheck::isReadOnly());
#endif
}
IMPL_LINK_NOARG( OfaMiscTabPage, TwoFigureHdl, weld::SpinButton&, void )
{
OUString aOutput( m_aStrDateInfo );
OUString aStr( m_xYearValueField->get_text() );
sal_Int32 nNum = aStr.toInt32();
if ( aStr.getLength() != 4 || nNum < m_xYearValueField->get_min() || nNum > m_xYearValueField->get_max() )
aOutput += "????";
else
{
nNum += 99;
aOutput += OUString::number( nNum );
}
m_xToYearFT->set_label( aOutput );
}
#if defined(_WIN32)
IMPL_STATIC_LINK_NOARG(OfaMiscTabPage, FileAssocClick, weld::Button&, void)
{
vcl::fileregistration::LaunchRegistrationUI();
}
#endif
class CanvasSettings
{
public:
CanvasSettings();
bool IsHardwareAccelerationAvailable() const;
private:
typedef std::vector< std::pair<OUString,Sequence<OUString> > > ServiceVector;
Reference<XNameAccess> mxForceFlagNameAccess;
ServiceVector maAvailableImplementations;
mutable bool mbHWAccelAvailable;
mutable bool mbHWAccelChecked;
};
CanvasSettings::CanvasSettings() :
mbHWAccelAvailable(false),
mbHWAccelChecked(false)
{
try
{
Reference<XMultiServiceFactory> xConfigProvider(
css::configuration::theDefaultProvider::get(
comphelper::getProcessComponentContext()));
Sequence<Any> aArgs1(comphelper::InitAnyPropertySequence(
{
{"nodepath", Any(u"/org.openoffice.Office.Canvas"_ustr)}
}));
mxForceFlagNameAccess.set(
xConfigProvider->createInstanceWithArguments(
u"com.sun.star.configuration.ConfigurationUpdateAccess"_ustr,
aArgs1 ),
UNO_QUERY_THROW );
Sequence<Any> aArgs2(comphelper::InitAnyPropertySequence(
{
{"nodepath", Any(u"/org.openoffice.Office.Canvas/CanvasServiceList"_ustr)}
}));
Reference<XNameAccess> xNameAccess(
xConfigProvider->createInstanceWithArguments(
u"com.sun.star.configuration.ConfigurationAccess"_ustr,
aArgs2 ), UNO_QUERY_THROW );
Reference<XHierarchicalNameAccess> xHierarchicalNameAccess(
xNameAccess, UNO_QUERY_THROW);
for (auto& serviceName : xNameAccess->getElementNames())
{
Reference<XNameAccess> xEntryNameAccess(
xHierarchicalNameAccess->getByHierarchicalName(serviceName),
UNO_QUERY );
if( xEntryNameAccess.is() )
{
Sequence<OUString> preferredImplementations;
if( xEntryNameAccess->getByName(u"PreferredImplementations"_ustr) >>= preferredImplementations )
maAvailableImplementations.emplace_back(serviceName, preferredImplementations);
}
}
}
catch (const Exception&)
{
}
}
bool CanvasSettings::IsHardwareAccelerationAvailable() const
{
if( !mbHWAccelChecked )
{
mbHWAccelChecked = true;
Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
// check whether any of the service lists has an
// implementation that presents the "HardwareAcceleration" property
for (auto const& availableImpl : maAvailableImplementations)
{
for (auto& currImpl : availableImpl.second)
{
try
{
Reference<XPropertySet> xPropSet( xFactory->createInstance(
currImpl.trim() ),
UNO_QUERY_THROW );
bool bHasAccel(false);
if( xPropSet->getPropertyValue(u"HardwareAcceleration"_ustr) >>= bHasAccel )
if( bHasAccel )
{
mbHWAccelAvailable = true;
return mbHWAccelAvailable;
}
}
catch (const Exception&)
{
}
}
}
}
return mbHWAccelAvailable;
}
// class OfaViewTabPage --------------------------------------------------
OfaViewTabPage::OfaViewTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
: SfxTabPage(pPage, pController, u"cui/ui/optviewpage.ui"_ustr, u"OptViewPage"_ustr, &rSet)
, pCanvasSettings(new CanvasSettings)
, m_xFontAntiAliasing(m_xBuilder->weld_check_button(u"aafont"_ustr))
, m_xFontAntiAliasingImg(m_xBuilder->weld_widget(u"lockaafont"_ustr))
, m_xAAPointLimitLabel(m_xBuilder->weld_label(u"aafrom"_ustr))
, m_xAAPointLimitLabelImg(m_xBuilder->weld_widget(u"lockaafrom"_ustr))
, m_xAAPointLimit(m_xBuilder->weld_metric_spin_button(u"aanf"_ustr, FieldUnit::PIXEL))
, m_xFontShowCB(m_xBuilder->weld_check_button(u"showfontpreview"_ustr))
, m_xFontShowImg(m_xBuilder->weld_widget(u"lockshowfontpreview"_ustr))
, m_xUseHardwareAccell(m_xBuilder->weld_check_button(u"useaccel"_ustr))
, m_xUseHardwareAccellImg(m_xBuilder->weld_widget(u"lockuseaccel"_ustr))
, m_xUseAntiAliase(m_xBuilder->weld_check_button(u"useaa"_ustr))
, m_xUseAntiAliaseImg(m_xBuilder->weld_widget(u"lockuseaa"_ustr))
, m_xUseSkia(m_xBuilder->weld_check_button(u"useskia"_ustr))
, m_xUseSkiaImg(m_xBuilder->weld_widget(u"lockuseskia"_ustr))
, m_xForceSkiaRaster(m_xBuilder->weld_check_button(u"forceskiaraster"_ustr))
, m_xForceSkiaRasterImg(m_xBuilder->weld_widget(u"lockforceskiaraster"_ustr))
, m_xSkiaStatusEnabled(m_xBuilder->weld_label(u"skiaenabled"_ustr))
, m_xSkiaStatusDisabled(m_xBuilder->weld_label(u"skiadisabled"_ustr))
, m_xSkiaLog(m_xBuilder->weld_button(u"btnSkialog"_ustr))
, m_xMouseMiddleLabel(m_xBuilder->weld_label(u"label12"_ustr))
, m_xMouseMiddleLB(m_xBuilder->weld_combo_box(u"mousemiddle"_ustr))
, m_xMouseMiddleImg(m_xBuilder->weld_widget(u"lockmousemiddle"_ustr))
, m_xRunGPTests(m_xBuilder->weld_button(u"btn_rungptest"_ustr))
{
m_xFontAntiAliasing->connect_toggled( LINK( this, OfaViewTabPage, OnAntialiasingToggled ) );
m_xUseSkia->connect_toggled(LINK(this, OfaViewTabPage, OnUseSkiaToggled));
m_xSkiaLog->connect_clicked(LINK(this, OfaViewTabPage, OnCopySkiaLog));
m_xRunGPTests->connect_clicked(LINK(this, OfaViewTabPage, OnRunGPTestClick));
// Hide "Run Graphics Test" button if Experimental Mode is off
if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
m_xRunGPTests->hide();
}
OfaViewTabPage::~OfaViewTabPage()
{
}
IMPL_LINK_NOARG(OfaViewTabPage, OnRunGPTestClick, weld::Button&, void)
{
GraphicsTestsDialog m_xGraphicsTestDialog(m_xContainer.get());
m_xGraphicsTestDialog.run();
}
IMPL_LINK_NOARG( OfaViewTabPage, OnAntialiasingToggled, weld::Toggleable&, void )
{
bool bAAEnabled = m_xFontAntiAliasing->get_active() && !officecfg::Office::Common::View::FontAntiAliasing::MinPixelHeight::isReadOnly();
m_xAAPointLimitLabel->set_sensitive(bAAEnabled);
m_xAAPointLimit->set_sensitive(bAAEnabled);
}
IMPL_LINK_NOARG(OfaViewTabPage, OnUseSkiaToggled, weld::Toggleable&, void)
{
UpdateSkiaStatus();
}
IMPL_LINK_NOARG(OfaViewTabPage, OnCopySkiaLog, weld::Button&, void)
{
#if HAVE_FEATURE_SKIA
css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard =
css::datatransfer::clipboard::SystemClipboard::create(
comphelper::getProcessComponentContext());
OUString sInfo = SkiaHelper::readLog();
vcl::unohelper::TextDataObject::CopyStringTo(sInfo, xClipboard);
m_xSkiaLog->set_from_icon_name(RID_SVXBMP_COPY);
#endif
}
void OfaViewTabPage::HideSkiaWidgets()
{
m_xUseSkia->hide();
m_xForceSkiaRaster->hide();
m_xSkiaStatusEnabled->hide();
m_xSkiaStatusDisabled->hide();
m_xSkiaLog->hide();
}
void OfaViewTabPage::UpdateSkiaStatus()
{
#if HAVE_FEATURE_SKIA
bool skiaHidden = true;
// For now Skia is used mainly on Windows, enable the controls there.
if (Application::GetToolkitName() == "win")
skiaHidden = false;
// It can also be used on Linux, but only with the rarely used 'gen' backend.
if (Application::GetToolkitName() == "x11")
skiaHidden = false;
// OSX backend has Skia support too.
if (Application::GetToolkitName() == "osx")
skiaHidden = false;
if (skiaHidden)
{
HideSkiaWidgets();
return;
}
// Easier than a custom translation string.
bool bEnabled = SkiaHelper::isVCLSkiaEnabled();
m_xSkiaStatusEnabled->set_visible(bEnabled);
m_xSkiaStatusDisabled->set_visible(!bEnabled);
#if defined(MACOSX) || defined(_WIN32)
m_xUseSkia->set_sensitive(false); // macOS/win can __only__ render via skia
#else
m_xUseSkia->set_sensitive(!officecfg::Office::Common::VCL::UseSkia::isReadOnly());
#endif
m_xUseSkiaImg->set_visible(officecfg::Office::Common::VCL::UseSkia::isReadOnly());
m_xForceSkiaRaster->set_sensitive(m_xUseSkia->get_active() && !officecfg::Office::Common::VCL::ForceSkiaRaster::isReadOnly());
m_xForceSkiaRasterImg->set_visible(officecfg::Office::Common::VCL::ForceSkiaRaster::isReadOnly());
m_xSkiaLog->set_sensitive(bEnabled);
// Technically the 'use hardware acceleration' option could be used to mean !forceSkiaRaster, but the implementation
// of the option is so tied to the implementation of the canvas module that it's simpler to ignore it.
UpdateHardwareAccelStatus();
#else
HideSkiaWidgets();
#endif
}
std::unique_ptr<SfxTabPage> OfaViewTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
{
return std::make_unique<OfaViewTabPage>(pPage, pController, *rAttrSet);
}
OUString OfaViewTabPage::GetAllStrings()
{
OUStringBuffer sAllStrings;
OUString labels[] = { u"label16"_ustr, u"label1"_ustr, u"label6"_ustr, u"label15"_ustr,
u"label14"_ustr, u"label8"_ustr, u"label9"_ustr, u"label4"_ustr, u"label12"_ustr,
u"label2"_ustr, u"skiaenabled"_ustr, u"skiadisabled"_ustr, u"label5"_ustr, u"aafrom"_ustr };
for (const auto& label : labels)
{
if (const auto pString = m_xBuilder->weld_label(label))
sAllStrings.append(pString->get_label() + " ");
}
OUString checkButton[]
= { u"useaccel"_ustr, u"useaa"_ustr, u"useskia"_ustr, u"forceskiaraster"_ustr, u"showfontpreview"_ustr, u"aafont"_ustr };
for (const auto& check : checkButton)
{
if (const auto pString = m_xBuilder->weld_check_button(check))
sAllStrings.append(pString->get_label() + " ");
}
sAllStrings.append(m_xSkiaLog->get_label() + " " + m_xRunGPTests->get_label() + " ");
return sAllStrings.toString().replaceAll("_", "");
}
bool OfaViewTabPage::FillItemSet( SfxItemSet* )
{
bool bModified = false;
bool bRepaintWindows(false);
bool bAppearanceChanged = false;
std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
// Middle Mouse Button
MouseMiddleButtonAction eOldMiddleMouse = static_cast<MouseMiddleButtonAction>(officecfg::Office::Common::View::Dialog::MiddleMouseButton::get());
short eNewMiddleMouse = m_xMouseMiddleLB->get_active();
if(eNewMiddleMouse > 2)
eNewMiddleMouse = 2;
if ( eNewMiddleMouse != static_cast<short>(eOldMiddleMouse) )
{
officecfg::Office::Common::View::Dialog::MiddleMouseButton::set(eNewMiddleMouse, batch);
bAppearanceChanged = true;
}
if (m_xFontAntiAliasing->get_state_changed_from_saved())
{
bool b = m_xFontAntiAliasing->get_active();
officecfg::Office::Common::View::FontAntiAliasing::Enabled::set(b, batch);
bAppearanceChanged = true;
}
if (m_xAAPointLimit->get_value_changed_from_saved())
{
sal_Int16 i = o3tl::sanitizing_cast<sal_Int16>(m_xAAPointLimit->get_value(FieldUnit::PIXEL));
officecfg::Office::Common::View::FontAntiAliasing::MinPixelHeight::set(i, batch);
bAppearanceChanged = true;
}
std::shared_ptr<comphelper::ConfigurationChanges> xChanges(comphelper::ConfigurationChanges::create());
if (m_xFontShowCB->get_state_changed_from_saved())
{
officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::set(m_xFontShowCB->get_active(), xChanges);
bModified = true;
}
// #i95644# if disabled, do not use value, see in ::Reset()
if (m_xUseHardwareAccell->get_sensitive())
{
if(m_xUseHardwareAccell->get_state_changed_from_saved())
{
officecfg::Office::Canvas::ForceSafeServiceImpl::set(m_xUseHardwareAccell->get_active(), xChanges);
bModified = true;
}
}
// #i95644# if disabled, do not use value, see in ::Reset()
if (m_xUseAntiAliase->get_sensitive())
{
if (m_xUseAntiAliase->get_active() != SvtOptionsDrawinglayer::IsAntiAliasing())
{
SvtOptionsDrawinglayer::SetAntiAliasing(m_xUseAntiAliase->get_active(), /*bTemporary*/false);
bModified = true;
bRepaintWindows = true;
}
}
if (m_xUseSkia->get_state_changed_from_saved() ||
m_xForceSkiaRaster->get_state_changed_from_saved())
{
officecfg::Office::Common::VCL::UseSkia::set(m_xUseSkia->get_active(), xChanges);
officecfg::Office::Common::VCL::ForceSkiaRaster::set(m_xForceSkiaRaster->get_active(), xChanges);
bModified = true;
}
xChanges->commit();
if ( bAppearanceChanged )
{
batch->commit();
SvtTabAppearanceCfg::SetApplicationDefaults ( GetpApp() );
}
if(bRepaintWindows)
{
vcl::Window* pAppWindow = Application::GetFirstTopLevelWindow();
while(pAppWindow)
{
pAppWindow->Invalidate();
pAppWindow = Application::GetNextTopLevelWindow(pAppWindow);
}
}
if (m_xUseSkia->get_state_changed_from_saved() ||
m_xForceSkiaRaster->get_state_changed_from_saved())
{
SolarMutexGuard aGuard;
if( svtools::executeRestartDialog(
comphelper::getProcessComponentContext(), nullptr,
svtools::RESTART_REASON_SKIA))
GetDialogController()->response(RET_OK);
}
return bModified;
}
void OfaViewTabPage::Reset( const SfxItemSet* )
{
bool bEnable = true;
// Middle Mouse Button
bEnable = !officecfg::Office::Common::View::Dialog::MiddleMouseButton::isReadOnly();
sal_Int16 nMiddleMouseButton = officecfg::Office::Common::View::Dialog::MiddleMouseButton::get();
m_xMouseMiddleLB->set_active(static_cast<short>(nMiddleMouseButton));
m_xMouseMiddleLabel->set_sensitive(bEnable);
m_xMouseMiddleLB->set_sensitive(bEnable);
m_xMouseMiddleImg->set_visible(!bEnable);
m_xMouseMiddleLB->save_value();
bEnable = !officecfg::Office::Common::View::FontAntiAliasing::Enabled::isReadOnly();
bool bFontAntiAliasing = officecfg::Office::Common::View::FontAntiAliasing::Enabled::get();
m_xFontAntiAliasing->set_active( bFontAntiAliasing );
m_xFontAntiAliasing->set_sensitive(bEnable);
m_xFontAntiAliasingImg->set_visible(!bEnable);
bEnable = !officecfg::Office::Common::View::FontAntiAliasing::MinPixelHeight::isReadOnly();
sal_Int16 nFontAntiAliasingMinPixelHeight = officecfg::Office::Common::View::FontAntiAliasing::MinPixelHeight::get();
m_xAAPointLimit->set_value(nFontAntiAliasingMinPixelHeight, FieldUnit::PIXEL);
m_xAAPointLimit->set_sensitive(bEnable);
m_xAAPointLimitLabelImg->set_visible(!bEnable);
// WorkingSet
bEnable = !officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::isReadOnly();
m_xFontShowCB->set_active(officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::get());
m_xFontShowCB->set_sensitive(bEnable);
m_xFontShowImg->set_visible(!bEnable);
UpdateHardwareAccelStatus();
m_xUseHardwareAccell->save_state();
{ // #i95644# AntiAliasing
m_xUseAntiAliase->set_active(SvtOptionsDrawinglayer::IsAntiAliasing());
bEnable = !officecfg::Office::Common::Drawinglayer::AntiAliasing::isReadOnly();
m_xUseAntiAliase->set_sensitive(bEnable);
m_xUseAntiAliaseImg->set_visible(!bEnable);
m_xUseAntiAliase->save_state();
}
#if defined(MACOSX) || defined(_WIN32)
m_xUseSkia->set_active(true); // macOS/win can __only__ render via skia
#else
m_xUseSkia->set_active(officecfg::Office::Common::VCL::UseSkia::get());
#endif
m_xForceSkiaRaster->set_active(officecfg::Office::Common::VCL::ForceSkiaRaster::get());
m_xUseSkia->save_state();
m_xForceSkiaRaster->save_state();
m_xFontAntiAliasing->save_state();
m_xAAPointLimit->save_value();
m_xFontShowCB->save_state();
OnAntialiasingToggled(*m_xFontAntiAliasing);
UpdateSkiaStatus();
}
void OfaViewTabPage::UpdateHardwareAccelStatus()
{
// #i95644# HW accel (unified to disable mechanism)
bool bHardwareAccRO = officecfg::Office::Canvas::ForceSafeServiceImpl::isReadOnly();
if(pCanvasSettings->IsHardwareAccelerationAvailable())
{
m_xUseHardwareAccell->set_active(officecfg::Office::Canvas::ForceSafeServiceImpl::get());
m_xUseHardwareAccell->set_sensitive(!bHardwareAccRO);
m_xUseHardwareAccellImg->set_visible(bHardwareAccRO);
}
else
{
m_xUseHardwareAccell->set_active(false);
m_xUseHardwareAccell->set_sensitive(false);
m_xUseHardwareAccellImg->set_visible(true);
}
#if HAVE_FEATURE_SKIA
m_xUseHardwareAccell->set_sensitive(!bHardwareAccRO && !m_xUseSkia->get_active());
#endif
}
struct LanguageConfig_Impl
{
SvtCTLOptions aCTLLanguageOptions;
SvtSysLocaleOptions aSysLocaleOptions;
SvtLinguConfig aLinguConfig;
};
static bool bLanguageCurrentDoc_Impl = false;
// some things we'll need...
constexpr OUString sAccessSrvc = u"com.sun.star.configuration.ConfigurationAccess"_ustr;
constexpr OUStringLiteral sAccessUpdSrvc = u"com.sun.star.configuration.ConfigurationUpdateAccess";
constexpr OUString sInstalledLocalesPath = u"org.openoffice.Setup/Office/InstalledLocales"_ustr;
constexpr OUString sUserLocalePath = u"org.openoffice.Office.Linguistic/General"_ustr;
constexpr OUString sUserLocaleKey = u"UILocale"_ustr;
static Sequence< OUString > seqInstalledLanguages;
static OUString lcl_getDatePatternsConfigString( const LocaleDataWrapper& rLocaleWrapper )
{
const Sequence< OUString >& aDateAcceptancePatterns = rLocaleWrapper.getDateAcceptancePatterns();
sal_Int32 nPatterns = aDateAcceptancePatterns.getLength();
OUStringBuffer aBuf( nPatterns * 6 ); // 6 := length of Y-M-D;
SAL_WARN_IF( !nPatterns, "cui.options", "No date acceptance pattern");
if (nPatterns)
{
aBuf.append(aDateAcceptancePatterns[0]);
for (sal_Int32 i=1; i < nPatterns; ++i)
aBuf.append(";" + aDateAcceptancePatterns[i]);
}
return aBuf.makeStringAndClear();
}
namespace
{
//what ui language will be selected by default if the user override of General::UILocale is unset ?
LanguageTag GetInstalledLocaleForSystemUILanguage()
{
css::uno::Sequence<OUString> inst(officecfg::Setup::Office::InstalledLocales::get()->getElementNames());
return LanguageTag(getInstalledLocaleForSystemUILanguage(inst, false)).makeFallback();
}
}
OfaLanguagesTabPage::OfaLanguagesTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
: SfxTabPage(pPage, pController, u"cui/ui/optlanguagespage.ui"_ustr, u"OptLanguagesPage"_ustr, &rSet)
, pLangConfig(new LanguageConfig_Impl)
, m_bDatePatternsValid(false)
, m_xUserInterfaceLB(m_xBuilder->weld_combo_box(u"userinterface"_ustr))
, m_xLocaleSettingFT(m_xBuilder->weld_label(u"localesettingFT"_ustr))
, m_xLocaleSettingLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"localesetting"_ustr)))
, m_xLocaleSettingImg(m_xBuilder->weld_widget(u"locklocalesetting"_ustr))
, m_xDecimalSeparatorFT(m_xBuilder->weld_label(u"label6"_ustr))
, m_xDecimalSeparatorCB(m_xBuilder->weld_check_button(u"decimalseparator"_ustr))
, m_xDecimalSeparatorImg(m_xBuilder->weld_widget(u"lockdecimalseparator"_ustr))
, m_xCurrencyFT(m_xBuilder->weld_label(u"defaultcurrency"_ustr))
, m_xCurrencyLB(m_xBuilder->weld_combo_box(u"currencylb"_ustr))
, m_xCurrencyImg(m_xBuilder->weld_widget(u"lockcurrencylb"_ustr))
, m_xDatePatternsFT(m_xBuilder->weld_label(u"dataaccpatterns"_ustr))
, m_xDatePatternsED(m_xBuilder->weld_entry(u"datepatterns"_ustr))
, m_xDatePatternsImg(m_xBuilder->weld_widget(u"lockdatepatterns"_ustr))
, m_xWesternLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"westernlanguage"_ustr)))
, m_xWesternLanguageFT(m_xBuilder->weld_label(u"western"_ustr))
, m_xWesternLanguageImg(m_xBuilder->weld_widget(u"lockwesternlanguage"_ustr))
, m_xAsianLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"asianlanguage"_ustr)))
, m_xAsianLanguageFT(m_xBuilder->weld_label(u"asian"_ustr))
, m_xAsianLanguageImg(m_xBuilder->weld_widget(u"lockasianlanguage"_ustr))
, m_xComplexLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"complexlanguage"_ustr)))
, m_xComplexLanguageFT(m_xBuilder->weld_label(u"complex"_ustr))
, m_xComplexLanguageImg(m_xBuilder->weld_widget(u"lockcomplexlanguage"_ustr))
, m_xCurrentDocCB(m_xBuilder->weld_check_button(u"currentdoc"_ustr))
, m_xIgnoreLanguageChangeCB(m_xBuilder->weld_check_button(u"ignorelanguagechange"_ustr))
, m_xIgnoreLanguageChangeImg(m_xBuilder->weld_widget(u"lockignorelanguagechange"_ustr))
{
// tdf#125483 save original default label
m_sDecimalSeparatorLabel = m_xDecimalSeparatorCB->get_label();
// initialize user interface language selection
m_sSystemDefaultString = SvtLanguageTable::GetLanguageString( LANGUAGE_SYSTEM );
OUString aUILang = m_sSystemDefaultString +
" - " +
SvtLanguageTable::GetLanguageString(GetInstalledLocaleForSystemUILanguage().getLanguageType());
m_xUserInterfaceLB->append(u"0"_ustr, aUILang);
m_xUserInterfaceLB->append_separator(u""_ustr);
try
{
Reference< XMultiServiceFactory > theConfigProvider(
css::configuration::theDefaultProvider::get(
comphelper::getProcessComponentContext()));
// find out which locales are currently installed and add them to the listbox
Sequence< Any > theArgs{ Any(NamedValue(u"nodepath"_ustr, Any(sInstalledLocalesPath))) };
Reference< XNameAccess > theNameAccess(
theConfigProvider->createInstanceWithArguments(sAccessSrvc, theArgs ), UNO_QUERY_THROW );
seqInstalledLanguages = theNameAccess->getElementNames();
LanguageType aLang = LANGUAGE_DONTKNOW;
std::vector< std::pair<sal_Int32, OUString> > aUILanguages;
for (sal_Int32 i=0; i<seqInstalledLanguages.getLength(); i++)
{
aLang = LanguageTag::convertToLanguageTypeWithFallback(seqInstalledLanguages[i]);
if (aLang != LANGUAGE_DONTKNOW)
{
OUString aLangStr( SvtLanguageTable::GetLanguageString( aLang ) );
aUILanguages.emplace_back(i+1, aLangStr);
}
}
std::sort(aUILanguages.begin(), aUILanguages.end(), [](const auto& l1, const auto& l2) {
static const auto aSorter = comphelper::string::NaturalStringSorter(
comphelper::getProcessComponentContext(),
Application::GetSettings().GetUILanguageTag().getLocale());
return aSorter.compare(l1.second, l2.second) < 0;
});
// tdf#114694: append the sorted list after the default entry and separator.
for (const auto & [ nGroupID, sGroupName ] : aUILanguages)
{
m_xUserInterfaceLB->append(OUString::number(nGroupID), sGroupName);
}
m_xUserInterfaceLB->set_active(0);
// find out whether the user has a specific locale specified
Sequence< Any > theArgs2{ Any(NamedValue(u"nodepath"_ustr, Any(sUserLocalePath))) };
theNameAccess.set(
theConfigProvider->createInstanceWithArguments(sAccessSrvc, theArgs2 ), UNO_QUERY_THROW );
if (theNameAccess->hasByName(sUserLocaleKey))
theNameAccess->getByName(sUserLocaleKey) >>= m_sUserLocaleValue;
// select the user specified locale in the listbox
if (!m_sUserLocaleValue.isEmpty())
{
for (sal_Int32 i = 0, nEntryCount = m_xUserInterfaceLB->get_count(); i < nEntryCount; ++i)
{
sal_Int32 d = m_xUserInterfaceLB->get_id(i).toInt32();
if ( d > 0 && seqInstalledLanguages.getLength() > d-1 && seqInstalledLanguages[d-1] == m_sUserLocaleValue)
m_xUserInterfaceLB->set_active(i);
}
}
}
catch (const Exception &)
{
// we'll just leave the box in its default setting and won't
// even give it event handler...
TOOLS_WARN_EXCEPTION("cui.options", "ignoring" );
}
m_xWesternLanguageLB->SetLanguageList(
SvxLanguageListFlags::WESTERN | SvxLanguageListFlags::ONLY_KNOWN, true, false, true, true,
LANGUAGE_SYSTEM, css::i18n::ScriptType::LATIN);
m_xAsianLanguageLB->SetLanguageList(
SvxLanguageListFlags::CJK | SvxLanguageListFlags::ONLY_KNOWN, true, false, true, true,
LANGUAGE_SYSTEM, css::i18n::ScriptType::ASIAN);
m_xComplexLanguageLB->SetLanguageList(
SvxLanguageListFlags::CTL | SvxLanguageListFlags::ONLY_KNOWN, true, false, true, true,
LANGUAGE_SYSTEM, css::i18n::ScriptType::COMPLEX);
m_xLocaleSettingLB->SetLanguageList(
SvxLanguageListFlags::ALL | SvxLanguageListFlags::ONLY_KNOWN, false, false, false, true,
LANGUAGE_USER_SYSTEM_CONFIG, css::i18n::ScriptType::WEAK);
const NfCurrencyTable& rCurrTab = SvNumberFormatter::GetTheCurrencyTable();
const NfCurrencyEntry& rCurr = SvNumberFormatter::GetCurrencyEntry( LANGUAGE_SYSTEM );
// insert SYSTEM entry
OUString aDefaultCurr = m_sSystemDefaultString + " - " + rCurr.GetBankSymbol();
m_xCurrencyLB->append(u"default"_ustr, aDefaultCurr);
m_xCurrencyLB->append_separator(u""_ustr);
assert(m_xCurrencyLB->find_id(u"default"_ustr) != -1);
// all currencies
OUString aTwoSpace( u" "_ustr );
sal_uInt16 nCurrCount = rCurrTab.size();
std::vector< const NfCurrencyEntry* > aCurrencies;
// first entry is SYSTEM, skip it
for ( sal_uInt16 j=1; j < nCurrCount; ++j )
{
aCurrencies.push_back(&rCurrTab[j]);
}
std::sort(aCurrencies.begin(), aCurrencies.end(),
[](const NfCurrencyEntry* c1, const NfCurrencyEntry* c2) {
return c1->GetBankSymbol().compareTo(c2->GetBankSymbol()) < 0;
});
for (auto &v : aCurrencies)
{
OUString aStr_ = v->GetBankSymbol() +
aTwoSpace +
v->GetSymbol();
aStr_ = ApplyLreOrRleEmbedding( aStr_ ) +
aTwoSpace +
ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString( v->GetLanguage() ) );
m_xCurrencyLB->append(weld::toId(v), aStr_);
}
m_xCurrencyLB->set_active(0);
m_xLocaleSettingLB->connect_changed( LINK( this, OfaLanguagesTabPage, LocaleSettingHdl ) );
m_xDatePatternsED->connect_changed( LINK( this, OfaLanguagesTabPage, DatePatternsHdl ) );
m_xIgnoreLanguageChangeCB->set_active( pLangConfig->aSysLocaleOptions.IsIgnoreLanguageChange() );
}
OfaLanguagesTabPage::~OfaLanguagesTabPage()
{
}
std::unique_ptr<SfxTabPage> OfaLanguagesTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
{
return std::make_unique<OfaLanguagesTabPage>(pPage, pController, *rAttrSet);
}
OUString OfaLanguagesTabPage::GetAllStrings()
{
OUStringBuffer sAllStrings;
OUString labels[]
= { u"label1"_ustr, u"label4"_ustr, u"label7"_ustr, u"localesettingFT"_ustr, u"defaultcurrency"_ustr,
u"label6"_ustr, u"dataaccpatterns"_ustr, u"label2"_ustr, u"western"_ustr, u"label3"_ustr };
for (const auto& label : labels)
{
if (const auto pString = m_xBuilder->weld_label(label))
sAllStrings.append(pString->get_label() + " ");
}
OUString checkButton[]
= { u"decimalseparator"_ustr, u"currentdoc"_ustr, u"ignorelanguagechange"_ustr };
for (const auto& check : checkButton)
{
if (const auto pString = m_xBuilder->weld_check_button(check))
sAllStrings.append(pString->get_label() + " ");
}
return sAllStrings.toString().replaceAll("_", "");
}
bool OfaLanguagesTabPage::FillItemSet( SfxItemSet* rSet )
{
// lock configuration broadcasters so that we can coordinate the notifications
pLangConfig->aSysLocaleOptions.BlockBroadcasts( true );
pLangConfig->aCTLLanguageOptions.BlockBroadcasts( true );
pLangConfig->aLinguConfig.BlockBroadcasts( true );
/*
* Sequence checking only matters when CTL support is enabled.
*
* So we only need to check for sequence checking if the CTL language has changed
*/
if (m_xComplexLanguageLB->get_active_id_changed_from_saved())
{
//sequence checking has to be switched on depending on the selected CTL language
LanguageType eCTLLang = m_xComplexLanguageLB->get_active_id();
bool bOn = MsLangId::needsSequenceChecking( eCTLLang);
pLangConfig->aCTLLanguageOptions.SetCTLSequenceCheckingRestricted(bOn);
pLangConfig->aCTLLanguageOptions.SetCTLSequenceChecking(bOn);
pLangConfig->aCTLLanguageOptions.SetCTLSequenceCheckingTypeAndReplace(bOn);
}
try
{
// handle settings for UI Language
// a change of setting needs to bring up a warning message
OUString aLangString;
sal_Int32 d = m_xUserInterfaceLB->get_active_id().toInt32();
if( d > 0 && seqInstalledLanguages.getLength() > d-1)
aLangString = seqInstalledLanguages[d-1];
/*
if( m_xUserInterfaceLB->GetSelectedEntryPos() > 0)
aLangString = ConvertLanguageToIsoString(m_xUserInterfaceLB->get_active_id());
*/
Reference< XMultiServiceFactory > theConfigProvider(
css::configuration::theDefaultProvider::get(
comphelper::getProcessComponentContext()));
Sequence< Any > theArgs{ Any(NamedValue(u"nodepath"_ustr, Any(sUserLocalePath))) };
Reference< XPropertySet >xProp(
theConfigProvider->createInstanceWithArguments(sAccessUpdSrvc, theArgs ), UNO_QUERY_THROW );
if ( m_sUserLocaleValue != aLangString)
{
// OSL_FAIL("UserInterface language was changed, restart.");
// write new value
xProp->setPropertyValue(sUserLocaleKey, Any(aLangString));
Reference< XChangesBatch >(xProp, UNO_QUERY_THROW)->commitChanges();
// display info
SolarMutexGuard aGuard;
if (svtools::executeRestartDialog(
comphelper::getProcessComponentContext(), GetFrameWeld(),
svtools::RESTART_REASON_LANGUAGE_CHANGE))
GetDialogController()->response(RET_OK);
// tell quickstarter to stop being a veto listener
const Reference< XComponentContext >& xContext(
comphelper::getProcessComponentContext());
css::office::Quickstart::createAndSetVeto(xContext, false, false, false/*DisableVeto*/);
}
}
catch (const Exception&)
{
// we'll just leave the box in its default setting and won't
// even give it event handler...
TOOLS_WARN_EXCEPTION("cui.options", "ignoring");
}
LanguageTag aLanguageTag( pLangConfig->aSysLocaleOptions.GetLanguageTag());
LanguageType eOldLocale = (aLanguageTag.isSystemLocale() ? LANGUAGE_SYSTEM :
aLanguageTag.makeFallback().getLanguageType());
LanguageType eNewLocale = m_xLocaleSettingLB->get_active_id();
// If the "Default ..." entry was selected that means SYSTEM, the actual
// eNewLocale value is temporary for the dialog only, do not resolve to
// what system currently is.
if (eNewLocale == LANGUAGE_USER_SYSTEM_CONFIG)
eNewLocale = LANGUAGE_SYSTEM;
if ( eOldLocale != eNewLocale )
{
// an empty string denotes SYSTEM locale
OUString sNewLang;
if ( eNewLocale != LANGUAGE_SYSTEM )
sNewLang = LanguageTag::convertToBcp47( eNewLocale);
// locale nowadays get to AppSettings via notification
// this will happen after releasing the lock on the ConfigurationBroadcaster at
// the end of this method
pLangConfig->aSysLocaleOptions.SetLocaleConfigString( sNewLang );
rSet->Put( SfxBoolItem( SID_OPT_LOCALE_CHANGED, true ) );
SvtScriptType nNewType = SvtLanguageOptions::GetScriptTypeOfLanguage( eNewLocale );
bool bNewCJK = bool( nNewType & SvtScriptType::ASIAN );
auto batch = comphelper::ConfigurationChanges::create();
SvtCompatibilityDefault aCompatOpts(batch);
aCompatOpts.set(u"ExpandWordSpace"_ustr, !bNewCJK);
batch->commit();
}
if(m_xDecimalSeparatorCB->get_state_changed_from_saved())
pLangConfig->aSysLocaleOptions.SetDecimalSeparatorAsLocale(m_xDecimalSeparatorCB->get_active());
if(m_xIgnoreLanguageChangeCB->get_state_changed_from_saved())
pLangConfig->aSysLocaleOptions.SetIgnoreLanguageChange(m_xIgnoreLanguageChangeCB->get_active());
// Configured currency, for example, USD-en-US or EUR-de-DE, or empty for locale default.
OUString sOldCurr = pLangConfig->aSysLocaleOptions.GetCurrencyConfigString();
OUString sId = m_xCurrencyLB->get_active_id();
const NfCurrencyEntry* pCurr = sId == "default" ? nullptr : weld::fromId<const NfCurrencyEntry*>(sId);
OUString sNewCurr;
if ( pCurr )
sNewCurr = SvtSysLocaleOptions::CreateCurrencyConfigString(
pCurr->GetBankSymbol(), pCurr->GetLanguage() );
if ( sOldCurr != sNewCurr )
pLangConfig->aSysLocaleOptions.SetCurrencyConfigString( sNewCurr );
// Configured date acceptance patterns, for example Y-M-D;M-D or empty for
// locale default.
if (m_bDatePatternsValid && m_xDatePatternsED->get_value_changed_from_saved())
pLangConfig->aSysLocaleOptions.SetDatePatternsConfigString( m_xDatePatternsED->get_text());
SfxObjectShell* pCurrentDocShell = SfxObjectShell::Current();
Reference< css::linguistic2::XLinguProperties > xLinguProp = LinguMgr::GetLinguPropertySet();
bool bCurrentDocCBChecked = m_xCurrentDocCB->get_active();
if (m_xCurrentDocCB->get_sensitive())
bLanguageCurrentDoc_Impl = bCurrentDocCBChecked;
bool bCurrentDocCBChanged = m_xCurrentDocCB->get_state_changed_from_saved();
bool bValChanged = m_xWesternLanguageLB->get_active_id_changed_from_saved();
if( (bCurrentDocCBChanged && !bCurrentDocCBChecked) || bValChanged)
{
LanguageType eSelectLang = m_xWesternLanguageLB->get_active_id();
if(!bCurrentDocCBChecked)
{
Any aValue;
Locale aLocale = LanguageTag::convertToLocale( eSelectLang, false);
aValue <<= aLocale;
pLangConfig->aLinguConfig.SetProperty( u"DefaultLocale", aValue );
if (xLinguProp.is())
xLinguProp->setDefaultLocale( aLocale );
}
if(pCurrentDocShell)
{
rSet->Put(SvxLanguageItem(MsLangId::resolveSystemLanguageByScriptType(eSelectLang, css::i18n::ScriptType::LATIN),
SID_ATTR_LANGUAGE));
}
}
bValChanged = m_xAsianLanguageLB->get_active_id_changed_from_saved();
if( (bCurrentDocCBChanged && !bCurrentDocCBChecked) || bValChanged)
{
LanguageType eSelectLang = m_xAsianLanguageLB->get_active_id();
if(!bCurrentDocCBChecked)
{
Any aValue;
Locale aLocale = LanguageTag::convertToLocale( eSelectLang, false);
aValue <<= aLocale;
pLangConfig->aLinguConfig.SetProperty( u"DefaultLocale_CJK", aValue );
if (xLinguProp.is())
xLinguProp->setDefaultLocale_CJK( aLocale );
}
if(pCurrentDocShell)
{
rSet->Put(SvxLanguageItem(MsLangId::resolveSystemLanguageByScriptType(eSelectLang, css::i18n::ScriptType::ASIAN),
SID_ATTR_CHAR_CJK_LANGUAGE));
}
}
bValChanged = m_xComplexLanguageLB->get_active_id_changed_from_saved();
if( (bCurrentDocCBChanged && !bCurrentDocCBChecked) || bValChanged)
{
LanguageType eSelectLang = m_xComplexLanguageLB->get_active_id();
if(!bCurrentDocCBChecked)
{
Any aValue;
Locale aLocale = LanguageTag::convertToLocale( eSelectLang, false);
aValue <<= aLocale;
pLangConfig->aLinguConfig.SetProperty( u"DefaultLocale_CTL", aValue );
if (xLinguProp.is())
xLinguProp->setDefaultLocale_CTL( aLocale );
}
if(pCurrentDocShell)
{
rSet->Put(SvxLanguageItem(MsLangId::resolveSystemLanguageByScriptType(eSelectLang, css::i18n::ScriptType::COMPLEX),
SID_ATTR_CHAR_CTL_LANGUAGE));
}
// tdf#163228: Mongolian script supports vertical text
pLangConfig->aCTLLanguageOptions.SetCTLVerticalText(
MsLangId::getPrimaryLanguage(eSelectLang)
== MsLangId::getPrimaryLanguage(LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA));
}
if ( pLangConfig->aSysLocaleOptions.IsModified() )
pLangConfig->aSysLocaleOptions.Commit();
// first release the lock on the ConfigurationBroadcaster for Locale changes
// it seems that our code relies on the fact that before other changes like e.g. currency
// are broadcasted locale changes have been done
pLangConfig->aSysLocaleOptions.BlockBroadcasts( false );
pLangConfig->aCTLLanguageOptions.BlockBroadcasts( false );
pLangConfig->aLinguConfig.BlockBroadcasts( false );
return false;
}
void OfaLanguagesTabPage::Reset( const SfxItemSet* rSet )
{
LanguageTag aLanguageTag( pLangConfig->aSysLocaleOptions.GetLanguageTag());
if ( aLanguageTag.isSystemLocale() )
m_xLocaleSettingLB->set_active_id( LANGUAGE_USER_SYSTEM_CONFIG );
else
m_xLocaleSettingLB->set_active_id( aLanguageTag.makeFallback().getLanguageType());
bool bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::Locale);
m_xLocaleSettingLB->set_sensitive(!bReadonly);
m_xLocaleSettingFT->set_sensitive(!bReadonly);
m_xLocaleSettingImg->set_visible(bReadonly);
m_xDecimalSeparatorCB->set_active( pLangConfig->aSysLocaleOptions.IsDecimalSeparatorAsLocale());
bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::DecimalSeparator);
m_xDecimalSeparatorCB->set_sensitive(!bReadonly);
m_xDecimalSeparatorFT->set_sensitive(!bReadonly);
m_xDecimalSeparatorImg->set_visible(bReadonly);
m_xDecimalSeparatorCB->save_state();
m_xIgnoreLanguageChangeCB->set_active( pLangConfig->aSysLocaleOptions.IsIgnoreLanguageChange());
bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::IgnoreLanguageChange);
m_xIgnoreLanguageChangeCB->set_sensitive(!bReadonly);
m_xIgnoreLanguageChangeImg->set_visible(bReadonly);
m_xIgnoreLanguageChangeCB->save_state();
// let LocaleSettingHdl enable/disable checkboxes for CJK/CTL support
// #i15812# must be done *before* the configured currency is set
// and update the decimal separator used for the given locale
LocaleSettingHdl(*m_xLocaleSettingLB->get_widget());
// configured currency, for example, USD-en-US or EUR-de-DE, or empty for locale default
const NfCurrencyEntry* pCurr = nullptr;
OUString sCurrency = pLangConfig->aSysLocaleOptions.GetCurrencyConfigString();
if ( !sCurrency.isEmpty() )
{
LanguageType eLang;
OUString aAbbrev;
SvtSysLocaleOptions::GetCurrencyAbbrevAndLanguage( aAbbrev, eLang, sCurrency );
pCurr = SvNumberFormatter::GetCurrencyEntry( aAbbrev, eLang );
}
// if pCurr==nullptr the SYSTEM entry is selected
OUString sId = !pCurr ? u"default"_ustr : weld::toId(pCurr);
m_xCurrencyLB->set_active_id(sId);
bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::Currency);
m_xCurrencyLB->set_sensitive(!bReadonly);
m_xCurrencyFT->set_sensitive(!bReadonly);
m_xCurrencyImg->set_visible(bReadonly);
// date acceptance patterns
OUString aDatePatternsString = pLangConfig->aSysLocaleOptions.GetDatePatternsConfigString();
if (aDatePatternsString.isEmpty())
{
const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
aDatePatternsString = lcl_getDatePatternsConfigString( rLocaleWrapper);
// Let's assume patterns are valid at this point.
m_bDatePatternsValid = true;
}
else
{
bool bModified = false;
m_bDatePatternsValid = validateDatePatterns( bModified, aDatePatternsString);
}
m_xDatePatternsED->set_text(aDatePatternsString);
m_xDatePatternsED->set_message_type( m_bDatePatternsValid ?
weld::EntryMessageType::Normal : weld::EntryMessageType::Error);
bReadonly = pLangConfig->aSysLocaleOptions.IsReadOnly(SvtSysLocaleOptions::EOption::DatePatterns);
m_xDatePatternsED->set_sensitive(!bReadonly);
m_xDatePatternsFT->set_sensitive(!bReadonly);
m_xDatePatternsImg->set_visible(bReadonly);
m_xDatePatternsED->save_value();
//western/CJK/CLK language
LanguageType eCurLang = LANGUAGE_NONE;
LanguageType eCurLangCJK = LANGUAGE_NONE;
LanguageType eCurLangCTL = LANGUAGE_NONE;
SfxObjectShell* pCurrentDocShell = SfxObjectShell::Current();
//collect the configuration values first
m_xCurrentDocCB->set_sensitive(false);
Any aWestLang;
Any aCJKLang;
Any aCTLLang;
try
{
aWestLang = pLangConfig->aLinguConfig.GetProperty(u"DefaultLocale");
Locale aLocale;
aWestLang >>= aLocale;
eCurLang = LanguageTag::convertToLanguageType( aLocale, false);
aCJKLang = pLangConfig->aLinguConfig.GetProperty(u"DefaultLocale_CJK");
aLocale = Locale();
aCJKLang >>= aLocale;
eCurLangCJK = LanguageTag::convertToLanguageType( aLocale, false);
aCTLLang = pLangConfig->aLinguConfig.GetProperty(u"DefaultLocale_CTL");
aLocale = Locale();
aCTLLang >>= aLocale;
eCurLangCTL = LanguageTag::convertToLanguageType( aLocale, false);
}
catch (const Exception&)
{
}
//overwrite them by the values provided by the DocShell
if(pCurrentDocShell)
{
m_xCurrentDocCB->set_sensitive(true);
m_xCurrentDocCB->set_active(bLanguageCurrentDoc_Impl);
if( const SvxLanguageItem* pLangItem = rSet->GetItemIfSet(SID_ATTR_LANGUAGE, false))
{
LanguageType eTempCurLang = pLangItem->GetValue();
if (MsLangId::resolveSystemLanguageByScriptType(eCurLang, css::i18n::ScriptType::LATIN) != eTempCurLang)
eCurLang = eTempCurLang;
}
if( const SvxLanguageItem* pLang = rSet->GetItemIfSet(SID_ATTR_CHAR_CJK_LANGUAGE, false))
{
LanguageType eTempCurLang = pLang->GetValue();
if (MsLangId::resolveSystemLanguageByScriptType(eCurLangCJK, css::i18n::ScriptType::ASIAN) != eTempCurLang)
eCurLangCJK = eTempCurLang;
}
if( const SvxLanguageItem* pLang = rSet->GetItemIfSet(SID_ATTR_CHAR_CTL_LANGUAGE, false))
{
LanguageType eTempCurLang = pLang->GetValue();
if (MsLangId::resolveSystemLanguageByScriptType(eCurLangCTL, css::i18n::ScriptType::COMPLEX) != eTempCurLang)
eCurLangCTL = eTempCurLang;
}
}
if(LANGUAGE_NONE == eCurLang || LANGUAGE_DONTKNOW == eCurLang)
m_xWesternLanguageLB->set_active_id(LANGUAGE_NONE);
else
m_xWesternLanguageLB->set_active_id(eCurLang);
if(LANGUAGE_NONE == eCurLangCJK || LANGUAGE_DONTKNOW == eCurLangCJK)
m_xAsianLanguageLB->set_active_id(LANGUAGE_NONE);
else
m_xAsianLanguageLB->set_active_id(eCurLangCJK);
if(LANGUAGE_NONE == eCurLangCTL || LANGUAGE_DONTKNOW == eCurLangCTL)
m_xComplexLanguageLB->set_active_id(LANGUAGE_NONE);
else
m_xComplexLanguageLB->set_active_id(eCurLangCTL);
m_xWesternLanguageLB->save_active_id();
m_xAsianLanguageLB->save_active_id();
m_xComplexLanguageLB->save_active_id();
m_xIgnoreLanguageChangeCB->save_state();
m_xCurrentDocCB->save_state();
bool bEnable = !pLangConfig->aLinguConfig.IsReadOnly( u"DefaultLocale" );
m_xWesternLanguageFT->set_sensitive( bEnable );
m_xWesternLanguageLB->set_sensitive( bEnable );
m_xWesternLanguageImg->set_visible( !bEnable );
bEnable = !pLangConfig->aLinguConfig.IsReadOnly(u"DefaultLocale_CJK");
m_xAsianLanguageFT->set_sensitive(bEnable);
m_xAsianLanguageLB->set_sensitive(bEnable);
m_xAsianLanguageImg->set_visible(!bEnable);
bEnable = !pLangConfig->aLinguConfig.IsReadOnly(u"DefaultLocale_CTL");
m_xComplexLanguageFT->set_sensitive(bEnable);
m_xComplexLanguageLB->set_sensitive(bEnable);
m_xComplexLanguageImg->set_visible(!bEnable);
// check the box "For the current document only"
// set the focus to the Western Language box
const SfxBoolItem* pLang = rSet->GetItemIfSet(SID_SET_DOCUMENT_LANGUAGE, false );
if ( pLang && pLang->GetValue() )
{
m_xWesternLanguageLB->grab_focus();
m_xCurrentDocCB->set_sensitive(true);
m_xCurrentDocCB->set_active(true);
}
}
IMPL_LINK_NOARG(OfaLanguagesTabPage, LocaleSettingHdl, weld::ComboBox&, void)
{
LanguageType eLang = m_xLocaleSettingLB->get_active_id();
const NfCurrencyEntry& rCurr = SvNumberFormatter::GetCurrencyEntry(
(eLang == LANGUAGE_USER_SYSTEM_CONFIG) ? MsLangId::getConfiguredSystemLanguage() : eLang);
static constexpr OUString aDefaultID = u"default"_ustr;
// Update the "Default ..." currency.
m_xCurrencyLB->remove_id(aDefaultID);
OUString aDefaultCurr = m_sSystemDefaultString + " - " + rCurr.GetBankSymbol();
m_xCurrencyLB->insert(0, aDefaultCurr, &aDefaultID, nullptr, nullptr);
assert(m_xCurrencyLB->find_id(aDefaultID) != -1);
m_xCurrencyLB->set_active_text(aDefaultCurr);
// obtain corresponding locale data
LocaleDataWrapper aLocaleWrapper(( LanguageTag(eLang) ));
// update the decimal separator key of the related CheckBox
OUString sTempLabel(m_sDecimalSeparatorLabel);
sTempLabel = sTempLabel.replaceFirst("%1", aLocaleWrapper.getNumDecimalSep() );
m_xDecimalSeparatorCB->set_label(sTempLabel);
// update the date acceptance patterns
OUString aDatePatternsString = lcl_getDatePatternsConfigString( aLocaleWrapper);
m_bDatePatternsValid = true;
m_xDatePatternsED->set_text( aDatePatternsString);
m_xDatePatternsED->set_message_type(weld::EntryMessageType::Normal);
}
IMPL_LINK( OfaLanguagesTabPage, DatePatternsHdl, weld::Entry&, rEd, void )
{
OUString aPatterns(rEd.get_text());
bool bModified = false;
const bool bValid = validateDatePatterns( bModified, aPatterns);
if (bModified)
{
// gtk3 keeps the cursor position on equal length set_text() but at
// least the 'gen' backend does not and resets to 0.
const int nCursorPos = rEd.get_position();
rEd.set_text(aPatterns);
rEd.set_position(nCursorPos);
}
if (bValid)
rEd.set_message_type(weld::EntryMessageType::Normal);
else
rEd.set_message_type(weld::EntryMessageType::Error);
m_bDatePatternsValid = bValid;
}
bool OfaLanguagesTabPage::validateDatePatterns( bool& rbModified, OUString& rPatterns )
{
bool bValid = true;
if (!rPatterns.isEmpty())
{
OUStringBuffer aBuf( rPatterns);
sal_Int32 nChar = 0;
for (sal_Int32 nIndex=0; nIndex >= 0 && bValid; ++nChar)
{
const OUString aPat( rPatterns.getToken( 0, ';', nIndex));
if (aPat.isEmpty() && nIndex < 0)
{
// Indicating failure when about to append a pattern is too
// confusing. Empty patterns are ignored anyway when sequencing
// to SvtSysLocale.
continue; // for
}
else if (aPat.getLength() < 2)
bValid = false;
else
{
bool bY, bM, bD;
bY = bM = bD = false;
bool bSep = true;
if (aPat.getLength() == 3)
{
// Disallow a pattern that would match a numeric input with
// decimal separator, like M.D
const LanguageType eLang = m_xLocaleSettingLB->get_active_id();
const LocaleDataWrapper aLocaleWrapper(( LanguageTag(eLang)));
if ( aPat[1] == aLocaleWrapper.getNumDecimalSep().toChar()
|| aPat[1] == aLocaleWrapper.getNumDecimalSepAlt().toChar())
{
bValid = false;
}
}
for (sal_Int32 i = 0; i < aPat.getLength() && bValid; /*nop*/)
{
const sal_Int32 j = i;
const sal_uInt32 c = aPat.iterateCodePoints( &i);
// Only one Y,M,D per pattern, separated by any character(s).
switch (c)
{
case 'y':
case 'Y':
if (bY || !bSep)
bValid = false;
else if (c == 'y')
{
aBuf[nChar] = 'Y';
rbModified = true;
}
bY = true;
bSep = false;
break;
case 'm':
case 'M':
if (bM || !bSep)
bValid = false;
else if (c == 'm')
{
aBuf[nChar] = 'M';
rbModified = true;
}
bM = true;
bSep = false;
break;
case 'd':
case 'D':
if (bD || !bSep)
bValid = false;
else if (c == 'd')
{
aBuf[nChar] = 'D';
rbModified = true;
}
bD = true;
bSep = false;
break;
default:
// A pattern must not start with a separator (but
// may end with).
if (!(bY || bM || bD))
bValid = false;
bSep = true;
}
nChar += i-j;
}
// At least one of Y,M,D
bValid &= (bY || bM || bD);
}
}
if (rbModified)
rPatterns = aBuf.makeStringAndClear();
}
return bValid;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V547 Expression 'bHasAccel' is always false.
↑ V1029 Numeric Truncation Error. Return value of the 'size' function is written to the 16-bit variable.