/* -*- 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 <memory>
#include <string_view>
#include <config_features.h>
#include <config_feature_opencl.h>
#include <config_feature_desktop.h>
#include <config_gpgme.h>
#include <officecfg/Office/Common.hxx>
#include <officecfg/Office/Writer.hxx>
#include <svx/dialogs.hrc>
#include <svx/svxids.hrc>
#include <treeopt.hrc>
#include <helpids.h>
#include "appearance.hxx"
#include "cfgchart.hxx"
#include "connpoolconfig.hxx"
#include "connpooloptions.hxx"
#include <cuioptgenrl.hxx>
#include <dbregister.hxx>
#include "dbregisterednamesconfig.hxx"
#include <dialmgr.hxx>
#include "fontsubs.hxx"
#include "optaccessibility.hxx"
#include <optasian.hxx>
#include "optchart.hxx"
#include "optctl.hxx"
#include "optfltr.hxx"
#include "optgdlg.hxx"
#include "opthtml.hxx"
#include "optinet2.hxx"
#include "optjava.hxx"
#include "optjsearch.hxx"
#include <optlingu.hxx>
#if HAVE_FEATURE_OPENCL
#include "optopencl.hxx"
#endif
#include <optpath.hxx>
#include "optsave.hxx"
#include "optupdt.hxx"
#include <treeopt.hxx>
#include "optbasic.hxx"
#include "optlanguagetool.hxx"
#include "optdeepl.hxx"
// include search util
#include <com/sun/star/util/SearchFlags.hpp>
#include <com/sun/star/util/SearchAlgorithms2.hpp>
#include <unotools/textsearch.hxx>
#include <com/sun/star/awt/XContainerWindowEventHandler.hpp>
#include <com/sun/star/awt/ContainerWindowProvider.hpp>
#include <com/sun/star/awt/XControl.hpp>
#include <com/sun/star/awt/PosSize.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/ModuleManager.hpp>
#include <com/sun/star/frame/UnknownModuleException.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/linguistic2/LinguProperties.hpp>
#include <comphelper/getexpandeduri.hxx>
#include <comphelper/processfactory.hxx>
#include <editeng/langitem.hxx>
#include <editeng/optitems.hxx>
#include <editeng/unolingu.hxx>
#include <linguistic/misc.hxx>
#include <o3tl/deleter.hxx>
#include <officecfg/Office/OptionsDialog.hxx>
#include <sfx2/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/module.hxx>
#include <sfx2/printopt.hxx>
#include <sfx2/shell.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/viewfrm.hxx>
#include <svl/flagitem.hxx>
#include <svl/intitem.hxx>
#include <svl/cjkoptions.hxx>
#include <svl/ctloptions.hxx>
#include <svx/databaseregistrationui.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <tools/urlobj.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <unotools/configmgr.hxx>
#include <unotools/moduleoptions.hxx>
#include <unotools/optionsdlg.hxx>
#include <unotools/viewoptions.hxx>
#include <utility>
#include <vcl/help.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weldutils.hxx>
#include <vcl/window.hxx>
#include <sal/log.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::linguistic2;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
LastPageSaver* OfaTreeOptionsDialog::pLastPageSaver = nullptr;
// some stuff for easier changes for SvtViewOptions
constexpr OUString VIEWOPT_DATANAME = u
"page data" _ustr;
static void SetViewOptUserItem( SvtViewOptions& rOpt,
const OUString& rData )
{
rOpt.SetUserItem( VIEWOPT_DATANAME, Any( rData ) );
}
static OUString GetViewOptUserItem(
const SvtViewOptions& rOpt )
{
Any aAny( rOpt.GetUserItem( VIEWOPT_DATANAME ) );
OUString aUserData;
aAny >>= aUserData;
return aUserData;
}
namespace {
struct ModuleToGroupNameMap_Impl
{
std::u16string_view m_pModule;
OUString m_sGroupName;
sal_uInt16 m_nNodeId;
};
}
static ModuleToGroupNameMap_Impl ModuleMap[] =
{
{ u
"ProductName" , OUString(), SID_GENERAL_OPTIONS },
{ u
"LanguageSettings" , OUString(), SID_LANGUAGE_OPTIONS },
{ u
"Internet" , OUString(), SID_INET_DLG },
{ u
"LoadSave" , OUString(), SID_FILTER_DLG },
{ u
"Writer" , OUString(), SID_SW_EDITOPTIONS },
{ u
"WriterWeb" , OUString(), SID_SW_ONLINEOPTIONS },
{ u
"Math" , OUString(), SID_SM_EDITOPTIONS },
{ u
"Calc" , OUString(), SID_SC_EDITOPTIONS },
{ u
"Impress" , OUString(), SID_SD_EDITOPTIONS },
{ u
"Draw" , OUString(), SID_SD_GRAPHIC_OPTIONS },
{ u
"Charts" , OUString(), SID_SCH_EDITOPTIONS },
{ u
"Base" , OUString(), SID_SB_STARBASEOPTIONS },
};
static void setGroupName( std::u16string_view rModule,
const OUString& rGroupName )
{
for (ModuleToGroupNameMap_Impl& rEntry : ModuleMap)
{
if ( rEntry.m_pModule == rModule )
{
rEntry.m_sGroupName = rGroupName;
break ;
}
}
}
static OUString getGroupName( std::u16string_view rModule,
bool bForced )
{
OUString sGroupName;
for (
const ModuleToGroupNameMap_Impl& rEntry : ModuleMap)
{
if ( rEntry.m_pModule == rModule )
{
sGroupName = rEntry.m_sGroupName;
break ;
}
}
if ( sGroupName.isEmpty() && bForced )
{
if ( rModule == u
"Writer" )
sGroupName = CuiResId(SID_SW_EDITOPTIONS_RES[0].first);
else if ( rModule == u
"WriterWeb" )
sGroupName = CuiResId(SID_SW_ONLINEOPTIONS_RES[0].first);
else if ( rModule == u
"Calc" )
sGroupName = CuiResId(SID_SC_EDITOPTIONS_RES[0].first);
else if ( rModule == u
"Impress" )
sGroupName = CuiResId(SID_SD_EDITOPTIONS_RES[0].first);
else if ( rModule == u
"Draw" )
sGroupName = CuiResId(SID_SD_GRAPHIC_OPTIONS_RES[0].first);
else if ( rModule == u
"Math" )
sGroupName = CuiResId(SID_SM_EDITOPTIONS_RES[0].first);
else if ( rModule == u
"Base" )
sGroupName = CuiResId(SID_SB_STARBASEOPTIONS_RES[0].first);
}
return sGroupName;
}
static void deleteGroupNames()
{
for (ModuleToGroupNameMap_Impl& rEntry : ModuleMap)
rEntry.m_sGroupName.clear();
}
static sal_uInt16 getGroupNodeId( std::u16string_view rModule )
{
sal_uInt16 nNodeId = 0xFFFF;
for (
const ModuleToGroupNameMap_Impl& rEntry : ModuleMap)
{
if ( rEntry.m_pModule == rModule )
{
nNodeId = rEntry.m_nNodeId;
break ;
}
}
return nNodeId;
}
namespace {
bool MailMergeCfgIsEmailSupported()
{
std::optional<
bool > b = officecfg::Office::Writer::MailMergeWizard::EMailSupported::g
et();
return b.has_value() && *b;
}
}
//typedef SfxTabPage* (*FNCreateTabPage)(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rAttrSet);
static std::unique_ptr<SfxTabPage> CreateGeneralTabPage(sal_uInt16 nId, weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
{
CreateTabPage fnCreate = nullptr;
switch (nId)
{
case RID_SFXPAGE_SAVE: fnCreate = &SvxSaveTabPage::Create; break ;
case RID_SFXPAGE_PATH: fnCreate = &SvxPathTabPage::Create; break ;
case RID_SFXPAGE_GENERAL: fnCreate = &SvxGeneralTabPage::Create; break ;
case RID_SFXPAGE_PRINTOPTIONS: fnCreate = &SfxCommonPrintOptionsTabPage::Create; break ;
case OFA_TP_LANGUAGES: fnCreate = &OfaLanguagesTabPage::Create; break ;
case RID_SFXPAGE_LINGU: fnCreate = &SvxLinguTabPage::Create; break ;
case OFA_TP_VIEW: fnCreate = &OfaViewTabPage::Create; break ;
case OFA_TP_MISC: fnCreate = &OfaMiscTabPage::Create; break ;
case RID_SVXPAGE_ASIAN_LAYOUT: fnCreate = &SvxAsianLayoutPage::Create; break ;
case RID_SVX_FONT_SUBSTITUTION: fnCreate = &SvxFontSubstTabPage::Create; break ;
case RID_SVXPAGE_INET_PROXY: fnCreate = &SvxProxyTabPage::Create; break ;
case RID_SVXPAGE_INET_SECURITY: fnCreate = &SvxSecurityTabPage::Create; break ;
case RID_SVXPAGE_INET_MAIL: fnCreate = &SvxEMailTabPage::Create; break ;
#if HAVE_FEATURE_DESKTOP
case RID_SVXPAGE_APPEARANCE: fnCreate = &SvxAppearanceTabPage::Create; break ;
#endif
case RID_OFAPAGE_HTMLOPT: fnCreate = &OfaHtmlTabPage::Create; break ;
case SID_OPTFILTER_MSOFFICE: fnCreate = &OfaMSFilterTabPage::Create; break ;
case RID_OFAPAGE_MSFILTEROPT2: fnCreate = &OfaMSFilterTabPage2::Create; break ;
case RID_SVXPAGE_JSEARCH_OPTIONS: fnCreate = &SvxJSearchOptionsPage::Create ; break ;
case SID_SB_CONNECTIONPOOLING: fnCreate = &::offapp::ConnectionPoolOptionsPage::Create; break ;
case SID_SB_DBREGISTEROPTIONS: fnCreate = &svx::DbRegistrationOptionsPage::Create; break ;
case RID_SVXPAGE_ACCESSIBILITYCONFIG: fnCreate = &SvxAccessibilityOptionsTabPage::Create; break ;
case RID_SVXPAGE_OPTIONS_CTL: fnCreate = &SvxCTLOptionsPage::Create ; break ;
case RID_SVXPAGE_LANGTOOL_OPTIONS: fnCreate = &OptLanguageToolTabPage::Create ; break ;
case RID_SVXPAGE_DEEPL_OPTIONS: fnCreate = &OptDeeplTabPage::Create ; break ;
case RID_SVXPAGE_OPTIONS_JAVA: fnCreate = &SvxJavaOptionsPage::Create ; break ;
#if HAVE_FEATURE_OPENCL
case RID_SVXPAGE_OPENCL: fnCreate = &SvxOpenCLTabPage::Create ; break ;
#endif
case RID_SVXPAGE_ONLINEUPDATE: fnCreate = &SvxOnlineUpdateTabPage::Create; break ;
case RID_OPTPAGE_CHART_DEFCOLORS: fnCreate = &SvxDefaultColorOptPage::Create; break ;
#if HAVE_FEATURE_SCRIPTING
case RID_SVXPAGE_BASICIDE_OPTIONS: fnCreate = &SvxBasicIDEOptionsPage::Create; break ;
#endif
}
return fnCreate ? (*fnCreate)( pPage, pController, &rSet ) : nullptr;
}
namespace {
struct OptionsMapping_Impl
{
OUString m_aGroupName;
OUString m_aPageName;
sal_uInt16 m_nPageId;
};
}
constexpr OptionsMapping_Impl OptionsMap_Impl[]
{
// GROUP PAGE PAGE-ID
{ u"ProductName" _ustr, u"" _ustr, SID_GENERAL_OPTIONS },
{ u"ProductName" _ustr, u"UserData" _ustr, RID_SFXPAGE_GENERAL },
{ u"ProductName" _ustr, u"General" _ustr, OFA_TP_MISC },
{ u"ProductName" _ustr, u"View" _ustr, OFA_TP_VIEW },
{ u"ProductName" _ustr, u"Print" _ustr, RID_SFXPAGE_PRINTOPTIONS },
{ u"ProductName" _ustr, u"Paths" _ustr, RID_SFXPAGE_PATH },
{ u"ProductName" _ustr, u"Fonts" _ustr, RID_SVX_FONT_SUBSTITUTION },
{ u"ProductName" _ustr, u"Security" _ustr, RID_SVXPAGE_INET_SECURITY },
{ u"ProductName" _ustr, u"Appearance" _ustr, RID_SVXPAGE_APPEARANCE },
{ u"ProductName" _ustr, u"Accessibility" _ustr, RID_SVXPAGE_ACCESSIBILITYCONFIG },
{ u"ProductName" _ustr, u"Java" _ustr, RID_SVXPAGE_OPTIONS_JAVA },
{ u"ProductName" _ustr, u"BasicIDEOptions" _ustr, RID_SVXPAGE_BASICIDE_OPTIONS },
{ u"ProductName" _ustr, u"OnlineUpdate" _ustr, RID_SVXPAGE_ONLINEUPDATE },
{ u"LanguageSettings" _ustr, u"" _ustr, SID_LANGUAGE_OPTIONS },
{ u"LanguageSettings" _ustr, u"Languages" _ustr, OFA_TP_LANGUAGES },
{ u"LanguageSettings" _ustr, u"WritingAids" _ustr, RID_SFXPAGE_LINGU },
{ u"LanguageSettings" _ustr, u"SearchingInJapanese" _ustr, RID_SVXPAGE_JSEARCH_OPTIONS },
{ u"LanguageSettings" _ustr, u"AsianLayout" _ustr, RID_SVXPAGE_ASIAN_LAYOUT },
{ u"LanguageSettings" _ustr, u"ComplexTextLayout" _ustr, RID_SVXPAGE_OPTIONS_CTL },
{ u"Internet" _ustr, u"" _ustr, SID_INET_DLG },
{ u"Internet" _ustr, u"Proxy" _ustr, RID_SVXPAGE_INET_PROXY },
{ u"Internet" _ustr, u"Email" _ustr, RID_SVXPAGE_INET_MAIL },
{ u"LoadSave" _ustr, u"" _ustr, SID_FILTER_DLG },
{ u"LoadSave" _ustr, u"General" _ustr, RID_SFXPAGE_SAVE },
{ u"LoadSave" _ustr, u"VBAProperties" _ustr, SID_OPTFILTER_MSOFFICE },
{ u"LoadSave" _ustr, u"MicrosoftOffice" _ustr, RID_OFAPAGE_MSFILTEROPT2 },
{ u"LoadSave" _ustr, u"HTMLCompatibility" _ustr, RID_OFAPAGE_HTMLOPT },
{ u"Writer" _ustr, u"" _ustr, SID_SW_EDITOPTIONS },
{ u"Writer" _ustr, u"General" _ustr, RID_SW_TP_OPTLOAD_PAGE },
{ u"Writer" _ustr, u"View" _ustr, RID_SW_TP_CONTENT_OPT },
{ u"Writer" _ustr, u"FormattingAids" _ustr, RID_SW_TP_OPTSHDWCRSR },
{ u"Writer" _ustr, u"Grid" _ustr, RID_SVXPAGE_GRID },
{ u"Writer" _ustr, u"BasicFontsWestern" _ustr, RID_SW_TP_STD_FONT },
{ u"Writer" _ustr, u"BasicFontsAsian" _ustr, RID_SW_TP_STD_FONT_CJK },
{ u"Writer" _ustr, u"BasicFontsCTL" _ustr, RID_SW_TP_STD_FONT_CTL },
{ u"Writer" _ustr, u"Print" _ustr, RID_SW_TP_OPTPRINT_PAGE },
{ u"Writer" _ustr, u"Table" _ustr, RID_SW_TP_OPTTABLE_PAGE },
{ u"Writer" _ustr, u"Changes" _ustr, RID_SW_TP_REDLINE_OPT },
{ u"Writer" _ustr, u"Comparison" _ustr, RID_SW_TP_COMPARISON_OPT },
{ u"Writer" _ustr, u"Compatibility" _ustr, RID_SW_TP_OPTCOMPATIBILITY_PAGE },
{ u"Writer" _ustr, u"AutoCaption" _ustr, RID_SW_TP_OPTCAPTION_PAGE },
{ u"Writer" _ustr, u"MailMerge" _ustr, RID_SW_TP_MAILCONFIG },
{ u"WriterWeb" _ustr, u"" _ustr, SID_SW_ONLINEOPTIONS },
{ u"WriterWeb" _ustr, u"View" _ustr, RID_SW_TP_HTML_CONTENT_OPT },
{ u"WriterWeb" _ustr, u"FormattingAids" _ustr, RID_SW_TP_HTML_OPTSHDWCRSR },
{ u"WriterWeb" _ustr, u"Grid" _ustr, RID_SW_TP_HTML_OPTGRID_PAGE },
{ u"WriterWeb" _ustr, u"Print" _ustr, RID_SW_TP_HTML_OPTPRINT_PAGE },
{ u"WriterWeb" _ustr, u"Table" _ustr, RID_SW_TP_HTML_OPTTABLE_PAGE },
{ u"Math" _ustr, u"" _ustr, SID_SM_EDITOPTIONS },
{ u"Math" _ustr, u"Settings" _ustr, SID_SM_TP_PRINTOPTIONS },
{ u"Calc" _ustr, u"" _ustr, SID_SC_EDITOPTIONS },
{ u"Calc" _ustr, u"General" _ustr, SID_SC_TP_LAYOUT },
{ u"Calc" _ustr, u"View" _ustr, SID_SC_TP_CONTENT },
{ u"Calc" _ustr, u"Calculate" _ustr, SID_SC_TP_CALC },
{ u"Calc" _ustr, u"Formula" _ustr, SID_SC_TP_FORMULA },
{ u"Calc" _ustr, u"SortLists" _ustr, SID_SC_TP_USERLISTS },
{ u"Calc" _ustr, u"Changes" _ustr, SID_SC_TP_CHANGES },
{ u"Calc" _ustr, u"Compatibility" _ustr, SID_SC_TP_COMPATIBILITY },
{ u"Calc" _ustr, u"Grid" _ustr, SID_SC_TP_GRID },
{ u"Calc" _ustr, u"Print" _ustr, RID_SC_TP_PRINT },
{ u"Impress" _ustr, u"" _ustr, SID_SD_EDITOPTIONS },
{ u"Impress" _ustr, u"General" _ustr, SID_SI_TP_MISC },
{ u"Impress" _ustr, u"View" _ustr, SID_SI_TP_CONTENTS },
{ u"Impress" _ustr, u"Grid" _ustr, SID_SI_TP_SNAP },
{ u"Impress" _ustr, u"Print" _ustr, SID_SI_TP_PRINT },
{ u"Draw" _ustr, u"" _ustr, SID_SD_GRAPHIC_OPTIONS },
{ u"Draw" _ustr, u"General" _ustr, SID_SD_TP_MISC },
{ u"Draw" _ustr, u"View" _ustr, SID_SD_TP_CONTENTS },
{ u"Draw" _ustr, u"Grid" _ustr, SID_SD_TP_SNAP },
{ u"Draw" _ustr, u"Print" _ustr, SID_SD_TP_PRINT },
{ u"Charts" _ustr, u"" _ustr, SID_SCH_EDITOPTIONS },
{ u"Charts" _ustr, u"DefaultColors" _ustr, RID_OPTPAGE_CHART_DEFCOLORS },
{ u"Base" _ustr, u"" _ustr, SID_SB_STARBASEOPTIONS },
{ u"Base" _ustr, u"Connections" _ustr, SID_SB_CONNECTIONPOOLING },
{ u"Base" _ustr, u"Databases" _ustr, SID_SB_DBREGISTEROPTIONS },
};
static bool lcl_getStringFromID( sal_uInt16 _nPageId, OUString& _rGroupName, OUString& _rPageName )
{
bool bRet = false ;
for (const auto & rMapping : OptionsMap_Impl )
{
if ( _nPageId == rMapping.m_nPageId )
{
bRet = true ;
_rGroupName = rMapping.m_aGroupName;
if ( !rMapping.m_aPageName.isEmpty() )
_rPageName = rMapping.m_aPageName;
break ;
}
}
return bRet;
}
static bool lcl_isOptionHidden( sal_uInt16 _nPageId, const SvtOptionsDialogOptions& _rOptOptions )
{
bool bIsHidden = false ;
OUString sGroupName, sPageName;
if ( lcl_getStringFromID( _nPageId, sGroupName, sPageName ) )
{
if ( sPageName.isEmpty() )
bIsHidden = _rOptOptions.IsGroupHidden( sGroupName );
else
bIsHidden = _rOptOptions.IsPageHidden( sPageName, sGroupName );
}
return bIsHidden;
}
struct OptionsPageInfo
{
std::unique_ptr<SfxTabPage> m_xPage;
sal_uInt16 m_nPageId;
OUString m_sPageURL;
OUString m_sEventHdl;
std::unique_ptr<ExtensionsTabPage> m_xExtPage;
explicit OptionsPageInfo( sal_uInt16 nId ) : m_nPageId( nId ) {}
};
struct OptionsGroupInfo
{
std::optional<SfxItemSet> m_pInItemSet;
std::unique_ptr<SfxItemSet> m_pOutItemSet;
SfxShell* m_pShell; // used to create the page
SfxModule* m_pModule; // used to create the ItemSet
sal_uInt16 m_nDialogId; // Id of the former dialog
OptionsGroupInfo( SfxShell* pSh, SfxModule* pMod, sal_uInt16 nId ) :
m_pShell( pSh ),
m_pModule( pMod ), m_nDialogId( nId ) {}
};
struct OptionsPageIdInfo
{
OUString m_sParentName;
OUString m_sPageName;
sal_uInt16 m_nParentId;
sal_uInt16 m_nPageId;
OptionsPageIdInfo(OUString sParentName, OUString sPageName, sal_uInt16 nParentId,
sal_uInt16 nPageId)
: m_sParentName(std::move(sParentName))
, m_sPageName(std::move(sPageName))
, m_nParentId(nParentId)
, m_nPageId(nPageId)
{
}
};
// Basic ctor with common initialization
OfaTreeOptionsDialog::OfaTreeOptionsDialog(weld::Window* pParent, bool fromExtensionManager)
: SfxOkDialogController(pParent, u"cui/ui/optionsdialog.ui" _ustr, u"OptionsDialog" _ustr)
, xOkPB(m_xBuilder->weld_button(u"ok" _ustr))
, xApplyPB(m_xBuilder->weld_button(u"apply" _ustr))
, xBackPB(m_xBuilder->weld_button(u"revert" _ustr))
, xTreeLB(m_xBuilder->weld_tree_view(u"pages" _ustr))
, xTabBox(m_xBuilder->weld_container(u"box" _ustr))
, m_xSearchEdit(m_xBuilder->weld_entry(u"searchEntry" _ustr))
, m_pParent(pParent)
, m_aUpdateDataTimer("OfaTreeOptionsDialog UpdateDataTimer" )
, bIsFirtsInitialize(true )
, sTitle(m_xDialog->get_title())
, bForgetSelection(false )
, bIsFromExtensionManager(fromExtensionManager)
, bIsForSetDocumentLanguage(false )
, bNeedsRestart(false )
, eRestartReason(svtools::RESTART_REASON_NONE)
{
Size aSize(xTreeLB->get_approximate_digit_width() * 100, xTreeLB->get_height_rows(30));
AbsoluteScreenPixelRectangle aScreen
= Application::GetScreenPosSizePixel(Application::GetDisplayBuiltInScreen());
// clamp height to max of 80% of screen height to make buttons accessible on smaller screens
aSize.setHeight(std::min(static_cast <tools::Long >(aScreen.GetHeight() * 0.8), aSize.Height()));
xTabBox->set_size_request(aSize.Width(), aSize.Height());
xTreeLB->set_size_request(xTreeLB->get_approximate_digit_width() * 35, aSize.Height());
// Init tree and handler
xTreeLB->set_help_id(HID_OFADLG_TREELISTBOX);
xTreeLB->connect_selection_changed(LINK(this , OfaTreeOptionsDialog, ShowPageHdl_Impl));
xBackPB->connect_clicked(LINK(this , OfaTreeOptionsDialog, BackHdl_Impl));
xApplyPB->connect_clicked(LINK(this , OfaTreeOptionsDialog, ApplyHdl_Impl));
xOkPB->connect_clicked(LINK(this , OfaTreeOptionsDialog, ApplyHdl_Impl));
m_xSearchEdit->connect_changed(LINK(this , OfaTreeOptionsDialog, SearchUpdateHdl));
m_xSearchEdit->connect_focus_out(LINK(this , OfaTreeOptionsDialog, FocusOut_Impl));
m_xDialog->connect_help(LINK(this , OfaTreeOptionsDialog, HelpHdl_Impl));
m_aUpdateDataTimer.SetInvokeHandler(LINK(this , OfaTreeOptionsDialog, ImplUpdateDataHdl));
m_aUpdateDataTimer.SetTimeout(EDIT_UPDATEDATA_TIMEOUT);
// Initialize search util
m_options.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE;
m_options.transliterateFlags |= TransliterationFlags::IGNORE_CASE;
m_options.searchFlag
|= (util::SearchFlags::REG_NOT_BEGINOFLINE | util::SearchFlags::REG_NOT_ENDOFLINE);
xTreeLB->set_accessible_name(sTitle);
}
// Ctor() with Frame -----------------------------------------------------
OfaTreeOptionsDialog::OfaTreeOptionsDialog(weld::Window* pParent, const Reference< XFrame >& _xFrame, bool bActivateLastSelection)
: OfaTreeOptionsDialog(pParent, false )
{
Initialize( _xFrame );
LoadExtensionOptions( u"" );
if (bActivateLastSelection)
ActivateLastSelection();
}
// Ctor() with ExtensionId -----------------------------------------------
OfaTreeOptionsDialog::OfaTreeOptionsDialog(weld::Window* pParent, std::u16string_view rExtensionId)
: OfaTreeOptionsDialog(pParent, !rExtensionId.empty())
{
LoadExtensionOptions( rExtensionId );
ActivateLastSelection();
}
void OfaTreeOptionsDialog::ImplDestroy()
{
xCurrentPageEntry.reset();
std::unique_ptr<weld::TreeIter> xEntry = xTreeLB->make_iterator();
bool bEntry = xTreeLB->get_iter_first(*xEntry);
// first children
while (bEntry)
{
// if Child (has parent), then OptionsPageInfo
if (xTreeLB->get_iter_depth(*xEntry))
{
OptionsPageInfo *pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xEntry));
if (pPageInfo->m_xPage)
{
pPageInfo->m_xPage->FillUserData();
OUString aPageData(pPageInfo->m_xPage->GetUserData());
if ( !aPageData.isEmpty() )
{
SvtViewOptions aTabPageOpt( EViewType::TabPage, OUString::number( pPageInfo->m_nPageId) );
SetViewOptUserItem( aTabPageOpt, aPageData );
}
pPageInfo->m_xPage.reset();
}
if (pPageInfo->m_nPageId == RID_SFXPAGE_LINGU)
{
// write personal dictionaries
Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
if (xDicList.is())
{
linguistic::SaveDictionaries( xDicList );
}
}
pPageInfo->m_xExtPage.reset();
delete pPageInfo;
}
bEntry = xTreeLB->iter_next(*xEntry);
}
// and parents
bEntry = xTreeLB->get_iter_first(*xEntry);
while (bEntry)
{
if (!xTreeLB->get_iter_depth(*xEntry))
{
OptionsGroupInfo* pGroupInfo = weld::fromId<OptionsGroupInfo*>(xTreeLB->get_id(*xEntry));
delete pGroupInfo;
}
bEntry = xTreeLB->iter_next(*xEntry);
}
deleteGroupNames();
}
OfaTreeOptionsDialog::~OfaTreeOptionsDialog()
{
suppress_fun_call_w_exception(ImplDestroy());
}
OptionsPageInfo* OfaTreeOptionsDialog::AddTabPage(
sal_uInt16 nId, const OUString& rPageName, sal_uInt16 nGroup )
{
std::unique_ptr<weld::TreeIter> xParent = xTreeLB->make_iterator();
if (!xTreeLB->get_iter_first(*xParent))
return nullptr;
xTreeLB->iter_nth_sibling(*xParent, nGroup);
OptionsPageInfo* pPageInfo = new OptionsPageInfo( nId );
OUString sId(weld::toId(pPageInfo));
xTreeLB->insert(xParent.get(), -1, &rPageName, &sId, nullptr, nullptr, false , nullptr);
return pPageInfo;
}
// the ItemSet* is passed on to the dialog's ownership
sal_uInt16 OfaTreeOptionsDialog::AddGroup(const OUString& rGroupName,
SfxShell* pCreateShell,
SfxModule* pCreateModule,
sal_uInt16 nDialogId )
{
OptionsGroupInfo* pInfo =
new OptionsGroupInfo( pCreateShell, pCreateModule, nDialogId );
OUString sId(weld::toId(pInfo));
xTreeLB->append(sId, rGroupName);
sal_uInt16 nRet = 0;
std::unique_ptr<weld::TreeIter> xEntry = xTreeLB->make_iterator();
bool bEntry = xTreeLB->get_iter_first(*xEntry);
while (bEntry)
{
if (!xTreeLB->get_iter_depth(*xEntry))
nRet++;
bEntry = xTreeLB->iter_next(*xEntry);
}
return nRet - 1;
}
IMPL_LINK_NOARG(OfaTreeOptionsDialog, ShowPageHdl_Impl, weld::TreeView&, void )
{
SelectHdl_Impl();
}
void OfaTreeOptionsDialog::ResetCurrentPageFromConfig()
{
if (!(xCurrentPageEntry && xTreeLB->get_iter_depth(*xCurrentPageEntry)))
return ;
OptionsPageInfo* pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xCurrentPageEntry));
if (pPageInfo->m_xPage)
{
std::unique_ptr<weld::TreeIter> xParent = xTreeLB->make_iterator(xCurrentPageEntry.get());
xTreeLB->iter_parent(*xParent);
OptionsGroupInfo* pGroupInfo =
weld::fromId<OptionsGroupInfo*>(xTreeLB->get_id(*xParent));
pPageInfo->m_xPage->Reset( &*pGroupInfo->m_pInItemSet );
}
else if ( pPageInfo->m_xExtPage )
pPageInfo->m_xExtPage->ResetPage();
}
IMPL_LINK_NOARG(OfaTreeOptionsDialog, BackHdl_Impl, weld::Button&, void )
{
ResetCurrentPageFromConfig();
}
void OfaTreeOptionsDialog::ApplyOptions()
{
std::unique_ptr<weld::TreeIter> xEntry = xTreeLB->make_iterator();
bool bEntry = xTreeLB->get_iter_first(*xEntry);
while (bEntry)
{
if (xTreeLB->get_iter_depth(*xEntry))
{
OptionsPageInfo* pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xEntry));
if ( pPageInfo->m_xPage && !pPageInfo->m_xPage->HasExchangeSupport() )
{
std::unique_ptr<weld::TreeIter> xParent = xTreeLB->make_iterator(xEntry.get());
xTreeLB->iter_parent(*xParent);
OptionsGroupInfo* pGroupInfo =
weld::fromId<OptionsGroupInfo*>(xTreeLB->get_id(*xParent));
pPageInfo->m_xPage->FillItemSet(pGroupInfo->m_pOutItemSet.get());
}
if ( pPageInfo->m_xExtPage )
{
pPageInfo->m_xExtPage->DeactivatePage();
pPageInfo->m_xExtPage->SavePage();
}
if ( pPageInfo->m_xPage && RID_OPTPAGE_CHART_DEFCOLORS == pPageInfo->m_nPageId )
{
SvxDefaultColorOptPage* pPage = static_cast <SvxDefaultColorOptPage *>(pPageInfo->m_xPage.get());
pPage->SaveChartOptions();
}
}
bEntry = xTreeLB->iter_next(*xEntry);
}
}
IMPL_LINK_NOARG(OfaTreeOptionsDialog, HelpHdl_Impl, weld::Widget&, bool )
{
Help* pHelp = Application::GetHelp();
if (pHelp && xCurrentPageEntry && xTreeLB->get_iter_depth(*xCurrentPageEntry))
{
OptionsPageInfo* pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xCurrentPageEntry));
if (pPageInfo->m_xPage)
{
OUString sHelpId(pPageInfo->m_xPage->GetHelpId());
pHelp->Start(sHelpId, m_xDialog.get());
return false ;
}
}
return true ;
}
IMPL_LINK(OfaTreeOptionsDialog, ApplyHdl_Impl, weld::Button&, rButton, void )
{
bool bOkPressed = &rButton == xOkPB.get();
OptionsGroupInfo* pGroupInfo = nullptr;
if (xCurrentPageEntry && xTreeLB->get_iter_depth(*xCurrentPageEntry))
{
OptionsPageInfo* pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xCurrentPageEntry));
if ( pPageInfo->m_xPage )
{
std::unique_ptr<weld::TreeIter> xParent = xTreeLB->make_iterator(xCurrentPageEntry.get());
xTreeLB->iter_parent(*xParent);
pGroupInfo = weld::fromId<OptionsGroupInfo*>(xTreeLB->get_id(*xParent));
if ( RID_SVXPAGE_COLOR != pPageInfo->m_nPageId
&& pPageInfo->m_xPage->HasExchangeSupport() )
{
DeactivateRC nLeave = pPageInfo->m_xPage->DeactivatePage(pGroupInfo->m_pOutItemSet.get());
if ( nLeave == DeactivateRC::KeepPage )
{
// the page mustn't be left, so return early
assert(xTreeLB->is_selected(*xCurrentPageEntry)); // presumably this must be true here
if (bOkPressed)
return ;
}
}
}
}
ApplyOptions();
ApplyItemSets();
utl::ConfigManager::storeConfigItems();
if (bOkPressed)
m_xDialog->response(RET_OK);
else
{
// tdf#137930 rebuild the in and out itemsets to reflect the current
// post-apply state
if (pGroupInfo && pGroupInfo->m_pInItemSet)
{
// tdf#138596 seeing as the SfxTabPages keep pointers to the m_pInItemSet
// we update the contents of the existing SfxItemSets to match
// the current settings, rather than create new ones
auto xInItemSet = pGroupInfo->m_pShell
? pGroupInfo->m_pShell->CreateItemSet( pGroupInfo->m_nDialogId )
: CreateItemSet( pGroupInfo->m_nDialogId );
pGroupInfo->m_pInItemSet->Set(*xInItemSet, false );
pGroupInfo->m_pOutItemSet->ClearItem();
}
// for the Apply case, now that the settings are saved to config,
// reload the current page so it knows what the config now states
ResetCurrentPageFromConfig();
// reselect it to undo possible DeactivatePage above
xCurrentPageEntry.reset();
SelectHdl_Impl();
}
if (!bNeedsRestart)
return ;
SolarMutexGuard aGuard;
weld::Window* pParent;
if (!bOkPressed)
pParent = m_xDialog.get();
else
{
m_xDialog->hide();
pParent = m_pParent;
}
bool bRestart = ::svtools::executeRestartDialog(comphelper::getProcessComponentContext(),
pParent, eRestartReason);
if (bRestart && !bOkPressed)
m_xDialog->response(RET_OK);
}
IMPL_LINK_NOARG(OfaTreeOptionsDialog, FocusOut_Impl, weld::Widget&, void )
{
if (m_aUpdateDataTimer.IsActive())
{
m_aUpdateDataTimer.Stop();
m_aUpdateDataTimer.Invoke();
}
}
IMPL_LINK_NOARG(OfaTreeOptionsDialog, SearchUpdateHdl, weld::Entry&, void )
{
m_aUpdateDataTimer.Start();
}
IMPL_LINK_NOARG(OfaTreeOptionsDialog, ImplUpdateDataHdl, Timer*, void )
{
// initializeAllDialogs() can take a long time, show wait cursor and disable input
m_xSearchEdit->set_editable(false );
m_xSearchEdit->set_busy_cursor(true );
// Pause redraw
xTreeLB->freeze();
if (bIsFirtsInitialize)
{
m_xSearchEdit->freeze();
xTreeLB->hide();
initializeAllDialogs();
m_xSearchEdit->thaw();
xTreeLB->show();
bIsFirtsInitialize = false ;
}
// Apply the search filter
OUString aSearchTerm(m_xSearchEdit->get_text());
int nMatchFound = applySearchFilter(aSearchTerm);
// Resume redraw
xTreeLB->thaw();
// select first child of first node after the search done
if (nMatchFound != -1)
selectFirstEntry();
m_xSearchEdit->set_editable(true );
m_xSearchEdit->set_busy_cursor(false );
}
void OfaTreeOptionsDialog::selectFirstEntry()
{
std::unique_ptr<weld::TreeIter> xTemp = xTreeLB->make_iterator();
bool bTemp = xTreeLB->get_iter_first(*xTemp);
while (bTemp)
{
// select only the first child
if (xTreeLB->get_iter_depth(*xTemp) && xTreeLB->get_id(*xTemp).toInt64())
{
std::unique_ptr<weld::TreeIter> xEntry(xTreeLB->make_iterator(xTemp.get()));
std::unique_ptr<weld::TreeIter> xParent(xTreeLB->make_iterator(xEntry.get()));
xTreeLB->iter_parent(*xParent);
xTreeLB->expand_row(*xParent);
xTreeLB->scroll_to_row(*xParent);
xTreeLB->scroll_to_row(*xEntry);
xTreeLB->set_cursor(*xEntry);
xTreeLB->select(*xEntry);
SelectHdl_Impl();
break ;
}
bTemp = xTreeLB->iter_next(*xTemp);
}
}
void OfaTreeOptionsDialog::initializeAllDialogs()
{
std::unique_ptr<weld::TreeIter> xEntry;
std::unique_ptr<weld::TreeIter> xTemp = xTreeLB->make_iterator();
bool bTemp = xTreeLB->get_iter_first(*xTemp);
while (bTemp)
{
if (xTreeLB->get_iter_depth(*xTemp) && xTreeLB->get_id(*xTemp).toInt64())
{
if (!(xEntry = xTreeLB->make_iterator(xTemp.get())))
{
xEntry = xTreeLB->make_iterator();
if (!xTreeLB->get_iter_first(*xEntry) || !xTreeLB->iter_next(*xEntry))
xEntry.reset();
}
if (!xEntry)
return ;
OptionsPageInfo* pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xEntry));
if (TreeOptHelper::getStringsFromDialog(pPageInfo->m_nPageId).isEmpty())
{
SolarMutexGuard aGuard;
initializeCurrentDialog(pPageInfo, xEntry);
}
}
bTemp = xTreeLB->iter_next(*xTemp);
}
}
void OfaTreeOptionsDialog::clearOptionsDialog()
{
// clear and reset
std::unique_ptr<weld::TreeIter> xEntry = xTreeLB->make_iterator();
bool bEntry = xTreeLB->get_iter_first(*xEntry);
while (bEntry)
{
if (xTreeLB->get_iter_depth(*xEntry))
{
OptionsPageInfo* pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xEntry));
if (pPageInfo->m_xPage)
pPageInfo->m_xPage.reset();
}
bEntry = xTreeLB->iter_next(*xEntry);
}
xCurrentPageEntry.reset();
}
// store Options tree with their page names
void OfaTreeOptionsDialog::storeOptionsTree()
{
m_aTreePageIds.clear();
sal_uInt16 aParentId = 0;
OUString sParentName;
std::unique_ptr<weld::TreeIter> xEntry = xTreeLB->make_iterator();
bool bEntry = xTreeLB->get_iter_first(*xEntry);
while (bEntry)
{
OptionsGroupInfo* pGroupInfo = weld::fromId<OptionsGroupInfo*>(xTreeLB->get_id(*xEntry));
bool bIsParentNode = !xTreeLB->get_iter_depth(*xEntry);
if (bIsParentNode)
{
// Parent node
sParentName = xTreeLB->get_text(*xEntry);
aParentId = pGroupInfo->m_nDialogId;
m_aTreePageIds.push_back(new OptionsPageIdInfo(sParentName, sParentName, aParentId, 0));
}
else
{
// Child node
OUString sChildName = xTreeLB->get_text(*xEntry);
OptionsPageInfo* pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xEntry));
m_aTreePageIds.push_back(
new OptionsPageIdInfo(sParentName, sChildName, aParentId, pPageInfo->m_nPageId));
}
bEntry = xTreeLB->iter_next(*xEntry);
}
}
int OfaTreeOptionsDialog::applySearchFilter(const OUString& rSearchTerm)
{
if (rSearchTerm.isEmpty())
{
clearOptionsDialog();
xTreeLB->clear();
Initialize(m_xFrame);
return 0;
}
m_options.searchString = rSearchTerm;
utl::TextSearch textSearch(m_options);
clearOptionsDialog();
if (xTreeLB->n_children() > 0)
xTreeLB->clear();
std::vector<std::pair<sal_uInt16, std::vector<sal_uInt16>>> aFoundIdsVector;
for (std::size_t i = 0; i < m_aTreePageIds.size(); ++i)
{
const OUString sParentName = m_aTreePageIds[i]->m_sParentName;
const OUString sPageName = m_aTreePageIds[i]->m_sPageName;
const sal_uInt16 nParentId = m_aTreePageIds[i]->m_nParentId;
const sal_uInt16 nPageId = m_aTreePageIds[i]->m_nPageId;
const OUString sPageStrings = TreeOptHelper::getStringsFromDialog(nPageId);
const OUString sPageNameAndStrings = sParentName + " " + sPageName + " " + sPageStrings;
sal_Int32 aStartPos = 0;
sal_Int32 aEndPos = sPageNameAndStrings.getLength();
// check if rSearchTerm matches with sPageNameAndStrings
if (textSearch.SearchForward(sPageNameAndStrings, &aStartPos, &aEndPos))
{
bool isFound = false ;
for (auto & aEntryId : aFoundIdsVector)
{
if (aEntryId.first == nParentId)
{
isFound = true ;
aEntryId.second.push_back(nPageId);
}
}
if (!isFound)
aFoundIdsVector.push_back({ nParentId, { nPageId } });
}
}
showDialog(aFoundIdsVector);
// if treeview is empty, return -1
return xTreeLB->n_children() ? 0 : -1;
}
void OfaTreeOptionsDialog::showDialog(VectorOfMatchedIds& pSearchIds)
{
//
// void generalOptions(); // SID_GENERAL_OPTIONS
// void loadAndSaveOptions(); // SID_FILTER_DLG
// void languageOptions(); // SID_LANGUAGE_OPTIONS
// void writerOptions(); // SID_SW_EDITOPTIONS
// void writerWebOptions(); // SID_SW_ONLINEOPTIONS
// void calcOptions(); // SID_SC_EDITOPTIONS
// void impressOptions(); // SID_SD_EDITOPTIONS
// void drawOptions(); // SID_SD_GRAPHIC_OPTIONS
// void mathOptions(); // SID_SM_EDITOPTIONS
// void databaseOptions(); // SID_SB_STARBASEOPTIONS
// void chartOptions(); // SID_SCH_EDITOPTIONS
// void internetOptions(); // SID_INET_DLG
//
for (auto & aEntryId : pSearchIds)
{
switch (aEntryId.first)
{
case SID_GENERAL_OPTIONS:
generalOptions(aEntryId.second);
break ;
case SID_FILTER_DLG:
loadAndSaveOptions(aEntryId.second);
break ;
case SID_LANGUAGE_OPTIONS:
languageOptions(aEntryId.second);
break ;
case SID_SW_EDITOPTIONS:
writerOptions(aEntryId.second);
break ;
case SID_SW_ONLINEOPTIONS:
writerWebOptions(aEntryId.second);
break ;
case SID_SC_EDITOPTIONS:
calcOptions(aEntryId.second);
break ;
case SID_SD_EDITOPTIONS:
impressOptions(aEntryId.second);
break ;
case SID_SD_GRAPHIC_OPTIONS:
drawOptions(aEntryId.second);
break ;
case SID_SM_EDITOPTIONS:
mathOptions(aEntryId.second);
break ;
case SID_SB_STARBASEOPTIONS:
databaseOptions(aEntryId.second);
break ;
case SID_SCH_EDITOPTIONS:
chartOptions(aEntryId.second);
break ;
case SID_INET_DLG:
internetOptions(aEntryId.second);
break ;
default :
break ;
}
}
}
void OfaTreeOptionsDialog::ApplyItemSets()
{
std::unique_ptr<weld::TreeIter> xEntry = xTreeLB->make_iterator();
bool bEntry = xTreeLB->get_iter_first(*xEntry);
while (bEntry)
{
if (!xTreeLB->get_iter_depth(*xEntry))
{
OptionsGroupInfo* pGroupInfo = weld::fromId<OptionsGroupInfo*>(xTreeLB->get_id(*xEntry));
if (pGroupInfo->m_pOutItemSet)
{
if (pGroupInfo->m_pShell)
pGroupInfo->m_pShell->ApplyItemSet( pGroupInfo->m_nDialogId, *pGroupInfo->m_pOutItemSet);
else
ApplyItemSet( pGroupInfo->m_nDialogId, *pGroupInfo->m_pOutItemSet);
}
}
bEntry = xTreeLB->iter_next(*xEntry);
}
}
void OfaTreeOptionsDialog::ActivatePage( sal_uInt16 nResId )
{
bIsForSetDocumentLanguage = false ;
if ( nResId == OFA_TP_LANGUAGES_FOR_SET_DOCUMENT_LANGUAGE )
{
bIsForSetDocumentLanguage = true ;
nResId = OFA_TP_LANGUAGES;
}
DBG_ASSERT( !bIsFromExtensionManager, "OfaTreeOptionsDialog::ActivatePage(): call from extension manager" );
if ( !pLastPageSaver )
pLastPageSaver = new LastPageSaver;
bForgetSelection = true ;
sal_uInt16 nTemp = pLastPageSaver->m_nLastPageId;
pLastPageSaver->m_nLastPageId = nResId;
ActivateLastSelection();
pLastPageSaver->m_nLastPageId = nTemp;
}
void OfaTreeOptionsDialog::ActivatePage( const OUString& rPageURL )
{
DBG_ASSERT( !bIsFromExtensionManager, "OfaTreeOptionsDialog::ActivatePage(): call from extension manager" );
if ( !pLastPageSaver )
pLastPageSaver = new LastPageSaver;
bForgetSelection = true ;
pLastPageSaver->m_nLastPageId = 0;
pLastPageSaver->m_sLastPageURL_Tools = rPageURL;
ActivateLastSelection();
}
void OfaTreeOptionsDialog::ActivateLastSelection()
{
std::unique_ptr<weld::TreeIter> xEntry;
if (pLastPageSaver)
{
OUString sLastURL = bIsFromExtensionManager ? pLastPageSaver->m_sLastPageURL_ExtMgr
: pLastPageSaver->m_sLastPageURL_Tools;
if ( sLastURL.isEmpty() )
{
sLastURL = !bIsFromExtensionManager ? pLastPageSaver->m_sLastPageURL_ExtMgr
: pLastPageSaver->m_sLastPageURL_Tools;
}
bool bMustExpand = ( INetURLObject( sLastURL ).GetProtocol() == INetProtocol::File );
std::unique_ptr<weld::TreeIter> xTemp = xTreeLB->make_iterator();
bool bTemp = xTreeLB->get_iter_first(*xTemp);
while (bTemp)
{
// restore only selection of a leaf
if (xTreeLB->get_iter_depth(*xTemp) && xTreeLB->get_id(*xTemp).toInt64())
{
OptionsPageInfo* pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xTemp));
OUString sPageURL = pPageInfo->m_sPageURL;
if ( bMustExpand )
{
sPageURL = comphelper::getExpandedUri(
comphelper::getProcessComponentContext(), sPageURL);
}
if ( ( !bIsFromExtensionManager
&& pPageInfo->m_nPageId && pPageInfo->m_nPageId == pLastPageSaver->m_nLastPageId )
|| ( !pPageInfo->m_nPageId && sLastURL == sPageURL ) )
{
xEntry = xTreeLB->make_iterator(xTemp.get());
break ;
}
}
bTemp = xTreeLB->iter_next(*xTemp);
}
}
if (!xEntry)
{
xEntry = xTreeLB->make_iterator();
if (!xTreeLB->get_iter_first(*xEntry) || !xTreeLB->iter_next(*xEntry))
xEntry.reset();
}
if (!xEntry)
return ;
std::unique_ptr<weld::TreeIter> xParent(xTreeLB->make_iterator(xEntry.get()));
xTreeLB->iter_parent(*xParent);
xTreeLB->expand_row(*xParent);
xTreeLB->scroll_to_row(*xParent);
xTreeLB->scroll_to_row(*xEntry);
xTreeLB->set_cursor(*xEntry);
xTreeLB->select(*xEntry);
m_xSearchEdit->grab_focus();
SelectHdl_Impl();
}
void OfaTreeOptionsDialog::InitItemSets(OptionsGroupInfo& rGroupInfo)
{
if (!rGroupInfo.m_pInItemSet)
rGroupInfo.m_pInItemSet.emplace( rGroupInfo.m_pShell
? *rGroupInfo.m_pShell->CreateItemSet( rGroupInfo.m_nDialogId )
: *CreateItemSet( rGroupInfo.m_nDialogId ) );
if (!rGroupInfo.m_pOutItemSet)
rGroupInfo.m_pOutItemSet = std::make_unique<SfxItemSet>(
*rGroupInfo.m_pInItemSet->GetPool(),
rGroupInfo.m_pInItemSet->GetRanges());
}
void OfaTreeOptionsDialog::initializeCurrentDialog(OptionsPageInfo*& pPageInfo,
const std::unique_ptr<weld::TreeIter>& xEntry)
{
std::unique_ptr<weld::TreeIter> xParent(xTreeLB->make_iterator(xEntry.get()));
bool bParent = xTreeLB->iter_parent(*xParent);
if (!bParent)
return ;
if (pPageInfo->m_xPage)
{
TreeOptHelper::storeStringsOfDialog(pPageInfo->m_nPageId,
pPageInfo->m_xPage->GetAllStrings());
return ;
}
OptionsGroupInfo* pGroupInfo = weld::fromId<OptionsGroupInfo*>(xTreeLB->get_id(*xParent));
if (!pPageInfo->m_xPage && pPageInfo->m_nPageId > 0)
{
InitItemSets(*pGroupInfo);
pPageInfo->m_xPage = ::CreateGeneralTabPage(pPageInfo->m_nPageId, xTabBox.get(), this ,
*pGroupInfo->m_pInItemSet);
if (!pPageInfo->m_xPage && pGroupInfo->m_pModule)
pPageInfo->m_xPage = pGroupInfo->m_pModule->CreateTabPage(
pPageInfo->m_nPageId, xTabBox.get(), this , *pGroupInfo->m_pInItemSet);
DBG_ASSERT(pPageInfo->m_xPage, "tabpage could not created" );
if (pPageInfo->m_xPage)
{
SvtViewOptions aTabPageOpt(EViewType::TabPage, OUString::number(pPageInfo->m_nPageId));
pPageInfo->m_xPage->SetUserData(GetViewOptUserItem(aTabPageOpt));
pPageInfo->m_xPage->SetFrame(m_xFrame);
pPageInfo->m_xPage->Reset(&*pGroupInfo->m_pInItemSet);
}
TreeOptHelper::storeStringsOfDialog(pPageInfo->m_nPageId,
pPageInfo->m_xPage->GetAllStrings());
pPageInfo->m_xPage->set_visible(false );
}
else if (0 == pPageInfo->m_nPageId && !pPageInfo->m_xExtPage)
{
if (!m_xContainerWinProvider.is())
m_xContainerWinProvider
= awt::ContainerWindowProvider::create(::comphelper::getProcessComponentContext());
pPageInfo->m_xExtPage = std::make_unique<ExtensionsTabPage>(
xTabBox.get(), pPageInfo->m_sPageURL, pPageInfo->m_sEventHdl, m_xContainerWinProvider);
pPageInfo->m_xExtPage->Hide();
}
BuilderPage* pNewPage = pPageInfo->m_xPage.get();
// fdo#58170 use current page's layout child HelpId, unless there isn't a current page
OUString sHelpId(pNewPage ? pNewPage->GetHelpId() : OUString());
if (sHelpId.isEmpty())
sHelpId = HID_OFADLG_TREELISTBOX;
xTreeLB->set_help_id(sHelpId);
}
void OfaTreeOptionsDialog::SelectHdl_Impl()
{
std::unique_ptr<weld::TreeIter> xEntry(xTreeLB->make_iterator());
if (!xTreeLB->get_cursor(xEntry.get()))
return ;
if (xCurrentPageEntry && xCurrentPageEntry->equal(*xEntry))
return ;
std::unique_ptr<weld::TreeIter> xParent(xTreeLB->make_iterator(xEntry.get()));
bool bParent = xTreeLB->iter_parent(*xParent);
// If the user has selected a category, automatically switch to a suitable
// default sub-page instead.
if (!bParent)
return ;
BuilderPage* pNewPage = nullptr;
OptionsPageInfo* pOptPageInfo = (xCurrentPageEntry && xTreeLB->get_iter_depth(*xCurrentPageEntry))
? weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xCurrentPageEntry)) : nullptr;
if (pOptPageInfo && pOptPageInfo->m_xPage && pOptPageInfo->m_xPage->IsVisible())
{
std::unique_ptr<weld::TreeIter> xCurParent(xTreeLB->make_iterator(xCurrentPageEntry.get()));
xTreeLB->iter_parent(*xCurParent);
OptionsGroupInfo* pGroupInfo = weld::fromId<OptionsGroupInfo*>(xTreeLB->get_id(*xCurParent));
DeactivateRC nLeave = DeactivateRC::LeavePage;
if ( RID_SVXPAGE_COLOR != pOptPageInfo->m_nPageId && pOptPageInfo->m_xPage->HasExchangeSupport() )
nLeave = pOptPageInfo->m_xPage->DeactivatePage( pGroupInfo->m_pOutItemSet.get() );
if ( nLeave == DeactivateRC::KeepPage )
{
// we cannot leave this page, this is may be from a user clicking a different entry
// in the tree so reselect the current page
xTreeLB->select(*xCurrentPageEntry);
return ;
}
else
pOptPageInfo->m_xPage->set_visible(false );
}
else if ( pOptPageInfo && pOptPageInfo->m_xExtPage )
{
pOptPageInfo->m_xExtPage->Hide();
pOptPageInfo->m_xExtPage->DeactivatePage();
}
OptionsPageInfo *pPageInfo = weld::fromId<OptionsPageInfo*>(xTreeLB->get_id(*xEntry));
OptionsGroupInfo* pGroupInfo = weld::fromId<OptionsGroupInfo*>(xTreeLB->get_id(*xParent));
if (!pPageInfo->m_xPage && pPageInfo->m_nPageId > 0)
{
InitItemSets(*pGroupInfo);
pPageInfo->m_xPage = ::CreateGeneralTabPage(pPageInfo->m_nPageId, xTabBox.get(), this , *pGroupInfo->m_pInItemSet);
if (!pPageInfo->m_xPage && pGroupInfo->m_pModule)
pPageInfo->m_xPage = pGroupInfo->m_pModule->CreateTabPage(pPageInfo->m_nPageId, xTabBox.get(), this , *pGroupInfo->m_pInItemSet);
DBG_ASSERT( pPageInfo->m_xPage, "tabpage could not created" );
if ( pPageInfo->m_xPage )
{
SvtViewOptions aTabPageOpt( EViewType::TabPage, OUString::number( pPageInfo->m_nPageId) );
pPageInfo->m_xPage->SetUserData( GetViewOptUserItem( aTabPageOpt ) );
pPageInfo->m_xPage->SetFrame( m_xFrame );
pPageInfo->m_xPage->Reset( &*pGroupInfo->m_pInItemSet );
}
}
else if ( 0 == pPageInfo->m_nPageId && !pPageInfo->m_xExtPage )
{
if ( !m_xContainerWinProvider.is() )
{
m_xContainerWinProvider = awt::ContainerWindowProvider::create( ::comphelper::getProcessComponentContext() );
}
pPageInfo->m_xExtPage = std::make_unique<ExtensionsTabPage>(
xTabBox.get(), pPageInfo->m_sPageURL, pPageInfo->m_sEventHdl, m_xContainerWinProvider);
}
if ( pPageInfo->m_xPage )
{
if ( RID_SVXPAGE_COLOR != pPageInfo->m_nPageId &&
pPageInfo->m_xPage->HasExchangeSupport())
{
pPageInfo->m_xPage->ActivatePage(*pGroupInfo->m_pOutItemSet);
}
pPageInfo->m_xPage->set_visible(true );
}
else if ( pPageInfo->m_xExtPage )
{
pPageInfo->m_xExtPage->Show();
pPageInfo->m_xExtPage->ActivatePage();
}
{
OUString sTitleText = sTitle
+ " - " + xTreeLB->get_text(*xParent)
+ " - " + xTreeLB->get_text(*xEntry);
m_xDialog->set_title(sTitleText);
}
xCurrentPageEntry = std::move(xEntry);
if ( !bForgetSelection )
{
if ( !pLastPageSaver )
pLastPageSaver = new LastPageSaver;
if ( !bIsFromExtensionManager )
pLastPageSaver->m_nLastPageId = pPageInfo->m_nPageId;
if ( pPageInfo->m_xExtPage )
{
if ( bIsFromExtensionManager )
pLastPageSaver->m_sLastPageURL_ExtMgr = pPageInfo->m_sPageURL;
else
pLastPageSaver->m_sLastPageURL_Tools = pPageInfo->m_sPageURL;
}
}
pNewPage = pPageInfo->m_xPage.get();
// fdo#58170 use current page's layout child HelpId, unless there isn't a current page
OUString sHelpId(pNewPage ? pNewPage->GetHelpId() : OUString());
if (sHelpId.isEmpty())
sHelpId = HID_OFADLG_TREELISTBOX;
xTreeLB->set_help_id(sHelpId);
}
std::optional<SfxItemSet> OfaTreeOptionsDialog::CreateItemSet( sal_uInt16 nId )
{
Reference< XLinguProperties > xProp( LinguMgr::GetLinguPropertySet() );
std::optional<SfxItemSet> pRet;
switch (nId)
{
case SID_GENERAL_OPTIONS:
{
pRet.emplace(
SfxGetpApp()->GetPool(),
svl::Items<
SID_HTML_MODE, SID_HTML_MODE,
SID_ATTR_METRIC, SID_ATTR_METRIC,
SID_AUTOSPELL_CHECK, SID_AUTOSPELL_CHECK,
SID_ATTR_QUICKLAUNCHER, SID_ATTR_QUICKLAUNCHER,
SID_ATTR_YEAR2000, SID_ATTR_YEAR2000> );
SfxItemSetFixed<SID_ATTR_QUICKLAUNCHER, SID_ATTR_QUICKLAUNCHER> aOptSet( SfxGetpApp()->GetPool() );
SfxApplication::GetOptions(aOptSet);
pRet->Put(aOptSet);
SfxViewFrame* pViewFrame = SfxViewFrame::Current();
if ( pViewFrame )
{
SfxPoolItemHolder aResult;
const SfxItemState aState(pViewFrame->GetDispatcher()->QueryState(SID_ATTR_YEAR2000, aResult));
const SfxUInt16Item* pItem(static_cast <const SfxUInt16Item*>(aResult.getItem()));
// miscellaneous - Year2000
if (SfxItemState::DEFAULT <= aState && nullptr != pItem)
pRet->Put( SfxUInt16Item( SID_ATTR_YEAR2000, pItem->GetValue() ) );
else
pRet->Put( SfxUInt16Item( SID_ATTR_YEAR2000, officecfg::Office::Common::DateFormat::TwoDigitYear::get() ) );
}
else
pRet->Put( SfxUInt16Item( SID_ATTR_YEAR2000, officecfg::Office::Common::DateFormat::TwoDigitYear::get() ) );
// miscellaneous - Tabulator
pRet->Put(SfxBoolItem(SID_PRINTER_NOTFOUND_WARN, officecfg::Office::Common::Print::Warning::NotFound::get()));
SfxPrinterChangeFlags nFlag = officecfg::Office::Common::Print::Warning::PaperSize::get() ? SfxPrinterChangeFlags::CHG_SIZE : SfxPrinterChangeFlags::NONE;
nFlag |= officecfg::Office::Common::Print::Warning::PaperOrientation::get() ? SfxPrinterChangeFlags::CHG_ORIENTATION : SfxPrinterChangeFlags::NONE;
pRet->Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, static_cast <int >(nFlag) ));
}
break ;
case SID_LANGUAGE_OPTIONS :
{
pRet.emplace(
SfxGetpApp()->GetPool(),
svl::Items<
SID_ATTR_CHAR_CJK_LANGUAGE, SID_ATTR_CHAR_CJK_LANGUAGE,
SID_ATTR_CHAR_CTL_LANGUAGE, SID_ATTR_CHAR_CTL_LANGUAGE,
SID_SET_DOCUMENT_LANGUAGE, SID_SET_DOCUMENT_LANGUAGE,
SID_ATTR_LANGUAGE, SID_ATTR_LANGUAGE,
SID_AUTOSPELL_CHECK, SID_AUTOSPELL_CHECK,
SID_OPT_LOCALE_CHANGED, SID_OPT_LOCALE_CHANGED>);
// for linguistic
SfxHyphenRegionItem aHyphen( SID_ATTR_HYPHENREGION );
sal_Int16 nMinLead = 2,
nMinTrail = 2;
if (xProp.is())
{
nMinLead = xProp->getHyphMinLeading();
nMinTrail = xProp->getHyphMinTrailing();
}
aHyphen.GetMinLead() = static_cast <sal_uInt8>(nMinLead);
aHyphen.GetMinTrail() = static_cast <sal_uInt8>(nMinTrail);
SfxViewFrame* pViewFrame = SfxViewFrame::Current();
if ( pViewFrame )
{
SfxPoolItemHolder aResult;
SfxDispatcher* pDispatch(pViewFrame->GetDispatcher());
SfxItemState aState(pDispatch->QueryState(SID_ATTR_LANGUAGE, aResult));
if (SfxItemState::DEFAULT <= aState)
pRet->Put(*aResult.getItem());
aState = pDispatch->QueryState(SID_ATTR_CHAR_CJK_LANGUAGE, aResult);
if (SfxItemState::DEFAULT <= aState)
pRet->Put(*aResult.getItem());
aState = pDispatch->QueryState(SID_ATTR_CHAR_CTL_LANGUAGE, aResult);
if (SfxItemState::DEFAULT <= aState)
pRet->Put(*aResult.getItem());
pRet->Put(aHyphen);
aState = pDispatch->QueryState(SID_AUTOSPELL_CHECK, aResult);
if (SfxItemState::DEFAULT <= aState)
{
pRet->Put(*aResult.getItem()); // allow share/refcounting
// pRet->Put(std::unique_ptr<SfxPoolItem>(aResult.getItem()->Clone()));
}
else
{
bool bVal = false ;
if (xProp.is())
{
bVal = xProp->getIsSpellAuto();
}
pRet->Put(SfxBoolItem(SID_AUTOSPELL_CHECK, bVal));
}
}
pRet->Put( SfxBoolItem( SID_SET_DOCUMENT_LANGUAGE, bIsForSetDocumentLanguage ) );
}
break ;
case SID_INET_DLG :
pRet.emplace( SfxGetpApp()->GetPool(),
svl::Items<
//SID_OPTIONS_START - ..END
SID_SAVEREL_INET, SID_SAVEREL_FSYS,
SID_INET_NOPROXY, SID_INET_HTTP_PROXY_PORT,
SID_SECURE_URL, SID_SECURE_URL> );
SfxApplication::GetOptions(*pRet);
break ;
case SID_FILTER_DLG:
pRet.emplace(
SfxGetpApp()->GetPool(),
svl::Items<
SID_ATTR_WARNALIENFORMAT, SID_ATTR_WARNALIENFORMAT,
SID_ATTR_DOCINFO, SID_ATTR_AUTOSAVEMINUTE,
SID_SAVEREL_INET, SID_SAVEREL_FSYS,
SID_ATTR_PRETTYPRINTING, SID_ATTR_PRETTYPRINTING> );
SfxApplication::GetOptions(*pRet);
break ;
case SID_SB_STARBASEOPTIONS:
pRet.emplace( SfxGetpApp()->GetPool(),
svl::Items<SID_SB_POOLING_ENABLED, SID_SB_DB_REGISTER> );
::offapp::ConnectionPoolConfig::GetOptions(*pRet);
svx::DbRegisteredNamesConfig::GetOptions(*pRet);
break ;
case SID_SCH_EDITOPTIONS:
{
pRet.emplace( SfxGetpApp()->GetPool(), svl::Items<SID_SCH_EDITOPTIONS, SID_SCH_EDITOPTIONS> );
pRet->Put( SvxChartColorTableItem( SID_SCH_EDITOPTIONS, SvxChartOptions::GetDefaultColors() ) );
break ;
}
}
return pRet;
}
void OfaTreeOptionsDialog::ApplyItemSet( sal_uInt16 nId, const SfxItemSet& rSet )
{
switch (nId)
{
case SID_GENERAL_OPTIONS:
{
std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
SfxItemSetFixed<SID_ATTR_QUICKLAUNCHER, SID_ATTR_QUICKLAUNCHER> aOptSet(SfxGetpApp()->GetPool());
aOptSet.Put(rSet);
if (aOptSet.Count())
SfxApplication::SetOptions( aOptSet );
// get dispatcher anew, because SetOptions() might have destroyed the dispatcher
SfxViewFrame *pViewFrame = SfxViewFrame::Current();
// evaluate Year2000
sal_uInt16 nY2K = USHRT_MAX;
const SfxUInt16Item* pYearItem = rSet.GetItemIfSet( SID_ATTR_YEAR2000, false );
if ( pYearItem )
nY2K = pYearItem->GetValue();
if ( USHRT_MAX != nY2K )
{
if ( pViewFrame )
{
SfxDispatcher* pDispatch = pViewFrame->GetDispatcher();
pDispatch->ExecuteList(SID_ATTR_YEAR2000,
SfxCallMode::ASYNCHRON, { pYearItem });
}
officecfg::Office::Common::DateFormat::TwoDigitYear::set(nY2K, batch);
}
// evaluate print
if (const SfxBoolItem* pWarnItem = rSet.GetItemIfSet(SID_PRINTER_NOTFOUND_WARN, false ))
officecfg::Office::Common::Print::Warning::NotFound::set(pWarnItem->GetValue(), batch);
if (const SfxFlagItem* pFlag = rSet.GetItemIfSet(SID_PRINTER_CHANGESTODOC, false ))
{
bool bPaperSizeWarning = bool (static_cast <SfxPrinterChangeFlags>(pFlag->GetValue()) & SfxPrinterChangeFlags::CHG_SIZE);
officecfg::Office::Common::Print::Warning::PaperSize::set(bPaperSizeWarning, batch);
bool bPaperOrientationWarning = bool (static_cast <SfxPrinterChangeFlags>(pFlag->GetValue()) & SfxPrinterChangeFlags::CHG_ORIENTATION);
officecfg::Office::Common::Print::Warning::PaperOrientation::set(bPaperOrientationWarning, batch);
}
// evaluate help options
bool bHelpTips = officecfg::Office::Common::Help::Tip::get();
if ( bHelpTips != Help::IsQuickHelpEnabled() )
bHelpTips ? Help::EnableQuickHelp() : Help::DisableQuickHelp();
bool bExtendedHelp = officecfg::Office::Common::Help::ExtendedTip::get();
if ( bExtendedHelp != Help::IsBalloonHelpEnabled() )
bExtendedHelp ? Help::EnableBalloonHelp() : Help::DisableBalloonHelp();
batch->commit();
}
break ;
case SID_LANGUAGE_OPTIONS :
{
OfaTreeOptionsDialog::ApplyLanguageOptions(rSet);
}
break ;
case SID_INET_DLG :
case SID_FILTER_DLG:
SfxApplication::SetOptions( rSet );
break ;
case SID_SB_STARBASEOPTIONS:
::offapp::ConnectionPoolConfig::SetOptions( rSet );
svx::DbRegisteredNamesConfig::SetOptions(rSet);
break ;
case SID_SCH_EDITOPTIONS:
// nothing to do. Chart options only apply to newly created charts
break ;
default :
{
SAL_WARN("cui.options" , "Unhandled option in ApplyItemSet" );
}
break ;
}
}
void OfaTreeOptionsDialog::ApplyLanguageOptions(const SfxItemSet& rSet)
{
bool bSaveSpellCheck = false ;
const SfxPoolItem* pItem = nullptr;
const Reference< XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
Reference< XLinguProperties > xProp = LinguProperties::create( xContext );
if ( const SfxHyphenRegionItem* pHyphenItem = rSet.GetItemIfSet(SID_ATTR_HYPHENREGION, false ) )
{
xProp->setHyphMinLeading( static_cast <sal_Int16>(pHyphenItem->GetMinLead()) );
xProp->setHyphMinTrailing( static_cast <sal_Int16>(pHyphenItem->GetMinTrail()) );
bSaveSpellCheck = true ;
}
SfxViewFrame *pViewFrame = SfxViewFrame::Current();
if ( pViewFrame )
{
SfxDispatcher* pDispatch = pViewFrame->GetDispatcher();
pItem = nullptr;
if (SfxItemState::SET == rSet.GetItemState( SID_ATTR_LANGUAGE, false , &pItem ))
{
pDispatch->ExecuteList(pItem->Which(), SfxCallMode::SYNCHRON, { pItem });
bSaveSpellCheck = true ;
}
if (SfxItemState::SET == rSet.GetItemState( SID_ATTR_CHAR_CTL_LANGUAGE, false , &pItem ))
{
pDispatch->ExecuteList(pItem->Which(), SfxCallMode::SYNCHRON, { pItem });
bSaveSpellCheck = true ;
}
if (SfxItemState::SET == rSet.GetItemState( SID_ATTR_CHAR_CJK_LANGUAGE, false , &pItem ))
{
pDispatch->ExecuteList(pItem->Which(), SfxCallMode::SYNCHRON, { pItem });
bSaveSpellCheck = true ;
}
if ( SfxItemState::SET == rSet.GetItemState(SID_AUTOSPELL_CHECK, false , &pItem ))
{
bool bOnlineSpelling = static_cast <const SfxBoolItem*>(pItem)->GetValue();
pDispatch->ExecuteList(SID_AUTOSPELL_CHECK,
SfxCallMode::ASYNCHRON|SfxCallMode::RECORD, { pItem });
xProp->setIsSpellAuto( bOnlineSpelling );
}
if ( bSaveSpellCheck )
{
//! the config item has changed since we modified the
//! property set it uses
pDispatch->Execute(SID_SPELLCHECKER_CHANGED, SfxCallMode::ASYNCHRON);
}
}
if ( SfxItemState::SET == rSet.GetItemState(SID_OPT_LOCALE_CHANGED, false , &pItem ))
{
SfxViewFrame* _pViewFrame = SfxViewFrame::GetFirst();
while ( _pViewFrame )
{
_pViewFrame->GetDispatcher()->ExecuteList(pItem->Which(),
SfxCallMode::ASYNCHRON, { pItem });
_pViewFrame = SfxViewFrame::GetNext( *_pViewFrame );
}
}
}
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=96 H=93 G=94
¤ Dauer der Verarbeitung: 0.24 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland