diff options
Diffstat (limited to 'cui/source/options')
71 files changed, 22688 insertions, 0 deletions
diff --git a/cui/source/options/certpath.cxx b/cui/source/options/certpath.cxx new file mode 100644 index 0000000000..91526e587c --- /dev/null +++ b/cui/source/options/certpath.cxx @@ -0,0 +1,237 @@ +/* -*- 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/. + */ + +#include <officecfg/Office/Common.hxx> +#include <osl/file.hxx> +#include <osl/security.hxx> +#include <sfx2/filedlghelper.hxx> +#include <comphelper/diagnose_ex.hxx> +#include "certpath.hxx" + +#include <com/sun/star/xml/crypto/NSSInitializer.hpp> +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> +#include <comphelper/processfactory.hxx> + +using namespace ::com::sun::star; + +CertPathDialog::CertPathDialog(weld::Window* pParent) + : GenericDialogController(pParent, "cui/ui/certdialog.ui", "CertDialog") + , m_xManualButton(m_xBuilder->weld_button("add")) + , m_xOKButton(m_xBuilder->weld_button("ok")) + , m_xCertPathList(m_xBuilder->weld_tree_view("paths")) + , m_sAddDialogText(m_xBuilder->weld_label("certdir")->get_label()) + , m_sManualLabel(m_xBuilder->weld_label("manual")->get_label()) +{ + m_xCertPathList->set_size_request(m_xCertPathList->get_approximate_digit_width() * 70, + m_xCertPathList->get_height_rows(6)); + + m_xCertPathList->enable_toggle_buttons(weld::ColumnToggleType::Radio); + m_xCertPathList->connect_toggled(LINK(this, CertPathDialog, CheckHdl_Impl)); + + m_xManualButton->connect_clicked( LINK( this, CertPathDialog, ManualHdl_Impl ) ); + m_xOKButton->connect_clicked( LINK( this, CertPathDialog, OKHdl_Impl ) ); +} + +void CertPathDialog::Init() +{ + m_xCertPathList->clear(); + m_xCertPathList->set_sensitive(true); + + try + { + uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext(); + uno::Reference<xml::crypto::XNSSInitializer> xCipherContextSupplier = xml::crypto::NSSInitializer::create(xContext); + + OUString sActivePath = xCipherContextSupplier->getNSSPath(); + auto aProductList = xCipherContextSupplier->getNSSProfiles(); + + // these map to the integer values of mozilla::MozillaProductType + const char* const productNames[4] = { + "", + "mozilla", + "firefox", + "thunderbird" + }; + + for (const auto& rNSSProfile : std::as_const(aProductList)) + { + if (rNSSProfile.Type == mozilla::MozillaProductType_Default) + { + if (rNSSProfile.Name == "MOZILLA_CERTIFICATE_FOLDER" && !rNSSProfile.Path.isEmpty()) + { + AddCertPath("$MOZILLA_CERTIFICATE_FOLDER", rNSSProfile.Path); + m_xCertPathList->set_sensitive(false); + } + else if (rNSSProfile.Name == "MANUAL") + AddManualCertPath(rNSSProfile.Path); + } + else + { + OUString sEntry = OUString::createFromAscii( + productNames[static_cast<int>(rNSSProfile.Type)]) + ":" + rNSSProfile.Name; + AddCertPath(sEntry, rNSSProfile.Path, rNSSProfile.Path == sActivePath); + } + } + + OUString sManualCertPath = officecfg::Office::Common::Security::Scripting::ManualCertDir::get(); + if (!sManualCertPath.isEmpty()) + AddManualCertPath(sManualCertPath, false); + } + catch (const uno::Exception&) + { + } +} + +void CertPathDialog::AddManualCertPath(const OUString& sUserSetCertPath, bool bSelect) +{ + if (sUserSetCertPath.isEmpty()) + return; + + ::osl::DirectoryItem aUserPathItem; + OUString sUserSetCertURLPath; + osl::FileBase::getFileURLFromSystemPath(sUserSetCertPath, sUserSetCertURLPath); + if (::osl::FileBase::E_None == ::osl::DirectoryItem::get(sUserSetCertURLPath, aUserPathItem)) + { + ::osl::FileStatus aStatus( osl_FileStatus_Mask_Validate ); + if (::osl::FileBase::E_None == aUserPathItem.getFileStatus(aStatus)) + // the cert path exists + AddCertPath(m_sManualLabel, sUserSetCertPath, bSelect); + } +} + +IMPL_LINK_NOARG(CertPathDialog, OKHdl_Impl, weld::Button&, void) +{ + try + { + std::shared_ptr< comphelper::ConfigurationChanges > batch( + comphelper::ConfigurationChanges::create()); + const int nEntry = m_xCertPathList->get_selected_index(); + officecfg::Office::Common::Security::Scripting::CertDir::set( + nEntry == -1 ? OUString() : m_xCertPathList->get_id(nEntry), batch); + officecfg::Office::Common::Security::Scripting::ManualCertDir::set(m_sManualPath, batch); + batch->commit(); + } + catch (const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("cui.options", "CertPathDialog::OKHdl_Impl()"); + } + + m_xDialog->response(RET_OK); +} + +bool CertPathDialog::isActiveServicePath() const +{ + int nEntry = m_xCertPathList->get_selected_index(); + if (nEntry == -1) + return true; + + try + { + uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext(); + uno::Reference<xml::crypto::XNSSInitializer> xCipherContextSupplier = xml::crypto::NSSInitializer::create(xContext); + + if (!xCipherContextSupplier->getIsNSSinitialized()) + return true; + return (xCipherContextSupplier->getNSSPath() == m_xCertPathList->get_id(nEntry)); + } + catch (const uno::Exception&) + { + return false; + } +} + +CertPathDialog::~CertPathDialog() +{ +} + +IMPL_LINK(CertPathDialog, CheckHdl_Impl, const weld::TreeView::iter_col&, rRowCol, void) +{ + HandleEntryChecked(m_xCertPathList->get_iter_index_in_parent(rRowCol.first)); +} + +void CertPathDialog::HandleEntryChecked(int nRow) +{ + const bool bChecked = m_xCertPathList->get_toggle(nRow) == TRISTATE_TRUE; + if (bChecked) + { + // we have radio button behavior -> so uncheck the other entries + m_xCertPathList->select(nRow); + const int nCount = m_xCertPathList->n_children(); + for (int i = 0; i < nCount; ++i) + { + if (i != nRow) + m_xCertPathList->set_toggle(i, TRISTATE_FALSE); + } + } +} + +void CertPathDialog::AddCertPath(const OUString &rProfile, const OUString &rPath, const bool bSelect) +{ + int nRow = -1; + for (int i = 0, nCount = m_xCertPathList->n_children(); i < nCount; ++i) + { + OUString sCertPath = m_xCertPathList->get_id(i); + //already exists, just select the original one + if (sCertPath == rPath) + { + const bool bWantSelected = bSelect || m_xCertPathList->get_toggle(i); + m_xCertPathList->set_toggle(i, bWantSelected ? TRISTATE_TRUE : TRISTATE_FALSE); + HandleEntryChecked(i); + return; + } + else if (m_xCertPathList->get_text(i, 0) == rProfile) + nRow = i; + } + + if (m_sManualLabel == rProfile) + m_sManualPath = rPath; + + if (nRow < 0) + { + m_xCertPathList->append(); + nRow = m_xCertPathList->n_children() - 1; + } + m_xCertPathList->set_toggle(nRow, bSelect ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xCertPathList->set_text(nRow, rProfile, 0); + m_xCertPathList->set_text(nRow, rPath, 1); + m_xCertPathList->set_id(nRow, rPath); + HandleEntryChecked(nRow); +} + +IMPL_LINK_NOARG(CertPathDialog, ManualHdl_Impl, weld::Button&, void) +{ + try + { + uno::Reference<ui::dialogs::XFolderPicker2> xFolderPicker = sfx2::createFolderPicker( + comphelper::getProcessComponentContext(), m_xDialog.get()); + + OUString sURL; + if (!m_sManualPath.isEmpty()) + osl::FileBase::getFileURLFromSystemPath(m_sManualPath, sURL); + if (sURL.isEmpty()) + osl::Security().getHomeDir(sURL); + xFolderPicker->setDisplayDirectory(sURL); + xFolderPicker->setDescription(m_sAddDialogText); + + if (xFolderPicker->execute() == ui::dialogs::ExecutableDialogResults::OK) + { + sURL = xFolderPicker->getDirectory(); + OUString aPath; + if (osl::FileBase::E_None == osl::FileBase::getSystemPathFromFileURL(sURL, aPath)) + AddCertPath(m_sManualLabel, aPath); + } + } + catch (const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("cui.options", ""); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/certpath.hxx b/cui/source/options/certpath.hxx new file mode 100644 index 0000000000..50addc1e83 --- /dev/null +++ b/cui/source/options/certpath.hxx @@ -0,0 +1,42 @@ +/* -*- 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/. + */ + +#pragma once + +#include <vcl/weld.hxx> + +class CertPathDialog : public weld::GenericDialogController +{ + std::unique_ptr<weld::Button> m_xManualButton; + std::unique_ptr<weld::Button> m_xOKButton; + std::unique_ptr<weld::TreeView> m_xCertPathList; + OUString m_sAddDialogText; + OUString m_sManualLabel; + OUString m_sManualPath; + + DECL_LINK(CheckHdl_Impl, const weld::TreeView::iter_col&, void); + DECL_LINK(ManualHdl_Impl, weld::Button&, void); + DECL_LINK(OKHdl_Impl, weld::Button&, void); + + void HandleEntryChecked(int nRow); + void AddCertPath(const OUString& rProfile, const OUString& rPath, bool bSelect = true); + void AddManualCertPath(const OUString& sUserSetCertPath, bool bSelect = true); + +public: + explicit CertPathDialog(weld::Window* pParent); + virtual ~CertPathDialog() override; + + void Init(); + + // returns true, if the service currently uses the selected path or is not initialized + // yet and therefore has no active NSS path. + bool isActiveServicePath() const; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/cfgchart.cxx b/cui/source/options/cfgchart.cxx new file mode 100644 index 0000000000..8d1bd5e413 --- /dev/null +++ b/cui/source/options/cfgchart.cxx @@ -0,0 +1,235 @@ +/* -*- 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 <com/sun/star/uno/Sequence.hxx> +#include <tools/debug.hxx> +#include <sal/log.hxx> +#include "cfgchart.hxx" +#include <dialmgr.hxx> +#include <strings.hrc> +#include <utility> +#include <officecfg/Office/Chart.hxx> + +#define ROW_COLOR_COUNT 12 + +using namespace com::sun::star; + +// accessors +size_t SvxChartColorTable::size() const +{ + return m_aColorEntries.size(); +} + +const XColorEntry & SvxChartColorTable::operator[]( size_t _nIndex ) const +{ + if ( _nIndex >= m_aColorEntries.size() ) + { + SAL_WARN( "cui.options", "SvxChartColorTable::[] invalid index" ); + return m_aColorEntries[ 0 ]; + } + + return m_aColorEntries[ _nIndex ]; +} + +Color SvxChartColorTable::getColor( size_t _nIndex ) const +{ + if ( _nIndex >= m_aColorEntries.size() ) + { + SAL_WARN( "cui.options", "SvxChartColorTable::getColorData invalid index" ); + return COL_BLACK; + } + + return m_aColorEntries[ _nIndex ].GetColor().GetRGBColor(); +} + +// mutators +void SvxChartColorTable::clear() +{ + m_aColorEntries.clear(); +} + +void SvxChartColorTable::append( const XColorEntry & _rEntry ) +{ + m_aColorEntries.push_back( _rEntry ); +} + +void SvxChartColorTable::remove( size_t _nIndex ) +{ + if (!m_aColorEntries.empty()) + m_aColorEntries.erase( m_aColorEntries.begin() + _nIndex); + + for (size_t i=0 ; i<m_aColorEntries.size(); i++) + { + m_aColorEntries[ i ].SetName( getDefaultName( i ) ); + } +} + +void SvxChartColorTable::replace( size_t _nIndex, const XColorEntry & _rEntry ) +{ + DBG_ASSERT( _nIndex <= m_aColorEntries.size(), + "SvxChartColorTable::replace invalid index" ); + + m_aColorEntries[ _nIndex ] = _rEntry; +} + +void SvxChartColorTable::useDefault() +{ + static const Color aColors[] = { + Color( 0x00, 0x45, 0x86 ), + Color( 0xff, 0x42, 0x0e ), + Color( 0xff, 0xd3, 0x20 ), + Color( 0x57, 0x9d, 0x1c ), + Color( 0x7e, 0x00, 0x21 ), + Color( 0x83, 0xca, 0xff ), + Color( 0x31, 0x40, 0x04 ), + Color( 0xae, 0xcf, 0x00 ), + Color( 0x4b, 0x1f, 0x6f ), + Color( 0xff, 0x95, 0x0e ), + Color( 0xc5, 0x00, 0x0b ), + Color( 0x00, 0x84, 0xd1 ) + }; + + clear(); + + for( sal_Int32 i=0; i<ROW_COLOR_COUNT; i++ ) + { + append( XColorEntry( aColors[ i % sizeof( aColors ) ], getDefaultName( i ) )); + } +} + +OUString SvxChartColorTable::getDefaultName( size_t _nIndex ) +{ + OUString aName; + + std::u16string_view sDefaultNamePrefix; + std::u16string_view sDefaultNamePostfix; + OUString aResName( CuiResId( RID_CUISTR_DIAGRAM_ROW ) ); + sal_Int32 nPos = aResName.indexOf( "$(ROW)" ); + if( nPos != -1 ) + { + sDefaultNamePrefix = aResName.subView( 0, nPos ); + sDefaultNamePostfix = aResName.subView( nPos + sizeof( "$(ROW)" ) - 1 ); + } + else + { + sDefaultNamePrefix = aResName; + } + + aName = sDefaultNamePrefix + OUString::number(_nIndex + 1) + sDefaultNamePostfix; + + return aName; +} + +// comparison +bool SvxChartColorTable::operator==( const SvxChartColorTable & _rOther ) const +{ + // note: XColorEntry has no operator == + bool bEqual = ( m_aColorEntries.size() == _rOther.m_aColorEntries.size() ); + + if( bEqual ) + { + for( size_t i = 0; i < m_aColorEntries.size(); ++i ) + { + if( getColor( i ) != _rOther.getColor( i )) + { + bEqual = false; + break; + } + } + } + + return bEqual; +} + + + + +SvxChartColorTable SvxChartOptions::GetDefaultColors() +{ + // 1. default colors for series + uno::Sequence< sal_Int64 > aColorSeq = officecfg::Office::Chart::DefaultColor::Series::get(); + + sal_Int32 nCount = aColorSeq.getLength(); + Color aCol; + + // create strings for entry names + OUString aResName( CuiResId( RID_CUISTR_DIAGRAM_ROW ) ); + std::u16string_view aPrefix, aPostfix; + OUString aName; + sal_Int32 nPos = aResName.indexOf( "$(ROW)" ); + if( nPos != -1 ) + { + aPrefix = aResName.subView( 0, nPos ); + sal_Int32 idx = nPos + sizeof( "$(ROW)" ) - 1; + aPostfix = aResName.subView( idx ); + } + else + aPrefix = aResName; + + // set color values + SvxChartColorTable aDefColors; + for( sal_Int32 i=0; i < nCount; i++ ) + { + aCol = Color(ColorTransparency, aColorSeq[ i ]); + + aName = aPrefix + OUString::number(i + 1) + aPostfix; + + aDefColors.append( XColorEntry( aCol, aName )); + } + + return aDefColors; +} + +void SvxChartOptions::SetDefaultColors( const SvxChartColorTable& rDefColors ) +{ + // 1. default colors for series + // convert list to sequence + const size_t nCount = rDefColors.size(); + uno::Sequence< sal_Int64 > aColors( nCount ); + auto aColorsRange = asNonConstRange(aColors); + for( size_t i=0; i < nCount; i++ ) + { + Color aData = rDefColors.getColor( i ); + aColorsRange[ i ] = sal_uInt32(aData); + } + std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); + officecfg::Office::Chart::DefaultColor::Series::set(aColors, batch); + batch->commit(); +} + + +SvxChartColorTableItem::SvxChartColorTableItem( sal_uInt16 nWhich_, SvxChartColorTable aTable ) : + SfxPoolItem( nWhich_ ), + m_aColorTable(std::move( aTable )) +{ +} + +SvxChartColorTableItem* SvxChartColorTableItem::Clone( SfxItemPool * ) const +{ + return new SvxChartColorTableItem( *this ); +} + +bool SvxChartColorTableItem::operator==( const SfxPoolItem& rAttr ) const +{ + assert(SfxPoolItem::operator==(rAttr)); + + return static_cast<const SvxChartColorTableItem & >( rAttr ).m_aColorTable == m_aColorTable; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/cfgchart.hxx b/cui/source/options/cfgchart.hxx new file mode 100644 index 0000000000..ce39b0a173 --- /dev/null +++ b/cui/source/options/cfgchart.hxx @@ -0,0 +1,79 @@ +/* -*- 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 . + */ + +#pragma once + +#include <svl/poolitem.hxx> +#include <svx/xtable.hxx> +#include <vector> + +class SvxChartColorTable +{ +private: + std::vector< XColorEntry > m_aColorEntries; + +public: + // accessors + size_t size() const; + const XColorEntry & operator[]( size_t _nIndex ) const; + Color getColor( size_t _nIndex ) const; + + // mutators + void clear(); + void append( const XColorEntry & _rEntry ); + void remove( size_t _nIndex ); + void replace( size_t _nIndex, const XColorEntry & _rEntry ); + void useDefault(); + static OUString getDefaultName(size_t _nIndex); + + // comparison + bool operator==( const SvxChartColorTable & _rOther ) const; +}; + + +// all options + +namespace SvxChartOptions +{ + SvxChartColorTable GetDefaultColors(); + void SetDefaultColors( const SvxChartColorTable& aCol ); +}; + + +// items +// Make Item read-only (no non-const access methods). Two reasons: +// (1) Preparation for Item refactor +// (2) Dangerous due to SfxItem may not be what you expect (e.g. when +// ::Set in SfxItemSet, not your instance may be used there, no control +// about what will happen without deep knowledge about SfxItems/SfxItemSets) +class SvxChartColorTableItem : public SfxPoolItem +{ +public: + SvxChartColorTableItem( sal_uInt16 nWhich, SvxChartColorTable ); + + virtual SvxChartColorTableItem* Clone( SfxItemPool *pPool = nullptr ) const override; + virtual bool operator==( const SfxPoolItem& ) const override; + + const SvxChartColorTable & GetColorList() const { return m_aColorTable;} + +private: + SvxChartColorTable m_aColorTable; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/connpoolconfig.cxx b/cui/source/options/connpoolconfig.cxx new file mode 100644 index 0000000000..8bf95ee0db --- /dev/null +++ b/cui/source/options/connpoolconfig.cxx @@ -0,0 +1,196 @@ +/* -*- 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 "connpoolconfig.hxx" +#include "connpoolsettings.hxx" + +#include <svl/itemset.hxx> +#include <svx/databaseregistrationui.hxx> +#include <unotools/confignode.hxx> +#include <svl/eitem.hxx> +#include <comphelper/processfactory.hxx> +#include "sdbcdriverenum.hxx" + +#include <com/sun/star/uno/Sequence.hxx> + +namespace offapp +{ + + + using namespace ::utl; + using namespace ::com::sun::star::uno; + + + static OUString getConnectionPoolNodeName() + { + return "org.openoffice.Office.DataAccess/ConnectionPool"; + } + + + static OUString getEnablePoolingNodeName() + { + return "EnablePooling"; + } + + + static OUString getDriverSettingsNodeName() + { + return "DriverSettings"; + } + + + static OUString getDriverNameNodeName() + { + return "DriverName"; + } + + + static OUString getEnableNodeName() + { + return "Enable"; + } + + + static OUString getTimeoutNodeName() + { + return "Timeout"; + } + + void ConnectionPoolConfig::GetOptions(SfxItemSet& _rFillItems) + { + // the config node where all pooling relevant info are stored under + OConfigurationTreeRoot aConnectionPoolRoot = OConfigurationTreeRoot::createWithComponentContext( + ::comphelper::getProcessComponentContext(), getConnectionPoolNodeName(), -1, OConfigurationTreeRoot::CM_READONLY); + + // the global "enabled" flag + Any aEnabled = aConnectionPoolRoot.getNodeValue(getEnablePoolingNodeName()); + bool bEnabled = true; + aEnabled >>= bEnabled; + _rFillItems.Put(SfxBoolItem(SID_SB_POOLING_ENABLED, bEnabled)); + + // the settings for the single drivers + DriverPoolingSettings aSettings; + // first get all the drivers register at the driver manager + ODriverEnumeration aEnumDrivers; + for (auto const& elem : aEnumDrivers) + { + aSettings.push_back(DriverPooling(elem)); + } + + // then look for which of them settings are stored in the configuration + OConfigurationNode aDriverSettings = aConnectionPoolRoot.openNode(getDriverSettingsNodeName()); + + Sequence< OUString > aDriverKeys = aDriverSettings.getNodeNames(); + const OUString* pDriverKeys = aDriverKeys.getConstArray(); + const OUString* pDriverKeysEnd = pDriverKeys + aDriverKeys.getLength(); + for (;pDriverKeys != pDriverKeysEnd; ++pDriverKeys) + { + // the name of the driver in this round + OConfigurationNode aThisDriverSettings = aDriverSettings.openNode(*pDriverKeys); + OUString sThisDriverName; + aThisDriverSettings.getNodeValue(getDriverNameNodeName()) >>= sThisDriverName; + + // look if we (resp. the driver manager) know this driver + // doing O(n) search here, which is expensive, but this doesn't matter in this small case ... + DriverPoolingSettings::iterator aLookup; + for ( aLookup = aSettings.begin(); + aLookup != aSettings.end(); + ++aLookup + ) + if (sThisDriverName == aLookup->sName) + break; + + if (aLookup == aSettings.end()) + { // do not know the driver - add it + aSettings.push_back(DriverPooling(sThisDriverName)); + + // and the position of the new entry + aLookup = aSettings.end(); + --aLookup; + } + + // now fill this entry with the settings from the configuration + aThisDriverSettings.getNodeValue(getEnableNodeName()) >>= aLookup->bEnabled; + aThisDriverSettings.getNodeValue(getTimeoutNodeName()) >>= aLookup->nTimeoutSeconds; + } + + _rFillItems.Put(DriverPoolingSettingsItem(SID_SB_DRIVER_TIMEOUTS, aSettings)); + } + + + void ConnectionPoolConfig::SetOptions(const SfxItemSet& _rSourceItems) + { + // the config node where all pooling relevant info are stored under + OConfigurationTreeRoot aConnectionPoolRoot = OConfigurationTreeRoot::createWithComponentContext( + ::comphelper::getProcessComponentContext(), getConnectionPoolNodeName()); + + if (!aConnectionPoolRoot.isValid()) + // already asserted by the OConfigurationTreeRoot + return; + + bool bNeedCommit = false; + + // the global "enabled" flag + const SfxBoolItem* pEnabled = _rSourceItems.GetItem<SfxBoolItem>(SID_SB_POOLING_ENABLED); + if (pEnabled) + { + bool bEnabled = pEnabled->GetValue(); + aConnectionPoolRoot.setNodeValue(getEnablePoolingNodeName(), Any(bEnabled)); + bNeedCommit = true; + } + + // the settings for the single drivers + const DriverPoolingSettingsItem* pDriverSettings = _rSourceItems.GetItem<DriverPoolingSettingsItem>(SID_SB_DRIVER_TIMEOUTS); + if (pDriverSettings) + { + OConfigurationNode aDriverSettings = aConnectionPoolRoot.openNode(getDriverSettingsNodeName()); + if (!aDriverSettings.isValid()) + return; + + OUString sThisDriverName; + OConfigurationNode aThisDriverSettings; + + const DriverPoolingSettings& rNewSettings = pDriverSettings->getSettings(); + for (auto const& newSetting : rNewSettings) + { + // need the name as OUString + sThisDriverName = newSetting.sName; + + // the sub-node for this driver + if (aDriverSettings.hasByName(newSetting.sName)) + aThisDriverSettings = aDriverSettings.openNode(newSetting.sName); + else + aThisDriverSettings = aDriverSettings.createNode(newSetting.sName); + + // set the values + aThisDriverSettings.setNodeValue(getDriverNameNodeName(), Any(sThisDriverName)); + aThisDriverSettings.setNodeValue(getEnableNodeName(), Any(newSetting.bEnabled)); + aThisDriverSettings.setNodeValue(getTimeoutNodeName(), Any(newSetting.nTimeoutSeconds)); + } + bNeedCommit = true; + } + if (bNeedCommit) + aConnectionPoolRoot.commit(); + } + + +} // namespace offapp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/connpoolconfig.hxx b/cui/source/options/connpoolconfig.hxx new file mode 100644 index 0000000000..41ec88d5b3 --- /dev/null +++ b/cui/source/options/connpoolconfig.hxx @@ -0,0 +1,38 @@ +/* -*- 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 . + */ + +#pragma once + +class SfxItemSet; + +namespace offapp +{ + + class ConnectionPoolConfig + { + + public: + static void GetOptions(SfxItemSet& _rFillItems); + static void SetOptions(const SfxItemSet& _rSourceItems); + }; + + +} // namespace offapp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/connpooloptions.cxx b/cui/source/options/connpooloptions.cxx new file mode 100644 index 0000000000..f6321f2252 --- /dev/null +++ b/cui/source/options/connpooloptions.cxx @@ -0,0 +1,307 @@ +/* -*- 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 <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include "connpooloptions.hxx" +#include "connpoolsettings.hxx" +#include <svl/eitem.hxx> +#include <svx/databaseregistrationui.hxx> +#include <strings.hrc> +#include <dialmgr.hxx> +#include <officecfg/Office/DataAccess.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +namespace offapp +{ + bool ConnectionPoolOptionsPage::isModifiedDriverList() const + { + if (m_aSettings.size() != m_aSavedSettings.size()) + return true; + + DriverPoolingSettings::const_iterator aSaved = m_aSavedSettings.begin(); + for (auto const& currentSetting : m_aSettings) + { + if (currentSetting != *aSaved) + return true; + ++aSaved; + } + + return false; + } + + ConnectionPoolOptionsPage::ConnectionPoolOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + : SfxTabPage(pPage, pController, "cui/ui/connpooloptions.ui", "ConnPoolPage", &_rAttrSet) + , m_sYes(CuiResId(RID_CUISTR_YES)) + , m_sNo(CuiResId(RID_CUISTR_NO)) + , m_xEnablePooling(m_xBuilder->weld_check_button("connectionpooling")) + , m_xEnablePoolingImg(m_xBuilder->weld_widget("lockconnectionpooling")) + , m_xDriversLabel(m_xBuilder->weld_label("driverslabel")) + , m_xDriverList(m_xBuilder->weld_tree_view("driverlist")) + , m_xDriverLabel(m_xBuilder->weld_label("driverlabel")) + , m_xDriver(m_xBuilder->weld_label("driver")) + , m_xDriverPoolingEnabled(m_xBuilder->weld_check_button("enablepooling")) + , m_xDriverPoolingEnabledImg(m_xBuilder->weld_widget("lockenablepooling")) + , m_xTimeoutLabel(m_xBuilder->weld_label("timeoutlabel")) + , m_xTimeout(m_xBuilder->weld_spin_button("timeout")) + , m_xTimeoutImg(m_xBuilder->weld_widget("locktimeout")) + { + m_xDriverList->set_size_request(m_xDriverList->get_approximate_digit_width() * 60, + m_xDriverList->get_height_rows(15)); + m_xDriverList->show(); + + std::vector<int> aWidths + { + o3tl::narrowing<int>(m_xDriverList->get_approximate_digit_width() * 50), + o3tl::narrowing<int>(m_xDriverList->get_approximate_digit_width() * 8) + }; + m_xDriverList->set_column_fixed_widths(aWidths); + + css::uno::Reference < css::uno::XComponentContext > xContext(::comphelper::getProcessComponentContext()); + m_xReadWriteAccess = css::configuration::ReadWriteAccess::create(xContext, "*"); + + m_xEnablePooling->connect_toggled( LINK(this, ConnectionPoolOptionsPage, OnEnabledDisabled) ); + m_xDriverPoolingEnabled->connect_toggled( LINK(this, ConnectionPoolOptionsPage, OnEnabledDisabled) ); + + m_xDriverList->connect_changed(LINK(this, ConnectionPoolOptionsPage, OnDriverRowChanged)); + m_xTimeout->connect_value_changed(LINK(this, ConnectionPoolOptionsPage, OnSpinValueChanged)); + } + + void ConnectionPoolOptionsPage::updateRow(size_t nRow) + { + auto const& currentSetting = m_aSettings[nRow]; + m_xDriverList->set_text(nRow, currentSetting.sName, 0); + if (currentSetting.bEnabled) + { + m_xDriverList->set_text(nRow, m_sYes, 1); + m_xDriverList->set_text(nRow, OUString::number(currentSetting.nTimeoutSeconds), 2); + } + else + { + m_xDriverList->set_text(nRow, m_sNo, 1); + m_xDriverList->set_text(nRow, "-", 2); + } + } + + void ConnectionPoolOptionsPage::updateCurrentRow() + { + int nRow = m_xDriverList->get_selected_index(); + if (nRow == -1) + return; + updateRow(nRow); + } + + void ConnectionPoolOptionsPage::UpdateDriverList(const DriverPoolingSettings& _rSettings) + { + m_aSettings = _rSettings; + + m_xDriverList->freeze(); + m_xDriverList->clear(); + + for (size_t i = 0; i < m_aSettings.size(); ++i) + { + m_xDriverList->append(); + updateRow(i); + } + + m_xDriverList->thaw(); + + if (!m_aSettings.empty()) + { + m_xDriverList->select(0); + OnDriverRowChanged(*m_xDriverList); + } + } + + ConnectionPoolOptionsPage::~ConnectionPoolOptionsPage() + { + } + + std::unique_ptr<SfxTabPage> ConnectionPoolOptionsPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique<ConnectionPoolOptionsPage>(pPage, pController, *_rAttrSet); + } + + void ConnectionPoolOptionsPage::implInitControls(const SfxItemSet& _rSet) + { + // the enabled flag + const SfxBoolItem* pEnabled = _rSet.GetItem<SfxBoolItem>(SID_SB_POOLING_ENABLED); + OSL_ENSURE(pEnabled, "ConnectionPoolOptionsPage::implInitControls: missing the Enabled item!"); + m_xEnablePooling->set_active(pEnabled == nullptr || pEnabled->GetValue()); + m_xEnablePooling->set_sensitive(!officecfg::Office::DataAccess::ConnectionPool::EnablePooling::isReadOnly()); + m_xEnablePoolingImg->set_visible(officecfg::Office::DataAccess::ConnectionPool::EnablePooling::isReadOnly()); + + m_xEnablePooling->save_state(); + + // the settings for the single drivers + const DriverPoolingSettingsItem* pDriverSettings = _rSet.GetItem<DriverPoolingSettingsItem>(SID_SB_DRIVER_TIMEOUTS); + if (pDriverSettings) + UpdateDriverList(pDriverSettings->getSettings()); + else + { + SAL_WARN("cui.options", "ConnectionPoolOptionsPage::implInitControls: missing the DriverTimeouts item!"); + UpdateDriverList(DriverPoolingSettings()); + } + saveDriverList(); + + // reflect the new settings + OnEnabledDisabled(*m_xEnablePooling); + } + + IMPL_LINK_NOARG(ConnectionPoolOptionsPage, OnSpinValueChanged, weld::SpinButton&, void) + { + commitTimeoutField(); + } + + OUString ConnectionPoolOptionsPage::GetAllStrings() + { + OUString sAllStrings; + OUString labels[] = { "label1", "driverslabel", "driverlabel", "timeoutlabel", "driver" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "connectionpooling", "enablepooling" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); + } + + bool ConnectionPoolOptionsPage::FillItemSet(SfxItemSet* _rSet) + { + commitTimeoutField(); + + bool bModified = false; + // the enabled flag + if (m_xEnablePooling->get_state_changed_from_saved()) + { + _rSet->Put(SfxBoolItem(SID_SB_POOLING_ENABLED, m_xEnablePooling->get_active())); + bModified = true; + } + + // the settings for the single drivers + if (isModifiedDriverList()) + { + _rSet->Put(DriverPoolingSettingsItem(SID_SB_DRIVER_TIMEOUTS, m_aSettings)); + bModified = true; + } + + return bModified; + } + + void ConnectionPoolOptionsPage::ActivatePage( const SfxItemSet& _rSet) + { + SfxTabPage::ActivatePage(_rSet); + implInitControls(_rSet); + } + + void ConnectionPoolOptionsPage::Reset(const SfxItemSet* _rSet) + { + implInitControls(*_rSet); + } + + IMPL_LINK_NOARG(ConnectionPoolOptionsPage, OnDriverRowChanged, weld::TreeView&, void) + { + const int nDriverPos = m_xDriverList->get_selected_index(); + bool bValidRow = (nDriverPos != -1); + m_xDriverPoolingEnabled->set_sensitive(bValidRow && m_xEnablePooling->get_active()); + m_xTimeoutLabel->set_sensitive(bValidRow); + m_xTimeout->set_sensitive(bValidRow); + + if (!bValidRow) + { // positioned on an invalid row + m_xDriver->set_label(OUString()); + } + else + { + auto const& currentSetting = m_aSettings[nDriverPos]; + m_xDriver->set_label(currentSetting.sName); + m_xDriverPoolingEnabled->set_active(currentSetting.bEnabled); + m_xTimeout->set_value(currentSetting.nTimeoutSeconds); + + OUString aConfigPath = officecfg::Office::DataAccess::ConnectionPool::DriverSettings::path() + "/" + currentSetting.sName; + css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath + "/Enable"); + bool bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0; + + m_xDriverPoolingEnabled->set_sensitive(!bReadOnly); + m_xDriverPoolingEnabledImg->set_visible(bReadOnly); + + aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath + "/Timeout"); + bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0; + + m_xTimeout->set_sensitive(!bReadOnly); + m_xTimeoutLabel->set_sensitive(!bReadOnly); + m_xTimeoutImg->set_visible(bReadOnly); + + OnEnabledDisabled(*m_xDriverPoolingEnabled); + } + } + + void ConnectionPoolOptionsPage::commitTimeoutField() + { + const int nDriverPos = m_xDriverList->get_selected_index(); + if (nDriverPos == -1) + return; + m_aSettings[nDriverPos].nTimeoutSeconds = m_xTimeout->get_value(); + updateCurrentRow(); + } + + IMPL_LINK( ConnectionPoolOptionsPage, OnEnabledDisabled, weld::Toggleable&, rCheckBox, void ) + { + bool bGloballyEnabled = m_xEnablePooling->get_active(); + bool bLocalDriverChanged = m_xDriverPoolingEnabled.get() == &rCheckBox; + + if (m_xEnablePooling.get() == &rCheckBox) + { + m_xDriversLabel->set_sensitive(bGloballyEnabled); + m_xDriverList->set_sensitive(bGloballyEnabled); + if (!bGloballyEnabled) + m_xDriverList->select(-1); + m_xDriverLabel->set_sensitive(bGloballyEnabled); + m_xDriver->set_sensitive(bGloballyEnabled); + m_xDriverPoolingEnabled->set_sensitive(bGloballyEnabled && !m_xDriverPoolingEnabledImg->get_visible()); + } + else + OSL_ENSURE(bLocalDriverChanged, "ConnectionPoolOptionsPage::OnEnabledDisabled: where did this come from?"); + + m_xTimeoutLabel->set_sensitive(bGloballyEnabled && m_xDriverPoolingEnabled->get_active() && !m_xTimeoutImg->get_visible()); + m_xTimeout->set_sensitive(bGloballyEnabled && m_xDriverPoolingEnabled->get_active() && !m_xTimeoutImg->get_visible()); + + if (bLocalDriverChanged) + { + // update the list + const int nDriverPos = m_xDriverList->get_selected_index(); + if (nDriverPos == -1) + return; + m_aSettings[nDriverPos].bEnabled = m_xDriverPoolingEnabled->get_active(); + updateCurrentRow(); + } + } + +} // namespace offapp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/connpooloptions.hxx b/cui/source/options/connpooloptions.hxx new file mode 100644 index 0000000000..2413f0d16d --- /dev/null +++ b/cui/source/options/connpooloptions.hxx @@ -0,0 +1,78 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sfx2/tabdlg.hxx> +#include <com/sun/star/configuration/ReadWriteAccess.hpp> + +#include "connpoolsettings.hxx" + +namespace offapp +{ + class ConnectionPoolOptionsPage final : public SfxTabPage + { + OUString m_sYes; + OUString m_sNo; + DriverPoolingSettings m_aSettings; + DriverPoolingSettings m_aSavedSettings; + + css::uno::Reference< css::configuration::XReadWriteAccess> m_xReadWriteAccess; + + std::unique_ptr<weld::CheckButton> m_xEnablePooling; + std::unique_ptr<weld::Widget> m_xEnablePoolingImg; + std::unique_ptr<weld::Label> m_xDriversLabel; + std::unique_ptr<weld::TreeView> m_xDriverList; + std::unique_ptr<weld::Label> m_xDriverLabel; + std::unique_ptr<weld::Label> m_xDriver; + std::unique_ptr<weld::CheckButton> m_xDriverPoolingEnabled; + std::unique_ptr<weld::Widget> m_xDriverPoolingEnabledImg; + std::unique_ptr<weld::Label> m_xTimeoutLabel; + std::unique_ptr<weld::SpinButton> m_xTimeout; + std::unique_ptr<weld::Widget> m_xTimeoutImg; + + public: + ConnectionPoolOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + virtual ~ConnectionPoolOptionsPage() override; + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet); + virtual OUString GetAllStrings() override; + + private: + virtual bool FillItemSet(SfxItemSet* _rSet) override; + virtual void Reset(const SfxItemSet* _rSet) override; + virtual void ActivatePage( const SfxItemSet& _rSet) override; + + void updateRow(size_t nRow); + void updateCurrentRow(); + void UpdateDriverList(const DriverPoolingSettings& _rSettings); + bool isModifiedDriverList() const; + void saveDriverList() { m_aSavedSettings = m_aSettings; } + + DECL_LINK(OnEnabledDisabled, weld::Toggleable&, void); + DECL_LINK(OnSpinValueChanged, weld::SpinButton&, void); + DECL_LINK(OnDriverRowChanged, weld::TreeView&, void); + + void implInitControls(const SfxItemSet& _rSet); + + void commitTimeoutField(); + }; + +} // namespace offapp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/connpoolsettings.cxx b/cui/source/options/connpoolsettings.cxx new file mode 100644 index 0000000000..e92b26da55 --- /dev/null +++ b/cui/source/options/connpoolsettings.cxx @@ -0,0 +1,84 @@ +/* -*- 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 <utility> + +#include "connpoolsettings.hxx" + + +namespace offapp +{ + + DriverPooling::DriverPooling( OUString _aName ) + :sName(std::move(_aName)) + ,bEnabled(false) + ,nTimeoutSeconds(120) + { + } + + + bool DriverPooling::operator == (const DriverPooling& _rR) const + { + return (sName == _rR.sName) + && (bEnabled == _rR.bEnabled) + && (nTimeoutSeconds == _rR.nTimeoutSeconds); + } + + DriverPoolingSettings::DriverPoolingSettings() + { + } + + + DriverPoolingSettingsItem::DriverPoolingSettingsItem( sal_uInt16 _nId, DriverPoolingSettings _aSettings ) + :SfxPoolItem(_nId) + ,m_aSettings(std::move(_aSettings)) + { + } + + + bool DriverPoolingSettingsItem::operator==( const SfxPoolItem& _rCompare ) const + { + assert(SfxPoolItem::operator==(_rCompare)); + const DriverPoolingSettingsItem* pItem = static_cast<const DriverPoolingSettingsItem*>( &_rCompare ); + + if (m_aSettings.size() != pItem->m_aSettings.size()) + return false; + + DriverPoolingSettings::const_iterator aForeign = pItem->m_aSettings.begin(); + for (auto const& ownSetting : m_aSettings) + { + if (ownSetting != *aForeign) + return false; + + ++aForeign; + } + + return true; + } + + DriverPoolingSettingsItem* DriverPoolingSettingsItem::Clone( SfxItemPool * ) const + { + return new DriverPoolingSettingsItem(*this); + } + + +} // namespace offapp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/connpoolsettings.hxx b/cui/source/options/connpoolsettings.hxx new file mode 100644 index 0000000000..1e2404b885 --- /dev/null +++ b/cui/source/options/connpoolsettings.hxx @@ -0,0 +1,86 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sal/config.h> + +#include <vector> + +#include <rtl/ustring.hxx> +#include <svl/poolitem.hxx> + + +namespace offapp +{ + + struct DriverPooling + { + OUString sName; + bool bEnabled; + sal_Int32 nTimeoutSeconds; + + explicit DriverPooling( OUString _aName ); + + bool operator == (const DriverPooling& _rR) const; + bool operator != (const DriverPooling& _rR) const { return !operator ==(_rR); } + }; + + class DriverPoolingSettings final + { + typedef std::vector<DriverPooling> DriverSettings; + DriverSettings m_aDrivers; + + public: + typedef DriverSettings::const_iterator const_iterator; + typedef DriverSettings::iterator iterator; + + DriverPoolingSettings(); + + size_t size() const { return m_aDrivers.size(); } + DriverPooling& operator[]( size_t nPos ) { return m_aDrivers[nPos]; } + bool empty() const { return m_aDrivers.empty(); } + + const_iterator begin() const { return m_aDrivers.begin(); } + const_iterator end() const { return m_aDrivers.end(); } + + iterator begin() { return m_aDrivers.begin(); } + iterator end() { return m_aDrivers.end(); } + + void push_back(const DriverPooling& _rElement) { m_aDrivers.push_back(_rElement); } + }; + + class DriverPoolingSettingsItem final : public SfxPoolItem + { + DriverPoolingSettings m_aSettings; + + public: + + DriverPoolingSettingsItem( sal_uInt16 _nId, DriverPoolingSettings _aSettings ); + + virtual bool operator==( const SfxPoolItem& ) const override; + virtual DriverPoolingSettingsItem* Clone( SfxItemPool *pPool = nullptr ) const override; + + const DriverPoolingSettings& getSettings() const { return m_aSettings; } + }; + + +} // namespace offapp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/cuisrchdlg.cxx b/cui/source/options/cuisrchdlg.cxx new file mode 100644 index 0000000000..f58985d90b --- /dev/null +++ b/cui/source/options/cuisrchdlg.cxx @@ -0,0 +1,50 @@ +/* -*- 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 <sfx2/basedlgs.hxx> + +#include <cuisrchdlg.hxx> + +#include "optjsearch.hxx" + + +// class SvxJSearchOptionsDialog ----------------------------------------- + +SvxJSearchOptionsDialog::SvxJSearchOptionsDialog(weld::Window *pParent, + const SfxItemSet& rOptionsSet, TransliterationFlags nInitialFlags) + : SfxSingleTabDialogController(pParent, &rOptionsSet) +{ + // m_xPage will be implicitly destroyed by the + // SfxSingleTabDialog destructor + SetTabPage(SvxJSearchOptionsPage::Create(get_content_area(), this, &rOptionsSet)); //! implicitly calls m_xPage->Reset(...)! + m_pPage = static_cast<SvxJSearchOptionsPage*>(GetTabPage()); + m_pPage->EnableSaveOptions(false); + m_pPage->SetTransliterationFlags(nInitialFlags); +} + +SvxJSearchOptionsDialog::~SvxJSearchOptionsDialog() +{ +} + +TransliterationFlags SvxJSearchOptionsDialog::GetTransliterationFlags() const +{ + return m_pPage->GetTransliterationFlags(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/dbregister.cxx b/cui/source/options/dbregister.cxx new file mode 100644 index 0000000000..8386cc5465 --- /dev/null +++ b/cui/source/options/dbregister.cxx @@ -0,0 +1,328 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <dbregister.hxx> +#include "dbregistersettings.hxx" +#include <o3tl/safeint.hxx> +#include <svl/filenotation.hxx> +#include <helpids.h> +#include <tools/debug.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <utility> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svl/itemset.hxx> +#include "doclinkdialog.hxx" +#include <dialmgr.hxx> +#include "dbregisterednamesconfig.hxx" +#include <svx/databaseregistrationui.hxx> +#include <o3tl/string_view.hxx> + +#define COL_TYPE 0 + +namespace svx +{ + + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::uno; +using namespace ::svt; + +// class RegistrationItemSetHolder ------------------------------------------------- + +RegistrationItemSetHolder::RegistrationItemSetHolder( SfxItemSet _aMasterSet ) + :m_aRegistrationItems(std::move( _aMasterSet )) +{ + DbRegisteredNamesConfig::GetOptions( m_aRegistrationItems ); +} + +RegistrationItemSetHolder::~RegistrationItemSetHolder() +{ +} + +// class DatabaseRegistrationDialog ------------------------------------------------ + +DatabaseRegistrationDialog::DatabaseRegistrationDialog(weld::Window* pParent, const SfxItemSet& rInAttrs) + : RegistrationItemSetHolder(rInAttrs) + , SfxSingleTabDialogController(pParent, &getRegistrationItems()) +{ + SetTabPage(DbRegistrationOptionsPage::Create(get_content_area(), this, &getRegistrationItems())); + m_xDialog->set_title(CuiResId(RID_CUISTR_REGISTERED_DATABASES)); +} + +short DatabaseRegistrationDialog::run() +{ + short result = SfxSingleTabDialogController::run(); + if (result == RET_OK) + { + DBG_ASSERT( GetOutputItemSet(), "DatabaseRegistrationDialog::Execute: no output items!" ); + if ( GetOutputItemSet() ) + DbRegisteredNamesConfig::SetOptions( *GetOutputItemSet() ); + } + return result; +} + +// class DbRegistrationOptionsPage -------------------------------------------------- + +DbRegistrationOptionsPage::DbRegistrationOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/dbregisterpage.ui", "DbRegisterPage", &rSet) + , m_nOldCount(0) + , m_bModified(false) + , m_xNew(m_xBuilder->weld_button("new")) + , m_xEdit(m_xBuilder->weld_button("edit")) + , m_xDelete(m_xBuilder->weld_button("delete")) + , m_xPathBox(m_xBuilder->weld_tree_view("pathctrl")) + , m_xIter(m_xPathBox->make_iterator()) +{ + Size aControlSize(m_xPathBox->get_approximate_digit_width() * 60, + m_xPathBox->get_height_rows(12)); + m_xPathBox->set_size_request(aControlSize.Width(), aControlSize.Height()); + + std::vector<int> aWidths + { + o3tl::narrowing<int>(m_xPathBox->get_approximate_digit_width() * 20) + }; + m_xPathBox->set_column_fixed_widths(aWidths); + + m_xNew->connect_clicked( LINK( this, DbRegistrationOptionsPage, NewHdl ) ); + m_xEdit->connect_clicked( LINK( this, DbRegistrationOptionsPage, EditHdl ) ); + m_xDelete->connect_clicked( LINK( this, DbRegistrationOptionsPage, DeleteHdl ) ); + + m_xPathBox->connect_column_clicked(LINK(this, DbRegistrationOptionsPage, HeaderSelect_Impl)); + + m_xPathBox->make_sorted(); + m_xPathBox->connect_row_activated( LINK( this, DbRegistrationOptionsPage, PathBoxDoubleClickHdl ) ); + m_xPathBox->connect_changed( LINK( this, DbRegistrationOptionsPage, PathSelect_Impl ) ); + + m_xPathBox->set_help_id(HID_DBPATH_CTL_PATH); +} + +DbRegistrationOptionsPage::~DbRegistrationOptionsPage() +{ + for (int i = 0, nCount = m_xPathBox->n_children(); i < nCount; ++i ) + delete weld::fromId<DatabaseRegistration*>(m_xPathBox->get_id(i)); +} + +std::unique_ptr<SfxTabPage> DbRegistrationOptionsPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<DbRegistrationOptionsPage>(pPage, pController, *rAttrSet); +} + +OUString DbRegistrationOptionsPage::GetAllStrings() +{ + OUString sAllStrings; + + if (const auto& pString = m_xBuilder->weld_label("label1")) + sAllStrings += pString->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool DbRegistrationOptionsPage::FillItemSet( SfxItemSet* rCoreSet ) +{ + // the settings for the single drivers + bool bModified = false; + DatabaseRegistrations aRegistrations; + int nCount = m_xPathBox->n_children(); + for (int i = 0; i < nCount; ++i) + { + DatabaseRegistration* pRegistration = weld::fromId<DatabaseRegistration*>(m_xPathBox->get_id(i)); + if ( pRegistration && !pRegistration->sLocation.isEmpty() ) + { + OUString sName(m_xPathBox->get_text(i, 0)); + OFileNotation aTransformer( pRegistration->sLocation ); + aRegistrations[ sName ] = DatabaseRegistration( aTransformer.get( OFileNotation::N_URL ), pRegistration->bReadOnly ); + } + } + if ( m_nOldCount != aRegistrations.size() || m_bModified ) + { + rCoreSet->Put(DatabaseMapItem( SID_SB_DB_REGISTER, std::move(aRegistrations) )); + bModified = true; + } + + return bModified; +} + +void DbRegistrationOptionsPage::Reset( const SfxItemSet* rSet ) +{ + // the settings for the single drivers + const DatabaseMapItem* pRegistrations = rSet->GetItem<DatabaseMapItem>(SID_SB_DB_REGISTER); + if ( !pRegistrations ) + return; + + m_xPathBox->clear(); + + const DatabaseRegistrations& rRegistrations = pRegistrations->getRegistrations(); + m_nOldCount = rRegistrations.size(); + for (auto const& elem : rRegistrations) + { + OFileNotation aTransformer( elem.second.sLocation ); + insertNewEntry( elem.first, aTransformer.get( OFileNotation::N_SYSTEM ), elem.second.bReadOnly ); + } + + OUString aUserData = GetUserData(); + if ( aUserData.isEmpty() ) + return; + + sal_Int32 nIdx {0}; + // restore column width + std::vector<int> aWidths + { + o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx)) + }; + m_xPathBox->set_column_fixed_widths(aWidths); + // restore sort direction + bool bUp = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx)) != 0; + m_xPathBox->set_sort_order(bUp); + m_xPathBox->set_sort_indicator(bUp ? TRISTATE_TRUE : TRISTATE_FALSE, COL_TYPE); +} + +void DbRegistrationOptionsPage::FillUserData() +{ + OUString aUserData = OUString::number( m_xPathBox->get_column_width(COL_TYPE) ) + ";"; + bool bUp = m_xPathBox->get_sort_order(); + aUserData += (bUp ? std::u16string_view(u"1") : std::u16string_view(u"0")); + SetUserData( aUserData ); +} + +IMPL_LINK_NOARG(DbRegistrationOptionsPage, DeleteHdl, weld::Button&, void) +{ + int nEntry = m_xPathBox->get_selected_index(); + if (nEntry != -1) + { + std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, CuiResId(RID_CUISTR_QUERY_DELETE_CONFIRM))); + if (xQuery->run() == RET_YES) + m_xPathBox->remove(nEntry); + } +} + +IMPL_LINK_NOARG(DbRegistrationOptionsPage, NewHdl, weld::Button&, void) +{ + openLinkDialog(OUString(),OUString()); +} + +IMPL_LINK_NOARG(DbRegistrationOptionsPage, PathBoxDoubleClickHdl, weld::TreeView&, bool) +{ + EditHdl(*m_xEdit); + return true; +} + +IMPL_LINK_NOARG(DbRegistrationOptionsPage, EditHdl, weld::Button&, void) +{ + int nEntry = m_xPathBox->get_selected_index(); + if (nEntry == -1) + return; + + DatabaseRegistration* pOldRegistration = weld::fromId<DatabaseRegistration*>(m_xPathBox->get_id(nEntry)); + if (!pOldRegistration || pOldRegistration->bReadOnly) + return; + + OUString sOldName = m_xPathBox->get_text(nEntry, 0); + openLinkDialog(sOldName, pOldRegistration->sLocation, nEntry); +} + +IMPL_LINK( DbRegistrationOptionsPage, HeaderSelect_Impl, int, nCol, void ) +{ + if (nCol != COL_TYPE) + return; + + bool bSortMode = m_xPathBox->get_sort_order(); + + //set new arrow positions in headerbar + bSortMode = !bSortMode; + m_xPathBox->set_sort_order(bSortMode); + + //sort lists + m_xPathBox->set_sort_indicator(bSortMode ? TRISTATE_TRUE : TRISTATE_FALSE, nCol); +} + +IMPL_LINK_NOARG(DbRegistrationOptionsPage, PathSelect_Impl, weld::TreeView&, void) +{ + DatabaseRegistration* pRegistration = weld::fromId<DatabaseRegistration*>(m_xPathBox->get_selected_id()); + + bool bReadOnly = true; + if (pRegistration) + { + bReadOnly = pRegistration->bReadOnly; + } + + m_xEdit->set_sensitive( !bReadOnly ); + m_xDelete->set_sensitive( !bReadOnly ); +} + +void DbRegistrationOptionsPage::insertNewEntry(const OUString& _sName,const OUString& _sLocation, const bool _bReadOnly) +{ + OUString sId(weld::toId(new DatabaseRegistration(_sLocation, _bReadOnly))); + m_xPathBox->insert(nullptr, -1, &_sName, &sId, nullptr, nullptr, false, m_xIter.get()); + + if (_bReadOnly) + m_xPathBox->set_image(*m_xIter, RID_SVXBMP_LOCK); + + m_xPathBox->set_text(*m_xIter, _sLocation, 1); +} + +void DbRegistrationOptionsPage::openLinkDialog(const OUString& sOldName, const OUString& sOldLocation, int nEntry) +{ + ODocumentLinkDialog aDlg(GetFrameWeld(), nEntry == -1); + + aDlg.setLink(sOldName, sOldLocation); + + // tdf#149195: control the name (ie check duplicate) only if new entry case + if (nEntry == -1) + aDlg.setNameValidator(LINK( this, DbRegistrationOptionsPage, NameValidator ) ); + + if (aDlg.run() != RET_OK) + return; + + OUString sNewName,sNewLocation; + aDlg.getLink(sNewName,sNewLocation); + if ( nEntry == -1 || sNewName != sOldName || sNewLocation != sOldLocation ) + { + if (nEntry != -1) + { + delete weld::fromId<DatabaseRegistration*>(m_xPathBox->get_id(nEntry)); + m_xPathBox->remove(nEntry); + } + insertNewEntry( sNewName, sNewLocation, false ); + m_bModified = true; + } +} + +IMPL_LINK( DbRegistrationOptionsPage, NameValidator, const OUString&, _rName, bool ) +{ + int nCount = m_xPathBox->n_children(); + for (int i = 0; i < nCount; ++i) + { + if (m_xPathBox->get_text(i, 0) == _rName) + return false; + } + return true; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/dbregisterednamesconfig.cxx b/cui/source/options/dbregisterednamesconfig.cxx new file mode 100644 index 0000000000..edbf316856 --- /dev/null +++ b/cui/source/options/dbregisterednamesconfig.cxx @@ -0,0 +1,122 @@ +/* -*- 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 "dbregisterednamesconfig.hxx" +#include "dbregistersettings.hxx" +#include <svx/databaseregistrationui.hxx> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <comphelper/processfactory.hxx> +#include <svl/itemset.hxx> +#include <comphelper/diagnose_ex.hxx> + + +namespace svx +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::container; + + void DbRegisteredNamesConfig::GetOptions( SfxItemSet& _rFillItems ) + { + DatabaseRegistrations aSettings; + + try + { + Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() ); + Reference< XDatabaseContext > xRegistrations( + DatabaseContext::create(xContext) ); + + Sequence< OUString > aRegistrationNames( xRegistrations->getRegistrationNames() ); + const OUString* pRegistrationName = aRegistrationNames.getConstArray(); + const OUString* pRegistrationNamesEnd = pRegistrationName + aRegistrationNames.getLength(); + for ( ; pRegistrationName != pRegistrationNamesEnd; ++pRegistrationName ) + { + OUString sLocation( xRegistrations->getDatabaseLocation( *pRegistrationName ) ); + aSettings[ *pRegistrationName ] = + DatabaseRegistration( sLocation, xRegistrations->isDatabaseRegistrationReadOnly( *pRegistrationName ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("cui.options"); + } + + _rFillItems.Put( DatabaseMapItem( SID_SB_DB_REGISTER, std::move(aSettings) ) ); + } + + + void DbRegisteredNamesConfig::SetOptions(const SfxItemSet& _rSourceItems) + { + // the settings for the single drivers + const DatabaseMapItem* pRegistrations = _rSourceItems.GetItem<DatabaseMapItem>(SID_SB_DB_REGISTER); + if ( !pRegistrations ) + return; + + try + { + Reference< XDatabaseContext > xRegistrations( + DatabaseContext::create( + comphelper::getProcessComponentContext())); + + const DatabaseRegistrations& rNewRegistrations = pRegistrations->getRegistrations(); + for ( DatabaseRegistrations::const_iterator reg = rNewRegistrations.begin(); + reg != rNewRegistrations.end(); + ++reg + ) + { + const OUString sName = reg->first; + const OUString sLocation = reg->second.sLocation; + + if ( xRegistrations->hasRegisteredDatabase( sName ) ) + { + if ( !xRegistrations->isDatabaseRegistrationReadOnly( sName ) ) + xRegistrations->changeDatabaseLocation( sName, sLocation ); + else + { + OSL_ENSURE( xRegistrations->getDatabaseLocation( sName ) == sLocation, + "DbRegisteredNamesConfig::SetOptions: somebody changed a read-only registration. How unrespectful." ); + } + } + else + xRegistrations->registerDatabaseLocation( sName, sLocation ); + } + + // delete unused entries + Sequence< OUString > aRegistrationNames = xRegistrations->getRegistrationNames(); + const OUString* pRegistrationName = aRegistrationNames.getConstArray(); + const OUString* pRegistrationNamesEnd = pRegistrationName + aRegistrationNames.getLength(); + for ( ; pRegistrationName != pRegistrationNamesEnd; ++pRegistrationName ) + { + if ( rNewRegistrations.find( *pRegistrationName ) == rNewRegistrations.end() ) + xRegistrations->revokeDatabaseLocation( *pRegistrationName ); + } + } + catch( const Exception& ) + { + //DBG_UNHANDLED_EXCEPTION(); + } + } + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/dbregisterednamesconfig.hxx b/cui/source/options/dbregisterednamesconfig.hxx new file mode 100644 index 0000000000..9decf7e113 --- /dev/null +++ b/cui/source/options/dbregisterednamesconfig.hxx @@ -0,0 +1,38 @@ +/* -*- 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 . + */ + +#pragma once + +class SfxItemSet; + +namespace svx +{ + + class DbRegisteredNamesConfig + { + + public: + static void GetOptions(SfxItemSet& _rFillItems); + static void SetOptions(const SfxItemSet& _rSourceItems); + }; + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/dbregistersettings.cxx b/cui/source/options/dbregistersettings.cxx new file mode 100644 index 0000000000..c544e1111f --- /dev/null +++ b/cui/source/options/dbregistersettings.cxx @@ -0,0 +1,55 @@ +/* -*- 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 "dbregistersettings.hxx" + +#include <rtl/ustring.hxx> + + +namespace svx +{ + + DatabaseMapItem::DatabaseMapItem( sal_uInt16 _nId, DatabaseRegistrations&& _rRegistrations ) + :SfxPoolItem( _nId ) + ,m_aRegistrations( std::move(_rRegistrations) ) + { + } + + bool DatabaseMapItem::operator==( const SfxPoolItem& _rCompare ) const + { + if (!SfxPoolItem::operator==(_rCompare)) + return false; + const DatabaseMapItem* pItem = static_cast<const DatabaseMapItem*>( &_rCompare ); + if ( !pItem ) + return false; + + if ( m_aRegistrations.size() != pItem->m_aRegistrations.size() ) + return false; + + return m_aRegistrations == pItem->m_aRegistrations; + } + + DatabaseMapItem* DatabaseMapItem::Clone( SfxItemPool* ) const + { + return new DatabaseMapItem( *this ); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/dbregistersettings.hxx b/cui/source/options/dbregistersettings.hxx new file mode 100644 index 0000000000..b1db16542f --- /dev/null +++ b/cui/source/options/dbregistersettings.hxx @@ -0,0 +1,80 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sal/config.h> + +#include <map> + +#include <svl/poolitem.hxx> +#include <utility> + + +namespace svx +{ + + + struct DatabaseRegistration + { + OUString sLocation; + bool bReadOnly; + + DatabaseRegistration() + :sLocation() + ,bReadOnly( true ) + { + } + + DatabaseRegistration( OUString _aLocation, const bool _bReadOnly ) + :sLocation(std::move( _aLocation )) + ,bReadOnly( _bReadOnly ) + { + } + + bool operator==( const DatabaseRegistration& _rhs ) const + { + return ( sLocation == _rhs.sLocation ); + // do not take the read-only-ness into account, this is not maintained everywhere, but only + // properly set when filling the struct from the XDatabaseRegistrations data + } + + }; + + typedef std::map< OUString, DatabaseRegistration > DatabaseRegistrations; + + class DatabaseMapItem final : public SfxPoolItem + { + DatabaseRegistrations m_aRegistrations; + + public: + + DatabaseMapItem( sal_uInt16 _nId, DatabaseRegistrations&& _rRegistrations ); + + virtual bool operator==( const SfxPoolItem& ) const override; + virtual DatabaseMapItem* Clone( SfxItemPool *pPool = nullptr ) const override; + + const DatabaseRegistrations& + getRegistrations() const { return m_aRegistrations; } + }; + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/doclinkdialog.cxx b/cui/source/options/doclinkdialog.cxx new file mode 100644 index 0000000000..f938399140 --- /dev/null +++ b/cui/source/options/doclinkdialog.cxx @@ -0,0 +1,244 @@ +/* -*- 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 "doclinkdialog.hxx" + +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <comphelper/processfactory.hxx> +#include <officecfg/Office/DataAccess.hxx> +#include <strings.hrc> +#include <svl/filenotation.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <ucbhelper/content.hxx> +#include <dialmgr.hxx> +#include <tools/urlobj.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/docfilt.hxx> + +namespace svx +{ + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::ucb; + using namespace ::svt; + + ODocumentLinkDialog::ODocumentLinkDialog(weld::Window* pParent, bool _bCreateNew) + : GenericDialogController(pParent, "cui/ui/databaselinkdialog.ui", "DatabaseLinkDialog") + , m_xBrowseFile(m_xBuilder->weld_button("browse")) + , m_xName(m_xBuilder->weld_entry("name")) + , m_xOK(m_xBuilder->weld_button("ok")) + , m_xAltTitle(m_xBuilder->weld_label("alttitle")) + , m_xURL(new SvtURLBox(m_xBuilder->weld_combo_box("url"))) + { + if (!_bCreateNew) + m_xDialog->set_title(m_xAltTitle->get_label()); + + m_xURL->SetSmartProtocol(INetProtocol::File); + m_xURL->DisableHistory(); + m_xURL->SetFilter(u"*.odb"); + + css::uno::Reference < css::uno::XComponentContext > xContext(::comphelper::getProcessComponentContext()); + m_xReadWriteAccess = css::configuration::ReadWriteAccess::create(xContext, "*"); + + m_xName->connect_changed( LINK(this, ODocumentLinkDialog, OnEntryModified) ); + m_xURL->connect_changed( LINK(this, ODocumentLinkDialog, OnComboBoxModified) ); + m_xBrowseFile->connect_clicked( LINK(this, ODocumentLinkDialog, OnBrowseFile) ); + m_xOK->connect_clicked( LINK(this, ODocumentLinkDialog, OnOk) ); + + validate(); + } + + ODocumentLinkDialog::~ODocumentLinkDialog() + { + } + + void ODocumentLinkDialog::setLink(const OUString& rName, const OUString& rURL) + { + m_xName->set_text(rName); + m_xURL->set_entry_text(rURL); + validate(); + } + + void ODocumentLinkDialog::getLink(OUString& rName, OUString& rURL) const + { + rName = m_xName->get_text(); + rURL = m_xURL->get_active_text(); + } + + void ODocumentLinkDialog::validate( ) + { + m_xOK->set_sensitive((!m_xName->get_text().isEmpty()) && (!m_xURL->get_active_text().isEmpty())); + + if (m_xOK->get_sensitive()) + { + Reference<container::XNameAccess> xItemList = officecfg::Office::DataAccess::RegisteredNames::get(); + Sequence< OUString > lNodeNames = xItemList->getElementNames(); + + for (const OUString& sNodeName : lNodeNames) + { + Reference<css::beans::XPropertySet> xSet; + xItemList->getByName(sNodeName) >>= xSet; + + OUString aDatabaseName; + if (xSet->getPropertySetInfo()->hasPropertyByName("Name")) + xSet->getPropertyValue("Name") >>= aDatabaseName; + + if (!aDatabaseName.isEmpty() && m_xName->get_text() == aDatabaseName) + { + const OUString aConfigPath = officecfg::Office::DataAccess::RegisteredNames::path() + "/" + sNodeName; + if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath + "/Name")) + { + css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath + "/Name"); + bool bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0; + + m_xURL->set_sensitive(!bReadOnly); + m_xBrowseFile->set_sensitive(!bReadOnly); + } + + if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath + "/Location")) + { + css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath + "/Location"); + bool bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0; + + m_xName->set_sensitive(!bReadOnly); + } + break; + } + } + } + } + + IMPL_LINK_NOARG(ODocumentLinkDialog, OnOk, weld::Button&, void) + { + // get the current URL + OUString sURL = m_xURL->get_active_text(); + OFileNotation aTransformer(sURL); + sURL = aTransformer.get(OFileNotation::N_URL); + + // check for the existence of the selected file + bool bFileExists = false; + try + { + ::ucbhelper::Content aFile(sURL, Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext()); + if (aFile.isDocument()) + bFileExists = true; + } + catch(Exception&) + { + } + + if (!bFileExists) + { + OUString sMsg = CuiResId(STR_LINKEDDOC_DOESNOTEXIST); + sMsg = sMsg.replaceFirst("$file$", m_xURL->get_active_text()); + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, sMsg)); + xErrorBox->run(); + return; + } // if (!bFileExists) + INetURLObject aURL( sURL ); + if ( aURL.GetProtocol() != INetProtocol::File ) + { + OUString sMsg = CuiResId(STR_LINKEDDOC_NO_SYSTEM_FILE); + sMsg = sMsg.replaceFirst("$file$", m_xURL->get_active_text()); + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, sMsg)); + xErrorBox->run(); + return; + } + + OUString sCurrentText = m_xName->get_text(); + if ( m_aNameValidator.IsSet() ) + { + if ( !m_aNameValidator.Call( sCurrentText ) ) + { + OUString sMsg = CuiResId(STR_NAME_CONFLICT); + sMsg = sMsg.replaceFirst("$file$", sCurrentText); + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, sMsg)); + xErrorBox->run(); + + m_xName->select_region(0, -1); + m_xName->grab_focus(); + return; + } + } + + m_xDialog->response(RET_OK); + } + + IMPL_LINK_NOARG(ODocumentLinkDialog, OnBrowseFile, weld::Button&, void) + { + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, FileDialogFlags::NONE, m_xDialog.get()); + std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)"); + if ( pFilter ) + { + aFileDlg.AddFilter(pFilter->GetUIName(),pFilter->GetDefaultExtension()); + aFileDlg.SetCurrentFilter(pFilter->GetUIName()); + } + + OUString sPath = m_xURL->get_active_text(); + if (!sPath.isEmpty()) + { + OFileNotation aTransformer( sPath, OFileNotation::N_SYSTEM ); + aFileDlg.SetDisplayDirectory( aTransformer.get( OFileNotation::N_URL ) ); + } + + if (ERRCODE_NONE != aFileDlg.Execute()) + return; + + if (m_xName->get_text().isEmpty()) + { // default the name to the base of the chosen URL + INetURLObject aParser; + + aParser.SetSmartProtocol(INetProtocol::File); + aParser.SetSmartURL(aFileDlg.GetPath()); + + m_xName->set_text(aParser.getBase(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset)); + + m_xName->select_region(0, -1); + m_xName->grab_focus(); + } + else + m_xURL->grab_focus(); + + // get the path in system notation + OFileNotation aTransformer(aFileDlg.GetPath(), OFileNotation::N_URL); + m_xURL->set_entry_text(aTransformer.get(OFileNotation::N_SYSTEM)); + + validate(); + } + + IMPL_LINK_NOARG(ODocumentLinkDialog, OnEntryModified, weld::Entry&, void) + { + validate(); + } + + IMPL_LINK_NOARG(ODocumentLinkDialog, OnComboBoxModified, weld::ComboBox&, void) + { + validate(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/doclinkdialog.hxx b/cui/source/options/doclinkdialog.hxx new file mode 100644 index 0000000000..3ea0d5027d --- /dev/null +++ b/cui/source/options/doclinkdialog.hxx @@ -0,0 +1,64 @@ +/* -*- 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 . + */ + +#pragma once + +#include <vcl/weld.hxx> +#include <svtools/inettbc.hxx> +#include <com/sun/star/configuration/ReadWriteAccess.hpp> + +namespace svx +{ + /** dialog for editing document links associated with data sources + */ + class ODocumentLinkDialog final : public weld::GenericDialogController + { + Link<const OUString&,bool> m_aNameValidator; + + css::uno::Reference< css::configuration::XReadWriteAccess> m_xReadWriteAccess; + + std::unique_ptr<weld::Button> m_xBrowseFile; + std::unique_ptr<weld::Entry> m_xName; + std::unique_ptr<weld::Button> m_xOK; + std::unique_ptr<weld::Label> m_xAltTitle; + std::unique_ptr<SvtURLBox> m_xURL; + + public: + ODocumentLinkDialog(weld::Window* pParent, bool bCreateNew); + virtual ~ODocumentLinkDialog() override; + + // name validation has to be done by an external instance + // the validator link gets a pointer to a String, and should return 0 if the string is not + // acceptable + void setNameValidator( const Link<const OUString&,bool>& _rValidator ) { m_aNameValidator = _rValidator; } + + void setLink( const OUString& _rName, const OUString& _rURL ); + void getLink( OUString& _rName, OUString& _rURL ) const; + + private: + DECL_LINK( OnEntryModified, weld::Entry&, void ); + DECL_LINK( OnComboBoxModified, weld::ComboBox&, void ); + DECL_LINK( OnBrowseFile, weld::Button&, void ); + DECL_LINK( OnOk, weld::Button&, void ); + + void validate(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/fontsubs.cxx b/cui/source/options/fontsubs.cxx new file mode 100644 index 0000000000..4d61a873e2 --- /dev/null +++ b/cui/source/options/fontsubs.cxx @@ -0,0 +1,449 @@ +/* -*- 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 <sal/config.h> + +#include <officecfg/Office/Common.hxx> +#include <svtools/ctrltool.hxx> +#include <vcl/svapp.hxx> +#include <svtools/fontsubstconfig.hxx> +#include "fontsubs.hxx" +#include <helpids.h> + +/*********************************************************************/ +/* */ +/* TabPage font replacement */ +/* */ +/*********************************************************************/ + +SvxFontSubstTabPage::SvxFontSubstTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optfontspage.ui", "OptFontsPage", &rSet) + , m_xUseTableCB(m_xBuilder->weld_check_button("usetable")) + , m_xUseTableImg(m_xBuilder->weld_widget("lockusetable")) + , m_xFont1CB(m_xBuilder->weld_combo_box("font1")) + , m_xFont2CB(m_xBuilder->weld_combo_box("font2")) + , m_xApply(m_xBuilder->weld_button("apply")) + , m_xDelete(m_xBuilder->weld_button("delete")) + , m_xCheckLB(m_xBuilder->weld_tree_view("checklb")) + , m_xFontNameLB(m_xBuilder->weld_combo_box("fontname")) + , m_xFontNameLabel(m_xBuilder->weld_label("label8")) + , m_xFontNameImg(m_xBuilder->weld_widget("lockfontname")) + , m_xNonPropFontsOnlyCB(m_xBuilder->weld_check_button("nonpropfontonly")) + , m_xNonPropFontsOnlyImg(m_xBuilder->weld_widget("locknonpropfontonly")) + , m_xFontHeightLB(m_xBuilder->weld_combo_box("fontheight")) + , m_xFontHeightLabel(m_xBuilder->weld_label("label9")) + , m_xFontHeightImg(m_xBuilder->weld_widget("lockfontheight")) +{ + m_xFont1CB->make_sorted(); + m_xFont1CB->set_size_request(1, -1); + m_xFont2CB->make_sorted(); + m_xFont2CB->set_size_request(1, -1); + m_sAutomatic = m_xFontNameLB->get_text(0); + assert(!m_sAutomatic.isEmpty()); + + m_xCheckLB->set_size_request(m_xCheckLB->get_approximate_digit_width() * 60, + m_xCheckLB->get_height_rows(8)); + m_xCheckLB->enable_toggle_buttons(weld::ColumnToggleType::Check); + m_xCheckLB->set_help_id(HID_OFA_FONT_SUBST_CLB); + m_xCheckLB->set_selection_mode(SelectionMode::Multiple); + + setColSizes(m_xCheckLB->get_size_request()); + m_xCheckLB->connect_size_allocate(LINK(this, SvxFontSubstTabPage, ResizeHdl)); + + m_xCheckLB->set_centered_column(0); + m_xCheckLB->set_centered_column(1); + + Link<weld::ComboBox&,void> aLink2(LINK(this, SvxFontSubstTabPage, SelectComboBoxHdl)); + Link<weld::Button&,void> aClickLink(LINK(this, SvxFontSubstTabPage, ClickHdl)); + + m_xCheckLB->connect_changed(LINK(this, SvxFontSubstTabPage, TreeListBoxSelectHdl)); + m_xCheckLB->connect_column_clicked(LINK(this, SvxFontSubstTabPage, HeaderBarClick)); + m_xUseTableCB->connect_toggled(LINK(this, SvxFontSubstTabPage, ToggleHdl)); + m_xFont1CB->connect_changed(aLink2); + m_xFont2CB->connect_changed(aLink2); + m_xApply->connect_clicked(aClickLink); + m_xDelete->connect_clicked(aClickLink); + + m_xNonPropFontsOnlyCB->connect_toggled(LINK(this, SvxFontSubstTabPage, NonPropFontsHdl)); + + sal_uInt16 nHeight; + for(nHeight = 6; nHeight <= 16; nHeight++) + m_xFontHeightLB->append_text(OUString::number(nHeight)); + for(nHeight = 18; nHeight <= 28; nHeight+= 2) + m_xFontHeightLB->append_text(OUString::number(nHeight)); + for(nHeight = 32; nHeight <= 48; nHeight+= 4) + m_xFontHeightLB->append_text(OUString::number(nHeight)); + for(nHeight = 54; nHeight <= 72; nHeight+= 6) + m_xFontHeightLB->append_text(OUString::number(nHeight)); + for(nHeight = 80; nHeight <= 96; nHeight+= 8) + m_xFontHeightLB->append_text(OUString::number(nHeight)); +} + +IMPL_LINK(SvxFontSubstTabPage, HeaderBarClick, int, nColumn, void) +{ + bool bSortAtoZ = m_xCheckLB->get_sort_order(); + + //set new arrow positions in headerbar + if (nColumn == m_xCheckLB->get_sort_column()) + { + bSortAtoZ = !bSortAtoZ; + m_xCheckLB->set_sort_order(bSortAtoZ); + } + else + { + m_xCheckLB->set_sort_indicator(TRISTATE_INDET, m_xCheckLB->get_sort_column()); + m_xCheckLB->set_sort_column(nColumn); + } + + if (nColumn != -1) + { + //sort lists + m_xCheckLB->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn); + } +} + +void SvxFontSubstTabPage::setColSizes(const Size& rSize) +{ + int nW1 = m_xCheckLB->get_pixel_size(m_xCheckLB->get_column_title(2)).Width(); + int nW2 = m_xCheckLB->get_pixel_size(m_xCheckLB->get_column_title(3)).Width(); + int nMax = std::max( nW1, nW2 ) + 6; // width of the longest header + a little offset + int nMin = m_xCheckLB->get_checkbox_column_width(); + nMax = std::max(nMax, nMin); + const int nDoubleMax = 2*nMax; + const int nRest = rSize.Width() - nDoubleMax; + std::vector<int> aWidths { nMax, nMax, nRest/2 }; + m_xCheckLB->set_column_fixed_widths(aWidths); +} + +IMPL_LINK(SvxFontSubstTabPage, ResizeHdl, const Size&, rSize, void) +{ + setColSizes(rSize); +} + +SvxFontSubstTabPage::~SvxFontSubstTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SvxFontSubstTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SvxFontSubstTabPage>(pPage, pController, *rAttrSet); +} + +OUString SvxFontSubstTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label4", "label2", "label3", "label1", "label8", "label9" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "usetable", "nonpropfontonly" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxFontSubstTabPage::FillItemSet( SfxItemSet* ) +{ + std::vector<SubstitutionStruct> aNewFontSubs; + + m_xCheckLB->all_foreach([this, &aNewFontSubs](weld::TreeIter& rIter) { + SubstitutionStruct aAdd; + aAdd.sFont = m_xCheckLB->get_text(rIter, 2); + aAdd.sReplaceBy = m_xCheckLB->get_text(rIter, 3); + aAdd.bReplaceAlways = m_xCheckLB->get_toggle(rIter, 0); + aAdd.bReplaceOnScreenOnly = m_xCheckLB->get_toggle(rIter, 1); + aNewFontSubs.push_back(aAdd); + return false; + }); + + svtools::SetFontSubstitutions(m_xUseTableCB->get_active(), aNewFontSubs); + svtools::ApplyFontSubstitutionsToVcl(); + + std::shared_ptr< comphelper::ConfigurationChanges > batch( + comphelper::ConfigurationChanges::create()); + if (m_xFontHeightLB->get_value_changed_from_saved()) + officecfg::Office::Common::Font::SourceViewFont::FontHeight::set( + static_cast< sal_Int16 >(m_xFontHeightLB->get_active_text().toInt32()), + batch); + if (m_xNonPropFontsOnlyCB->get_state_changed_from_saved()) + officecfg::Office::Common::Font::SourceViewFont:: + NonProportionalFontsOnly::set( + m_xNonPropFontsOnlyCB->get_active(), batch); + //font name changes cannot be detected by saved values + OUString sFontName; + if (m_xFontNameLB->get_active() != -1) + sFontName = m_xFontNameLB->get_active_text(); + officecfg::Office::Common::Font::SourceViewFont::FontName::set( + std::optional< OUString >(sFontName), batch); + batch->commit(); + + return false; +} + +void SvxFontSubstTabPage::Reset( const SfxItemSet* ) +{ + m_xCheckLB->freeze(); + m_xCheckLB->clear(); + + m_xFont1CB->freeze(); + m_xFont1CB->clear(); + m_xFont2CB->freeze(); + m_xFont2CB->clear(); + + FontList aFntLst(Application::GetDefaultDevice()); + sal_uInt16 nFontCount = aFntLst.GetFontNameCount(); + for (sal_uInt16 i = 0; i < nFontCount; ++i) + { + const FontMetric& rFontMetric = aFntLst.GetFontName(i); + m_xFont1CB->append_text(rFontMetric.GetFamilyName()); + m_xFont2CB->append_text(rFontMetric.GetFamilyName()); + } + + m_xFont2CB->thaw(); + m_xFont1CB->thaw(); + + bool bEnable = !officecfg::Office::Common::Font::Substitution::Replacement::isReadOnly(); + m_xUseTableCB->set_active(svtools::IsFontSubstitutionsEnabled()); + m_xUseTableCB->set_sensitive(bEnable); + m_xUseTableImg->set_visible(!bEnable); + + std::vector<SubstitutionStruct> aFontSubs = svtools::GetFontSubstitutions(); + std::unique_ptr<weld::TreeIter> xIter(m_xCheckLB->make_iterator()); + for (auto const & sub: aFontSubs) + { + m_xCheckLB->append(xIter.get()); + m_xCheckLB->set_toggle(*xIter, sub.bReplaceAlways ? TRISTATE_TRUE : TRISTATE_FALSE, 0); + m_xCheckLB->set_toggle(*xIter, sub.bReplaceOnScreenOnly ? TRISTATE_TRUE : TRISTATE_FALSE, 1); + m_xCheckLB->set_text(*xIter, sub.sFont, 2); + m_xCheckLB->set_text(*xIter, sub.sReplaceBy, 3); + } + + m_xCheckLB->thaw(); + + m_xCheckLB->make_sorted(); + m_xCheckLB->set_sort_column(2); + m_xCheckLB->set_sort_indicator(TRISTATE_TRUE, 2); + + SelectHdl(m_xFont1CB.get()); + + //fill font name box first + m_xNonPropFontsOnlyCB->set_active( + officecfg::Office::Common::Font::SourceViewFont:: + NonProportionalFontsOnly::get()); + NonPropFontsHdl(*m_xNonPropFontsOnlyCB); + OUString sFontName( + officecfg::Office::Common::Font::SourceViewFont::FontName::get(). + value_or(OUString())); + if(!sFontName.isEmpty()) + m_xFontNameLB->set_active_text(sFontName); + else + m_xFontNameLB->set_active(0); + m_xFontHeightLB->set_active_text( + OUString::number( + officecfg::Office::Common::Font::SourceViewFont::FontHeight:: + get())); + + bEnable = !officecfg::Office::Common::Font::SourceViewFont::FontName::isReadOnly(); + m_xFontNameLB->set_sensitive(bEnable); + m_xFontNameLabel->set_sensitive(bEnable); + m_xFontNameImg->set_visible(!bEnable); + + m_xNonPropFontsOnlyCB->set_sensitive(bEnable); + m_xNonPropFontsOnlyImg->set_visible(!bEnable); + + m_xFontHeightLB->set_sensitive(bEnable); + m_xFontHeightLabel->set_sensitive(bEnable); + m_xFontHeightImg->set_visible(!bEnable); + + m_xNonPropFontsOnlyCB->save_state(); + m_xFontHeightLB->save_value(); +} + +IMPL_LINK(SvxFontSubstTabPage, ToggleHdl, weld::Toggleable&, rButton, void) +{ + SelectHdl(&rButton); +} + +IMPL_LINK(SvxFontSubstTabPage, ClickHdl, weld::Button&, rButton, void) +{ + SelectHdl(&rButton); +} + +IMPL_LINK(SvxFontSubstTabPage, TreeListBoxSelectHdl, weld::TreeView&, rButton, void) +{ + SelectHdl(&rButton); +} + +IMPL_LINK(SvxFontSubstTabPage, SelectComboBoxHdl, weld::ComboBox&, rBox, void) +{ + SelectHdl(&rBox); +} + +namespace +{ + // search in the "font" column + int findText(const weld::TreeView& rTreeView, std::u16string_view rCol) + { + for (int i = 0, nEntryCount = rTreeView.n_children(); i < nEntryCount; ++i) + { + if (rTreeView.get_text(i, 2) == rCol) + return i; + } + return -1; + } + + bool findRow(const weld::TreeView& rTreeView, std::u16string_view rCol1, std::u16string_view rCol2) + { + int nRow = findText(rTreeView, rCol1); + if (nRow == -1) + return false; + return rTreeView.get_text(nRow, 3) == rCol2; + } +} + +void SvxFontSubstTabPage::SelectHdl(const weld::Widget* pWin) +{ + if (pWin == m_xApply.get() || pWin == m_xDelete.get()) + { + int nPos = findText(*m_xCheckLB, m_xFont1CB->get_active_text()); + if (pWin == m_xApply.get()) + { + m_xCheckLB->unselect_all(); + if (nPos != -1) + { + // change entry + m_xCheckLB->set_text(nPos, m_xFont2CB->get_active_text(), 3); + m_xCheckLB->select(nPos); + } + else + { + // new entry + OUString sFont1 = m_xFont1CB->get_active_text(); + OUString sFont2 = m_xFont2CB->get_active_text(); + + std::unique_ptr<weld::TreeIter> xIter(m_xCheckLB->make_iterator()); + m_xCheckLB->append(xIter.get()); + m_xCheckLB->set_toggle(*xIter, TRISTATE_FALSE, 0); + m_xCheckLB->set_toggle(*xIter, TRISTATE_FALSE, 1); + m_xCheckLB->set_text(*xIter, sFont1, 2); + m_xCheckLB->set_text(*xIter, sFont2, 3); + m_xCheckLB->select(*xIter); + } + } + else if (pWin == m_xDelete.get()) + { + m_xCheckLB->remove_selection(); + } + } + + if (pWin == m_xCheckLB.get()) + { + const int nSelectedRowCount = m_xCheckLB->count_selected_rows(); + if (nSelectedRowCount == 1) + { + int nRow = m_xCheckLB->get_selected_index(); + m_xFont1CB->set_entry_text(m_xCheckLB->get_text(nRow, 2)); + m_xFont2CB->set_entry_text(m_xCheckLB->get_text(nRow, 3)); + } + else if (nSelectedRowCount > 1) + { + m_xFont1CB->set_entry_text(OUString()); + m_xFont2CB->set_entry_text(OUString()); + } + } + + if (pWin == m_xFont1CB.get()) + { + int nPos = findText(*m_xCheckLB, m_xFont1CB->get_active_text()); + + if (nPos != -1) + { + int nSelectedRow = m_xCheckLB->get_selected_index(); + if (nPos != nSelectedRow) + { + m_xCheckLB->unselect_all(); + m_xCheckLB->select(nPos); + } + } + else + m_xCheckLB->unselect_all(); + } + + CheckEnable(); +} + +IMPL_LINK(SvxFontSubstTabPage, NonPropFontsHdl, weld::Toggleable&, rBox, void) +{ + OUString sFontName = m_xFontNameLB->get_active_text(); + bool bNonPropOnly = rBox.get_active(); + m_xFontNameLB->clear(); + FontList aFntLst( Application::GetDefaultDevice() ); + m_xFontNameLB->append_text(m_sAutomatic); + sal_uInt16 nFontCount = aFntLst.GetFontNameCount(); + for(sal_uInt16 nFont = 0; nFont < nFontCount; nFont++) + { + const FontMetric& rFontMetric = aFntLst.GetFontName( nFont ); + if(!bNonPropOnly || rFontMetric.GetPitch() == PITCH_FIXED) + m_xFontNameLB->append_text(rFontMetric.GetFamilyName()); + } + m_xFontNameLB->set_active_text(sFontName); +} + +void SvxFontSubstTabPage::CheckEnable() +{ + bool bEnableAll = m_xUseTableCB->get_active() && !officecfg::Office::Common::Font::SourceViewFont::FontName::isReadOnly(); + m_xCheckLB->set_sensitive(bEnableAll); + m_xFont1CB->set_sensitive(bEnableAll); + m_xFont2CB->set_sensitive(bEnableAll); + + bool bApply = bEnableAll, bDelete = bEnableAll; + + if (bEnableAll) + { + int nEntry = m_xCheckLB->get_selected_index(); + + if (m_xFont1CB->get_active_text().isEmpty() || m_xFont2CB->get_active_text().isEmpty()) + bApply = false; + else if (m_xFont1CB->get_active_text() == m_xFont2CB->get_active_text()) + bApply = false; + else if (findRow(*m_xCheckLB, m_xFont1CB->get_active_text(), m_xFont2CB->get_active_text())) + bApply = false; + else if (nEntry != -1 && m_xCheckLB->count_selected_rows() != 1) + bApply = false; + else + bApply = true; + + bDelete = nEntry != -1; + } + + m_xApply->set_sensitive(bApply); + m_xDelete->set_sensitive(bDelete); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/fontsubs.hxx b/cui/source/options/fontsubs.hxx new file mode 100644 index 0000000000..e91a9818e5 --- /dev/null +++ b/cui/source/options/fontsubs.hxx @@ -0,0 +1,70 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sfx2/tabdlg.hxx> + +// class SvxFontSubstTabPage ---------------------------------------------------- +class SvtFontSubstConfig; +class SvxFontSubstTabPage : public SfxTabPage +{ + OUString m_sAutomatic; + + std::unique_ptr<weld::CheckButton> m_xUseTableCB; + std::unique_ptr<weld::Widget> m_xUseTableImg; + std::unique_ptr<weld::ComboBox> m_xFont1CB; + std::unique_ptr<weld::ComboBox> m_xFont2CB; + std::unique_ptr<weld::Button> m_xApply; + std::unique_ptr<weld::Button> m_xDelete; + std::unique_ptr<weld::TreeView> m_xCheckLB; + std::unique_ptr<weld::ComboBox> m_xFontNameLB; + std::unique_ptr<weld::Label> m_xFontNameLabel; + std::unique_ptr<weld::Widget> m_xFontNameImg; + std::unique_ptr<weld::CheckButton> m_xNonPropFontsOnlyCB; + std::unique_ptr<weld::Widget> m_xNonPropFontsOnlyImg; + std::unique_ptr<weld::ComboBox> m_xFontHeightLB; + std::unique_ptr<weld::Label> m_xFontHeightLabel; + std::unique_ptr<weld::Widget> m_xFontHeightImg; + + DECL_LINK(SelectComboBoxHdl, weld::ComboBox&, void); + DECL_LINK(ToggleHdl, weld::Toggleable&, void); + DECL_LINK(ClickHdl, weld::Button&, void); + DECL_LINK(TreeListBoxSelectHdl, weld::TreeView&, void); + DECL_LINK(NonPropFontsHdl, weld::Toggleable&, void); + DECL_LINK(HeaderBarClick, int, void); + DECL_LINK(ResizeHdl, const Size&, void); + + void SelectHdl(const weld::Widget* pWidget); + + void CheckEnable(); + void setColSizes(const Size& rSize); + +public: + SvxFontSubstTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + virtual ~SvxFontSubstTabPage() override; + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optaboutconfig.cxx b/cui/source/options/optaboutconfig.cxx new file mode 100644 index 0000000000..f927363f86 --- /dev/null +++ b/cui/source/options/optaboutconfig.cxx @@ -0,0 +1,1109 @@ +/* -*- 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/. + */ + +#include "optaboutconfig.hxx" +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> + +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/configuration/ReadWriteAccess.hpp> +#include <com/sun/star/configuration/XDocumentation.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/container/XHierarchicalName.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/uno/TypeClass.hpp> +#include <com/sun/star/util/InvalidStateException.hpp> +#include <com/sun/star/util/SearchAlgorithms2.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <cppu/unotype.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <unotools/textsearch.hxx> +#include <utility> +#include <vcl/event.hxx> + +#include <dialmgr.hxx> +#include <strings.hrc> + +#include <algorithm> +#include <memory> +#include <vector> + +using namespace ::com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::container; + +struct Prop_Impl +{ + OUString Name; + OUString Property; + Any Value; + + Prop_Impl(OUString sName, OUString sProperty, Any aValue) + : Name(std::move(sName)) + , Property(std::move(sProperty)) + , Value(std::move(aValue)) + { + } +}; + +struct UserData +{ + bool bIsPropertyPath; + bool bIsReadOnly; + bool bWasModified; + OUString sPropertyPath; + Any aPropertyValue; + OUString sTooltip; + int aLineage; + Reference<XNameAccess> aXNameAccess; + + explicit UserData(OUString aPropertyPath, Any aPropValue, OUString aTooltip, bool isReadOnly, + bool wasModified) + : bIsPropertyPath(true) + , bIsReadOnly(isReadOnly) + , bWasModified(wasModified) + , sPropertyPath(std::move(aPropertyPath)) + , aPropertyValue(aPropValue) + , sTooltip(std::move(aTooltip)) + , aLineage(0) + { + } + + explicit UserData(Reference<XNameAccess> const& rXNameAccess, int rIndex) + : bIsPropertyPath(false) + , bIsReadOnly(false) + , bWasModified(false) + , aLineage(rIndex) + , aXNameAccess(rXNameAccess) + { + } +}; + +CuiAboutConfigTabPage::CuiAboutConfigTabPage(weld::Window* pParent) + : GenericDialogController(pParent, "cui/ui/aboutconfigdialog.ui", "AboutConfig") + , m_xResetBtn(m_xBuilder->weld_button("reset")) + , m_xEditBtn(m_xBuilder->weld_button("edit")) + , m_xSearchBtn(m_xBuilder->weld_button("searchButton")) + , m_xModifiedCheckBtn(m_xBuilder->weld_check_button("modifiedButton")) + , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry")) + , m_xPrefBox(m_xBuilder->weld_tree_view("preferences")) + , m_xScratchIter(m_xPrefBox->make_iterator()) + , m_bSorted(false) + , m_pParent(pParent) +{ + m_xPrefBox->set_size_request(m_xPrefBox->get_approximate_digit_width() * 100, + m_xPrefBox->get_height_rows(23)); + m_xPrefBox->connect_column_clicked(LINK(this, CuiAboutConfigTabPage, HeaderBarClick)); + + m_xEditBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, StandardHdl_Impl)); + m_xResetBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, ResetBtnHdl_Impl)); + m_xPrefBox->connect_row_activated(LINK(this, CuiAboutConfigTabPage, DoubleClickHdl_Impl)); + m_xPrefBox->connect_expanding(LINK(this, CuiAboutConfigTabPage, ExpandingHdl_Impl)); + m_xSearchBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, SearchHdl_Impl)); + m_xModifiedCheckBtn->connect_toggled(LINK(this, CuiAboutConfigTabPage, ModifiedHdl_Impl)); + + 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); + + float fWidth = m_xPrefBox->get_approximate_digit_width(); + std::vector<int> aWidths{ o3tl::narrowing<int>(fWidth * 65), o3tl::narrowing<int>(fWidth * 20), + o3tl::narrowing<int>(fWidth * 8) }; + m_xPrefBox->set_column_fixed_widths(aWidths); + + m_xPrefBox->connect_query_tooltip(LINK(this, CuiAboutConfigTabPage, QueryTooltip)); +} + +IMPL_LINK(CuiAboutConfigTabPage, QueryTooltip, const weld::TreeIter&, rIter, OUString) +{ + UserData* pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(rIter)); + OUStringBuffer ret; + if (pUserData && pUserData->bIsReadOnly) + { + ret.append(CuiResId(RID_CUISTR_OPT_READONLY)); + } + if (pUserData && !pUserData->sTooltip.isEmpty()) + { + if (pUserData->bIsReadOnly) + ret.append("\n\n"); + ret.append(pUserData->sTooltip); + } + + return ret.makeStringAndClear(); +} + +IMPL_LINK(CuiAboutConfigTabPage, HeaderBarClick, int, nColumn, void) +{ + if (!m_bSorted) + { + m_xPrefBox->make_sorted(); + m_bSorted = true; + } + + bool bSortAtoZ = m_xPrefBox->get_sort_order(); + + //set new arrow positions in headerbar + if (nColumn == m_xPrefBox->get_sort_column()) + { + bSortAtoZ = !bSortAtoZ; + m_xPrefBox->set_sort_order(bSortAtoZ); + } + else + { + int nOldSortColumn = m_xPrefBox->get_sort_column(); + if (nOldSortColumn != -1) + m_xPrefBox->set_sort_indicator(TRISTATE_INDET, nOldSortColumn); + m_xPrefBox->set_sort_column(nColumn); + } + + if (nColumn != -1) + { + //sort lists + m_xPrefBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn); + } +} + +IMPL_STATIC_LINK_NOARG(CuiAboutConfigTabPage, ValidNameHdl, SvxNameDialog&, bool) +{ + // Allow empty value + return true; +} + +CuiAboutConfigTabPage::~CuiAboutConfigTabPage() {} + +void CuiAboutConfigTabPage::InsertEntry(const OUString& rPropertyPath, Any aPropertyValue, + const OUString& rProp, const OUString& rStatus, + const OUString& rType, const OUString& rValue, + const OUString& rTooltip, + const weld::TreeIter* pParentEntry, bool bInsertToPrefBox, + bool bIsReadOnly, bool bWasModified) +{ + bool bOnlyModified = m_xModifiedCheckBtn->get_active(); + if (bOnlyModified && !bWasModified) + return; + + m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath, aPropertyValue, rTooltip, + bIsReadOnly, bWasModified)); + if (bInsertToPrefBox) + { + OUString sId(weld::toId(m_vectorUserData.back().get())); + m_xPrefBox->insert(pParentEntry, -1, &rProp, &sId, nullptr, nullptr, false, + m_xScratchIter.get()); + m_xPrefBox->set_text(*m_xScratchIter, rStatus, 1); + m_xPrefBox->set_text(*m_xScratchIter, rType, 2); + m_xPrefBox->set_text(*m_xScratchIter, rValue, 3); + m_xPrefBox->set_text_emphasis(*m_xScratchIter, bWasModified, -1); + m_xPrefBox->set_sensitive(*m_xScratchIter, !bIsReadOnly, -1); + } + else + { + m_prefBoxEntries.push_back( + { rProp, rStatus, rType, rValue, m_vectorUserData.back().get() }); + } +} + +void CuiAboutConfigTabPage::InputChanged() +{ + weld::WaitObject aWait(m_xDialog.get()); + + m_xPrefBox->hide(); + m_xPrefBox->clear(); + m_xPrefBox->freeze(); + + if (m_bSorted) + m_xPrefBox->make_unsorted(); + + if (m_xSearchEdit->get_text().isEmpty()) + { + m_xPrefBox->clear(); + Reference<XNameAccess> xConfigAccess = getConfigAccess("/", false); + FillItems(xConfigAccess); + } + else + { + m_options.searchString = m_xSearchEdit->get_text(); + utl::TextSearch textSearch(m_options); + for (auto const& it : m_prefBoxEntries) + { + sal_Int32 endPos, startPos = 0; + + for (size_t i = 0; i < 5; ++i) + { + OUString scrTxt; + + if (i == 0) + scrTxt = it.pUserData->sPropertyPath; + else if (i == 1) + scrTxt = it.sProp; + else if (i == 2) + scrTxt = it.sStatus; + else if (i == 3) + scrTxt = it.sType; + else if (i == 4) + scrTxt = it.sValue; + + endPos = scrTxt.getLength(); + if (textSearch.SearchForward(scrTxt, &startPos, &endPos)) + { + InsertEntry(it); + break; + } + } + } + } + + m_xPrefBox->thaw(); + if (m_bSorted) + m_xPrefBox->make_sorted(); + + m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) { + m_xPrefBox->expand_row(rEntry); + return false; + }); + m_xPrefBox->show(); +} + +void CuiAboutConfigTabPage::Reset() +{ + weld::WaitObject aWait(m_xDialog.get()); + + m_xPrefBox->clear(); + m_vectorOfModified.clear(); + if (m_bSorted) + { + m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column()); + m_xPrefBox->make_unsorted(); + m_bSorted = false; + } + m_prefBoxEntries.clear(); + m_modifiedPrefBoxEntries.clear(); + + m_xPrefBox->freeze(); + Reference<XNameAccess> xConfigAccess = getConfigAccess("/", false); + //Load all XNameAccess to m_prefBoxEntries + FillItems(xConfigAccess, nullptr, 0, true); + //Load xConfigAccess' children to m_prefBox + FillItems(xConfigAccess); + m_xPrefBox->thaw(); +} + +void CuiAboutConfigTabPage::FillItemSet() +{ + std::vector<std::shared_ptr<Prop_Impl>>::iterator pIter; + for (pIter = m_vectorOfModified.begin(); pIter != m_vectorOfModified.end(); ++pIter) + { + Reference<XNameAccess> xUpdateAccess = getConfigAccess((*pIter)->Name, true); + Reference<XNameReplace> xNameReplace(xUpdateAccess, UNO_QUERY_THROW); + + xNameReplace->replaceByName((*pIter)->Property, (*pIter)->Value); + + Reference<util::XChangesBatch> xChangesBatch(xUpdateAccess, UNO_QUERY_THROW); + xChangesBatch->commitChanges(); + } +} + +namespace +{ +OUString lcl_StringListToString(const uno::Sequence<OUString>& seq) +{ + OUStringBuffer sBuffer; + for (sal_Int32 i = 0; i != seq.getLength(); ++i) + { + if (i != 0) + sBuffer.append(","); + sBuffer.append(seq[i]); + } + return sBuffer.makeStringAndClear(); +} + +OUString lcl_IntListToString(const uno::Sequence<sal_Int16>& seq) +{ + OUStringBuffer sBuffer; + for (sal_Int32 i = 0; i != seq.getLength(); ++i) + { + if (i != 0) + sBuffer.append(","); + sBuffer.append(OUString::number(seq[i])); + } + return sBuffer.makeStringAndClear(); +} + +OUString lcl_IntListToString(const uno::Sequence<sal_Int32>& seq) +{ + OUStringBuffer sBuffer; + for (sal_Int32 i = 0; i != seq.getLength(); ++i) + { + if (i != 0) + sBuffer.append(","); + sBuffer.append(OUString::number(seq[i])); + } + return sBuffer.makeStringAndClear(); +} + +OUString lcl_IntListToString(const uno::Sequence<sal_Int64>& seq) +{ + OUStringBuffer sBuffer; + for (sal_Int32 i = 0; i != seq.getLength(); ++i) + { + if (i != 0) + sBuffer.append(","); + sBuffer.append(OUString::number(seq[i])); + } + return sBuffer.makeStringAndClear(); +} + +OUString lcl_DoubleListToString(const uno::Sequence<double>& seq) +{ + OUStringBuffer sBuffer; + for (sal_Int32 i = 0; i != seq.getLength(); ++i) + { + if (i != 0) + sBuffer.append(","); + sBuffer.append(OUString::number(seq[i])); + } + return sBuffer.makeStringAndClear(); +} +} + +void CuiAboutConfigTabPage::FillItems(const Reference<XNameAccess>& xNameAccess, + const weld::TreeIter* pParentEntry, int lineage, + bool bLoadAll) +{ + OUString sPath + = Reference<XHierarchicalName>(xNameAccess, uno::UNO_QUERY_THROW)->getHierarchicalName(); + const uno::Sequence<OUString> seqItems = xNameAccess->getElementNames(); + for (const OUString& item : seqItems) + { + Any aNode = xNameAccess->getByName(item); + + bool bNotLeaf = false; + + Reference<XNameAccess> xNextNameAccess; + try + { + xNextNameAccess.set(aNode, uno::UNO_QUERY); + bNotLeaf = xNextNameAccess.is(); + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("cui.options", "CuiAboutConfigTabPage"); + } + + if (bNotLeaf) + { + if (bLoadAll) + FillItems(xNextNameAccess, nullptr, lineage + 1, true); + else + { + // not leaf node + m_vectorUserData.push_back( + std::make_unique<UserData>(xNextNameAccess, lineage + 1)); + OUString sId(weld::toId(m_vectorUserData.back().get())); + + m_xPrefBox->insert(pParentEntry, -1, &item, &sId, nullptr, nullptr, true, + m_xScratchIter.get()); + // Necessary, without this the selection line will be truncated. + m_xPrefBox->set_text(*m_xScratchIter, "", 1); + m_xPrefBox->set_text(*m_xScratchIter, "", 2); + m_xPrefBox->set_text(*m_xScratchIter, "", 3); + m_xPrefBox->set_sensitive(*m_xScratchIter, true); + } + } + else + { + // leaf node + OUString sPropertyName = item; + auto it = std::find_if(m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(), + [&sPath, &sPropertyName](const prefBoxEntry& rEntry) -> bool { + return rEntry.pUserData->sPropertyPath == sPath + && rEntry.sStatus == sPropertyName; + }); + + css::uno::Reference<css::configuration::XReadWriteAccess> m_xReadWriteAccess; + m_xReadWriteAccess = css::configuration::ReadWriteAccess::create( + ::comphelper::getProcessComponentContext(), "*"); + beans::Property aProperty; + bool bReadOnly = false; + OUString sFullPath(sPath + "/" + sPropertyName); + try + { + aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(sFullPath); + bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0; + } + catch (css::beans::UnknownPropertyException) + { + SAL_WARN("cui.options", "unknown property: " << sFullPath); + } + + OUString sTooltip; + OUString sType; + bool bWasModified = false; + css::uno::Type aType = cppu::UnoType<void>::get(); + OUString sDynamicType = aNode.getValueTypeName(); + try + { + Reference<configuration::XDocumentation> xDocumentation(xNameAccess, + UNO_QUERY_THROW); + sTooltip + = xDocumentation->getDescriptionByHierarchicalName(sPath + "/" + sPropertyName); + aType = xDocumentation->getTypeByHierarchicalName(sFullPath); + bWasModified = xDocumentation->getModifiedByHierarchicalName(sFullPath); + } + catch (css::container::NoSuchElementException) + { + } + catch (css::util::InvalidStateException) + { + } + + OUStringBuffer sValue; + + // Fall back to dynamic type when this is empty + if (aType == cppu::UnoType<void>::get() && sDynamicType != "void") + { + if (sDynamicType == "boolean") + aType = cppu::UnoType<sal_Bool>::get(); + else if (sDynamicType == "short") + aType = cppu::UnoType<sal_Int16>::get(); + else if (sDynamicType == "long") + aType = cppu::UnoType<sal_Int32>::get(); + else if (sDynamicType == "hyper") + aType = cppu::UnoType<sal_Int64>::get(); + else if (sDynamicType == "double") + aType = cppu::UnoType<double>::get(); + else if (sDynamicType == "string") + aType = cppu::UnoType<OUString>::get(); + else if (sDynamicType == "[]byte") + aType = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(); + else if (sDynamicType == "[]boolean") + aType = cppu::UnoType<css::uno::Sequence<sal_Bool>>::get(); + else if (sDynamicType == "[]short") + aType = cppu::UnoType<css::uno::Sequence<sal_Int16>>::get(); + else if (sDynamicType == "[]long") + aType = cppu::UnoType<css::uno::Sequence<sal_Int32>>::get(); + else if (sDynamicType == "[]hyper") + aType = cppu::UnoType<css::uno::Sequence<sal_Int64>>::get(); + else if (sDynamicType == "[]double") + aType = cppu::UnoType<css::uno::Sequence<double>>::get(); + else if (sDynamicType == "[]string") + aType = cppu::UnoType<css::uno::Sequence<OUString>>::get(); + else if (sDynamicType == "[][]byte") + aType = cppu::UnoType<css::uno::Sequence<css::uno::Sequence<sal_Int8>>>::get(); + } + + if (it != m_modifiedPrefBoxEntries.end()) + sValue = it->sValue; + else + { + bool bHasValue = sDynamicType != "void"; + if (aType == cppu::UnoType<sal_Bool>::get()) + { + if (bHasValue) + sValue = OUString::boolean(aNode.get<bool>()); + sType = "boolean"; + } + else if (aType == cppu::UnoType<sal_Int16>::get()) + { + if (bHasValue) + sValue = OUString::number(aNode.get<sal_Int16>()); + sType = "short"; + } + else if (aType == cppu::UnoType<sal_Int32>::get()) + { + if (bHasValue) + sValue = OUString::number(aNode.get<sal_Int32>()); + sType = "int"; + } + else if (aType == cppu::UnoType<sal_Int64>::get()) + { + if (bHasValue) + sValue = OUString::number(aNode.get<sal_Int64>()); + sType = "long"; + } + else if (aType == cppu::UnoType<double>::get()) + { + if (bHasValue) + sValue = OUString::number(aNode.get<double>()); + sType = "double"; + } + else if (aType == cppu::UnoType<OUString>::get()) + { + if (bHasValue) + sValue = aNode.get<OUString>(); + sType = "string"; + } + else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int8>>::get()) + { + if (bHasValue) + { + const uno::Sequence<sal_Int8> seq = aNode.get<uno::Sequence<sal_Int8>>(); + for (sal_Int8 j : seq) + { + OUString s = OUString::number(static_cast<sal_uInt8>(j), 16); + if (s.getLength() == 1) + { + sValue.append("0"); + } + sValue.append(s.toAsciiUpperCase()); + } + } + sType = "hexBinary"; + } + else if (aType == cppu::UnoType<css::uno::Sequence<sal_Bool>>::get()) + { + if (bHasValue) + { + uno::Sequence<sal_Bool> seq = aNode.get<uno::Sequence<sal_Bool>>(); + for (sal_Int32 j = 0; j != seq.getLength(); ++j) + { + if (j != 0) + { + sValue.append(","); + } + sValue.append(OUString::boolean(seq[j])); + } + } + sType = "boolean-list"; + } + else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int16>>::get()) + { + if (bHasValue) + { + uno::Sequence<sal_Int16> seq = aNode.get<uno::Sequence<sal_Int16>>(); + for (sal_Int32 j = 0; j != seq.getLength(); ++j) + { + if (j != 0) + { + sValue.append(","); + } + sValue.append(static_cast<sal_Int32>(seq[j])); + } + } + sType = "short-list"; + } + else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int32>>::get()) + { + if (bHasValue) + { + uno::Sequence<sal_Int32> seq = aNode.get<uno::Sequence<sal_Int32>>(); + for (sal_Int32 j = 0; j != seq.getLength(); ++j) + { + if (j != 0) + { + sValue.append(","); + } + sValue.append(seq[j]); + } + } + sType = "int-list"; + } + else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int64>>::get()) + { + if (bHasValue) + { + uno::Sequence<sal_Int64> seq = aNode.get<uno::Sequence<sal_Int64>>(); + for (sal_Int32 j = 0; j != seq.getLength(); ++j) + { + if (j != 0) + { + sValue.append(","); + } + sValue.append(seq[j]); + } + } + sType = "long-list"; + } + else if (aType == cppu::UnoType<css::uno::Sequence<double>>::get()) + { + if (bHasValue) + { + uno::Sequence<double> seq = aNode.get<uno::Sequence<double>>(); + for (sal_Int32 j = 0; j != seq.getLength(); ++j) + { + if (j != 0) + { + sValue.append(","); + } + sValue.append(seq[j]); + } + } + sType = "double-list"; + } + else if (aType == cppu::UnoType<css::uno::Sequence<OUString>>::get()) + { + if (bHasValue) + sValue = lcl_StringListToString(aNode.get<uno::Sequence<OUString>>()); + sType = "string-list"; + } + else if (aType + == cppu::UnoType<css::uno::Sequence<css::uno::Sequence<sal_Int8>>>::get()) + { + if (bHasValue) + { + const uno::Sequence<uno::Sequence<sal_Int8>> seq + = aNode.get<uno::Sequence<uno::Sequence<sal_Int8>>>(); + for (sal_Int32 j = 0; j != seq.getLength(); ++j) + { + if (j != 0) + { + sValue.append(","); + } + for (sal_Int8 k : seq[j]) + { + OUString s = OUString::number(static_cast<sal_uInt8>(k), 16); + if (s.getLength() == 1) + { + sValue.append("0"); + } + sValue.append(s.toAsciiUpperCase()); + } + } + } + sType = "hexBinary-list"; + } + else + { + SAL_INFO("cui.options", "path \"" << sPath << "\" member " << item + << " of unsupported type " << sType); + continue; + } + } + + //Short name + int index = 0; + for (int j = 1; j < lineage; ++j) + index = sPath.indexOf("/", index + 1); + + InsertEntry(sPath, aNode, sPath.copy(index + 1), item, sType, + sValue.makeStringAndClear(), sTooltip, pParentEntry, !bLoadAll, bReadOnly, + bWasModified); + } + } +} + +Reference<XNameAccess> CuiAboutConfigTabPage::getConfigAccess(const OUString& sNodePath, + bool bUpdate) +{ + uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext()); + + uno::Reference<lang::XMultiServiceFactory> xConfigProvider( + css::configuration::theDefaultProvider::get(xContext)); + + beans::NamedValue aProperty; + aProperty.Name = "nodepath"; + aProperty.Value <<= sNodePath; + + uno::Sequence<uno::Any> aArgumentList{ uno::Any(aProperty) }; + + OUString sAccessString; + + if (bUpdate) + sAccessString = "com.sun.star.configuration.ConfigurationUpdateAccess"; + else + sAccessString = "com.sun.star.configuration.ConfigurationAccess"; + + uno::Reference<container::XNameAccess> xNameAccess( + xConfigProvider->createInstanceWithArguments(sAccessString, aArgumentList), + uno::UNO_QUERY_THROW); + + return xNameAccess; +} + +void CuiAboutConfigTabPage::AddToModifiedVector(const std::shared_ptr<Prop_Impl>& rProp) +{ + bool isModifiedBefore = false; + //Check if value modified before + for (std::shared_ptr<Prop_Impl>& nInd : m_vectorOfModified) + { + if (rProp->Name == nInd->Name && rProp->Property == nInd->Property) + { + //property modified before. Assign reference to the modified value + //do your changes on this object. They will be saved later. + nInd = rProp; + isModifiedBefore = true; + break; + } + } + + if (!isModifiedBefore) + m_vectorOfModified.push_back(rProp); + //property is not modified before +} + +std::vector<OUString> +CuiAboutConfigTabPage::commaStringToSequence(std::u16string_view rCommaSepString) +{ + std::vector<OUString> tempVector; + + sal_Int32 index = 0; + do + { + OUString word(o3tl::getToken(rCommaSepString, 0, u',', index)); + word = word.trim(); + if (!word.isEmpty()) + tempVector.push_back(word); + } while (index >= 0); + return tempVector; +} + +IMPL_LINK_NOARG(CuiAboutConfigTabPage, ResetBtnHdl_Impl, weld::Button&, void) { Reset(); } + +IMPL_LINK_NOARG(CuiAboutConfigTabPage, DoubleClickHdl_Impl, weld::TreeView&, bool) +{ + StandardHdl_Impl(*m_xEditBtn); + return true; +} + +IMPL_LINK_NOARG(CuiAboutConfigTabPage, StandardHdl_Impl, weld::Button&, void) +{ + if (!m_xPrefBox->get_selected(m_xScratchIter.get())) + return; + + UserData* pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(*m_xScratchIter)); + if (!pUserData || !pUserData->bIsPropertyPath || pUserData->bIsReadOnly) + return; + + //if selection is a node + OUString sPropertyName = m_xPrefBox->get_text(*m_xScratchIter, 1); + OUString sPropertyType = m_xPrefBox->get_text(*m_xScratchIter, 2); + OUString sPropertyValue = m_xPrefBox->get_text(*m_xScratchIter, 3); + + auto pProperty + = std::make_shared<Prop_Impl>(pUserData->sPropertyPath, sPropertyName, Any(sPropertyValue)); + bool bSaveChanges = false; + + bool bOpenDialog = true; + OUString sDialogValue; + + if (sPropertyType == "boolean") + { + bool bValue; + if (sPropertyValue == "true") + { + sDialogValue = "false"; + bValue = false; + } + else + { + sDialogValue = "true"; + bValue = true; + } + + pProperty->Value <<= bValue; + bOpenDialog = false; + bSaveChanges = true; + } + else + { + sDialogValue = sPropertyValue; + bOpenDialog = true; + } + + try + { + if (bOpenDialog) + { + if (sPropertyType == "short" || sPropertyType == "int" || sPropertyType == "long") + { + sal_Int64 nMin = sPropertyType == "short" + ? SAL_MIN_INT16 + : sPropertyType == "int" ? SAL_MIN_INT32 : SAL_MIN_INT64; + sal_Int64 nMax = sPropertyType == "short" + ? SAL_MAX_INT16 + : sPropertyType == "int" ? SAL_MAX_INT32 : SAL_MAX_INT64; + SvxNumberDialog aNumberDialog(m_xDialog.get(), sPropertyName, + sDialogValue.toInt64(), nMin, nMax); + if (aNumberDialog.run() == RET_OK) + { + sal_Int64 nNewValue = aNumberDialog.GetNumber(); + if (sPropertyType == "short") + { + pProperty->Value <<= static_cast<sal_Int16>(nNewValue); + } + else if (sPropertyType == "int") + { + pProperty->Value <<= static_cast<sal_Int32>(nNewValue); + } + else if (sPropertyType == "long") + { + pProperty->Value <<= nNewValue; + } + bSaveChanges = true; + sDialogValue = OUString::number(nNewValue); + } + } + else if (sPropertyType == "double") + { + SvxDecimalNumberDialog aNumberDialog(m_xDialog.get(), sPropertyName, + sDialogValue.toDouble()); + if (aNumberDialog.run() == RET_OK) + { + double fNewValue = aNumberDialog.GetNumber(); + pProperty->Value <<= fNewValue; + bSaveChanges = true; + sDialogValue = OUString::number(fNewValue); + } + } + else if (sPropertyType == "string") + { + SvxNameDialog aNameDialog(m_xDialog.get(), sDialogValue, sPropertyName); + aNameDialog.SetCheckNameHdl(LINK(this, CuiAboutConfigTabPage, ValidNameHdl)); + if (aNameDialog.run() == RET_OK) + { + sDialogValue = aNameDialog.GetName(); + pProperty->Value <<= sDialogValue; + bSaveChanges = true; + } + } + else if (sPropertyType == "short-list") + { + SvxListDialog aListDialog(m_xDialog.get()); + aListDialog.SetEntries(commaStringToSequence(sDialogValue)); + aListDialog.SetMode(ListMode::Int16); + if (aListDialog.run() == RET_OK) + { + std::vector<OUString> seqStr = aListDialog.GetEntries(); + uno::Sequence<sal_Int16> seqShort(seqStr.size()); + std::transform( + seqStr.begin(), seqStr.end(), seqShort.getArray(), + [](const auto& str) { return static_cast<sal_Int16>(str.toInt32()); }); + pProperty->Value <<= seqShort; + sDialogValue = lcl_IntListToString(seqShort); + bSaveChanges = true; + } + } + else if (sPropertyType == "int-list") + { + SvxListDialog aListDialog(m_xDialog.get()); + aListDialog.SetEntries(commaStringToSequence(sDialogValue)); + aListDialog.SetMode(ListMode::Int32); + if (aListDialog.run() == RET_OK) + { + std::vector<OUString> seqStr = aListDialog.GetEntries(); + uno::Sequence<sal_Int32> seq(seqStr.size()); + std::transform( + seqStr.begin(), seqStr.end(), seq.getArray(), + [](const auto& str) { return static_cast<sal_Int32>(str.toInt32()); }); + pProperty->Value <<= seq; + sDialogValue = lcl_IntListToString(seq); + bSaveChanges = true; + } + } + else if (sPropertyType == "long-list") + { + SvxListDialog aListDialog(m_xDialog.get()); + aListDialog.SetEntries(commaStringToSequence(sDialogValue)); + aListDialog.SetMode(ListMode::Int64); + if (aListDialog.run() == RET_OK) + { + std::vector<OUString> seqStr = aListDialog.GetEntries(); + uno::Sequence<sal_Int64> seq(seqStr.size()); + std::transform( + seqStr.begin(), seqStr.end(), seq.getArray(), + [](const auto& str) { return static_cast<sal_Int64>(str.toInt32()); }); + pProperty->Value <<= seq; + sDialogValue = lcl_IntListToString(seq); + bSaveChanges = true; + } + } + else if (sPropertyType == "double-list") + { + SvxListDialog aListDialog(m_xDialog.get()); + aListDialog.SetEntries(commaStringToSequence(sDialogValue)); + aListDialog.SetMode(ListMode::Double); + if (aListDialog.run() == RET_OK) + { + std::vector<OUString> seqStr = aListDialog.GetEntries(); + uno::Sequence<double> seq(seqStr.size()); + std::transform( + seqStr.begin(), seqStr.end(), seq.getArray(), + [](const auto& str) { return static_cast<double>(str.toDouble()); }); + pProperty->Value <<= seq; + sDialogValue = lcl_DoubleListToString(seq); + bSaveChanges = true; + } + } + else if (sPropertyType == "string-list") + { + SvxListDialog aListDialog(m_xDialog.get()); + uno::Sequence<OUString> aList + = pUserData->aPropertyValue.get<uno::Sequence<OUString>>(); + aListDialog.SetEntries( + comphelper::sequenceToContainer<std::vector<OUString>>(aList)); + aListDialog.SetMode(ListMode::String); + if (aListDialog.run() == RET_OK) + { + auto seq = comphelper::containerToSequence(aListDialog.GetEntries()); + sDialogValue = lcl_StringListToString(seq); + pProperty->Value <<= seq; + bSaveChanges = true; + } + } + else //unknown + throw uno::Exception("unknown property type " + sPropertyType, nullptr); + } + + if (bSaveChanges) + { + AddToModifiedVector(pProperty); + pUserData->aPropertyValue = pProperty->Value; + + //update listbox value. + m_xPrefBox->set_text(*m_xScratchIter, sPropertyType, 2); + m_xPrefBox->set_text(*m_xScratchIter, sDialogValue, 3); + m_xPrefBox->set_text_emphasis(*m_xScratchIter, true, -1); + //update m_prefBoxEntries + auto it = std::find_if( + m_prefBoxEntries.begin(), m_prefBoxEntries.end(), + [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool { + return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath + && rEntry.sStatus == sPropertyName; + }); + if (it != m_prefBoxEntries.end()) + { + it->sValue = sDialogValue; + it->pUserData->bWasModified = true; + + auto modifiedIt = std::find_if( + m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(), + [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool { + return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath + && rEntry.sStatus == sPropertyName; + }); + + if (modifiedIt != m_modifiedPrefBoxEntries.end()) + { + modifiedIt->sValue = sDialogValue; + modifiedIt->pUserData->bWasModified = true; + } + else + { + m_modifiedPrefBoxEntries.push_back(*it); + } + } + } + } + catch (uno::Exception&) + { + } +} + +IMPL_LINK_NOARG(CuiAboutConfigTabPage, SearchHdl_Impl, weld::Button&, void) { InputChanged(); } + +IMPL_LINK_NOARG(CuiAboutConfigTabPage, ModifiedHdl_Impl, weld::Toggleable&, void) +{ + InputChanged(); +} + +void CuiAboutConfigTabPage::InsertEntry(const prefBoxEntry& rEntry) +{ + bool bOnlyModified = m_xModifiedCheckBtn->get_active(); + if (bOnlyModified && !rEntry.pUserData->bWasModified) + return; + + OUString sPathWithProperty = rEntry.pUserData->sPropertyPath; + sal_Int32 index = sPathWithProperty.lastIndexOf(rEntry.sProp); + OUString sPath = sPathWithProperty.copy(0, index); + index = 0; + std::unique_ptr<weld::TreeIter> xParentEntry(m_xPrefBox->make_iterator()); + std::unique_ptr<weld::TreeIter> xGrandParentEntry; + + do + { + int prevIndex = index; + index = sPath.indexOf("/", index + 1); + // deal with no parent case (tdf#107811) + if (index < 0) + { + OUString sId(weld::toId(rEntry.pUserData)); + m_xPrefBox->insert(nullptr, -1, &rEntry.sProp, &sId, nullptr, nullptr, false, + m_xScratchIter.get()); + m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1); + m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2); + m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3); + m_xPrefBox->set_text_emphasis(*m_xScratchIter, rEntry.pUserData->bWasModified, -1); + m_xPrefBox->set_sensitive(*m_xScratchIter, !rEntry.pUserData->bIsReadOnly); + return; + } + OUString sParentName = sPath.copy(prevIndex + 1, index - prevIndex - 1); + + bool hasEntry = false; + bool bStartOk; + + if (!xGrandParentEntry) + bStartOk = m_xPrefBox->get_iter_first(*xParentEntry); + else + { + m_xPrefBox->copy_iterator(*xGrandParentEntry, *xParentEntry); + bStartOk = m_xPrefBox->iter_children(*xParentEntry); + } + + if (bStartOk) + { + do + { + if (m_xPrefBox->get_text(*xParentEntry, 0) == sParentName) + { + hasEntry = true; + break; + } + } while (m_xPrefBox->iter_next_sibling(*xParentEntry)); + } + + if (!hasEntry) + { + m_xPrefBox->insert(xGrandParentEntry.get(), -1, &sParentName, nullptr, nullptr, nullptr, + false, xParentEntry.get()); + //It is needed, without this the selection line will be truncated. + m_xPrefBox->set_text(*xParentEntry, "", 1); + m_xPrefBox->set_text(*xParentEntry, "", 2); + m_xPrefBox->set_text(*xParentEntry, "", 3); + m_xPrefBox->set_sensitive(*xParentEntry, true); + } + + xGrandParentEntry = m_xPrefBox->make_iterator(xParentEntry.get()); + } while (index < sPath.getLength() - 1); + + OUString sId(weld::toId(rEntry.pUserData)); + m_xPrefBox->insert(xParentEntry.get(), -1, &rEntry.sProp, &sId, nullptr, nullptr, false, + m_xScratchIter.get()); + m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1); + m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2); + m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3); + m_xPrefBox->set_text_emphasis(*m_xScratchIter, rEntry.pUserData->bWasModified, -1); + m_xPrefBox->set_sensitive(*m_xScratchIter, !rEntry.pUserData->bIsReadOnly); +} + +IMPL_LINK(CuiAboutConfigTabPage, ExpandingHdl_Impl, const weld::TreeIter&, rEntry, bool) +{ + if (m_xPrefBox->iter_has_child(rEntry)) + return true; + UserData* pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(rEntry)); + if (pUserData && !pUserData->bIsPropertyPath) + { + assert(pUserData->aXNameAccess.is()); + FillItems(pUserData->aXNameAccess, &rEntry, pUserData->aLineage); + } + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optaboutconfig.hxx b/cui/source/options/optaboutconfig.hxx new file mode 100644 index 0000000000..bc4f7a32f3 --- /dev/null +++ b/cui/source/options/optaboutconfig.hxx @@ -0,0 +1,90 @@ +/* -*- 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/. + */ + +#pragma once + +#include <com/sun/star/container/XNameAccess.hpp> + +#include <dlgname.hxx> +#include <i18nutil/searchopt.hxx> +#include <vcl/weld.hxx> + +#include <vector> + +class CuiAboutConfigTabPage; +class CuiAboutConfigValueDialog; +struct Prop_Impl; +struct UserData; + +struct prefBoxEntry +{ + OUString sProp; + OUString sStatus; + OUString sType; + OUString sValue; + UserData* pUserData; +}; + +class CuiAboutConfigTabPage : public weld::GenericDialogController +{ +private: + std::unique_ptr<weld::Button> m_xResetBtn; + std::unique_ptr<weld::Button> m_xEditBtn; + std::unique_ptr<weld::Button> m_xSearchBtn; + std::unique_ptr<weld::CheckButton> m_xModifiedCheckBtn; + std::unique_ptr<weld::Entry> m_xSearchEdit; + std::unique_ptr<weld::TreeView> m_xPrefBox; + std::unique_ptr<weld::TreeIter> m_xScratchIter; + + std::vector<std::unique_ptr<UserData>> m_vectorUserData; + + std::vector<prefBoxEntry> m_modifiedPrefBoxEntries; + std::vector<std::shared_ptr<Prop_Impl>> m_vectorOfModified; + + //for search + i18nutil::SearchOptions2 m_options; + std::vector<prefBoxEntry> m_prefBoxEntries; + + bool m_bSorted; + weld::Window* m_pParent; + + void AddToModifiedVector(const std::shared_ptr<Prop_Impl>& rProp); + static std::vector<OUString> commaStringToSequence(std::u16string_view rCommaSepString); + void InsertEntry(const prefBoxEntry& rEntry); + + DECL_LINK(QueryTooltip, const weld::TreeIter& rIter, OUString); + DECL_LINK(StandardHdl_Impl, weld::Button&, void); + DECL_LINK(DoubleClickHdl_Impl, weld::TreeView&, bool); + DECL_LINK(ResetBtnHdl_Impl, weld::Button&, void); + DECL_LINK(SearchHdl_Impl, weld::Button&, void); + DECL_LINK(ModifiedHdl_Impl, weld::Toggleable&, void); + DECL_LINK(ExpandingHdl_Impl, const weld::TreeIter&, bool); + DECL_LINK(HeaderBarClick, int, void); + DECL_STATIC_LINK(CuiAboutConfigTabPage, ValidNameHdl, SvxNameDialog&, bool); + DECL_LINK(EditNumberHdl, SvxListDialog&, OUString); + +public: + explicit CuiAboutConfigTabPage(weld::Window* pParent); + virtual ~CuiAboutConfigTabPage() override; + void InsertEntry(const OUString& rPropertyPath, css::uno::Any aPropertyValue, + const OUString& rProp, const OUString& rStatus, const OUString& rType, + const OUString& rValue, const OUString& rTooltip, + const weld::TreeIter* pParentEntry, bool bInsertToPrefBox, bool bIsReadOnly, + bool bWasMOdified); + void Reset(); + void InputChanged(); + void FillItems(const css::uno::Reference<css::container::XNameAccess>& xNameAccess, + const weld::TreeIter* pParentEntry = nullptr, int lineage = 0, + bool bLoadAll = false); + static css::uno::Reference<css::container::XNameAccess> + getConfigAccess(const OUString& sNodePath, bool bUpdate); + void FillItemSet(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optaccessibility.cxx b/cui/source/options/optaccessibility.cxx new file mode 100644 index 0000000000..008a4a2735 --- /dev/null +++ b/cui/source/options/optaccessibility.cxx @@ -0,0 +1,160 @@ +/* -*- 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 "optaccessibility.hxx" +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <officecfg/Office/Common.hxx> + +SvxAccessibilityOptionsTabPage::SvxAccessibilityOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optaccessibilitypage.ui", "OptAccessibilityPage", &rSet) + , m_xAccessibilityTool(m_xBuilder->weld_check_button("acctool")) + , m_xTextSelectionInReadonly(m_xBuilder->weld_check_button("textselinreadonly")) + , m_xTextSelectionInReadonlyImg(m_xBuilder->weld_widget("locktextselinreadonly")) + , m_xAnimatedGraphics(m_xBuilder->weld_check_button("animatedgraphics")) + , m_xAnimatedGraphicsImg(m_xBuilder->weld_widget("lockanimatedgraphics")) + , m_xAnimatedTexts(m_xBuilder->weld_check_button("animatedtext")) + , m_xAnimatedTextsImg(m_xBuilder->weld_widget("lockanimatedtext")) + , m_xHighContrast(m_xBuilder->weld_combo_box("highcontrast")) + , m_xHighContrastImg(m_xBuilder->weld_widget("lockhighcontrast")) + , m_xHighContrastLabel(m_xBuilder->weld_label("label13")) + , m_xAutomaticFontColor(m_xBuilder->weld_check_button("autofontcolor")) + , m_xAutomaticFontColorImg(m_xBuilder->weld_widget("lockautofontcolor")) + , m_xPagePreviews(m_xBuilder->weld_check_button("systempagepreviewcolor")) + , m_xPagePreviewsImg(m_xBuilder->weld_widget("locksystempagepreviewcolor")) +{ +#ifdef UNX + // UNIX: read the gconf2 setting instead to use the checkbox + m_xAccessibilityTool->hide(); +#endif +} + +SvxAccessibilityOptionsTabPage::~SvxAccessibilityOptionsTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SvxAccessibilityOptionsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SvxAccessibilityOptionsTabPage>(pPage, pController, *rAttrSet); +} + +OUString SvxAccessibilityOptionsTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "label13" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "acctool", "textselinreadonly", "animatedgraphics", + "animatedtext", "autofontcolor", "systempagepreviewcolor" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxAccessibilityOptionsTabPage::FillItemSet( SfxItemSet* ) +{ + std::shared_ptr<comphelper::ConfigurationChanges> batch( comphelper::ConfigurationChanges::create() ); + if ( !officecfg::Office::Common::Accessibility::IsForPagePreviews::isReadOnly() ) + officecfg::Office::Common::Accessibility::IsForPagePreviews::set(m_xPagePreviews->get_active(), batch); + if ( !officecfg::Office::Common::Accessibility::IsAllowAnimatedGraphics::isReadOnly() ) + officecfg::Office::Common::Accessibility::IsAllowAnimatedGraphics::set(m_xAnimatedGraphics->get_active(), batch); + if ( !officecfg::Office::Common::Accessibility::IsAllowAnimatedText::isReadOnly() ) + officecfg::Office::Common::Accessibility::IsAllowAnimatedText::set(m_xAnimatedTexts->get_active(), batch); + if ( !officecfg::Office::Common::Accessibility::IsAutomaticFontColor::isReadOnly() ) + officecfg::Office::Common::Accessibility::IsAutomaticFontColor::set(m_xAutomaticFontColor->get_active(), batch); + if ( !officecfg::Office::Common::Accessibility::IsSelectionInReadonly::isReadOnly() ) + officecfg::Office::Common::Accessibility::IsSelectionInReadonly::set(m_xTextSelectionInReadonly->get_active(), batch); + if ( !officecfg::Office::Common::Accessibility::HighContrast::isReadOnly() ) + officecfg::Office::Common::Accessibility::HighContrast::set(m_xHighContrast->get_active(), batch); + batch->commit(); + + AllSettings aAllSettings = Application::GetSettings(); + MiscSettings aMiscSettings = aAllSettings.GetMiscSettings(); +#ifndef UNX + aMiscSettings.SetEnableATToolSupport(m_xAccessibilityTool->get_active()); +#endif + aAllSettings.SetMiscSettings(aMiscSettings); + Application::MergeSystemSettings( aAllSettings ); + Application::SetSettings(aAllSettings); + + return false; +} + +void SvxAccessibilityOptionsTabPage::Reset( const SfxItemSet* ) +{ + m_xPagePreviews->set_active( officecfg::Office::Common::Accessibility::IsForPagePreviews::get() ); + if (officecfg::Office::Common::Accessibility::IsForPagePreviews::isReadOnly()) + { + m_xPagePreviews->set_sensitive(false); + m_xPagePreviewsImg->set_visible(true); + } + + m_xAnimatedGraphics->set_active( officecfg::Office::Common::Accessibility::IsAllowAnimatedGraphics::get() ); + if (officecfg::Office::Common::Accessibility::IsAllowAnimatedGraphics::isReadOnly()) + { + m_xAnimatedGraphics->set_sensitive(false); + m_xAnimatedGraphicsImg->set_visible(true); + } + + m_xAnimatedTexts->set_active( officecfg::Office::Common::Accessibility::IsAllowAnimatedText::get() ); + if (officecfg::Office::Common::Accessibility::IsAllowAnimatedText::isReadOnly()) + { + m_xAnimatedTexts->set_sensitive(false); + m_xAnimatedTextsImg->set_visible(true); + } + + m_xAutomaticFontColor->set_active( officecfg::Office::Common::Accessibility::IsAutomaticFontColor::get() ); + if (officecfg::Office::Common::Accessibility::IsAutomaticFontColor::isReadOnly()) + { + m_xAutomaticFontColor->set_sensitive(false); + m_xAutomaticFontColorImg->set_visible(true); + } + + m_xTextSelectionInReadonly->set_active( officecfg::Office::Common::Accessibility::IsSelectionInReadonly::get() ); + if (officecfg::Office::Common::Accessibility::IsSelectionInReadonly::isReadOnly()) + { + m_xTextSelectionInReadonly->set_sensitive(false); + m_xTextSelectionInReadonlyImg->set_visible(true); + } + + m_xHighContrast->set_active( officecfg::Office::Common::Accessibility::HighContrast::get() ); + if (officecfg::Office::Common::Accessibility::HighContrast::isReadOnly()) + { + m_xHighContrast->set_sensitive(false); + m_xHighContrastLabel->set_sensitive(false); + m_xHighContrastImg->set_visible(true); + } + + AllSettings aAllSettings = Application::GetSettings(); + const MiscSettings& aMiscSettings = aAllSettings.GetMiscSettings(); + m_xAccessibilityTool->set_active(aMiscSettings.GetEnableATToolSupport()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optaccessibility.hxx b/cui/source/options/optaccessibility.hxx new file mode 100644 index 0000000000..73fe167c16 --- /dev/null +++ b/cui/source/options/optaccessibility.hxx @@ -0,0 +1,52 @@ +/* -*- 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 . + */ +#pragma once + +#include <sfx2/tabdlg.hxx> + +class SvxAccessibilityOptionsTabPage : public SfxTabPage +{ + std::unique_ptr<weld::CheckButton> m_xAccessibilityTool; + std::unique_ptr<weld::CheckButton> m_xTextSelectionInReadonly; + std::unique_ptr<weld::Widget> m_xTextSelectionInReadonlyImg; + std::unique_ptr<weld::CheckButton> m_xAnimatedGraphics; + std::unique_ptr<weld::Widget> m_xAnimatedGraphicsImg; + std::unique_ptr<weld::CheckButton> m_xAnimatedTexts; + std::unique_ptr<weld::Widget> m_xAnimatedTextsImg; + std::unique_ptr<weld::ComboBox> m_xHighContrast; + std::unique_ptr<weld::Widget> m_xHighContrastImg; + std::unique_ptr<weld::Label> m_xHighContrastLabel; + std::unique_ptr<weld::CheckButton> m_xAutomaticFontColor; + std::unique_ptr<weld::Widget> m_xAutomaticFontColorImg; + std::unique_ptr<weld::CheckButton> m_xPagePreviews; + std::unique_ptr<weld::Widget> m_xPagePreviewsImg; + +public: + SvxAccessibilityOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~SvxAccessibilityOptionsTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optasian.cxx b/cui/source/options/optasian.cxx new file mode 100644 index 0000000000..e0ce4a3a63 --- /dev/null +++ b/cui/source/options/optasian.cxx @@ -0,0 +1,409 @@ +/* -*- 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 <map> +#include <optasian.hxx> +#include <tools/debug.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <o3tl/any.hxx> +#include <i18nlangtag/mslangid.hxx> +#include <svl/asiancfg.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/i18n/XForbiddenCharacters.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <sfx2/viewfrm.hxx> +#include <sfx2/objsh.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <unotools/localedatawrapper.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::i18n; +using namespace com::sun::star::frame; +using namespace com::sun::star::beans; + +constexpr OUString cIsKernAsianPunctuation = u"IsKernAsianPunctuation"_ustr; +constexpr OUString cCharacterCompressionType = u"CharacterCompressionType"_ustr; + +namespace { + +struct SvxForbiddenChars_Impl +{ + bool bRemoved; + std::optional<ForbiddenCharacters> oCharacters; +}; + +} + +struct SvxAsianLayoutPage_Impl +{ + SvxAsianConfig aConfig; + SvxAsianLayoutPage_Impl() {} + + Reference< XForbiddenCharacters > xForbidden; + Reference< XPropertySet > xPrSet; + Reference< XPropertySetInfo > xPrSetInfo; + std::map< LanguageType, SvxForbiddenChars_Impl > + aChangedLanguagesMap; + + bool hasForbiddenCharacters(LanguageType eLang); + SvxForbiddenChars_Impl* getForbiddenCharacters(LanguageType eLang); + void addForbiddenCharacters(LanguageType eLang, std::optional<ForbiddenCharacters> oForbidden); +}; + +bool SvxAsianLayoutPage_Impl::hasForbiddenCharacters(LanguageType eLang) +{ + return aChangedLanguagesMap.count( eLang ); +} + +SvxForbiddenChars_Impl* SvxAsianLayoutPage_Impl::getForbiddenCharacters(LanguageType eLang) +{ + auto it = aChangedLanguagesMap.find( eLang ); + DBG_ASSERT( ( it != aChangedLanguagesMap.end() ), "language not available"); + if( it != aChangedLanguagesMap.end() ) + return &it->second; + return nullptr; +} + +void SvxAsianLayoutPage_Impl::addForbiddenCharacters( + LanguageType eLang, std::optional<ForbiddenCharacters> oForbidden) +{ + auto itOld = aChangedLanguagesMap.find( eLang ); + if( itOld == aChangedLanguagesMap.end() ) + { + SvxForbiddenChars_Impl aChar; + aChar.bRemoved = !oForbidden.has_value(); + aChar.oCharacters = std::move(oForbidden); + aChangedLanguagesMap.emplace( eLang, std::move(aChar) ); + } + else + { + itOld->second.bRemoved = !oForbidden.has_value(); + itOld->second.oCharacters = std::move(oForbidden); + } +} + +static LanguageType eLastUsedLanguageTypeForForbiddenCharacters(USHRT_MAX); + +SvxAsianLayoutPage::SvxAsianLayoutPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optasianpage.ui", "OptAsianPage", &rSet) + , pImpl(new SvxAsianLayoutPage_Impl) + , m_xCharKerningRB(m_xBuilder->weld_radio_button("charkerning")) + , m_xCharPunctKerningRB(m_xBuilder->weld_radio_button("charpunctkerning")) + , m_xNoCompressionRB(m_xBuilder->weld_radio_button("nocompression")) + , m_xPunctCompressionRB(m_xBuilder->weld_radio_button("punctcompression")) + , m_xPunctKanaCompressionRB(m_xBuilder->weld_radio_button("punctkanacompression")) + , m_xLanguageFT(m_xBuilder->weld_label("languageft")) + , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("language"))) + , m_xStandardCB(m_xBuilder->weld_check_button("standard")) + , m_xStartFT(m_xBuilder->weld_label("startft")) + , m_xStartED(m_xBuilder->weld_entry("start")) + , m_xEndFT(m_xBuilder->weld_label("endft")) + , m_xEndED(m_xBuilder->weld_entry("end")) + , m_xHintFT(m_xBuilder->weld_label("hintft")) +{ + LanguageHdl(*m_xLanguageLB->get_widget()); + m_xLanguageLB->connect_changed(LINK(this, SvxAsianLayoutPage, LanguageHdl)); + m_xStandardCB->connect_toggled(LINK(this, SvxAsianLayoutPage, ChangeStandardHdl)); + Link<weld::Entry&,void> aLk(LINK(this, SvxAsianLayoutPage, ModifyHdl)); + m_xStartED->connect_changed(aLk); + m_xEndED->connect_changed(aLk); + + m_xLanguageLB->SetLanguageList( SvxLanguageListFlags::FBD_CHARS, false, false ); +} + +SvxAsianLayoutPage::~SvxAsianLayoutPage() +{ +} + +std::unique_ptr<SfxTabPage> SvxAsianLayoutPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SvxAsianLayoutPage>(pPage, pController, *rAttrSet); +} + +OUString SvxAsianLayoutPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] + = { "label1", "label2", "label3", "languageft", "startft", "endft", "hintft" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString radioButton[] = { "charkerning", "charpunctkerning", "nocompression", + "punctcompression", "punctkanacompression" }; + + for (const auto& radio : radioButton) + { + if (const auto& pString = m_xBuilder->weld_radio_button(radio)) + sAllStrings += pString->get_label() + " "; + } + + sAllStrings += m_xStandardCB->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxAsianLayoutPage::FillItemSet( SfxItemSet* ) +{ + if(m_xCharKerningRB->get_state_changed_from_saved()) + { + pImpl->aConfig.SetKerningWesternTextOnly(m_xCharKerningRB->get_active()); + OUString sPunct(cIsKernAsianPunctuation); + if(pImpl->xPrSetInfo.is() && pImpl->xPrSetInfo->hasPropertyByName(sPunct)) + { + bool bVal = !m_xCharKerningRB->get_active(); + pImpl->xPrSet->setPropertyValue(sPunct, Any(bVal)); + } + } + + if(m_xNoCompressionRB->get_state_changed_from_saved() || + m_xPunctCompressionRB->get_state_changed_from_saved()) + { + CharCompressType nSet = m_xNoCompressionRB->get_active() ? CharCompressType::NONE : + m_xPunctCompressionRB->get_active() ? CharCompressType::PunctuationOnly : + CharCompressType::PunctuationAndKana; + pImpl->aConfig.SetCharDistanceCompression(nSet); + OUString sCompress(cCharacterCompressionType); + if(pImpl->xPrSetInfo.is() && pImpl->xPrSetInfo->hasPropertyByName(sCompress)) + { + pImpl->xPrSet->setPropertyValue(sCompress, Any(static_cast<sal_uInt16>(nSet))); + } + } + pImpl->aConfig.Commit(); + if(pImpl->xForbidden.is()) + { + try + { + for (auto const& changedLanguage : pImpl->aChangedLanguagesMap) + { + Locale aLocale( LanguageTag::convertToLocale(changedLanguage.first)); + if(changedLanguage.second.bRemoved) + pImpl->xForbidden->removeForbiddenCharacters( aLocale ); + else if(changedLanguage.second.oCharacters) + pImpl->xForbidden->setForbiddenCharacters( aLocale, *( changedLanguage.second.oCharacters ) ); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "cui.options", "in XForbiddenCharacters"); + } + } + eLastUsedLanguageTypeForForbiddenCharacters = m_xLanguageLB->get_active_id(); + + return false; +} + +void SvxAsianLayoutPage::Reset( const SfxItemSet* ) +{ + SfxViewFrame* pCurFrm = SfxViewFrame::Current(); + SfxObjectShell* pDocSh = pCurFrm ? pCurFrm->GetObjectShell() : nullptr; + Reference< XModel > xModel; + if(pDocSh) + xModel = pDocSh->GetModel(); + Reference<XMultiServiceFactory> xFact(xModel, UNO_QUERY); + if(xFact.is()) + { + pImpl->xPrSet.set(xFact->createInstance("com.sun.star.document.Settings"), UNO_QUERY); + } + if( pImpl->xPrSet.is() ) + pImpl->xPrSetInfo = pImpl->xPrSet->getPropertySetInfo(); + bool bKernWesternText = pImpl->aConfig.IsKerningWesternTextOnly(); + CharCompressType nCompress = pImpl->aConfig.GetCharDistanceCompression(); + if(pImpl->xPrSetInfo.is()) + { + OUString sForbidden("ForbiddenCharacters"); + if(pImpl->xPrSetInfo->hasPropertyByName(sForbidden)) + { + Any aForbidden = pImpl->xPrSet->getPropertyValue(sForbidden); + aForbidden >>= pImpl->xForbidden; + } + OUString sCompress(cCharacterCompressionType); + if(pImpl->xPrSetInfo->hasPropertyByName(sCompress)) + { + Any aVal = pImpl->xPrSet->getPropertyValue(sCompress); + sal_uInt16 nTmp; + if (aVal >>= nTmp) + nCompress = static_cast<CharCompressType>(nTmp); + } + OUString sPunct(cIsKernAsianPunctuation); + if(pImpl->xPrSetInfo->hasPropertyByName(sPunct)) + { + Any aVal = pImpl->xPrSet->getPropertyValue(sPunct); + bKernWesternText = !*o3tl::doAccess<bool>(aVal); + } + } + else + { + m_xLanguageFT->set_sensitive(false); + m_xLanguageLB->set_sensitive(false); + m_xStandardCB->set_sensitive(false); + m_xStartFT->set_sensitive(false); + m_xStartED->set_sensitive(false); + m_xEndFT->set_sensitive(false); + m_xEndED->set_sensitive(false); + m_xHintFT->set_sensitive(false); + } + if(bKernWesternText) + m_xCharKerningRB->set_active(true); + else + m_xCharPunctKerningRB->set_active(true); + switch(nCompress) + { + case CharCompressType::NONE : m_xNoCompressionRB->set_active(true); break; + case CharCompressType::PunctuationOnly : m_xPunctCompressionRB->set_active(true); break; + default: m_xPunctKanaCompressionRB->set_active(true); + } + m_xCharKerningRB->save_state(); + m_xNoCompressionRB->save_state(); + m_xPunctCompressionRB->save_state(); + m_xPunctKanaCompressionRB->save_state(); + + m_xLanguageLB->set_active(0); + //preselect the system language in the box - if available + if(LanguageType(USHRT_MAX) == eLastUsedLanguageTypeForForbiddenCharacters) + { + eLastUsedLanguageTypeForForbiddenCharacters = + Application::GetSettings().GetLanguageTag().getLanguageType(); + if (MsLangId::isSimplifiedChinese(eLastUsedLanguageTypeForForbiddenCharacters)) + eLastUsedLanguageTypeForForbiddenCharacters = LANGUAGE_CHINESE_SIMPLIFIED; + else if (MsLangId::isTraditionalChinese(eLastUsedLanguageTypeForForbiddenCharacters)) + eLastUsedLanguageTypeForForbiddenCharacters = LANGUAGE_CHINESE_TRADITIONAL; + } + m_xLanguageLB->set_active_id(eLastUsedLanguageTypeForForbiddenCharacters); + LanguageHdl(*m_xLanguageLB->get_widget()); +} + +IMPL_LINK_NOARG(SvxAsianLayoutPage, LanguageHdl, weld::ComboBox&, void) +{ + //set current value + LanguageType eSelectLanguage = m_xLanguageLB->get_active_id(); + LanguageTag aLanguageTag( eSelectLanguage); + const Locale& aLocale( aLanguageTag.getLocale()); + + OUString sStart, sEnd; + bool bAvail; + if(pImpl->xForbidden.is()) + { + bAvail = pImpl->hasForbiddenCharacters(eSelectLanguage); + if(bAvail) + { + SvxForbiddenChars_Impl* pElement = pImpl->getForbiddenCharacters(eSelectLanguage); + if(pElement->bRemoved || !pElement->oCharacters) + { + bAvail = false; + } + else + { + sStart = pElement->oCharacters->beginLine; + sEnd = pElement->oCharacters->endLine; + } + } + else + { + try + { + bAvail = pImpl->xForbidden->hasForbiddenCharacters(aLocale); + if(bAvail) + { + ForbiddenCharacters aForbidden = pImpl->xForbidden->getForbiddenCharacters( aLocale ); + sStart = aForbidden.beginLine; + sEnd = aForbidden.endLine; + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "cui.options", "in XForbiddenCharacters"); + } + } + } + else + { + bAvail = pImpl->aConfig.GetStartEndChars( aLocale, sStart, sEnd ); + } + if(!bAvail) + { + LocaleDataWrapper aWrap( std::move(aLanguageTag) ); + ForbiddenCharacters aForbidden = aWrap.getForbiddenCharacters(); + sStart = aForbidden.beginLine; + sEnd = aForbidden.endLine; + } + m_xStandardCB->set_active(!bAvail); + m_xStartED->set_sensitive(bAvail); + m_xEndED->set_sensitive(bAvail); + m_xStartFT->set_sensitive(bAvail); + m_xEndFT->set_sensitive(bAvail); + m_xStartED->set_text(sStart); + m_xEndED->set_text(sEnd); +} + +IMPL_LINK(SvxAsianLayoutPage, ChangeStandardHdl, weld::Toggleable&, rBox, void) +{ + bool bCheck = rBox.get_active(); + m_xStartED->set_sensitive(!bCheck); + m_xEndED->set_sensitive(!bCheck); + m_xStartFT->set_sensitive(!bCheck); + m_xEndFT->set_sensitive(!bCheck); + + ModifyHdl(*m_xStartED); +} + +IMPL_LINK(SvxAsianLayoutPage, ModifyHdl, weld::Entry&, rEdit, void) +{ + LanguageType eSelectLanguage = m_xLanguageLB->get_active_id(); + Locale aLocale( LanguageTag::convertToLocale( eSelectLanguage )); + OUString sStart = m_xStartED->get_text(); + OUString sEnd = m_xEndED->get_text(); + bool bEnable = rEdit.get_sensitive(); + if(pImpl->xForbidden.is()) + { + try + { + if(bEnable) + { + ForbiddenCharacters aFCSet; + aFCSet.beginLine = sStart; + aFCSet.endLine = sEnd; + pImpl->addForbiddenCharacters(eSelectLanguage, std::move(aFCSet)); + } + else + pImpl->addForbiddenCharacters(eSelectLanguage, std::nullopt); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "cui.options", "in XForbiddenCharacters"); + } + } + pImpl->aConfig.SetStartEndChars( aLocale, bEnable ? &sStart : nullptr, bEnable ? &sEnd : nullptr); +} + +WhichRangesContainer SvxAsianLayoutPage::GetRanges() +{ + //no items are used + return WhichRangesContainer(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optbasic.cxx b/cui/source/options/optbasic.cxx new file mode 100644 index 0000000000..bbe20fd01e --- /dev/null +++ b/cui/source/options/optbasic.cxx @@ -0,0 +1,154 @@ +/* -*- 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 "optbasic.hxx" +#include <basic/codecompletecache.hxx> +#include <officecfg/Office/BasicIDE.hxx> + +SvxBasicIDEOptionsPage::SvxBasicIDEOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optbasicidepage.ui", "OptBasicIDEPage", &rSet) + , m_xCodeCompleteChk(m_xBuilder->weld_check_button("codecomplete_enable")) + , m_xAutocloseProcChk(m_xBuilder->weld_check_button("autoclose_proc")) + , m_xAutocloseParenChk(m_xBuilder->weld_check_button("autoclose_paren")) + , m_xAutocloseQuotesChk(m_xBuilder->weld_check_button("autoclose_quotes")) + , m_xAutoCorrectChk(m_xBuilder->weld_check_button("autocorrect")) + , m_xUseExtendedTypesChk(m_xBuilder->weld_check_button("extendedtypes_enable")) +{ + LoadConfig(); +} + +SvxBasicIDEOptionsPage::~SvxBasicIDEOptionsPage() +{ +} + +void SvxBasicIDEOptionsPage::LoadConfig() +{ + m_xCodeCompleteChk->set_active( officecfg::Office::BasicIDE::Autocomplete::CodeComplete::get() ); + m_xCodeCompleteChk->set_sensitive( !officecfg::Office::BasicIDE::Autocomplete::CodeComplete::isReadOnly() ); + m_xAutocloseProcChk->set_active( officecfg::Office::BasicIDE::Autocomplete::AutocloseProc::get() ); + m_xAutocloseProcChk->set_sensitive( !officecfg::Office::BasicIDE::Autocomplete::AutocloseProc::isReadOnly() ); + m_xAutocloseQuotesChk->set_active( officecfg::Office::BasicIDE::Autocomplete::AutocloseDoubleQuotes::get() ); + m_xAutocloseQuotesChk->set_sensitive( !officecfg::Office::BasicIDE::Autocomplete::AutocloseDoubleQuotes::isReadOnly() ); + m_xAutocloseParenChk->set_active( officecfg::Office::BasicIDE::Autocomplete::AutocloseParenthesis::get() ); + m_xAutocloseParenChk->set_sensitive( !officecfg::Office::BasicIDE::Autocomplete::AutocloseParenthesis::isReadOnly() ); + m_xAutoCorrectChk->set_active( officecfg::Office::BasicIDE::Autocomplete::AutoCorrect::get() ); + m_xAutoCorrectChk->set_sensitive( !officecfg::Office::BasicIDE::Autocomplete::AutoCorrect::isReadOnly() ); + m_xUseExtendedTypesChk->set_active( officecfg::Office::BasicIDE::Autocomplete::UseExtended::get() ); + m_xUseExtendedTypesChk->set_sensitive( !officecfg::Office::BasicIDE::Autocomplete::UseExtended::isReadOnly() ); +} + +OUString SvxBasicIDEOptionsPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "label3" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "codecomplete_enable", "autocorrect", "autoclose_quotes", + "autoclose_paren", "autoclose_proc", "extendedtypes_enable" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxBasicIDEOptionsPage::FillItemSet( SfxItemSet* /*rCoreSet*/ ) +{ + bool bModified = false; + std::shared_ptr< comphelper::ConfigurationChanges > batch( comphelper::ConfigurationChanges::create() ); + + if( m_xAutocloseProcChk->get_state_changed_from_saved() ) + { + officecfg::Office::BasicIDE::Autocomplete::AutocloseProc::set( m_xAutocloseProcChk->get_active(), batch ); + CodeCompleteOptions::SetProcedureAutoCompleteOn( m_xAutocloseProcChk->get_active() ); + bModified = true; + } + + if( m_xCodeCompleteChk->get_state_changed_from_saved() ) + { + //std::shared_ptr< comphelper::ConfigurationChanges > batch( comphelper::ConfigurationChanges::create() ); + officecfg::Office::BasicIDE::Autocomplete::CodeComplete::set( m_xCodeCompleteChk->get_active(), batch ); + CodeCompleteOptions::SetCodeCompleteOn( m_xCodeCompleteChk->get_active() ); + bModified = true; + } + + if( m_xUseExtendedTypesChk->get_state_changed_from_saved() ) + { + officecfg::Office::BasicIDE::Autocomplete::UseExtended::set( m_xUseExtendedTypesChk->get_active(), batch ); + CodeCompleteOptions::SetExtendedTypeDeclaration( m_xUseExtendedTypesChk->get_active() ); + bModified = true; + } + + if( m_xAutocloseParenChk->get_state_changed_from_saved() ) + { + officecfg::Office::BasicIDE::Autocomplete::AutocloseParenthesis::set( m_xAutocloseParenChk->get_active(), batch ); + CodeCompleteOptions::SetAutoCloseParenthesisOn( m_xAutocloseParenChk->get_active() ); + bModified = true; + } + + if( m_xAutocloseQuotesChk->get_state_changed_from_saved() ) + { + officecfg::Office::BasicIDE::Autocomplete::AutocloseDoubleQuotes::set( m_xAutocloseQuotesChk->get_active(), batch ); + CodeCompleteOptions::SetAutoCloseQuotesOn( m_xAutocloseQuotesChk->get_active() ); + bModified = true; + } + + if( m_xAutoCorrectChk->get_state_changed_from_saved() ) + { + officecfg::Office::BasicIDE::Autocomplete::AutoCorrect::set( m_xAutoCorrectChk->get_active(), batch ); + CodeCompleteOptions::SetAutoCorrectOn( m_xAutoCorrectChk->get_active() ); + bModified = true; + } + + if( bModified ) + batch->commit(); + + return bModified; +} + +void SvxBasicIDEOptionsPage::Reset( const SfxItemSet* /*rSet*/ ) +{ + LoadConfig(); + m_xCodeCompleteChk->save_state(); + m_xAutocloseProcChk->save_state(); + m_xAutocloseQuotesChk->save_state(); + m_xAutocloseParenChk->save_state(); + m_xAutoCorrectChk->save_state(); + m_xUseExtendedTypesChk->save_state(); +} + +std::unique_ptr<SfxTabPage> SvxBasicIDEOptionsPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SvxBasicIDEOptionsPage>(pPage, pController, *rAttrSet); +} + +void SvxBasicIDEOptionsPage::FillUserData() +{ + SetUserData( OUString() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optbasic.hxx b/cui/source/options/optbasic.hxx new file mode 100644 index 0000000000..bc4274eaca --- /dev/null +++ b/cui/source/options/optbasic.hxx @@ -0,0 +1,50 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sfx2/tabdlg.hxx> + +class SvxBasicIDEOptionsPage: public SfxTabPage +{ +private: + std::unique_ptr<weld::CheckButton> m_xCodeCompleteChk; + std::unique_ptr<weld::CheckButton> m_xAutocloseProcChk; + std::unique_ptr<weld::CheckButton> m_xAutocloseParenChk; + std::unique_ptr<weld::CheckButton> m_xAutocloseQuotesChk; + std::unique_ptr<weld::CheckButton> m_xAutoCorrectChk; + std::unique_ptr<weld::CheckButton> m_xUseExtendedTypesChk; + + void LoadConfig(); + +public: + SvxBasicIDEOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~SvxBasicIDEOptionsPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + virtual void FillUserData() override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optchart.cxx b/cui/source/options/optchart.cxx new file mode 100644 index 0000000000..eef87d2cd3 --- /dev/null +++ b/cui/source/options/optchart.cxx @@ -0,0 +1,300 @@ +/* -*- 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 "optchart.hxx" +#include <svx/SvxColorValueSet.hxx> +#include <vcl/virdev.hxx> +#include <vcl/weld.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <svx/svxids.hrc> +#include <osl/diagnose.h> +#include <officecfg/Office/Common.hxx> +#include <officecfg/Office/Chart.hxx> + +void SvxDefaultColorOptPage::InsertColorEntry(const XColorEntry& rEntry, sal_Int32 nPos) +{ + const Color& rColor = rEntry.GetColor(); + const OUString& rStr = rEntry.GetName(); + + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + Size aImageSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize(); + + ScopedVclPtrInstance<VirtualDevice> xDevice; + xDevice->SetOutputSize(aImageSize); + const ::tools::Rectangle aRect(Point(0, 0), aImageSize); + xDevice->SetFillColor(rColor); + xDevice->SetLineColor(rStyleSettings.GetDisableColor()); + xDevice->DrawRect(aRect); + + m_xLbChartColors->insert(nullptr, nPos, &rStr, nullptr, + nullptr, xDevice.get(), false, nullptr); + + if (nPos == -1) + aColorList.push_back( rColor ); + else + { + ImpColorList::iterator it = aColorList.begin(); + std::advance( it, nPos ); + aColorList.insert( it, rColor ); + } +} + +void SvxDefaultColorOptPage::RemoveColorEntry(sal_Int32 nPos) +{ + m_xLbChartColors->remove(nPos); + ImpColorList::iterator it = aColorList.begin(); + std::advance(it, nPos); + aColorList.erase(it); +} + +void SvxDefaultColorOptPage::ClearColorEntries() +{ + aColorList.clear(); + m_xLbChartColors->clear(); +} + +void SvxDefaultColorOptPage::ModifyColorEntry(const XColorEntry& rEntry, sal_Int32 nPos) +{ + RemoveColorEntry(nPos); + InsertColorEntry(rEntry, nPos); +} + +void SvxDefaultColorOptPage::FillBoxChartColorLB() +{ + if (!m_SvxChartColorTableUniquePtr) + return; + + m_xLbChartColors->freeze(); + ClearColorEntries(); + const tools::Long nCount(m_SvxChartColorTableUniquePtr->size()); + for (tools::Long i = 0; i < nCount; ++i) + InsertColorEntry((*m_SvxChartColorTableUniquePtr)[i]); + m_xLbChartColors->thaw(); +} + +SvxDefaultColorOptPage::SvxDefaultColorOptPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "cui/ui/optchartcolorspage.ui", "OptChartColorsPage", &rInAttrs) + , m_xLbChartColors(m_xBuilder->weld_tree_view("colors")) + , m_xLbPaletteSelector(m_xBuilder->weld_combo_box("paletteselector")) + , m_xPBDefault(m_xBuilder->weld_button("default")) + , m_xPBAdd(m_xBuilder->weld_button("add")) + , m_xPBRemove(m_xBuilder->weld_button("delete")) + , m_xValSetColorBox(new SvxColorValueSet(m_xBuilder->weld_scrolled_window("tablewin", true))) + , m_xValSetColorBoxWin(new weld::CustomWeld(*m_xBuilder, "table", *m_xValSetColorBox)) +{ + m_xLbChartColors->set_size_request(-1, m_xLbChartColors->get_height_rows(16)); + + if (officecfg::Office::Chart::DefaultColor::Series::isReadOnly()) + { + m_xPBDefault->set_sensitive(false); + m_xPBAdd->set_sensitive(false); + m_xPBRemove->set_sensitive(false); + m_xValSetColorBoxWin->set_sensitive(false); + } + + m_xPBDefault->connect_clicked( LINK( this, SvxDefaultColorOptPage, ResetToDefaults ) ); + m_xPBAdd->connect_clicked( LINK( this, SvxDefaultColorOptPage, AddChartColor ) ); + m_xPBRemove->connect_clicked( LINK( this, SvxDefaultColorOptPage, RemoveChartColor ) ); + m_xValSetColorBox->SetSelectHdl( LINK( this, SvxDefaultColorOptPage, BoxClickedHdl ) ); + m_xLbPaletteSelector->connect_changed( LINK( this, SvxDefaultColorOptPage, SelectPaletteLbHdl ) ); + + m_xValSetColorBox->SetStyle( m_xValSetColorBox->GetStyle() + | WB_ITEMBORDER | WB_NAMEFIELD | WB_VSCROLL ); + + if ( const SvxChartColorTableItem* pEditOptionsItem = rInAttrs.GetItemIfSet( SID_SCH_EDITOPTIONS, false ) ) + { + m_SvxChartColorTableUniquePtr = std::make_unique<SvxChartColorTable>( + pEditOptionsItem->GetColorList()); + } + else + { + m_SvxChartColorTableUniquePtr = std::make_unique<SvxChartColorTable>(); + m_SvxChartColorTableUniquePtr->useDefault(); + SvxChartOptions::SetDefaultColors(*m_SvxChartColorTableUniquePtr); + } + + Construct(); +} + +SvxDefaultColorOptPage::~SvxDefaultColorOptPage() +{ + m_xValSetColorBoxWin.reset(); + m_xValSetColorBox.reset(); +} + +void SvxDefaultColorOptPage::Construct() +{ + FillBoxChartColorLB(); + FillPaletteLB(); + + m_xLbChartColors->select( 0 ); +} + +std::unique_ptr<SfxTabPage> SvxDefaultColorOptPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrs ) +{ + return std::make_unique<SvxDefaultColorOptPage>( pPage, pController, *rAttrs ); +} + +OUString SvxDefaultColorOptPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label20", "label1" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString buttons[] = { "add", "delete", "default" }; + + for (const auto& btn : buttons) + { + if (const auto& pString = m_xBuilder->weld_button(btn)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxDefaultColorOptPage::FillItemSet( SfxItemSet* rOutAttrs ) +{ + if( m_SvxChartColorTableUniquePtr ) + { + rOutAttrs->Put(SvxChartColorTableItem(SID_SCH_EDITOPTIONS, *m_SvxChartColorTableUniquePtr)); + } + + return true; +} + +void SvxDefaultColorOptPage::Reset( const SfxItemSet* ) +{ + m_xLbChartColors->select( 0 ); +} + +void SvxDefaultColorOptPage::FillPaletteLB() +{ + m_xLbPaletteSelector->clear(); + std::vector<OUString> aPaletteList = aPaletteManager.GetPaletteList(); + for (auto const& palette : aPaletteList) + m_xLbPaletteSelector->append_text(palette); + + OUString aPaletteName(officecfg::Office::Common::UserColors::PaletteName::get()); + m_xLbPaletteSelector->set_active_text(aPaletteName); + if (m_xLbPaletteSelector->get_active() != -1) + SelectPaletteLbHdl( *m_xLbPaletteSelector ); +} + +void SvxDefaultColorOptPage::SaveChartOptions() +{ + if (m_SvxChartColorTableUniquePtr) + SvxChartOptions::SetDefaultColors(*m_SvxChartColorTableUniquePtr); +} + +// event handlers + + +// ResetToDefaults +IMPL_LINK_NOARG(SvxDefaultColorOptPage, ResetToDefaults, weld::Button&, void) +{ + if( m_SvxChartColorTableUniquePtr ) + { + m_SvxChartColorTableUniquePtr->useDefault(); + + FillBoxChartColorLB(); + + m_xLbChartColors->grab_focus(); + m_xLbChartColors->select( 0 ); + m_xPBRemove->set_sensitive(true); + } +} + +// AddChartColor +IMPL_LINK_NOARG(SvxDefaultColorOptPage, AddChartColor, weld::Button&, void) +{ + if( m_SvxChartColorTableUniquePtr ) + { + Color const black( 0x00, 0x00, 0x00 ); + + m_SvxChartColorTableUniquePtr->append( + XColorEntry(black, SvxChartColorTable::getDefaultName(m_SvxChartColorTableUniquePtr->size()))); + + FillBoxChartColorLB(); + m_xLbChartColors->grab_focus(); + m_xLbChartColors->select(m_SvxChartColorTableUniquePtr->size() - 1); + m_xPBRemove->set_sensitive(true); + } +} + +// RemoveChartColor +IMPL_LINK_NOARG( SvxDefaultColorOptPage, RemoveChartColor, weld::Button&, void ) +{ + sal_Int32 nIndex = m_xLbChartColors->get_selected_index(); + if (nIndex == -1) + return; + + if( !m_SvxChartColorTableUniquePtr ) + return; + + OSL_ENSURE(m_SvxChartColorTableUniquePtr->size() > 1, "don't delete the last chart color"); + + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "cui/ui/querydeletechartcolordialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteChartColorDialog")); + + if (RET_YES != xQuery->run()) + return; + + m_SvxChartColorTableUniquePtr->remove(nIndex); + + FillBoxChartColorLB(); + + m_xLbChartColors->grab_focus(); + + if (nIndex == m_xLbChartColors->n_children() && m_xLbChartColors->n_children() > 0) + m_xLbChartColors->select(m_SvxChartColorTableUniquePtr->size() - 1); + else if (m_xLbChartColors->n_children() > 0) + m_xLbChartColors->select( nIndex ); + else + m_xPBRemove->set_sensitive(true); +} + +IMPL_LINK_NOARG( SvxDefaultColorOptPage, SelectPaletteLbHdl, weld::ComboBox&, void) +{ + sal_Int32 nPos = m_xLbPaletteSelector->get_active(); + aPaletteManager.SetPalette( nPos ); + aPaletteManager.ReloadColorSet( *m_xValSetColorBox ); + m_xValSetColorBox->Resize(); +} + +IMPL_LINK_NOARG(SvxDefaultColorOptPage, BoxClickedHdl, ValueSet*, void) +{ + sal_Int32 nIdx = m_xLbChartColors->get_selected_index(); + if (nIdx != -1) + { + const XColorEntry aEntry(m_xValSetColorBox->GetItemColor(m_xValSetColorBox->GetSelectedItemId()), m_xLbChartColors->get_selected_text()); + + ModifyColorEntry(aEntry, nIdx); + m_SvxChartColorTableUniquePtr->replace(nIdx, aEntry); + + m_xLbChartColors->select(nIdx); // reselect entry + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optchart.hxx b/cui/source/options/optchart.hxx new file mode 100644 index 0000000000..22a01495b2 --- /dev/null +++ b/cui/source/options/optchart.hxx @@ -0,0 +1,81 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sfx2/tabdlg.hxx> +#include <svtools/valueset.hxx> +#include <svx/xtable.hxx> +#include <svx/PaletteManager.hxx> +#include <vcl/customweld.hxx> + +#include "cfgchart.hxx" + +typedef std::vector<Color> ImpColorList; + +class SvxDefaultColorOptPage : public SfxTabPage +{ +private: + // no reason to use a cloned SfxItem here (SvxChartColorTableItem) + // that just leads to non-const SfxItem and potential trouble + std::unique_ptr<SvxChartColorTable> m_SvxChartColorTableUniquePtr; + + ImpColorList aColorList; + PaletteManager aPaletteManager; + + std::unique_ptr<weld::TreeView> m_xLbChartColors; + std::unique_ptr<weld::ComboBox> m_xLbPaletteSelector; + std::unique_ptr<weld::Button> m_xPBDefault; + std::unique_ptr<weld::Button> m_xPBAdd; + std::unique_ptr<weld::Button> m_xPBRemove; + std::unique_ptr<SvxColorValueSet> m_xValSetColorBox; + std::unique_ptr<weld::CustomWeld> m_xValSetColorBoxWin; + + DECL_LINK(ResetToDefaults, weld::Button&, void); + DECL_LINK(AddChartColor, weld::Button&, void); + DECL_LINK(RemoveChartColor, weld::Button&, void); + DECL_LINK(BoxClickedHdl, ValueSet*, void); + DECL_LINK(SelectPaletteLbHdl, weld::ComboBox&, void); + + void FillPaletteLB(); + +private: + void InsertColorEntry(const XColorEntry& rEntry, sal_Int32 nPos = -1); + void RemoveColorEntry(sal_Int32 nPos); + void ModifyColorEntry(const XColorEntry& rEntry, sal_Int32 nPos); + void ClearColorEntries(); + void FillBoxChartColorLB(); + +public: + SvxDefaultColorOptPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~SvxDefaultColorOptPage() override; + + void Construct(); + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rOutAttrs ) override; + virtual void Reset( const SfxItemSet* rInAttrs ) override; + + void SaveChartOptions(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optcolor.cxx b/cui/source/options/optcolor.cxx new file mode 100644 index 0000000000..c8841205f3 --- /dev/null +++ b/cui/source/options/optcolor.cxx @@ -0,0 +1,980 @@ +/* -*- 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 <sal/config.h> + +#include <bitset> + +#include <tools/debug.hxx> +#include <editeng/editids.hrc> +#include <svtools/colorcfg.hxx> +#include <svtools/extcolorcfg.hxx> +#include <svx/colorbox.hxx> +#include <unotools/moduleoptions.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svx/svxdlg.hxx> +#include <helpids.h> +#include <dialmgr.hxx> +#include "optcolor.hxx" +#include <strings.hrc> +#include <svtools/miscopt.hxx> +#include <officecfg/Office/Common.hxx> +using namespace ::com::sun::star; +using namespace ::svtools; + +namespace +{ + +// list of default groups +enum Group +{ + Group_General, + Group_Writer, + Group_Html, + Group_Calc, + Group_Draw, + Group_Basic, + Group_Sql, + + nGroupCount +}; + +// group data +struct +{ + // group + Group eGroup; + // .ui group name + OUString pGroup; +} +const vGroupInfo[] = +{ + // the groups are in the same order as in enum Group above + { Group_General, "general" }, + { Group_Writer, "writer" }, + { Group_Html, "html" }, + { Group_Calc, "calc" }, + { Group_Draw, "draw" }, + { Group_Basic, "basic" }, + { Group_Sql, "sql" } +}; + +// color config entry data (see ColorConfigWindow_Impl::Entry below) +struct +{ + // group + Group eGroup; + //checkbox (or simple text) + OUString pText; + //color listbox + OUString pColor; + // has checkbox? + bool bCheckBox; +} +const vEntryInfo[] = +{ + #define IDS(Name) \ + SAL_STRINGIFY(Name), SAL_STRINGIFY(Name##_lb), false + + #define IDS_CB(Name) \ + SAL_STRINGIFY(Name), SAL_STRINGIFY(Name##_lb), true + + // The list of these entries (enum ColorConfigEntry) are in colorcfg.hxx. + + { Group_General, IDS(doccolor) }, + { Group_General, IDS_CB(docboundaries) }, + { Group_General, IDS(appback) }, + { Group_General, IDS_CB(objboundaries) }, + { Group_General, IDS_CB(tblboundaries) }, + { Group_General, IDS(font) }, + { Group_General, IDS_CB(unvisitedlinks) }, + { Group_General, IDS_CB(visitedlinks) }, + { Group_General, IDS(autospellcheck) }, + { Group_General, IDS(grammarcheck) }, + { Group_General, IDS(smarttags) }, + { Group_General, IDS_CB(shadows) }, + + { Group_Writer, IDS(writergrid) }, + { Group_Writer, IDS_CB(field) }, + { Group_Writer, IDS_CB(index) }, + { Group_Writer, IDS(direct) }, + { Group_Writer, IDS(script) }, + { Group_Writer, IDS_CB(section) }, + { Group_Writer, IDS(hdft) }, + { Group_Writer, IDS(pagebreak) }, + + { Group_Html, IDS(sgml) }, + { Group_Html, IDS(htmlcomment) }, + { Group_Html, IDS(htmlkeyword) }, + { Group_Html, IDS(unknown) }, + + { Group_Calc, IDS(calcgrid) }, + { Group_Calc, IDS(brk) }, + { Group_Calc, IDS(brkmanual) }, + { Group_Calc, IDS(brkauto) }, + { Group_Calc, IDS_CB(hiddencolrow) }, + { Group_Calc, IDS_CB(textoverflow) }, + { Group_Calc, IDS(comments) }, + { Group_Calc, IDS(det) }, + { Group_Calc, IDS(deterror) }, + { Group_Calc, IDS(ref) }, + { Group_Calc, IDS(notes) }, + { Group_Calc, IDS(values) }, + { Group_Calc, IDS(formulas) }, + { Group_Calc, IDS(text) }, + { Group_Calc, IDS(protectedcells) }, + + { Group_Draw, IDS(drawgrid) }, + + { Group_Basic, IDS(basiceditor) }, + { Group_Basic, IDS(basicid) }, + { Group_Basic, IDS(basiccomment) }, + { Group_Basic, IDS(basicnumber) }, + { Group_Basic, IDS(basicstring) }, + { Group_Basic, IDS(basicop) }, + { Group_Basic, IDS(basickeyword) }, + { Group_Basic, IDS(error) }, + + { Group_Sql, IDS(sqlid) }, + { Group_Sql, IDS(sqlnumber) }, + { Group_Sql, IDS(sqlstring) }, + { Group_Sql, IDS(sqlop) }, + { Group_Sql, IDS(sqlkeyword) }, + { Group_Sql, IDS(sqlparam) }, + { Group_Sql, IDS(sqlcomment) } + + #undef IDS +}; + +// Maps the names of default color schemes to the corresponding TranslateId +const std::map<OUString, OUString> &getColorSchemes() +{ + static std::map<OUString, OUString> const vColorSchemes = { + {"COLOR_SCHEME_LIBREOFFICE_AUTOMATIC", CuiResId(RID_COLOR_SCHEME_LIBREOFFICE_AUTOMATIC)}, + }; + return vColorSchemes; +}; + +// If the color scheme name has a translated string, then return the translation +// Or else simply return the input string +// For non-translatable color schemes, the ID and the name are the same +OUString lcl_SchemeIdToTranslatedName(const OUString& sSchemeId) +{ + auto it = getColorSchemes().find(sSchemeId); + if (it != getColorSchemes().end()) + return it->second; + return sSchemeId; +} + +// Given a translated color scheme name, return the scheme ID used in the UI.xcu file +// For non-translatable color schemes, the ID and the name are the same +OUString lcl_TranslatedNameToSchemeId(const OUString& sName) +{ + for (auto it = getColorSchemes().begin(); it != getColorSchemes().end(); ++it) + if (it->second == sName) + return it->first; + return sName; +} + +// ColorConfigWindow_Impl + +class ColorConfigWindow_Impl +{ +public: + explicit ColorConfigWindow_Impl(weld::Window* pTopLevel, weld::Container* pParent); + +public: + void SetLinks(Link<weld::Toggleable&,void> const&, + Link<ColorListBox&,void> const&, + Link<weld::Widget&,void> const&, + weld::ScrolledWindow& rScroll); + void Update(EditableColorConfig const*, EditableExtendedColorConfig const*); + void UpdateEntries(); + void ClickHdl(EditableColorConfig*, const weld::Toggleable&); + void ColorHdl(EditableColorConfig*, EditableExtendedColorConfig*, const ColorListBox*); + + weld::Widget& GetWidget1() + { + return *m_xWidget1; + } + + weld::Widget& GetWidget2() + { + return *m_xWidget2; + } + + weld::Widget& GetBody() + { + return *m_xBox; + } + + int GetLabelIndent() const + { + return m_nCheckBoxLabelOffset; + } + +private: + // Chapter -- horizontal group separator stripe with text + class Chapter + { + // text + std::unique_ptr<weld::Label> m_xText; + public: + Chapter(weld::Builder& rBuilder, const OUString& pLabelWidget, bool bShow); + void SetText(const OUString& rLabel) { m_xText->set_label(rLabel); } + }; + + // Entry -- a color config entry: + // text (checkbox) + color list box + struct Entry + { + Entry(weld::Window* pTopLevel, weld::Builder& rBuilder, const OUString& pTextWidget, const OUString& pColorWidget, + const Color& rColor, int nCheckBoxLabelOffset, const ColorListBox* pCache, bool bCheckBox, bool bShow); + void SetText(const OUString& rLabel) { dynamic_cast<weld::Label&>(*m_xText).set_label(rLabel); } + int get_height_request() const + { + return std::max(m_xText->get_preferred_size().Height(), + m_xColorList->get_widget().get_preferred_size().Height()); + } + void Hide(); + + void SetLinks(Link<weld::Toggleable&,void> const&, + Link<ColorListBox&,void> const&, + Link<weld::Widget&,void> const&); + void Update (ColorConfigValue const&); + void Update (ExtendedColorConfigValue const&); + void ColorChanged (ColorConfigValue&); + void ColorChanged (ExtendedColorConfigValue&); + + bool Is(const weld::Toggleable* pBox) const { return m_xText.get() == pBox; } + bool Is(const ColorListBox* pBox) const { return m_xColorList.get() == pBox; } + + // checkbox (CheckBox) or simple text (FixedText) + std::unique_ptr<weld::Widget> m_xText; + // color list box + std::unique_ptr<ColorListBox> m_xColorList; + // default color + Color m_aDefaultColor; + }; + +private: + weld::Window* m_pTopLevel; + int m_nCheckBoxLabelOffset; + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Box> m_xBox; + std::unique_ptr<weld::Widget> m_xWidget1; + std::unique_ptr<weld::Widget> m_xWidget2; + + std::vector<std::unique_ptr<weld::Builder>> vExtBuilders; + std::vector<std::unique_ptr<weld::Container>> vExtContainers; + // vChapters -- groups (group headers) + std::vector<std::shared_ptr<Chapter> > vChapters; + // vEntries -- color options + std::vector<std::shared_ptr<Entry> > vEntries; + + // module options + SvtModuleOptions aModuleOptions; + + // initialization + void CreateEntries(); + +private: + + bool IsGroupVisible (Group) const; +}; + +} // namespace + +// ColorConfigWindow_Impl::Chapter + +// ctor for default groups +// rParent: parent window (ColorConfigWindow_Impl) +// eGroup: which group is this? +ColorConfigWindow_Impl::Chapter::Chapter(weld::Builder& rBuilder, const OUString& pLabelWidget, bool bShow) + : m_xText(rBuilder.weld_label(pLabelWidget)) +{ + if (!bShow) + m_xText->hide(); +} + +// ColorConfigWindow_Impl::Entry +ColorConfigWindow_Impl::Entry::Entry(weld::Window* pTopLevel, weld::Builder& rBuilder, + const OUString& pTextWidget, const OUString& pColorWidget, + const Color& rColor, int nCheckBoxLabelOffset, + const ColorListBox* pCache, bool bCheckBox, bool bShow) + : m_xColorList(new ColorListBox(rBuilder.weld_menu_button(pColorWidget), + [pTopLevel]{ return pTopLevel; }, pCache)) + , m_aDefaultColor(rColor) +{ + if (bCheckBox) + m_xText = rBuilder.weld_check_button(pTextWidget); + else + m_xText = rBuilder.weld_label(pTextWidget); + + // color list + m_xColorList->SetSlotId(SID_ATTR_CHAR_COLOR); + m_xColorList->SetAutoDisplayColor(m_aDefaultColor); + + if (!bCheckBox) + { + m_xText->set_margin_start(m_xText->get_margin_start() + + nCheckBoxLabelOffset); + } + + if (!bShow) + Hide(); +} + +void ColorConfigWindow_Impl::Entry::Hide() +{ + m_xText->hide(); + m_xColorList->hide(); +} + +// SetLinks() +void ColorConfigWindow_Impl::Entry::SetLinks(Link<weld::Toggleable&,void> const& rCheckLink, + Link<ColorListBox&,void> const& rColorLink, + Link<weld::Widget&,void> const& rGetFocusLink) +{ + m_xColorList->SetSelectHdl(rColorLink); + m_xColorList->connect_focus_in(rGetFocusLink); + if (weld::Toggleable* pCheckBox = dynamic_cast<weld::Toggleable*>(m_xText.get())) + { + pCheckBox->connect_toggled(rCheckLink); + pCheckBox->connect_focus_in(rGetFocusLink); + } +} + +// updates a default color config entry +void ColorConfigWindow_Impl::Entry::Update(ColorConfigValue const& rValue) +{ + Color aColor(rValue.nColor); + m_xColorList->SelectEntry(aColor); + if (weld::Toggleable* pCheckBox = dynamic_cast<weld::Toggleable*>(m_xText.get())) + pCheckBox->set_active(rValue.bIsVisible); +} + +// updates an extended color config entry +void ColorConfigWindow_Impl::Entry::Update(ExtendedColorConfigValue const& rValue) +{ + Color aColor(rValue.getColor()); + if (rValue.getColor() == rValue.getDefaultColor()) + m_xColorList->SelectEntry(COL_AUTO); + else + m_xColorList->SelectEntry(aColor); +} + +// color of a default entry has changed +void ColorConfigWindow_Impl::Entry::ColorChanged(ColorConfigValue& rValue) +{ + Color aColor = m_xColorList->GetSelectEntryColor(); + rValue.nColor = aColor; +} + +// color of an extended entry has changed +void ColorConfigWindow_Impl::Entry::ColorChanged(ExtendedColorConfigValue& rValue) +{ + Color aColor = m_xColorList->GetSelectEntryColor(); + rValue.setColor(aColor); + if (aColor == COL_AUTO) + { + rValue.setColor(rValue.getDefaultColor()); + } +} + +// ColorConfigWindow_Impl +ColorConfigWindow_Impl::ColorConfigWindow_Impl(weld::Window* pTopLevel, weld::Container* pParent) + : m_pTopLevel(pTopLevel) + , m_xBuilder(Application::CreateBuilder(pParent, "cui/ui/colorconfigwin.ui")) + , m_xBox(m_xBuilder->weld_box("ColorConfigWindow")) + , m_xWidget1(m_xBuilder->weld_widget("docboundaries")) + , m_xWidget2(m_xBuilder->weld_widget("docboundaries_lb")) +{ + CreateEntries(); +} + +void ColorConfigWindow_Impl::CreateEntries() +{ + std::bitset<nGroupCount> aModulesInstalled; + // creating group headers + vChapters.reserve(nGroupCount); + for (unsigned i = 0; i != nGroupCount; ++i) + { + aModulesInstalled[i] = IsGroupVisible(vGroupInfo[i].eGroup); + vChapters.push_back(std::make_shared<Chapter>(*m_xBuilder, vGroupInfo[i].pGroup, aModulesInstalled[i])); + } + + // Here we want to get the amount to add to the position of a FixedText to + // get it to align its contents with that of a CheckBox + { + OUString sSampleText("XXXXXX"); + std::unique_ptr<weld::CheckButton> xCheckBox(m_xBuilder->weld_check_button("docboundaries")); + std::unique_ptr<weld::Label> xFixedText(m_xBuilder->weld_label("doccolor")); + OUString sOrigCheck(xCheckBox->get_label()); + OUString sOrigFixed(xFixedText->get_label()); + xCheckBox->set_label(sSampleText); + xFixedText->set_label(sSampleText); + Size aCheckSize(xCheckBox->get_preferred_size()); + Size aFixedSize(xFixedText->get_preferred_size()); + xCheckBox->set_label(sOrigCheck); + xFixedText->set_label(sOrigFixed); + m_nCheckBoxLabelOffset = aCheckSize.Width() - aFixedSize.Width(); + } + + const ColorListBox* pCache = nullptr; + + // creating entries + vEntries.reserve(ColorConfigEntryCount); + for (size_t i = 0; i < std::size(vEntryInfo); ++i) + { + vEntries.push_back(std::make_shared<Entry>(m_pTopLevel, *m_xBuilder, + vEntryInfo[i].pText, vEntryInfo[i].pColor, + ColorConfig::GetDefaultColor(static_cast<ColorConfigEntry>(i)), + m_nCheckBoxLabelOffset, pCache, + vEntryInfo[i].bCheckBox, + aModulesInstalled[vEntryInfo[i].eGroup])); + if (!pCache) + pCache = vEntries.back()->m_xColorList.get(); + } + + // extended entries + ExtendedColorConfig aExtConfig; + unsigned const nExtGroupCount = aExtConfig.GetComponentCount(); + if (!nExtGroupCount) + return; + + for (unsigned j = 0; j != nExtGroupCount; ++j) + { + vExtBuilders.emplace_back(Application::CreateBuilder(m_xBox.get(), "cui/ui/chapterfragment.ui")); + vExtContainers.emplace_back(vExtBuilders.back()->weld_frame("ChapterFragment")); + + OUString const sComponentName = aExtConfig.GetComponentName(j); + vChapters.push_back(std::make_shared<Chapter>( + *vExtBuilders.back(), "chapter", true)); + vChapters.back()->SetText(aExtConfig.GetComponentDisplayName(sComponentName)); + + vExtContainers.emplace_back(vExtBuilders.back()->weld_box("contents")); + weld::Container* pChapterBox = vExtContainers.back().get(); + + unsigned nColorCount = aExtConfig.GetComponentColorCount(sComponentName); + for (unsigned i = 0; i != nColorCount; ++i) + { + vExtBuilders.emplace_back(Application::CreateBuilder(pChapterBox, "cui/ui/colorfragment.ui")); + vExtContainers.emplace_back(vExtBuilders.back()->weld_container("ColorFragment")); + + ExtendedColorConfigValue const aColorEntry = + aExtConfig.GetComponentColorConfigValue(sComponentName, i); + vEntries.push_back(std::make_shared<Entry>(m_pTopLevel, *vExtBuilders.back(), + "label", "button", aColorEntry.getDefaultColor(), + m_nCheckBoxLabelOffset, pCache, false, true)); + vEntries.back()->SetText(aColorEntry.getDisplayName()); + } + } +} + +// SetLinks() +void ColorConfigWindow_Impl::SetLinks(Link<weld::Toggleable&,void> const& aCheckLink, + Link<ColorListBox&,void> const& aColorLink, + Link<weld::Widget&,void> const& rGetFocusLink, + weld::ScrolledWindow& rScroll) +{ + if (vEntries.empty()) + return; + for (auto const & i: vEntries) + i->SetLinks(aCheckLink, aColorLink, rGetFocusLink); + // 6 is the spacing set on ColorConfigWindow + rScroll.vadjustment_set_step_increment(vEntries[0]->get_height_request() + 6); +} + +// Update() +void ColorConfigWindow_Impl::Update ( + EditableColorConfig const* pConfig, + EditableExtendedColorConfig const* pExtConfig) +{ + // updating default entries + for (unsigned i = 0; i != ColorConfigEntryCount; ++i) + { + ColorConfigEntry const aColorEntry = static_cast<ColorConfigEntry>(i); + vEntries[i]->Update( + pConfig->GetColorValue(aColorEntry) + ); + } + + // updating extended entries + decltype(vEntries)::size_type i = ColorConfigEntryCount; + unsigned const nExtCount = pExtConfig->GetComponentCount(); + for (unsigned j = 0; j != nExtCount; ++j) + { + OUString sComponentName = pExtConfig->GetComponentName(j); + unsigned const nColorCount = pExtConfig->GetComponentColorCount(sComponentName); + for (unsigned k = 0; i != vEntries.size() && k != nColorCount; ++i, ++k) + vEntries[i]->Update( + pExtConfig->GetComponentColorConfigValue(sComponentName, k) + ); + } +} + +void ColorConfigWindow_Impl::UpdateEntries() +{ + for (unsigned i = 0; i != ColorConfigEntryCount; ++i) + { + ColorConfigEntry const aEntry = static_cast<ColorConfigEntry>(i); + Color aColor = ColorConfig::GetDefaultColor(aEntry); + vEntries[i]->m_xColorList->SetAutoDisplayColor(aColor); + } +} + +// ClickHdl() +void ColorConfigWindow_Impl::ClickHdl(EditableColorConfig* pConfig, const weld::Toggleable& rBox) +{ + for (unsigned i = 0; i != ColorConfigEntryCount; ++i) + { + if (vEntries[i]->Is(&rBox)) + { + ColorConfigEntry const aEntry = static_cast<ColorConfigEntry>(i); + ColorConfigValue aValue = pConfig->GetColorValue(aEntry); + aValue.bIsVisible = rBox.get_active(); + pConfig->SetColorValue(aEntry, aValue); + break; + } + } +} + +// ColorHdl() +void ColorConfigWindow_Impl::ColorHdl( + EditableColorConfig* pConfig, EditableExtendedColorConfig* pExtConfig, + const ColorListBox* pBox) +{ + unsigned i = 0; + + // default entries + for ( ; i != ColorConfigEntryCount; ++i) + { + if (pBox && vEntries[i]->Is(pBox)) + { + ColorConfigEntry const aColorEntry = static_cast<ColorConfigEntry>(i); + ColorConfigValue aValue = pConfig->GetColorValue(aColorEntry); + vEntries[i]->ColorChanged(aValue); + pConfig->SetColorValue(aColorEntry, aValue); + break; + } + } + + // extended entries + unsigned const nExtCount = pExtConfig->GetComponentCount(); + i = ColorConfigEntryCount; + for (unsigned j = 0; j != nExtCount; ++j) + { + OUString sComponentName = pExtConfig->GetComponentName(j); + unsigned const nColorCount = pExtConfig->GetComponentColorCount(sComponentName); + unsigned const nCount = vEntries.size(); + for (unsigned k = 0; i != nCount && k != nColorCount; ++i, ++k) + { + if (pBox && vEntries[i]->Is(pBox)) + { + ExtendedColorConfigValue aValue = + pExtConfig->GetComponentColorConfigValue(sComponentName, k); + vEntries[i]->ColorChanged(aValue); + pExtConfig->SetColorValue(sComponentName, aValue); + break; + } + } + } +} + + +// IsGroupVisible() +bool ColorConfigWindow_Impl::IsGroupVisible (Group eGroup) const +{ + switch (eGroup) + { + case Group_Writer: + case Group_Html: + return aModuleOptions.IsModuleInstalled(SvtModuleOptions::EModule::WRITER); + case Group_Calc: + return aModuleOptions.IsModuleInstalled(SvtModuleOptions::EModule::CALC); + case Group_Draw: + return + aModuleOptions.IsModuleInstalled(SvtModuleOptions::EModule::DRAW) || + aModuleOptions.IsModuleInstalled(SvtModuleOptions::EModule::IMPRESS); + case Group_Sql: + return aModuleOptions.IsModuleInstalled(SvtModuleOptions::EModule::DATABASE); + default: + return true; + } +} + +class ColorConfigCtrl_Impl +{ + std::unique_ptr<weld::ScrolledWindow> m_xVScroll; + std::unique_ptr<weld::Container> m_xBody; + std::unique_ptr<ColorConfigWindow_Impl> m_xScrollWindow; + + EditableColorConfig* pColorConfig; + EditableExtendedColorConfig* pExtColorConfig; + + DECL_LINK(ClickHdl, weld::Toggleable&, void); + DECL_LINK(ColorHdl, ColorListBox&, void); + DECL_LINK(ControlFocusHdl, weld::Widget&, void); + +public: + explicit ColorConfigCtrl_Impl(weld::Window* pTopLevel, weld::Builder& rbuilder); + + void SetConfig (EditableColorConfig& rConfig) { pColorConfig = &rConfig; } + void SetExtendedConfig (EditableExtendedColorConfig& rConfig) { pExtColorConfig = &rConfig; } + void Update(); + void UpdateEntries(); + tools::Long GetScrollPosition() const + { + return m_xVScroll->vadjustment_get_value(); + } + void SetScrollPosition(tools::Long nSet) + { + m_xVScroll->vadjustment_set_value(nSet); + } + weld::Widget& GetWidget1() + { + return m_xScrollWindow->GetWidget1(); + } + weld::Widget& GetWidget2() + { + return m_xScrollWindow->GetWidget2(); + } + int GetLabelIndent() const + { + return m_xScrollWindow->GetLabelIndent(); + } +}; + +ColorConfigCtrl_Impl::ColorConfigCtrl_Impl(weld::Window* pTopLevel, weld::Builder& rBuilder) + : m_xVScroll(rBuilder.weld_scrolled_window("scroll")) + , m_xBody(rBuilder.weld_container("colorconfig")) + , m_xScrollWindow(std::make_unique<ColorConfigWindow_Impl>(pTopLevel, m_xBody.get())) + , pColorConfig(nullptr) + , pExtColorConfig(nullptr) +{ + m_xBody->set_stack_background(); + + Link<weld::Toggleable&,void> aCheckLink = LINK(this, ColorConfigCtrl_Impl, ClickHdl); + Link<ColorListBox&,void> aColorLink = LINK(this, ColorConfigCtrl_Impl, ColorHdl); + Link<weld::Widget&,void> const& aGetFocusLink = LINK(this, ColorConfigCtrl_Impl, ControlFocusHdl); + m_xScrollWindow->SetLinks(aCheckLink, aColorLink, aGetFocusLink, *m_xVScroll); +} + +void ColorConfigCtrl_Impl::Update () +{ + DBG_ASSERT(pColorConfig, "Configuration not set"); + m_xScrollWindow->Update(pColorConfig, pExtColorConfig); +} + +void ColorConfigCtrl_Impl::UpdateEntries() +{ + m_xScrollWindow->UpdateEntries(); +} + +IMPL_LINK(ColorConfigCtrl_Impl, ClickHdl, weld::Toggleable&, rBox, void) +{ + DBG_ASSERT(pColorConfig, "Configuration not set"); + m_xScrollWindow->ClickHdl(pColorConfig, rBox); +} + +// a color list has changed +IMPL_LINK(ColorConfigCtrl_Impl, ColorHdl, ColorListBox&, rBox, void) +{ + DBG_ASSERT(pColorConfig, "Configuration not set" ); + m_xScrollWindow->ColorHdl(pColorConfig, pExtColorConfig, &rBox); +} + +IMPL_LINK(ColorConfigCtrl_Impl, ControlFocusHdl, weld::Widget&, rCtrl, void) +{ + // determine whether a control is completely visible + // and make it visible + unsigned const nWinHeight = m_xVScroll->vadjustment_get_page_size(); + + // calc visible area + auto nThumbPos = m_xVScroll->vadjustment_get_value(); + int const nWinTop = nThumbPos; + int const nWinBottom = nWinTop + nWinHeight; + + int x, nCtrlPosY, width, nHeight; + rCtrl.get_extents_relative_to(m_xScrollWindow->GetBody(), x, nCtrlPosY, width, nHeight); + + int const nSelectedItemTop = nCtrlPosY; + int const nSelectedItemBottom = nCtrlPosY + nHeight; + bool const shouldScrollDown = nSelectedItemBottom >= nWinBottom; + bool const shouldScrollUp = nSelectedItemTop <= nWinTop; + bool const isNeedToScroll = shouldScrollDown || shouldScrollUp || nCtrlPosY < 0; + + if (!isNeedToScroll) + return; + + if (shouldScrollDown) + { + int nOffset = nSelectedItemBottom - nWinBottom; + nThumbPos += nOffset + 2; + } + else + { + int nOffset = nWinTop - nSelectedItemTop; + nThumbPos -= nOffset + 2; + if(nThumbPos < 0) + nThumbPos = 0; + } + m_xVScroll->vadjustment_set_value(nThumbPos); +} + +// SvxColorOptionsTabPage +SvxColorOptionsTabPage::SvxColorOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "cui/ui/optappearancepage.ui", "OptAppearancePage", &rCoreSet) + , bFillItemSetCalled(false) + , m_nSizeAllocEventId(nullptr) + , m_xAutoColorLB(m_xBuilder->weld_combo_box("autocolorlb")) + , m_xColorSchemeLB(m_xBuilder->weld_combo_box("colorschemelb")) + , m_xSaveSchemePB(m_xBuilder->weld_button("save")) + , m_xDeleteSchemePB(m_xBuilder->weld_button("delete")) + , m_xColorConfigCT(new ColorConfigCtrl_Impl(pController->getDialog(), *m_xBuilder)) + , m_xTable(m_xBuilder->weld_widget("table")) + , m_xOnFT(m_xBuilder->weld_label("on")) + , m_xColorFT(m_xBuilder->weld_label("colorsetting")) + , m_rWidget1(m_xColorConfigCT->GetWidget1()) + , m_rWidget2(m_xColorConfigCT->GetWidget2()) +{ + m_xColorSchemeLB->make_sorted(); + m_xColorSchemeLB->connect_changed(LINK(this, SvxColorOptionsTabPage, SchemeChangedHdl_Impl)); + m_xAutoColorLB->connect_changed(LINK(this, SvxColorOptionsTabPage, onAutoColorChanged)); + Link<weld::Button&,void> aLk = LINK(this, SvxColorOptionsTabPage, SaveDeleteHdl_Impl ); + m_xSaveSchemePB->connect_clicked(aLk); + m_xDeleteSchemePB->connect_clicked(aLk); + + m_rWidget1.connect_size_allocate(LINK(this, SvxColorOptionsTabPage, AdjustHeaderBar)); + m_rWidget2.connect_size_allocate(LINK(this, SvxColorOptionsTabPage, AdjustHeaderBar)); +} + +SvxColorOptionsTabPage::~SvxColorOptionsTabPage() +{ + if (pColorConfig) + { + //when the dialog is cancelled but the color scheme ListBox has been changed these + //changes need to be undone + if (!bFillItemSetCalled && m_xColorSchemeLB->get_value_changed_from_saved()) + { + OUString sOldScheme = m_xColorSchemeLB->get_saved_value(); + if(!sOldScheme.isEmpty()) + { + pColorConfig->SetCurrentSchemeName(sOldScheme); + pExtColorConfig->SetCurrentSchemeName(sOldScheme); + } + } + pColorConfig->ClearModified(); + pColorConfig->EnableBroadcast(); + pColorConfig.reset(); + + pExtColorConfig->ClearModified(); + pExtColorConfig->EnableBroadcast(); + pExtColorConfig.reset(); + } + m_xColorConfigCT.reset(); + if (m_nSizeAllocEventId) + Application::RemoveUserEvent(m_nSizeAllocEventId); +} + +std::unique_ptr<SfxTabPage> SvxColorOptionsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SvxColorOptionsTabPage>(pPage, pController, *rAttrSet); +} + +OUString SvxColorOptionsTabPage::GetAllStrings() +{ + // buttons are excluded + OUString sAllStrings; + OUString labels[] = { "label2", "label3", "autocolor", "uielements", "colorsetting" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxColorOptionsTabPage::FillItemSet( SfxItemSet* ) +{ + bFillItemSetCalled = true; + if (m_xColorSchemeLB->get_value_changed_from_saved()) + { + pColorConfig->SetModified(); + pExtColorConfig->SetModified(); + } + if (pColorConfig->IsModified()) + pColorConfig->Commit(); + if (pExtColorConfig->IsModified()) + pExtColorConfig->Commit(); + return true; +} + +void SvxColorOptionsTabPage::Reset( const SfxItemSet* ) +{ + if(pColorConfig) + { + pColorConfig->ClearModified(); + pColorConfig->DisableBroadcast(); + } + pColorConfig.reset(new EditableColorConfig); + m_xColorConfigCT->SetConfig(*pColorConfig); + + if(pExtColorConfig) + { + pExtColorConfig->ClearModified(); + pExtColorConfig->DisableBroadcast(); + } + pExtColorConfig.reset(new EditableExtendedColorConfig); + m_xColorConfigCT->SetExtendedConfig(*pExtColorConfig); + + m_xAutoColorLB->set_active( MiscSettings::GetAppColorMode() ); + + OUString sUser = GetUserData(); + //has to be called always to speed up accessibility tools + m_xColorConfigCT->SetScrollPosition(sUser.toInt32()); + m_xColorSchemeLB->clear(); + const uno::Sequence< OUString > aSchemes = pColorConfig->GetSchemeNames(); + for(const OUString& s : aSchemes) + m_xColorSchemeLB->append_text(lcl_SchemeIdToTranslatedName(s)); + m_xColorSchemeLB->set_active_text(lcl_SchemeIdToTranslatedName(pColorConfig->GetCurrentSchemeName())); + m_xColorSchemeLB->save_value(); + m_xDeleteSchemePB->set_sensitive( aSchemes.getLength() > 1 ); + UpdateColorConfig(); +} + +DeactivateRC SvxColorOptionsTabPage::DeactivatePage( SfxItemSet* pSet_ ) +{ + if ( pSet_ ) + FillItemSet( pSet_ ); + return DeactivateRC::LeavePage; +} + +void SvxColorOptionsTabPage::UpdateColorConfig() +{ + //update the color config control + m_xColorConfigCT->Update(); +} + +IMPL_LINK_NOARG(SvxColorOptionsTabPage, onAutoColorChanged, weld::ComboBox&, void) +{ + MiscSettings::SetAppColorMode( m_xAutoColorLB->get_active() ); + + m_xColorConfigCT->UpdateEntries(); + + pColorConfig->LoadScheme(lcl_TranslatedNameToSchemeId(m_xColorSchemeLB->get_active_text())); + pExtColorConfig->LoadScheme(lcl_TranslatedNameToSchemeId(m_xColorSchemeLB->get_active_text())); + UpdateColorConfig(); +} + +IMPL_LINK(SvxColorOptionsTabPage, SchemeChangedHdl_Impl, weld::ComboBox&, rBox, void) +{ + pColorConfig->LoadScheme(lcl_TranslatedNameToSchemeId(rBox.get_active_text())); + pExtColorConfig->LoadScheme(lcl_TranslatedNameToSchemeId(rBox.get_active_text())); + UpdateColorConfig(); +} + +IMPL_LINK(SvxColorOptionsTabPage, SaveDeleteHdl_Impl, weld::Button&, rButton, void) +{ + if (m_xSaveSchemePB.get() == &rButton) + { + OUString sName; + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractSvxNameDialog> aNameDlg(pFact->CreateSvxNameDialog(GetFrameWeld(), + sName, CuiResId(RID_CUISTR_COLOR_CONFIG_SAVE2) )); + aNameDlg->SetCheckNameHdl( LINK(this, SvxColorOptionsTabPage, CheckNameHdl_Impl)); + aNameDlg->SetText(CuiResId(RID_CUISTR_COLOR_CONFIG_SAVE1)); + aNameDlg->SetHelpId(HID_OPTIONS_COLORCONFIG_SAVE_SCHEME); + aNameDlg->SetCheckNameHdl( LINK(this, SvxColorOptionsTabPage, CheckNameHdl_Impl)); + if(RET_OK == aNameDlg->Execute()) + { + aNameDlg->GetName(sName); + pColorConfig->AddScheme(sName); + pExtColorConfig->AddScheme(sName); + m_xColorSchemeLB->append_text(sName); + m_xColorSchemeLB->set_active_text(sName); + SchemeChangedHdl_Impl(*m_xColorSchemeLB); + } + } + else + { + DBG_ASSERT(m_xColorSchemeLB->get_count() > 1, "don't delete the last scheme"); + std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + CuiResId(RID_CUISTR_COLOR_CONFIG_DELETE))); + xQuery->set_title(CuiResId(RID_CUISTR_COLOR_CONFIG_DELETE_TITLE)); + if (RET_YES == xQuery->run()) + { + OUString sDeleteScheme(m_xColorSchemeLB->get_active_text()); + m_xColorSchemeLB->remove(m_xColorSchemeLB->get_active()); + m_xColorSchemeLB->set_active(0); + SchemeChangedHdl_Impl(*m_xColorSchemeLB); + //first select the new scheme and then delete the old one + pColorConfig->DeleteScheme(sDeleteScheme); + pExtColorConfig->DeleteScheme(sDeleteScheme); + } + } + m_xDeleteSchemePB->set_sensitive(m_xColorSchemeLB->get_count() > 1); +} + +IMPL_LINK(SvxColorOptionsTabPage, CheckNameHdl_Impl, AbstractSvxNameDialog&, rDialog, bool ) +{ + OUString sName; + rDialog.GetName(sName); + return !sName.isEmpty() && m_xColorSchemeLB->find_text(sName) == -1; +} + +void SvxColorOptionsTabPage::FillUserData() +{ + SetUserData(OUString::number(m_xColorConfigCT->GetScrollPosition())); +} + +IMPL_LINK_NOARG(SvxColorOptionsTabPage, AdjustHeaderBar, const Size&, void) +{ + if (m_nSizeAllocEventId) + return; + m_nSizeAllocEventId = Application::PostUserEvent(LINK(this, SvxColorOptionsTabPage, PostAdjustHeaderBar)); +} + +IMPL_LINK_NOARG(SvxColorOptionsTabPage, PostAdjustHeaderBar, void*, void) +{ + m_nSizeAllocEventId = nullptr; + + // horizontal positions + int nX1, nX2, nX3, y, width, height; + if (!m_rWidget1.get_extents_relative_to(*m_xTable, nX1, y, width, height)) + return; + if (!m_rWidget2.get_extents_relative_to(*m_xTable, nX2, y, width, height)) + return; + if (!m_xTable->get_extents_relative_to(*m_xTable, nX3, y, width, height)) + return; + + // 6 is the column-spacing of the parent grid of these labels + auto nTextWidth1 = nX1 + m_xColorConfigCT->GetLabelIndent() - 6; + m_xOnFT->set_size_request(nTextWidth1, -1); + auto nTextWidth3 = width - nX2; + m_xColorFT->set_size_request(nTextWidth3, -1); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optcolor.hxx b/cui/source/options/optcolor.hxx new file mode 100644 index 0000000000..396746dea0 --- /dev/null +++ b/cui/source/options/optcolor.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ +#pragma once + +#include <sfx2/tabdlg.hxx> + +namespace svtools {class EditableColorConfig;class EditableExtendedColorConfig;} +class ColorConfigCtrl_Impl; +class AbstractSvxNameDialog; +struct ImplSVEvent; + +class SvxColorOptionsTabPage : public SfxTabPage +{ + bool bFillItemSetCalled; + + ImplSVEvent* m_nSizeAllocEventId; + + std::unique_ptr<weld::ComboBox> m_xAutoColorLB; + std::unique_ptr<weld::ComboBox> m_xColorSchemeLB; + std::unique_ptr<weld::Button> m_xSaveSchemePB; + std::unique_ptr<weld::Button> m_xDeleteSchemePB; + std::unique_ptr<ColorConfigCtrl_Impl> m_xColorConfigCT; + std::unique_ptr<weld::Widget> m_xTable; + std::unique_ptr<weld::Label> m_xOnFT; + std::unique_ptr<weld::Label> m_xColorFT; + + weld::Widget& m_rWidget1; + weld::Widget& m_rWidget2; + + std::unique_ptr<svtools::EditableColorConfig> pColorConfig; + std::unique_ptr<svtools::EditableExtendedColorConfig> pExtColorConfig; + + DECL_LINK(SchemeChangedHdl_Impl, weld::ComboBox&, void); + DECL_LINK(onAutoColorChanged, weld::ComboBox&, void); + DECL_LINK(SaveDeleteHdl_Impl, weld::Button&, void); + DECL_LINK(CheckNameHdl_Impl, AbstractSvxNameDialog&, bool); + DECL_LINK(AdjustHeaderBar, const Size&, void); + DECL_LINK(PostAdjustHeaderBar, void *, void); + void UpdateColorConfig(); + +public: + SvxColorOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~SvxColorOptionsTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + + virtual DeactivateRC DeactivatePage( SfxItemSet* pSet ) override; + virtual void FillUserData() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optctl.cxx b/cui/source/options/optctl.cxx new file mode 100644 index 0000000000..10140c2eab --- /dev/null +++ b/cui/source/options/optctl.cxx @@ -0,0 +1,174 @@ +/* -*- 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 "optctl.hxx" +#include <svl/ctloptions.hxx> +#include <sal/log.hxx> +#include <tools/debug.hxx> + +// class SvxCTLOptionsPage ----------------------------------------------------- + +IMPL_LINK_NOARG(SvxCTLOptionsPage, SequenceCheckingCB_Hdl, weld::Toggleable&, void) +{ + bool bIsSequenceChecking = m_xSequenceCheckingCB->get_active(); + m_xRestrictedCB->set_sensitive( bIsSequenceChecking ); + m_xTypeReplaceCB->set_sensitive( bIsSequenceChecking ); + // #i48117#: by default restricted and type&replace have to be switched on + if (bIsSequenceChecking) + { + m_xTypeReplaceCB->set_active(true); + m_xRestrictedCB->set_active(true); + } +} + +SvxCTLOptionsPage::SvxCTLOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optctlpage.ui", "OptCTLPage", &rSet) + , m_xSequenceCheckingCB(m_xBuilder->weld_check_button("sequencechecking")) + , m_xRestrictedCB(m_xBuilder->weld_check_button("restricted")) + , m_xTypeReplaceCB(m_xBuilder->weld_check_button("typeandreplace")) + , m_xMovementLogicalRB(m_xBuilder->weld_radio_button("movementlogical")) + , m_xMovementVisualRB(m_xBuilder->weld_radio_button("movementvisual")) + , m_xNumeralsLB(m_xBuilder->weld_combo_box("numerals")) +{ + m_xSequenceCheckingCB->connect_toggled(LINK(this, SvxCTLOptionsPage, SequenceCheckingCB_Hdl)); +} + +SvxCTLOptionsPage::~SvxCTLOptionsPage() +{ +} + +std::unique_ptr<SfxTabPage> SvxCTLOptionsPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SvxCTLOptionsPage>( pPage, pController, *rAttrSet ); +} + +OUString SvxCTLOptionsPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "label3", "label4", "label5" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "sequencechecking", "restricted", "typeandreplace" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + OUString radioButton[] = { "movementlogical", "movementvisual" }; + + for (const auto& radio : radioButton) + { + if (const auto& pString = m_xBuilder->weld_radio_button(radio)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxCTLOptionsPage::FillItemSet( SfxItemSet* ) +{ + bool bModified = false; + SvtCTLOptions aCTLOptions; + + // Sequence checking + bool bChecked = m_xSequenceCheckingCB->get_active(); + if ( m_xSequenceCheckingCB->get_state_changed_from_saved() ) + { + aCTLOptions.SetCTLSequenceChecking( bChecked ); + bModified = true; + } + + bChecked = m_xRestrictedCB->get_active(); + if( m_xRestrictedCB->get_state_changed_from_saved() ) + { + aCTLOptions.SetCTLSequenceCheckingRestricted( bChecked ); + bModified = true; + } + bChecked = m_xTypeReplaceCB->get_active(); + if( m_xTypeReplaceCB->get_state_changed_from_saved()) + { + aCTLOptions.SetCTLSequenceCheckingTypeAndReplace(bChecked); + bModified = true; + } + + bool bLogicalChecked = m_xMovementLogicalRB->get_active(); + if ( m_xMovementLogicalRB->get_state_changed_from_saved() || + m_xMovementVisualRB->get_state_changed_from_saved() ) + { + SvtCTLOptions::CursorMovement eMovement = + bLogicalChecked ? SvtCTLOptions::MOVEMENT_LOGICAL : SvtCTLOptions::MOVEMENT_VISUAL; + aCTLOptions.SetCTLCursorMovement( eMovement ); + bModified = true; + } + + if (m_xNumeralsLB->get_value_changed_from_saved()) + { + const sal_Int32 nPos = m_xNumeralsLB->get_active(); + aCTLOptions.SetCTLTextNumerals( static_cast<SvtCTLOptions::TextNumerals>(nPos) ); + bModified = true; + } + + return bModified; +} + +void SvxCTLOptionsPage::Reset( const SfxItemSet* ) +{ + m_xSequenceCheckingCB->set_active( SvtCTLOptions::IsCTLSequenceChecking() ); + m_xRestrictedCB->set_active( SvtCTLOptions::IsCTLSequenceCheckingRestricted() ); + m_xTypeReplaceCB->set_active( SvtCTLOptions::IsCTLSequenceCheckingTypeAndReplace() ); + + SvtCTLOptions::CursorMovement eMovement = SvtCTLOptions::GetCTLCursorMovement(); + switch ( eMovement ) + { + case SvtCTLOptions::MOVEMENT_LOGICAL : + m_xMovementLogicalRB->set_active(true); + break; + + case SvtCTLOptions::MOVEMENT_VISUAL : + m_xMovementVisualRB->set_active(true); + break; + + default: + SAL_WARN( "cui.options", "SvxCTLOptionsPage::Reset(): invalid movement enum" ); + } + + sal_uInt16 nPos = static_cast<sal_uInt16>(SvtCTLOptions::GetCTLTextNumerals()); + DBG_ASSERT( nPos < m_xNumeralsLB->get_count(), "SvxCTLOptionsPage::Reset(): invalid numerals enum" ); + m_xNumeralsLB->set_active(nPos); + + m_xSequenceCheckingCB->save_state(); + m_xRestrictedCB->save_state(); + m_xTypeReplaceCB->save_state(); + m_xMovementLogicalRB->save_state(); + m_xMovementVisualRB->save_state(); + m_xNumeralsLB->save_value(); + + bool bIsSequenceChecking = m_xSequenceCheckingCB->get_active(); + m_xRestrictedCB->set_sensitive( bIsSequenceChecking ); + m_xTypeReplaceCB->set_sensitive( bIsSequenceChecking ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optctl.hxx b/cui/source/options/optctl.hxx new file mode 100644 index 0000000000..35c07d3a81 --- /dev/null +++ b/cui/source/options/optctl.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ +#pragma once + +#include <sfx2/tabdlg.hxx> + +// class SvxCTLOptionsPage ----------------------------------------------------- + +class SvxCTLOptionsPage : public SfxTabPage +{ +private: + std::unique_ptr<weld::CheckButton> m_xSequenceCheckingCB; + std::unique_ptr<weld::CheckButton> m_xRestrictedCB; + std::unique_ptr<weld::CheckButton> m_xTypeReplaceCB; + std::unique_ptr<weld::RadioButton> m_xMovementLogicalRB; + std::unique_ptr<weld::RadioButton> m_xMovementVisualRB; + std::unique_ptr<weld::ComboBox> m_xNumeralsLB; + + DECL_LINK( SequenceCheckingCB_Hdl, weld::Toggleable&, void ); + +public: + SvxCTLOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~SvxCTLOptionsPage() override; + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optdeepl.cxx b/cui/source/options/optdeepl.cxx new file mode 100644 index 0000000000..ba068fe28a --- /dev/null +++ b/cui/source/options/optdeepl.cxx @@ -0,0 +1,78 @@ +/* -*- 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 "optdeepl.hxx" +#include <officecfg/Office/Linguistic.hxx> + +OptDeeplTabPage::OptDeeplTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optdeeplpage.ui", "OptDeeplPage", &rSet) + , m_xAPIUrl(m_xBuilder->weld_entry("apiurl")) + , m_xAuthKey(m_xBuilder->weld_entry("authkey")) +{ +} + +OptDeeplTabPage::~OptDeeplTabPage() {} + +void OptDeeplTabPage::Reset(const SfxItemSet*) +{ + std::optional<OUString> oDeeplAPIUrl + = officecfg::Office::Linguistic::Translation::Deepl::ApiURL::get(); + if (oDeeplAPIUrl && !oDeeplAPIUrl->isEmpty()) + m_xAPIUrl->set_text(*officecfg::Office::Linguistic::Translation::Deepl::ApiURL::get()); + + std::optional<OUString> oDeeplAuthKey + = officecfg::Office::Linguistic::Translation::Deepl::AuthKey::get(); + if (oDeeplAuthKey && !oDeeplAuthKey->isEmpty()) + m_xAuthKey->set_text(*officecfg::Office::Linguistic::Translation::Deepl::AuthKey::get()); +} + +OUString OptDeeplTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "label3" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + if (const auto& pString = m_xBuilder->weld_link_button("privacy")) + sAllStrings += pString->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool OptDeeplTabPage::FillItemSet(SfxItemSet*) +{ + std::shared_ptr<comphelper::ConfigurationChanges> batch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Linguistic::Translation::Deepl::ApiURL::set(m_xAPIUrl->get_text(), batch); + officecfg::Office::Linguistic::Translation::Deepl::AuthKey::set(m_xAuthKey->get_text(), batch); + batch->commit(); + return false; +} + +std::unique_ptr<SfxTabPage> OptDeeplTabPage::Create(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<OptDeeplTabPage>(pPage, pController, *rAttrSet); +} diff --git a/cui/source/options/optdeepl.hxx b/cui/source/options/optdeepl.hxx new file mode 100644 index 0000000000..51714c6850 --- /dev/null +++ b/cui/source/options/optdeepl.hxx @@ -0,0 +1,39 @@ +/* -*- 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 . + */ +#pragma once +#include <sfx2/tabdlg.hxx> + +class OptDeeplTabPage : public SfxTabPage +{ +public: + OptDeeplTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet); + virtual ~OptDeeplTabPage() override; + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet(SfxItemSet* rSet) override; + virtual void Reset(const SfxItemSet* rSet) override; + +private: + std::unique_ptr<weld::Entry> m_xAPIUrl; + std::unique_ptr<weld::Entry> m_xAuthKey; +}; diff --git a/cui/source/options/optdict.cxx b/cui/source/options/optdict.cxx new file mode 100644 index 0000000000..dbe7f80e3d --- /dev/null +++ b/cui/source/options/optdict.cxx @@ -0,0 +1,781 @@ +/* -*- 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 <editeng/unolingu.hxx> +#include <o3tl/safeint.hxx> +#include <svx/dialmgr.hxx> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/linguistic2/XDictionary.hpp> +#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> +#include <comphelper/string.hxx> +#include <tools/debug.hxx> +#include <unotools/collatorwrapper.hxx> +#include <unotools/intlwrapper.hxx> +#include <unotools/syslocale.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +#include <linguistic/misc.hxx> +#include <strings.hrc> +#include <optdict.hxx> +#include <dialmgr.hxx> +#include <svx/svxerr.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::linguistic2; +using namespace linguistic; + +// static function ------------------------------------------------------- + +static OUString getNormDicEntry_Impl(std::u16string_view rText) +{ + OUString aTmp(comphelper::string::stripEnd(rText, '.')); + // non-standard hyphenation + if (aTmp.indexOf('[') > -1) + { + OUStringBuffer aTmp2 ( aTmp.getLength() ); + bool bSkip = false; + for (sal_Int32 i = 0; i < aTmp.getLength(); i++) + { + sal_Unicode cTmp = aTmp[i]; + if (cTmp == '[') + bSkip = true; + else if (!bSkip) + aTmp2.append( cTmp ); + else if (cTmp == ']') + bSkip = false; + } + aTmp = aTmp2.makeStringAndClear(); + } + return aTmp.replaceAll("=", ""); +} + +// tdf#154499 separate words of a phrase only by a single space, +// i.e. trim terminating spaces and replace space sequences with single spaces +static OUString fixSpace(OUString sText) +{ + sText = sText.trim(); + + sal_Int32 nLen; + do + { + nLen = sText.getLength(); + sText = sText.replaceAll(" ", " "); + } + while ( sText.getLength() < nLen ); + + return sText; +} + +namespace { + +// Compare Dictionary Entry result +enum CDE_RESULT { CDE_EQUAL, CDE_SIMILAR, CDE_DIFFERENT }; + +} + +static CDE_RESULT cmpDicEntry_Impl( std::u16string_view rText1, std::u16string_view rText2 ) +{ + CDE_RESULT eRes = CDE_DIFFERENT; + + if (rText1 == rText2) + eRes = CDE_EQUAL; + else + { // similar = equal up to trailing '.' and hyphenation positions + // marked with '=' and '[' + alternative spelling pattern + ']' + if (getNormDicEntry_Impl( rText1 ) == getNormDicEntry_Impl( rText2 )) + eRes = CDE_SIMILAR; + } + + return eRes; +} + +// class SvxNewDictionaryDialog ------------------------------------------- + +SvxNewDictionaryDialog::SvxNewDictionaryDialog(weld::Window* pParent) + : GenericDialogController(pParent, "cui/ui/optnewdictionarydialog.ui", "OptNewDictionaryDialog") + , m_xNameEdit(m_xBuilder->weld_entry("nameedit")) + , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("language"))) + , m_xExceptBtn(m_xBuilder->weld_check_button("except")) + , m_xOKBtn(m_xBuilder->weld_button("ok")) +{ + // Prevent creation of dictionary without a name. + m_xOKBtn->set_sensitive(false); + + // install handler + m_xNameEdit->connect_changed(LINK(this, SvxNewDictionaryDialog, ModifyHdl_Impl)); + m_xOKBtn->connect_clicked(LINK(this, SvxNewDictionaryDialog, OKHdl_Impl)); + + // display languages + m_xLanguageLB->SetLanguageList(SvxLanguageListFlags::ALL, true, true); + m_xLanguageLB->set_active(0); +} + +IMPL_LINK_NOARG(SvxNewDictionaryDialog, OKHdl_Impl, weld::Button&, void) +{ + + // add extension for personal dictionaries + OUString sDict = comphelper::string::stripEnd(m_xNameEdit->get_text(), ' ') + ".dic"; + + Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() ); + + Sequence< Reference< XDictionary > > aDics; + if (xDicList.is()) + aDics = xDicList->getDictionaries(); + const Reference< XDictionary > *pDic = aDics.getConstArray(); + sal_Int32 nCount = aDics.getLength(); + + bool bFound = false; + sal_Int32 i; + for (i = 0; !bFound && i < nCount; ++i ) + if ( sDict.equalsIgnoreAsciiCase( pDic[i]->getName()) ) + bFound = true; + + if ( sDict.indexOf("/") != -1 || sDict.indexOf("\\") != -1 ) + { + // Detected an invalid character. + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + CuiResId(RID_CUISTR_OPT_INVALID_DICT_NAME))); + xInfoBox->run(); + m_xNameEdit->grab_focus(); + return; + } + + if ( bFound ) + { + // duplicate names? + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + CuiResId(RID_CUISTR_OPT_DOUBLE_DICTS))); + xInfoBox->run(); + m_xNameEdit->grab_focus(); + return; + } + + // create and add + LanguageType nLang = m_xLanguageLB->get_active_id(); + try + { + // create new dictionary + DictionaryType eType = m_xExceptBtn->get_active() ? + DictionaryType_NEGATIVE : DictionaryType_POSITIVE; + if (xDicList.is()) + { + lang::Locale aLocale( LanguageTag::convertToLocale(nLang) ); + OUString aURL( linguistic::GetWritableDictionaryURL( sDict ) ); + m_xNewDic = xDicList->createDictionary(sDict, aLocale, eType, aURL); + m_xNewDic->setActive(true); + } + DBG_ASSERT(m_xNewDic.is(), "NULL pointer"); + } + catch(...) + { + m_xNewDic = nullptr; + // error: couldn't create new dictionary + SfxErrorContext aContext( ERRCTX_SVX_LINGU_DICTIONARY, OUString(), + m_xDialog.get(), RID_SVXERRCTX, SvxResLocale() ); + ErrorHandler::HandleError( ErrCodeMsg( + ERRCODE_SVX_LINGU_DICT_NOTWRITEABLE, sDict ) ); + m_xDialog->response(RET_CANCEL); + } + + if (xDicList.is() && m_xNewDic.is()) + { + xDicList->addDictionary(m_xNewDic); + + // refresh list of dictionaries + //! dictionaries may have been added/removed elsewhere too. + aDics = xDicList->getDictionaries(); + } + + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(SvxNewDictionaryDialog, ModifyHdl_Impl, weld::Entry&, void) +{ + m_xOKBtn->set_sensitive(!m_xNameEdit->get_text().isEmpty()); +} + +// class SvxEditDictionaryDialog ------------------------------------------- + +SvxEditDictionaryDialog::SvxEditDictionaryDialog(weld::Window* pParent, std::u16string_view rName) + : GenericDialogController(pParent, "cui/ui/editdictionarydialog.ui", "EditDictionaryDialog") + , sModify(CuiResId(STR_MODIFY)) + , bFirstSelect(false) + , bDoNothing(false) + , bDicIsReadonly(false) + , m_xAllDictsLB(m_xBuilder->weld_combo_box("book")) + , m_xLangFT(m_xBuilder->weld_label("lang_label")) + , m_xLangLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("lang"))) + , m_xWordED(m_xBuilder->weld_entry("word")) + , m_xReplaceFT(m_xBuilder->weld_label("replace_label")) + , m_xReplaceED(m_xBuilder->weld_entry("replace")) + , m_xSingleColumnLB(m_xBuilder->weld_tree_view("words")) + , m_xDoubleColumnLB(m_xBuilder->weld_tree_view("replaces")) + , m_xNewReplacePB(m_xBuilder->weld_button("newreplace")) + , m_xDeletePB(m_xBuilder->weld_button("delete")) +{ + sReplaceFT_Text = m_xReplaceFT->get_label(); + m_xSingleColumnLB->set_size_request(-1, m_xSingleColumnLB->get_height_rows(8)); + m_xDoubleColumnLB->set_size_request(-1, m_xDoubleColumnLB->get_height_rows(8)); + m_pWordsLB = m_xDoubleColumnLB.get(); + m_xSingleColumnLB->hide(); + + //set to max of both sizes to avoid resizes + sNew = m_xNewReplacePB->get_label(); + auto nNewWidth = m_xNewReplacePB->get_preferred_size().Width(); + m_xNewReplacePB->set_label(sModify); + auto nReplaceWidth = m_xNewReplacePB->get_preferred_size().Width(); + m_xNewReplacePB->set_label(sNew); + m_xNewReplacePB->set_size_request(std::max(nNewWidth, nReplaceWidth), -1); + + if (LinguMgr::GetDictionaryList().is()) + aDics = LinguMgr::GetDictionaryList()->getDictionaries(); + + m_xSingleColumnLB->connect_changed(LINK(this, SvxEditDictionaryDialog, SelectHdl)); + m_xDoubleColumnLB->connect_changed(LINK(this, SvxEditDictionaryDialog, SelectHdl)); + + std::vector<int> aWidths + { + o3tl::narrowing<int>(m_xDoubleColumnLB->get_approximate_digit_width() * 22) + }; + m_xDoubleColumnLB->set_column_fixed_widths(aWidths); + + // install handler + m_xNewReplacePB->connect_clicked( + LINK( this, SvxEditDictionaryDialog, NewDelButtonHdl)); + m_xDeletePB->connect_clicked( + LINK( this, SvxEditDictionaryDialog, NewDelButtonHdl)); + + m_xLangLB->connect_changed( + LINK( this, SvxEditDictionaryDialog, SelectLangHdl_Impl ) ); + m_xAllDictsLB->connect_changed( + LINK( this, SvxEditDictionaryDialog, SelectBookHdl_Impl ) ); + + m_xWordED->connect_changed(LINK(this, SvxEditDictionaryDialog, ModifyHdl)); + m_xReplaceED->connect_changed(LINK(this, SvxEditDictionaryDialog, ModifyHdl)); + m_xWordED->connect_activate(LINK(this, SvxEditDictionaryDialog, NewDelActionHdl)); + m_xReplaceED->connect_activate(LINK(this, SvxEditDictionaryDialog, NewDelActionHdl)); + + // fill listbox with all available WB's + const Reference< XDictionary > *pDic = aDics.getConstArray(); + sal_Int32 nCount = aDics.getLength(); + + OUString aLookUpEntry; + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< XDictionary > xDic = pDic[i]; + if (xDic.is()) + { + bool bNegative = xDic->getDictionaryType() == DictionaryType_NEGATIVE; + OUString aDicName( xDic->getName() ); + const OUString aTxt( ::GetDicInfoStr( aDicName, + LanguageTag( xDic->getLocale() ).getLanguageType(), bNegative ) ); + m_xAllDictsLB->append_text(aTxt); + + if (rName == aDicName) + aLookUpEntry = aTxt; + } + } + + m_xLangLB->SetLanguageList( SvxLanguageListFlags::ALL, true, true ); + + if ( nCount > 0 ) + { + m_xAllDictsLB->set_active_text(aLookUpEntry); + int nPos = m_xAllDictsLB->get_active(); + + if (nPos == -1) + { + nPos = 0; + m_xAllDictsLB->set_active(nPos); + } + Reference< XDictionary > xDic; + if (nPos != -1) + xDic = aDics[ nPos ]; + if (xDic.is()) + SetLanguage_Impl( LanguageTag( xDic->getLocale() ).getLanguageType() ); + + // check if dictionary is read-only + SetDicReadonly_Impl(xDic); + bool bEnable = !IsDicReadonly_Impl(); + m_xNewReplacePB->set_sensitive( false ); + m_xDeletePB->set_sensitive( false ); + m_xLangFT->set_sensitive( bEnable ); + m_xLangLB->set_sensitive( bEnable ); + ShowWords_Impl( nPos ); + } + else + { + m_xNewReplacePB->set_sensitive(false); + m_xDeletePB->set_sensitive(false); + } + + m_xWordED->connect_size_allocate(LINK(this, SvxEditDictionaryDialog, EntrySizeAllocHdl)); + m_xReplaceED->connect_size_allocate(LINK(this, SvxEditDictionaryDialog, EntrySizeAllocHdl)); +} + +IMPL_LINK_NOARG(SvxEditDictionaryDialog, EntrySizeAllocHdl, const Size&, void) +{ + std::vector<int> aWidths; + int x, y, width, height; + if (m_xReplaceED->get_extents_relative_to(*m_pWordsLB, x, y, width, height)) + { + aWidths.push_back(x); + m_xDoubleColumnLB->set_column_fixed_widths(aWidths); + } +} + +SvxEditDictionaryDialog::~SvxEditDictionaryDialog() +{ +} + +void SvxEditDictionaryDialog::SetDicReadonly_Impl( + Reference< XDictionary > const &xDic ) +{ + // enable or disable new and delete button according to file attributes + bDicIsReadonly = true; + if (xDic.is()) + { + Reference< frame::XStorable > xStor( xDic, UNO_QUERY ); + if ( !xStor.is() // non persistent dictionary + || !xStor->hasLocation() // not yet persistent + || !xStor->isReadonly() ) + { + bDicIsReadonly = false; + } + } +} + +void SvxEditDictionaryDialog::SetLanguage_Impl(LanguageType nLanguage) +{ + // select language + m_xLangLB->set_active_id(nLanguage); +} + +int SvxEditDictionaryDialog::GetLBInsertPos(std::u16string_view rDicWord) +{ + IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag()); + const CollatorWrapper* pCollator = aIntlWrapper.getCollator(); + int j; + int nCount = m_pWordsLB->n_children(); + for (j = 0; j < nCount; ++j) + { + OUString aNormEntry( getNormDicEntry_Impl( rDicWord ) ); + sal_Int32 nCmpRes = pCollator-> + compareString( aNormEntry, getNormDicEntry_Impl( m_pWordsLB->get_text(j, 0) ) ); + if (nCmpRes < 0) + break; + } + + return j; +} + +void SvxEditDictionaryDialog::RemoveDictEntry(int nEntry) +{ + int nLBPos = m_xAllDictsLB->get_active(); + if (nEntry != -1 && nLBPos != -1) + { + OUString sTmpShort(m_pWordsLB->get_text(nEntry, 0)); + + Reference<XDictionary> xDic = aDics.getConstArray()[nLBPos]; + if (xDic->remove(sTmpShort)) // sal_True on success + { + m_pWordsLB->remove(nEntry); + SelectHdl(*m_pWordsLB); + } + } +} + +IMPL_LINK_NOARG(SvxEditDictionaryDialog, SelectBookHdl_Impl, weld::ComboBox&, void) +{ + int nPos = m_xAllDictsLB->get_active(); + if (nPos == -1) + return; + + m_xNewReplacePB->set_sensitive( false ); + m_xDeletePB->set_sensitive( false ); + // display dictionary + ShowWords_Impl( nPos ); + // enable or disable new and delete button according to file attributes + Reference< XDictionary > const & xDic = aDics[ nPos ]; + if (xDic.is()) + SetLanguage_Impl( LanguageTag( xDic->getLocale() ).getLanguageType() ); + + SetDicReadonly_Impl(xDic); + bool bEnable = !IsDicReadonly_Impl(); + m_xLangFT->set_sensitive( bEnable ); + m_xLangLB->set_sensitive( bEnable ); +} + +IMPL_LINK_NOARG(SvxEditDictionaryDialog, SelectLangHdl_Impl, weld::ComboBox&, void) +{ + int nDicPos = m_xAllDictsLB->get_active(); + LanguageType nLang = m_xLangLB->get_active_id(); + Reference< XDictionary > const & xDic = aDics[ nDicPos ]; + LanguageType nOldLang = LanguageTag( xDic->getLocale() ).getLanguageType(); + + if ( nLang == nOldLang ) + return; + + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Question, VclButtonsType::YesNo, + CuiResId(RID_CUISTR_CONFIRM_SET_LANGUAGE))); + OUString sTxt(xBox->get_primary_text()); + sTxt = sTxt.replaceFirst("%1", m_xAllDictsLB->get_active_text()); + xBox->set_primary_text(sTxt); + + if (xBox->run() == RET_YES) + { + xDic->setLocale( LanguageTag::convertToLocale( nLang ) ); + bool bNegativ = xDic->getDictionaryType() == DictionaryType_NEGATIVE; + + const OUString sName( + ::GetDicInfoStr( xDic->getName(), + LanguageTag( xDic->getLocale() ).getLanguageType(), + bNegativ ) ); + m_xAllDictsLB->remove(nDicPos); + m_xAllDictsLB->insert_text(nDicPos, sName); + m_xAllDictsLB->set_active(nDicPos); + } + else + SetLanguage_Impl( nOldLang ); +} + +void SvxEditDictionaryDialog::ShowWords_Impl( sal_uInt16 nId ) +{ + Reference< XDictionary > xDic = aDics.getConstArray()[ nId ]; + + weld::WaitObject aWait(m_xDialog.get()); + + m_xWordED->set_text(OUString()); + m_xReplaceED->set_text(OUString()); + + bool bIsNegative = xDic->getDictionaryType() != DictionaryType_POSITIVE; + bool bLangNone = LanguageTag( + xDic->getLocale() ).getLanguageType() == LANGUAGE_NONE; + + // The label is "Replace By" only in negative dictionaries (forbidden + // words), otherwise "Grammar By" in language-specific dictionaries + // (where the optional second word is the sample word for + // the Hunspell based affixation/compounding of the new dictionary word) + if (bIsNegative) + { + m_xReplaceFT->set_label(sReplaceFT_Text); + } else if (!bLangNone) { + m_xReplaceFT->set_label(CuiResId(RID_CUISTR_OPT_GRAMMAR_BY)); + } + + if(bIsNegative || !bLangNone) + { + // make controls for replacement text active + if (!m_xReplaceFT->get_visible()) + { + m_xReplaceFT->show(); + m_xReplaceED->show(); + m_xSingleColumnLB->hide(); + m_xDoubleColumnLB->show(); + m_pWordsLB = m_xDoubleColumnLB.get(); + } + } + else + { + // deactivate controls for replacement text + if (m_xReplaceFT->get_visible()) + { + m_xReplaceFT->hide(); + m_xReplaceED->hide(); + m_xDoubleColumnLB->hide(); + m_xSingleColumnLB->show(); + m_pWordsLB = m_xSingleColumnLB.get(); + } + } + + m_pWordsLB->clear(); + + Sequence< Reference< XDictionaryEntry > > aEntries( xDic->getEntries() ); + const Reference< XDictionaryEntry > *pEntry = aEntries.getConstArray(); + sal_Int32 nCount = aEntries.getLength(); + std::vector<OUString> aSortedDicEntries; + aSortedDicEntries.reserve(nCount); + for (sal_Int32 i = 0; i < nCount; i++) + { + OUString aStr = pEntry[i]->getDictionaryWord(); + if(!pEntry[i]->getReplacementText().isEmpty()) + { + aStr += "\t" + pEntry[i]->getReplacementText(); + } + aSortedDicEntries.push_back(aStr); + } + + IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag()); + const CollatorWrapper* pCollator = aIntlWrapper.getCollator(); + std::sort(aSortedDicEntries.begin(), aSortedDicEntries.end(), + [&] (OUString const & lhs, OUString const & rhs) + { + sal_Int32 nCmpRes = pCollator-> + compareString( getNormDicEntry_Impl(lhs), getNormDicEntry_Impl( rhs ) ); + return nCmpRes < 0; + }); + + m_pWordsLB->freeze(); // speed up insert + int nRow = 0; + for (OUString const & rStr : aSortedDicEntries) + { + m_pWordsLB->append_text(rStr.getToken(0, '\t')); + if (m_pWordsLB == m_xDoubleColumnLB.get()) + { + OUString sReplace = rStr.getToken(1, '\t'); + m_pWordsLB->set_text(nRow, sReplace, 1); + ++nRow; + } + } + m_pWordsLB->thaw(); + + if (m_pWordsLB->n_children()) + { + m_pWordsLB->select(0); + m_pWordsLB->set_cursor(0); + SelectHdl(*m_pWordsLB); + } +} + +IMPL_LINK(SvxEditDictionaryDialog, SelectHdl, weld::TreeView&, rBox, void) +{ + if (bDoNothing) + return; + + int nEntry = rBox.get_selected_index(); + + if(!bFirstSelect) + { + if (nEntry != -1) + { + OUString sTmpShort(rBox.get_text(nEntry, 0)); + // without this the cursor is always at the beginning of a word, if the text + // is set over the ModifyHdl, although you're editing there at the moment + if (m_xWordED->get_text() != sTmpShort) + m_xWordED->set_text(sTmpShort); + if (&rBox == m_xDoubleColumnLB.get()) + m_xReplaceED->set_text(rBox.get_text(nEntry, 1)); + } + } + else + bFirstSelect = false; + + // entries in the list box should exactly correspond to those from the + // dictionary. Thus: + m_xNewReplacePB->set_sensitive(false); + m_xDeletePB->set_sensitive(nEntry != -1 && !IsDicReadonly_Impl()); +} + +IMPL_LINK(SvxEditDictionaryDialog, NewDelButtonHdl, weld::Button&, rBtn, void) +{ + NewDelHdl(&rBtn); +} + +IMPL_LINK(SvxEditDictionaryDialog, NewDelActionHdl, weld::Entry&, rDictEdit, bool) +{ + return NewDelHdl(&rDictEdit); +} + +bool SvxEditDictionaryDialog::NewDelHdl(const weld::Widget* pBtn) +{ + if (pBtn == m_xDeletePB.get()) + { + m_xWordED->set_text(""); + m_xReplaceED->set_text(""); + m_xDeletePB->set_sensitive(false); + + int nEntry = m_pWordsLB->get_selected_index(); + RemoveDictEntry(nEntry); // remove entry from dic and list-box + } + if (pBtn == m_xNewReplacePB.get() || m_xNewReplacePB->get_sensitive()) + { + int nEntry = m_pWordsLB->get_selected_index(); + OUString aNewWord(fixSpace(m_xWordED->get_text())); + OUString sEntry(aNewWord); + OUString aReplaceStr(fixSpace(m_xReplaceED->get_text())); + + DictionaryError nAddRes = DictionaryError::UNKNOWN; + int nPos = m_xAllDictsLB->get_active(); + if (nPos != -1 && !aNewWord.isEmpty()) + { + DBG_ASSERT(nPos < aDics.getLength(), "invalid dictionary index"); + Reference< XDictionary > const & xDic = aDics[ nPos ]; + if (xDic.is()) + { + // make changes in dic + + bool bIsNegEntry = xDic->getDictionaryType() == DictionaryType_NEGATIVE; + + OUString aRplcText; + if(!aReplaceStr.isEmpty()) + aRplcText = aReplaceStr; + + if (nEntry != -1) // entry selected in m_pWordsLB ie action = modify entry + xDic->remove(m_pWordsLB->get_text(nEntry, 0)); + // if remove has failed the following add should fail too + // and thus a warning message should be triggered... + + nAddRes = linguistic::AddEntryToDic( xDic, + aNewWord, bIsNegEntry, + aRplcText, false ); + } + } + if (DictionaryError::NONE != nAddRes) + SvxDicError(m_xDialog.get(), nAddRes); + + if (DictionaryError::NONE == nAddRes && !sEntry.isEmpty()) + { + // insert new entry in list-box etc... + m_pWordsLB->freeze(); + + if (nEntry != -1) // entry selected in m_pWordsLB ie action = modify entry + { + m_pWordsLB->set_text(nEntry, sEntry); + if (!aReplaceStr.isEmpty()) + m_pWordsLB->set_text(nEntry, aReplaceStr, 1); + } + else + { + nEntry = GetLBInsertPos(aNewWord); + m_pWordsLB->insert_text(nEntry, sEntry); + if(!aReplaceStr.isEmpty()) + m_pWordsLB->set_text(nEntry, aReplaceStr, 1); + } + + m_pWordsLB->thaw(); + m_pWordsLB->scroll_to_row(nEntry); + + // if the request came from the ReplaceEdit, give focus to the ShortEdit + if (m_xReplaceED->has_focus()) + m_xWordED->grab_focus(); + } + } + else + { + // this can only be an enter in one of the two edit fields + // which means EndDialog() - has to be evaluated in KeyInput + return false; + } + ModifyHdl(*m_xWordED); + return true; +} + +IMPL_LINK(SvxEditDictionaryDialog, ModifyHdl, weld::Entry&, rEdt, void) +{ + OUString rEntry = rEdt.get_text(); + + sal_Int32 nWordLen = rEntry.getLength(); + const OUString& rRepString = fixSpace(m_xReplaceED->get_text()); + + bool bEnableNewReplace = false; + bool bEnableDelete = false; + OUString aNewReplaceText = sNew; + + if (&rEdt == m_xWordED.get()) + { + if(nWordLen>0) + { + bool bFound = false; + bool bTmpSelEntry=false; + CDE_RESULT eCmpRes = CDE_DIFFERENT; + + bool bDoubleColumn = m_pWordsLB == m_xDoubleColumnLB.get(); + + for (int i = 0, nCount = m_pWordsLB->n_children(); i < nCount; ++i) + { + OUString aTestStr(m_pWordsLB->get_text(i, 0)); + eCmpRes = cmpDicEntry_Impl( rEntry, aTestStr ); + if(CDE_DIFFERENT != eCmpRes) + { + if(!rRepString.isEmpty()) + bFirstSelect = true; + bDoNothing=true; + m_pWordsLB->set_cursor(i); + bDoNothing=false; + if (bDoubleColumn) + m_xReplaceED->set_text(m_pWordsLB->get_text(i, 1)); + + if (CDE_SIMILAR == eCmpRes) + { + aNewReplaceText = sModify; + bEnableNewReplace = true; + } + bFound= true; + break; + } + else if(getNormDicEntry_Impl(aTestStr).indexOf( + getNormDicEntry_Impl( rEntry ) ) == 0 + && !bTmpSelEntry) + { + bDoNothing=true; + m_pWordsLB->scroll_to_row(i); + bDoNothing=false; + bTmpSelEntry=true; + + aNewReplaceText = sNew; + bEnableNewReplace = true; + } + } + + if(!bFound) + { + m_pWordsLB->unselect_all(); + aNewReplaceText = sNew; + bEnableNewReplace = true; + } + bEnableDelete = CDE_DIFFERENT != eCmpRes; + } + else if (m_pWordsLB->n_children() > 0) + { + bDoNothing=true; + m_pWordsLB->scroll_to_row(0); + bDoNothing=false; + } + } + else if(&rEdt == m_xReplaceED.get()) + { + OUString aReplaceText; + OUString aWordText; + int nFirstSel = m_pWordsLB->get_selected_index(); + if (nFirstSel != -1) // a m_pWordsLB entry is selected + { + aWordText = m_pWordsLB->get_text(nFirstSel, 0); + aReplaceText = m_pWordsLB->get_text(nFirstSel, 1); + + aNewReplaceText = sModify; + bEnableDelete = true; + } + bool bIsChange = + CDE_EQUAL != cmpDicEntry_Impl(fixSpace(m_xWordED->get_text()), aWordText) + || CDE_EQUAL != cmpDicEntry_Impl(fixSpace(m_xReplaceED->get_text()), aReplaceText); + if (!fixSpace(m_xWordED->get_text()).isEmpty() && bIsChange) + bEnableNewReplace = true; + } + + m_xNewReplacePB->set_label(aNewReplaceText); + m_xNewReplacePB->set_sensitive(bEnableNewReplace && !IsDicReadonly_Impl()); + m_xDeletePB->set_sensitive(bEnableDelete && !IsDicReadonly_Impl()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optfltr.cxx b/cui/source/options/optfltr.cxx new file mode 100644 index 0000000000..b582b065bc --- /dev/null +++ b/cui/source/options/optfltr.cxx @@ -0,0 +1,472 @@ +/* -*- 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 <unotools/moduleoptions.hxx> +#include <unotools/fltrcfg.hxx> +#include <officecfg/Office/Common.hxx> +#include <officecfg/Office/Calc.hxx> +#include <officecfg/Office/Writer.hxx> +#include <officecfg/Office/Impress.hxx> +#include "optfltr.hxx" +#include <strings.hrc> +#include <dialmgr.hxx> + +enum class MSFltrPg2_CheckBoxEntries { + Math, + Writer, + Calc, + Impress, + SmartArt, + Visio, + PDF, + InvalidCBEntry +}; + + +OfaMSFilterTabPage::OfaMSFilterTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optfltrpage.ui", "OptFltrPage", &rSet) + , m_xWBasicCodeCB(m_xBuilder->weld_check_button("wo_basic")) + , m_xWBasicCodeImg(m_xBuilder->weld_widget("lockwo_basic")) + , m_xWBasicWbctblCB(m_xBuilder->weld_check_button("wo_exec")) + , m_xWBasicWbctblImg(m_xBuilder->weld_widget("lockwo_exec")) + , m_xWBasicStgCB(m_xBuilder->weld_check_button("wo_saveorig")) + , m_xWBasicStgImg(m_xBuilder->weld_widget("lockwo_saveorig")) + , m_xEBasicCodeCB(m_xBuilder->weld_check_button("ex_basic")) + , m_xEBasicCodeImg(m_xBuilder->weld_widget("lockex_basic")) + , m_xEBasicExectblCB(m_xBuilder->weld_check_button("ex_exec")) + , m_xEBasicExectblImg(m_xBuilder->weld_widget("lockex_exec")) + , m_xEBasicStgCB(m_xBuilder->weld_check_button("ex_saveorig")) + , m_xEBasicStgImg(m_xBuilder->weld_widget("lockex_saveorig")) + , m_xPBasicCodeCB(m_xBuilder->weld_check_button("pp_basic")) + , m_xPBasicCodeImg(m_xBuilder->weld_widget("lockpp_basic")) + , m_xPBasicStgCB(m_xBuilder->weld_check_button("pp_saveorig")) + , m_xPBasicStgImg(m_xBuilder->weld_widget("lockpp_saveorig")) +{ + m_xWBasicCodeCB->connect_toggled( LINK( this, OfaMSFilterTabPage, LoadWordBasicCheckHdl_Impl ) ); + m_xEBasicCodeCB->connect_toggled( LINK( this, OfaMSFilterTabPage, LoadExcelBasicCheckHdl_Impl ) ); +} + +OfaMSFilterTabPage::~OfaMSFilterTabPage() +{ +} + +IMPL_LINK_NOARG(OfaMSFilterTabPage, LoadWordBasicCheckHdl_Impl, weld::Toggleable&, void) +{ + m_xWBasicWbctblCB->set_sensitive(m_xWBasicCodeCB->get_active() && !officecfg::Office::Writer::Filter::Import::VBA::Executable::isReadOnly()); + m_xWBasicWbctblImg->set_visible(officecfg::Office::Writer::Filter::Import::VBA::Executable::isReadOnly()); +} + +IMPL_LINK_NOARG(OfaMSFilterTabPage, LoadExcelBasicCheckHdl_Impl, weld::Toggleable&, void) +{ + m_xEBasicExectblCB->set_sensitive(m_xEBasicCodeCB->get_active() && !officecfg::Office::Calc::Filter::Import::VBA::Executable::isReadOnly()); + m_xEBasicExectblImg->set_visible(officecfg::Office::Calc::Filter::Import::VBA::Executable::isReadOnly()); +} + +std::unique_ptr<SfxTabPage> OfaMSFilterTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<OfaMSFilterTabPage>(pPage, pController, *rAttrSet); +} + +OUString OfaMSFilterTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "label3" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "wo_basic", "wo_exec", "wo_saveorig", "ex_basic", + "ex_exec", "ex_saveorig", "pp_basic", "pp_saveorig" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool OfaMSFilterTabPage::FillItemSet( SfxItemSet* ) +{ + SvtFilterOptions& rOpt = SvtFilterOptions::Get(); + + if( m_xWBasicCodeCB->get_state_changed_from_saved() ) + rOpt.SetLoadWordBasicCode( m_xWBasicCodeCB->get_active() ); + if( m_xWBasicWbctblCB->get_state_changed_from_saved() ) + rOpt.SetLoadWordBasicExecutable( m_xWBasicWbctblCB->get_active() ); + if( m_xWBasicStgCB->get_state_changed_from_saved() ) + rOpt.SetLoadWordBasicStorage( m_xWBasicStgCB->get_active() ); + + if( m_xEBasicCodeCB->get_state_changed_from_saved()) + rOpt.SetLoadExcelBasicCode( m_xEBasicCodeCB->get_active() ); + if( m_xEBasicExectblCB->get_state_changed_from_saved()) + rOpt.SetLoadExcelBasicExecutable( m_xEBasicExectblCB->get_active() ); + if( m_xEBasicStgCB->get_state_changed_from_saved()) + rOpt.SetLoadExcelBasicStorage( m_xEBasicStgCB->get_active() ); + + if( m_xPBasicCodeCB->get_state_changed_from_saved()) + rOpt.SetLoadPPointBasicCode( m_xPBasicCodeCB->get_active() ); + if( m_xPBasicStgCB->get_state_changed_from_saved()) + rOpt.SetLoadPPointBasicStorage( m_xPBasicStgCB->get_active() ); + + return false; +} + +void OfaMSFilterTabPage::Reset( const SfxItemSet* ) +{ + const SvtFilterOptions& rOpt = SvtFilterOptions::Get(); + + m_xWBasicCodeCB->set_active( rOpt.IsLoadWordBasicCode() ); + m_xWBasicCodeCB->set_sensitive(!officecfg::Office::Writer::Filter::Import::VBA::Load::isReadOnly()); + m_xWBasicCodeImg->set_visible(officecfg::Office::Writer::Filter::Import::VBA::Load::isReadOnly()); + m_xWBasicCodeCB->save_state(); + m_xWBasicWbctblCB->set_active( rOpt.IsLoadWordBasicExecutable() ); + m_xWBasicWbctblCB->set_sensitive(!officecfg::Office::Writer::Filter::Import::VBA::Executable::isReadOnly()); + m_xWBasicWbctblImg->set_visible(officecfg::Office::Writer::Filter::Import::VBA::Executable::isReadOnly()); + m_xWBasicWbctblCB->save_state(); + m_xWBasicStgCB->set_active( rOpt.IsLoadWordBasicStorage() ); + m_xWBasicStgCB->set_sensitive(!officecfg::Office::Writer::Filter::Import::VBA::Save::isReadOnly()); + m_xWBasicStgImg->set_visible(officecfg::Office::Writer::Filter::Import::VBA::Save::isReadOnly()); + m_xWBasicStgCB->save_state(); + LoadWordBasicCheckHdl_Impl( *m_xWBasicCodeCB ); + + m_xEBasicCodeCB->set_active( rOpt.IsLoadExcelBasicCode() ); + m_xEBasicCodeCB->set_sensitive(!officecfg::Office::Calc::Filter::Import::VBA::Load::isReadOnly()); + m_xEBasicCodeImg->set_visible(officecfg::Office::Calc::Filter::Import::VBA::Load::isReadOnly()); + m_xEBasicCodeCB->save_state(); + m_xEBasicExectblCB->set_active( rOpt.IsLoadExcelBasicExecutable() ); + m_xEBasicExectblCB->set_sensitive(!officecfg::Office::Calc::Filter::Import::VBA::Executable::isReadOnly()); + m_xEBasicExectblImg->set_visible(officecfg::Office::Calc::Filter::Import::VBA::Executable::isReadOnly()); + m_xEBasicExectblCB->save_state(); + m_xEBasicStgCB->set_active( rOpt.IsLoadExcelBasicStorage() ); + m_xEBasicStgCB->set_sensitive(!officecfg::Office::Calc::Filter::Import::VBA::Save::isReadOnly()); + m_xEBasicStgImg->set_visible(officecfg::Office::Calc::Filter::Import::VBA::Save::isReadOnly()); + m_xEBasicStgCB->save_state(); + LoadExcelBasicCheckHdl_Impl( *m_xEBasicCodeCB ); + + m_xPBasicCodeCB->set_active( rOpt.IsLoadPPointBasicCode() ); + m_xPBasicCodeCB->set_sensitive(!officecfg::Office::Impress::Filter::Import::VBA::Load::isReadOnly()); + m_xPBasicCodeImg->set_visible(officecfg::Office::Impress::Filter::Import::VBA::Load::isReadOnly()); + m_xPBasicCodeCB->save_state(); + m_xPBasicStgCB->set_active( rOpt.IsLoadPPointBasicStorage() ); + m_xPBasicStgCB->set_sensitive(!officecfg::Office::Impress::Filter::Import::VBA::Save::isReadOnly()); + m_xPBasicStgImg->set_visible(officecfg::Office::Impress::Filter::Import::VBA::Save::isReadOnly()); + m_xPBasicStgCB->save_state(); +} + +OfaMSFilterTabPage2::OfaMSFilterTabPage2(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optfltrembedpage.ui", "OptFilterPage", &rSet) + , sChgToFromMath(CuiResId(RID_CUISTR_CHG_MATH)) + , sChgToFromWriter(CuiResId(RID_CUISTR_CHG_WRITER)) + , sChgToFromCalc(CuiResId(RID_CUISTR_CHG_CALC)) + , sChgToFromImpress(CuiResId(RID_CUISTR_CHG_IMPRESS)) + , sChgToFromSmartArt(CuiResId(RID_CUISTR_CHG_SMARTART)) + , sChgToFromVisio(CuiResId(RID_CUISTR_CHG_VISIO)) + , sChgToFromPDF(CuiResId(RID_CUISTR_CHG_PDF)) + , m_xCheckLB(m_xBuilder->weld_tree_view("checklbcontainer")) + , m_xHighlightingFT(m_xBuilder->weld_label("label5")) + , m_xHighlightingRB(m_xBuilder->weld_radio_button("highlighting")) + , m_xShadingRB(m_xBuilder->weld_radio_button("shading")) + , m_xShadingImg(m_xBuilder->weld_widget("lockbuttonbox1")) + , m_xMSOLockFileCB(m_xBuilder->weld_check_button("mso_lockfile")) + , m_xMSOLockFileImg(m_xBuilder->weld_widget("lockmso_lockfile")) +{ + std::vector<int> aWidths + { + m_xCheckLB->get_checkbox_column_width(), + m_xCheckLB->get_checkbox_column_width() + }; + m_xCheckLB->set_column_fixed_widths(aWidths); +} + +OfaMSFilterTabPage2::~OfaMSFilterTabPage2() +{ +} + +std::unique_ptr<SfxTabPage> OfaMSFilterTabPage2::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<OfaMSFilterTabPage2>( pPage, pController, *rAttrSet ); +} + +OUString OfaMSFilterTabPage2::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "label3", "label4", "label5", "label6" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString radioButton[] = { "highlighting", "shading" }; + + for (const auto& radio : radioButton) + { + if (const auto& pString = m_xBuilder->weld_radio_button(radio)) + sAllStrings += pString->get_label() + " "; + } + + sAllStrings += m_xMSOLockFileCB->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool OfaMSFilterTabPage2::FillItemSet( SfxItemSet* ) +{ + SvtFilterOptions& rOpt = SvtFilterOptions::Get(); + + static struct ChkCBoxEntries{ + MSFltrPg2_CheckBoxEntries eType; + bool (SvtFilterOptions::*FnIs)() const; + void (SvtFilterOptions::*FnSet)( bool bFlag ); + } const aChkArr[] = { + { MSFltrPg2_CheckBoxEntries::Math, &SvtFilterOptions::IsMathType2Math, + &SvtFilterOptions::SetMathType2Math }, + { MSFltrPg2_CheckBoxEntries::Math, &SvtFilterOptions::IsMath2MathType, + &SvtFilterOptions::SetMath2MathType }, + { MSFltrPg2_CheckBoxEntries::Writer, &SvtFilterOptions::IsWinWord2Writer, + &SvtFilterOptions::SetWinWord2Writer }, + { MSFltrPg2_CheckBoxEntries::Writer, &SvtFilterOptions::IsWriter2WinWord, + &SvtFilterOptions::SetWriter2WinWord }, + { MSFltrPg2_CheckBoxEntries::Calc, &SvtFilterOptions::IsExcel2Calc, + &SvtFilterOptions::SetExcel2Calc }, + { MSFltrPg2_CheckBoxEntries::Calc, &SvtFilterOptions::IsCalc2Excel, + &SvtFilterOptions::SetCalc2Excel }, + { MSFltrPg2_CheckBoxEntries::Impress, &SvtFilterOptions::IsPowerPoint2Impress, + &SvtFilterOptions::SetPowerPoint2Impress }, + { MSFltrPg2_CheckBoxEntries::Impress, &SvtFilterOptions::IsImpress2PowerPoint, + &SvtFilterOptions::SetImpress2PowerPoint }, + { MSFltrPg2_CheckBoxEntries::SmartArt, &SvtFilterOptions::IsSmartArt2Shape, + &SvtFilterOptions::SetSmartArt2Shape }, + { MSFltrPg2_CheckBoxEntries::Visio, &SvtFilterOptions::IsVisio2Draw, + &SvtFilterOptions::SetVisio2Draw }, + }; + + bool bFirstCol = true; + for( const ChkCBoxEntries & rEntry : aChkArr ) + { + // we loop through the list, alternating reading the first/second column, + // each row appears twice in the list (except for smartart and later entries, which are + // import only) + sal_uInt16 nCol = bFirstCol ? 0 : 1; + bFirstCol = !bFirstCol; + int nEntry = GetEntry4Type(rEntry.eType); + if (nEntry != -1) + { + bool bCheck = m_xCheckLB->get_toggle(nEntry, nCol); + if( bCheck != (rOpt.*rEntry.FnIs)() ) + (rOpt.*rEntry.FnSet)( bCheck ); + } + if (rEntry.eType == MSFltrPg2_CheckBoxEntries::SmartArt) + { + bFirstCol = !bFirstCol; + } + } + int nPDFEntry = GetEntry4Type(MSFltrPg2_CheckBoxEntries::PDF); + bool bPDFCheck = m_xCheckLB->get_toggle(nPDFEntry, 0); + if (bPDFCheck != officecfg::Office::Common::Filter::Adobe::Import::PDFToDraw::get()) + { + std::shared_ptr<comphelper::ConfigurationChanges> pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Filter::Adobe::Import::PDFToDraw::set(bPDFCheck, pBatch); + pBatch->commit(); + } + + if( m_xHighlightingRB->get_state_changed_from_saved() ) + { + if (m_xHighlightingRB->get_active()) + rOpt.SetCharBackground2Highlighting(); + else + rOpt.SetCharBackground2Shading(); + } + + if (m_xMSOLockFileCB->get_state_changed_from_saved()) + { + rOpt.EnableMSOLockFileCreation(m_xMSOLockFileCB->get_active()); + } + + return true; +} + +void OfaMSFilterTabPage2::Reset( const SfxItemSet* ) +{ + SvtFilterOptions& rOpt = SvtFilterOptions::Get(); + + m_xCheckLB->freeze(); + m_xCheckLB->clear(); + + SvtModuleOptions aModuleOpt; + + // int the same sequence as the enums of MSFltrPg2_CheckBoxEntries + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::MATH ) ) + InsertEntry( sChgToFromMath, MSFltrPg2_CheckBoxEntries::Math ); + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) + InsertEntry( sChgToFromWriter, MSFltrPg2_CheckBoxEntries::Writer ); + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) ) + InsertEntry( sChgToFromCalc, MSFltrPg2_CheckBoxEntries::Calc ); + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) ) + InsertEntry( sChgToFromImpress, MSFltrPg2_CheckBoxEntries::Impress ); + InsertEntry( sChgToFromSmartArt, MSFltrPg2_CheckBoxEntries::SmartArt, false ); + if (aModuleOpt.IsModuleInstalled(SvtModuleOptions::EModule::DRAW)) + { + InsertEntry(sChgToFromVisio, MSFltrPg2_CheckBoxEntries::Visio, false); + InsertEntry(sChgToFromPDF, MSFltrPg2_CheckBoxEntries::PDF, false); + } + + static struct ChkCBoxEntries{ + MSFltrPg2_CheckBoxEntries eType; + bool (SvtFilterOptions::*FnIs)() const; + } const aChkArr[] = { + { MSFltrPg2_CheckBoxEntries::Math, &SvtFilterOptions::IsMathType2Math }, + { MSFltrPg2_CheckBoxEntries::Math, &SvtFilterOptions::IsMath2MathType }, + { MSFltrPg2_CheckBoxEntries::Writer, &SvtFilterOptions::IsWinWord2Writer }, + { MSFltrPg2_CheckBoxEntries::Writer, &SvtFilterOptions::IsWriter2WinWord }, + { MSFltrPg2_CheckBoxEntries::Calc, &SvtFilterOptions::IsExcel2Calc }, + { MSFltrPg2_CheckBoxEntries::Calc, &SvtFilterOptions::IsCalc2Excel }, + { MSFltrPg2_CheckBoxEntries::Impress, &SvtFilterOptions::IsPowerPoint2Impress }, + { MSFltrPg2_CheckBoxEntries::Impress, &SvtFilterOptions::IsImpress2PowerPoint }, + { MSFltrPg2_CheckBoxEntries::SmartArt, &SvtFilterOptions::IsSmartArt2Shape }, + { MSFltrPg2_CheckBoxEntries::Visio, &SvtFilterOptions::IsVisio2Draw }, + { MSFltrPg2_CheckBoxEntries::PDF, nullptr }, + }; + + bool bFirstCol = true; + bool bReadOnly = false; + for( const ChkCBoxEntries & rArr : aChkArr ) + { + // we loop through the list, alternating reading the first/second column, + // each row appears twice in the list (except for smartart and later entries, which are + // import only) + sal_uInt16 nCol = bFirstCol ? 0 : 1; + bFirstCol = !bFirstCol; + int nEntry = GetEntry4Type( rArr.eType ); + if (nEntry != -1) + { + bool bCheck = false; + if (rArr.eType != MSFltrPg2_CheckBoxEntries::PDF) + { + bCheck = (rOpt.*rArr.FnIs)(); + switch (rArr.eType) + { + case MSFltrPg2_CheckBoxEntries::Math: + if (nCol == 0) + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Import::MathTypeToMath::isReadOnly(); + else + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Export::MathToMathType::isReadOnly(); + break; + case MSFltrPg2_CheckBoxEntries::Writer: + if (nCol == 0) + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Import::WinWordToWriter::isReadOnly(); + else + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Export::WriterToWinWord::isReadOnly(); + break; + case MSFltrPg2_CheckBoxEntries::Calc: + if (nCol == 0) + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Import::ExcelToCalc::isReadOnly(); + else + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Export::CalcToExcel::isReadOnly(); + break; + case MSFltrPg2_CheckBoxEntries::Impress: + if (nCol == 0) + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Import::PowerPointToImpress::isReadOnly(); + else + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Export::ImpressToPowerPoint::isReadOnly(); + break; + case MSFltrPg2_CheckBoxEntries::SmartArt: + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::isReadOnly(); + break; + case MSFltrPg2_CheckBoxEntries::Visio: + bReadOnly = officecfg::Office::Common::Filter::Microsoft::Import::VisioToDraw::isReadOnly(); + break; + default: + break; + } + } + else + { + bCheck = officecfg::Office::Common::Filter::Adobe::Import::PDFToDraw::get(); + bReadOnly = officecfg::Office::Common::Filter::Adobe::Import::PDFToDraw::isReadOnly(); + nCol = 0; + } + m_xCheckLB->set_toggle(nEntry, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE, nCol); + m_xCheckLB->set_sensitive(nEntry, !bReadOnly, nCol); + } + if (rArr.eType == MSFltrPg2_CheckBoxEntries::SmartArt) + { + bFirstCol = !bFirstCol; + } + } + m_xCheckLB->thaw(); + + if (rOpt.IsCharBackground2Highlighting()) + m_xHighlightingRB->set_active(true); + else + m_xShadingRB->set_active(true); + + if (officecfg::Office::Common::Filter::Microsoft::Export::CharBackgroundToHighlighting::isReadOnly()) + { + m_xHighlightingRB->set_sensitive(false); + m_xShadingRB->set_sensitive(false); + m_xHighlightingFT->set_sensitive(false); + m_xShadingImg->set_visible(true); + } + + m_xHighlightingRB->save_state(); + + m_xMSOLockFileCB->set_active(rOpt.IsMSOLockFileCreationIsEnabled()); + m_xMSOLockFileCB->save_state(); + m_xMSOLockFileCB->set_sensitive(!officecfg::Office::Common::Filter::Microsoft::Import::CreateMSOLockFiles::isReadOnly()); + m_xMSOLockFileImg->set_visible(officecfg::Office::Common::Filter::Microsoft::Import::CreateMSOLockFiles::isReadOnly()); +} + +void OfaMSFilterTabPage2::InsertEntry( const OUString& _rTxt, MSFltrPg2_CheckBoxEntries _nType ) +{ + InsertEntry( _rTxt, _nType, true ); +} + +void OfaMSFilterTabPage2::InsertEntry( const OUString& _rTxt, MSFltrPg2_CheckBoxEntries _nType, + bool saveEnabled ) +{ + int nPos = m_xCheckLB->n_children(); + m_xCheckLB->append(); + m_xCheckLB->set_toggle(nPos, TRISTATE_FALSE, 0); + if (saveEnabled) + m_xCheckLB->set_toggle(nPos, TRISTATE_FALSE, 1); + m_xCheckLB->set_text(nPos, _rTxt, 2); + m_xCheckLB->set_id(nPos, OUString::number(static_cast<sal_Int32>(_nType))); +} + +int OfaMSFilterTabPage2::GetEntry4Type( MSFltrPg2_CheckBoxEntries _nType ) const +{ + for (int i = 0, nEntryCount = m_xCheckLB->n_children(); i < nEntryCount; ++i) + { + if (_nType == static_cast<MSFltrPg2_CheckBoxEntries>(m_xCheckLB->get_id(i).toInt32())) + return i; + } + return -1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optfltr.hxx b/cui/source/options/optfltr.hxx new file mode 100644 index 0000000000..51a51ec044 --- /dev/null +++ b/cui/source/options/optfltr.hxx @@ -0,0 +1,95 @@ +/* -*- 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 . + */ +#pragma once + +#include <sfx2/tabdlg.hxx> + +class OfaMSFilterTabPage : public SfxTabPage +{ + std::unique_ptr<weld::CheckButton> m_xWBasicCodeCB; + std::unique_ptr<weld::Widget> m_xWBasicCodeImg; + std::unique_ptr<weld::CheckButton> m_xWBasicWbctblCB; + std::unique_ptr<weld::Widget> m_xWBasicWbctblImg; + std::unique_ptr<weld::CheckButton> m_xWBasicStgCB; + std::unique_ptr<weld::Widget> m_xWBasicStgImg; + std::unique_ptr<weld::CheckButton> m_xEBasicCodeCB; + std::unique_ptr<weld::Widget> m_xEBasicCodeImg; + std::unique_ptr<weld::CheckButton> m_xEBasicExectblCB; + std::unique_ptr<weld::Widget> m_xEBasicExectblImg; + std::unique_ptr<weld::CheckButton> m_xEBasicStgCB; + std::unique_ptr<weld::Widget> m_xEBasicStgImg; + std::unique_ptr<weld::CheckButton> m_xPBasicCodeCB; + std::unique_ptr<weld::Widget> m_xPBasicCodeImg; + std::unique_ptr<weld::CheckButton> m_xPBasicStgCB; + std::unique_ptr<weld::Widget> m_xPBasicStgImg; + + DECL_LINK(LoadWordBasicCheckHdl_Impl, weld::Toggleable&, void); + DECL_LINK(LoadExcelBasicCheckHdl_Impl, weld::Toggleable&, void); +public: + OfaMSFilterTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet ); + virtual ~OfaMSFilterTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +enum class MSFltrPg2_CheckBoxEntries; + +class OfaMSFilterTabPage2 : public SfxTabPage +{ + OUString sChgToFromMath, + sChgToFromWriter, + sChgToFromCalc, + sChgToFromImpress, + sChgToFromSmartArt, + sChgToFromVisio, + sChgToFromPDF; + + std::unique_ptr<weld::TreeView> m_xCheckLB; + std::unique_ptr<weld::Label> m_xHighlightingFT; + std::unique_ptr<weld::RadioButton> m_xHighlightingRB; + std::unique_ptr<weld::RadioButton> m_xShadingRB; + std::unique_ptr<weld::Widget> m_xShadingImg; + std::unique_ptr<weld::CheckButton> m_xMSOLockFileCB; + std::unique_ptr<weld::Widget> m_xMSOLockFileImg; + + void InsertEntry( const OUString& _rTxt, MSFltrPg2_CheckBoxEntries _nType ); + void InsertEntry( const OUString& _rTxt, MSFltrPg2_CheckBoxEntries _nType, + bool saveEnabled ); + int GetEntry4Type( MSFltrPg2_CheckBoxEntries _nType ) const; + +public: + OfaMSFilterTabPage2(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + virtual ~OfaMSFilterTabPage2() override; + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optgdlg.cxx b/cui/source/options/optgdlg.cxx new file mode 100644 index 0000000000..941164e504 --- /dev/null +++ b/cui/source/options/optgdlg.cxx @@ -0,0 +1,2004 @@ +/* -*- 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 <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 <svtools/miscopt.hxx> +#include <unotools/syslocaleoptions.hxx> +#include <sfx2/objsh.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/propertyvalue.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/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/XNameReplace.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.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 <comphelper/dispatchcommand.hxx> + +#include <vcl/vclenum.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/window.hxx> +#include <vcl/IconThemeInfo.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 <svtools/imgdef.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 +{ +OUString impl_SystemFileOpenServiceName() +{ + #if defined(_WIN32) + return "com.sun.star.ui.dialogs.SystemFilePicker"; + #elif defined MACOSX + return "com.sun.star.ui.dialogs.AquaFilePicker"; + #else + return 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 + { + 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, "cui/ui/optgeneralpage.ui", "OptGeneralPage", &rSet) + , m_xExtHelpCB(m_xBuilder->weld_check_button("exthelp")) + , m_xExtHelpImg(m_xBuilder->weld_widget("lockexthelp")) + , m_xPopUpNoHelpCB(m_xBuilder->weld_check_button("popupnohelp")) + , m_xPopUpNoHelpImg(m_xBuilder->weld_widget("lockpopupnohelp")) + , m_xShowTipOfTheDay(m_xBuilder->weld_check_button("cbShowTipOfTheDay")) + , m_xShowTipOfTheDayImg(m_xBuilder->weld_widget("lockcbShowTipOfTheDay")) + , m_xFileDlgFrame(m_xBuilder->weld_widget("filedlgframe")) + , m_xFileDlgROImage(m_xBuilder->weld_widget("lockimage")) + , m_xFileDlgCB(m_xBuilder->weld_check_button("filedlg")) + , m_xDocStatusCB(m_xBuilder->weld_check_button("docstatus")) + , m_xDocStatusImg(m_xBuilder->weld_widget("lockdocstatus")) + , m_xYearFrame(m_xBuilder->weld_widget("yearframe")) + , m_xYearLabel(m_xBuilder->weld_label("yearslabel")) + , m_xYearValueField(m_xBuilder->weld_spin_button("year")) + , m_xToYearFT(m_xBuilder->weld_label("toyear")) + , m_xYearFrameImg(m_xBuilder->weld_widget("lockyears")) +#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() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "label4", "label5", "yearslabel", + "toyear", "label7", "label8", "label9" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] + = { "exthelp", "popupnohelp", "cbShowTipOfTheDay", "filedlg", + "docstatus", "crashreport", "quicklaunch", "cbPerformFileExtCheck" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + if (const auto& pString = m_xBuilder->weld_button("assocfiles")) + sAllStrings += pString->get_label() + " "; + + return sAllStrings.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_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(); + + if (!lcl_HasSystemFilePicker()) + m_xFileDlgFrame->hide(); + else + { + bEnable = !officecfg::Office::Common::Misc::UseSystemFileDialog::isReadOnly(); + m_xFileDlgCB->set_sensitive(bEnable); + m_xFileDlgROImage->set_visible(!bEnable); + } + m_xFileDlgCB->set_active(!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) + const SfxPoolItem* pItem = nullptr; + SfxItemState eState = rSet->GetItemState( SID_ATTR_QUICKLAUNCHER, false, &pItem ); + if ( SfxItemState::SET == eState ) + m_xQuickLaunchCB->set_active( static_cast<const SfxBoolItem*>(pItem)->GetValue() ); + else if ( SfxItemState::DISABLED == eState ) + { + // 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 IsHardwareAccelerationEnabled() const; + bool IsHardwareAccelerationAvailable() const; + bool IsHardwareAccelerationRO() const; + void EnabledHardwareAcceleration( bool _bEnabled ) 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(OUString("/org.openoffice.Office.Canvas"))} + })); + mxForceFlagNameAccess.set( + xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationUpdateAccess", + aArgs1 ), + UNO_QUERY_THROW ); + + Sequence<Any> aArgs2(comphelper::InitAnyPropertySequence( + { + {"nodepath", Any(OUString("/org.openoffice.Office.Canvas/CanvasServiceList"))} + })); + Reference<XNameAccess> xNameAccess( + xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", + aArgs2 ), UNO_QUERY_THROW ); + Reference<XHierarchicalNameAccess> xHierarchicalNameAccess( + xNameAccess, UNO_QUERY_THROW); + + Sequence<OUString> serviceNames = xNameAccess->getElementNames(); + const OUString* pCurr = serviceNames.getConstArray(); + const OUString* const pEnd = pCurr + serviceNames.getLength(); + while( pCurr != pEnd ) + { + Reference<XNameAccess> xEntryNameAccess( + xHierarchicalNameAccess->getByHierarchicalName(*pCurr), + UNO_QUERY ); + + if( xEntryNameAccess.is() ) + { + Sequence<OUString> preferredImplementations; + if( xEntryNameAccess->getByName("PreferredImplementations") >>= preferredImplementations ) + maAvailableImplementations.emplace_back(*pCurr,preferredImplementations ); + } + + ++pCurr; + } + } + 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) + { + const OUString* pCurrImpl = availableImpl.second.getConstArray(); + const OUString* const pEndImpl = pCurrImpl + availableImpl.second.getLength(); + + while( pCurrImpl != pEndImpl ) + { + try + { + Reference<XPropertySet> xPropSet( xFactory->createInstance( + pCurrImpl->trim() ), + UNO_QUERY_THROW ); + bool bHasAccel(false); + if( xPropSet->getPropertyValue("HardwareAcceleration") >>= bHasAccel ) + if( bHasAccel ) + { + mbHWAccelAvailable = true; + return mbHWAccelAvailable; + } + } + catch (const Exception&) + { + } + + ++pCurrImpl; + } + } + } + + return mbHWAccelAvailable; +} + +bool CanvasSettings::IsHardwareAccelerationEnabled() const +{ + bool bForceLastEntry(false); + if( !mxForceFlagNameAccess.is() ) + return true; + + if( !(mxForceFlagNameAccess->getByName("ForceSafeServiceImpl") >>= bForceLastEntry) ) + return true; + + return !bForceLastEntry; +} + +bool CanvasSettings::IsHardwareAccelerationRO() const +{ + Reference< XPropertySet > xSet(mxForceFlagNameAccess, UNO_QUERY); + if (!xSet.is()) + return true; + + Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo(); + Property aProp = xInfo->getPropertyByName("ForceSafeServiceImpl"); + return ((aProp.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY); +} + +void CanvasSettings::EnabledHardwareAcceleration( bool _bEnabled ) const +{ + Reference< XNameReplace > xNameReplace( + mxForceFlagNameAccess, UNO_QUERY ); + + if( !xNameReplace.is() ) + return; + + xNameReplace->replaceByName( "ForceSafeServiceImpl", Any(!_bEnabled) ); + + Reference< XChangesBatch > xChangesBatch( + mxForceFlagNameAccess, UNO_QUERY ); + + if( !xChangesBatch.is() ) + return; + + xChangesBatch->commitChanges(); +} + +// class OfaViewTabPage -------------------------------------------------- + +static bool DisplayNameCompareLessThan(const vcl::IconThemeInfo& rInfo1, const vcl::IconThemeInfo& rInfo2) +{ + return rInfo1.GetDisplayName().compareTo(rInfo2.GetDisplayName()) < 0; +} + +OfaViewTabPage::OfaViewTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optviewpage.ui", "OptViewPage", &rSet) + , nSizeLB_InitialSelection(0) + , nSidebarSizeLB_InitialSelection(0) + , nNotebookbarSizeLB_InitialSelection(0) + , nStyleLB_InitialSelection(0) + , pCanvasSettings(new CanvasSettings) + , m_xIconSizeLabel(m_xBuilder->weld_label("label14")) + , m_xIconSizeLB(m_xBuilder->weld_combo_box("iconsize")) + , m_xIconSizeImg(m_xBuilder->weld_widget("lockiconsize")) + , m_xSidebarIconSizeLabel(m_xBuilder->weld_label("label9")) + , m_xSidebarIconSizeLB(m_xBuilder->weld_combo_box("sidebariconsize")) + , m_xSidebarIconSizeImg(m_xBuilder->weld_widget("locksidebariconsize")) + , m_xNotebookbarIconSizeLabel(m_xBuilder->weld_label("label8")) + , m_xNotebookbarIconSizeLB(m_xBuilder->weld_combo_box("notebookbariconsize")) + , m_xNotebookbarIconSizeImg(m_xBuilder->weld_widget("locknotebookbariconsize")) + , m_xDarkModeFrame(m_xBuilder->weld_widget("darkmode")) + , m_xAppearanceStyleLabel(m_xBuilder->weld_label("label7")) + , m_xAppearanceStyleLB(m_xBuilder->weld_combo_box("appearance")) + , m_xAppearanceStyleImg(m_xBuilder->weld_widget("lockappearance")) + , m_xIconStyleLabel(m_xBuilder->weld_label("label6")) + , m_xIconStyleLB(m_xBuilder->weld_combo_box("iconstyle")) + , m_xIconStyleImg(m_xBuilder->weld_widget("lockiconstyle")) + , m_xFontAntiAliasing(m_xBuilder->weld_check_button("aafont")) + , m_xFontAntiAliasingImg(m_xBuilder->weld_widget("lockaafont")) + , m_xAAPointLimitLabel(m_xBuilder->weld_label("aafrom")) + , m_xAAPointLimitLabelImg(m_xBuilder->weld_widget("lockaafrom")) + , m_xAAPointLimit(m_xBuilder->weld_metric_spin_button("aanf", FieldUnit::PIXEL)) + , m_xFontShowCB(m_xBuilder->weld_check_button("showfontpreview")) + , m_xFontShowImg(m_xBuilder->weld_widget("lockshowfontpreview")) + , m_xUseHardwareAccell(m_xBuilder->weld_check_button("useaccel")) + , m_xUseHardwareAccellImg(m_xBuilder->weld_widget("lockuseaccel")) + , m_xUseAntiAliase(m_xBuilder->weld_check_button("useaa")) + , m_xUseAntiAliaseImg(m_xBuilder->weld_widget("lockuseaa")) + , m_xUseSkia(m_xBuilder->weld_check_button("useskia")) + , m_xUseSkiaImg(m_xBuilder->weld_widget("lockuseskia")) + , m_xForceSkiaRaster(m_xBuilder->weld_check_button("forceskiaraster")) + , m_xForceSkiaRasterImg(m_xBuilder->weld_widget("lockforceskiaraster")) + , m_xSkiaStatusEnabled(m_xBuilder->weld_label("skiaenabled")) + , m_xSkiaStatusDisabled(m_xBuilder->weld_label("skiadisabled")) + , m_xSkiaLog(m_xBuilder->weld_button("btnSkialog")) + , m_xMouseMiddleLabel(m_xBuilder->weld_label("label12")) + , m_xMouseMiddleLB(m_xBuilder->weld_combo_box("mousemiddle")) + , m_xMouseMiddleImg(m_xBuilder->weld_widget("lockmousemiddle")) + , m_xMoreIcons(m_xBuilder->weld_button("btnMoreIcons")) + , m_xRunGPTests(m_xBuilder->weld_button("btn_rungptest")) + , m_sAutoStr(m_xIconStyleLB->get_text(0)) +{ + OUString sToolKitName(Application::GetToolkitName()); + const bool bHasDarkMode = sToolKitName.startsWith("gtk") || sToolKitName == "osx" || sToolKitName == "win"; + if (!bHasDarkMode) + m_xDarkModeFrame->hide(); + + m_xFontAntiAliasing->connect_toggled( LINK( this, OfaViewTabPage, OnAntialiasingToggled ) ); + + m_xUseSkia->connect_toggled(LINK(this, OfaViewTabPage, OnUseSkiaToggled)); + m_xSkiaLog->connect_clicked(LINK(this, OfaViewTabPage, OnCopySkiaLog)); + + UpdateIconThemes(); + + m_xIconStyleLB->set_active(0); + + m_xMoreIcons->connect_clicked(LINK(this, OfaViewTabPage, OnMoreIconsClick)); + m_xRunGPTests->connect_clicked( LINK( this, OfaViewTabPage, OnRunGPTestClick)); +} + +void OfaViewTabPage::UpdateIconThemes() +{ + // Set known icon themes + m_xIconStyleLB->clear(); + StyleSettings aStyleSettings = Application::GetSettings().GetStyleSettings(); + mInstalledIconThemes = aStyleSettings.GetInstalledIconThemes(); + std::sort(mInstalledIconThemes.begin(), mInstalledIconThemes.end(), DisplayNameCompareLessThan); + + // Start with the automatically chosen icon theme + OUString autoThemeId = aStyleSettings.GetAutomaticallyChosenIconTheme(); + const vcl::IconThemeInfo& autoIconTheme = vcl::IconThemeInfo::FindIconThemeById(mInstalledIconThemes, autoThemeId); + + OUString entryForAuto = m_sAutoStr + " (" + autoIconTheme.GetDisplayName() + ")"; + m_xIconStyleLB->append("auto", entryForAuto); // index 0 means choose style automatically + + // separate auto and other icon themes + m_xIconStyleLB->append_separator(""); + + for (auto const& installIconTheme : mInstalledIconThemes) + m_xIconStyleLB->append(installIconTheme.GetThemeId(), installIconTheme.GetDisplayName()); +} + +OfaViewTabPage::~OfaViewTabPage() +{ +} + +IMPL_LINK_NOARG(OfaViewTabPage, OnRunGPTestClick, weld::Button&, void) +{ + GraphicsTestsDialog m_xGraphicsTestDialog(m_xContainer.get()); + m_xGraphicsTestDialog.run(); +} + +IMPL_STATIC_LINK_NOARG(OfaViewTabPage, OnMoreIconsClick, weld::Button&, void) +{ + css::uno::Sequence<css::beans::PropertyValue> aArgs{ comphelper::makePropertyValue( + "AdditionsTag", OUString("Icons")) }; + comphelper::dispatchCommand(".uno:AdditionsDialog", aArgs); +} + +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); + + m_xUseSkia->set_sensitive(!officecfg::Office::Common::VCL::UseSkia::isReadOnly()); + 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() +{ + OUString sAllStrings; + OUString labels[] = { "label16", "label7", "label1", "label6", "label15", + "label14", "label8", "label9", "label4", "label12", + "label2", "skiaenabled", "skiadisabled", "label5", "aafrom" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] + = { "useaccel", "useaa", "useskia", "forceskiaraster", "showfontpreview", "aafont" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + sAllStrings += m_xSkiaLog->get_label() + " " + m_xRunGPTests->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool OfaViewTabPage::FillItemSet( SfxItemSet* ) +{ + bool bModified = false; + bool bDarkModeOptModified = false; + bool bRepaintWindows(false); + std::shared_ptr<comphelper::ConfigurationChanges> xChanges(comphelper::ConfigurationChanges::create()); + + SvtMiscOptions aMiscOptions; + const sal_Int32 nSizeLB_NewSelection = m_xIconSizeLB->get_active(); + if( nSizeLB_InitialSelection != nSizeLB_NewSelection ) + { + // from now on it's modified, even if via auto setting the same size was set as now selected in the LB + sal_Int16 eSet = SFX_SYMBOLS_SIZE_AUTO; + switch( nSizeLB_NewSelection ) + { + case 0: eSet = SFX_SYMBOLS_SIZE_AUTO; break; + case 1: eSet = SFX_SYMBOLS_SIZE_SMALL; break; + case 2: eSet = SFX_SYMBOLS_SIZE_LARGE; break; + case 3: eSet = SFX_SYMBOLS_SIZE_32; break; + default: + SAL_WARN("cui.options", "OfaViewTabPage::FillItemSet(): This state of m_xIconSizeLB should not be possible!"); + } + aMiscOptions.SetSymbolsSize( eSet ); + } + + const sal_Int32 nSidebarSizeLB_NewSelection = m_xSidebarIconSizeLB->get_active(); + if( nSidebarSizeLB_InitialSelection != nSidebarSizeLB_NewSelection ) + { + // from now on it's modified, even if via auto setting the same size was set as now selected in the LB + ToolBoxButtonSize eSet = ToolBoxButtonSize::DontCare; + switch( nSidebarSizeLB_NewSelection ) + { + case 0: eSet = ToolBoxButtonSize::DontCare; break; + case 1: eSet = ToolBoxButtonSize::Small; break; + case 2: eSet = ToolBoxButtonSize::Large; break; + default: + SAL_WARN("cui.options", "OfaViewTabPage::FillItemSet(): This state of m_xSidebarIconSizeLB should not be possible!"); + } + officecfg::Office::Common::Misc::SidebarIconSize::set(static_cast<sal_Int16>(eSet), xChanges); + } + + const sal_Int32 nNotebookbarSizeLB_NewSelection = m_xNotebookbarIconSizeLB->get_active(); + if( nNotebookbarSizeLB_InitialSelection != nNotebookbarSizeLB_NewSelection ) + { + // from now on it's modified, even if via auto setting the same size was set as now selected in the LB + ToolBoxButtonSize eSet = ToolBoxButtonSize::DontCare; + switch( nNotebookbarSizeLB_NewSelection ) + { + case 0: eSet = ToolBoxButtonSize::DontCare; break; + case 1: eSet = ToolBoxButtonSize::Small; break; + case 2: eSet = ToolBoxButtonSize::Large; break; + default: + SAL_WARN("cui.options", "OfaViewTabPage::FillItemSet(): This state of m_xNotebookbarIconSizeLB should not be possible!"); + } + officecfg::Office::Common::Misc::NotebookbarIconSize::set(static_cast<sal_Int16>(eSet), xChanges); + } + + const sal_Int32 nStyleLB_NewSelection = m_xIconStyleLB->get_active(); + if( nStyleLB_InitialSelection != nStyleLB_NewSelection ) + { + aMiscOptions.SetIconTheme(m_xIconStyleLB->get_active_id()); + nStyleLB_InitialSelection = nStyleLB_NewSelection; + } + + 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_Int64 i = m_xAAPointLimit->get_value(FieldUnit::PIXEL); + officecfg::Office::Common::View::FontAntiAliasing::MinPixelHeight::set(i, batch); + bAppearanceChanged = true; + } + + if (m_xFontShowCB->get_state_changed_from_saved()) + { + officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::set(m_xFontShowCB->get_active(), xChanges); + bModified = true; + } + + if (m_xAppearanceStyleLB->get_value_changed_from_saved()) + { + bDarkModeOptModified = true; + 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()) + { + pCanvasSettings->EnabledHardwareAcceleration(m_xUseHardwareAccell->get_active()); + 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 (bDarkModeOptModified) + MiscSettings::SetDarkMode(m_xAppearanceStyleLB->get_active()); + + 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* ) +{ + SvtMiscOptions aMiscOptions; + bool bEnable = true; + + if (SvtMiscOptions::GetSymbolsSize() != SFX_SYMBOLS_SIZE_AUTO) + { + nSizeLB_InitialSelection = 1; + + if (SvtMiscOptions::GetSymbolsSize() == SFX_SYMBOLS_SIZE_LARGE) + nSizeLB_InitialSelection = 2; + else if (SvtMiscOptions::GetSymbolsSize() == SFX_SYMBOLS_SIZE_32) + nSizeLB_InitialSelection = 3; + } + bEnable = !officecfg::Office::Common::Misc::SymbolSet::isReadOnly(); + m_xIconSizeLB->set_active( nSizeLB_InitialSelection ); + m_xIconSizeLabel->set_sensitive(bEnable); + m_xIconSizeLB->set_sensitive(bEnable); + m_xMoreIcons->set_sensitive(bEnable); + m_xIconSizeImg->set_visible(!bEnable); + m_xIconSizeLB->save_value(); + + ToolBoxButtonSize eSidebarIconSize = static_cast<ToolBoxButtonSize>(officecfg::Office::Common::Misc::SidebarIconSize::get()); + if( eSidebarIconSize == ToolBoxButtonSize::DontCare ) + ; // do nothing + else if( eSidebarIconSize == ToolBoxButtonSize::Small ) + nSidebarSizeLB_InitialSelection = 1; + else if( eSidebarIconSize == ToolBoxButtonSize::Large ) + nSidebarSizeLB_InitialSelection = 2; + + bEnable = !officecfg::Office::Common::Misc::SidebarIconSize::isReadOnly(); + m_xSidebarIconSizeLB->set_active( nSidebarSizeLB_InitialSelection ); + m_xSidebarIconSizeLabel->set_sensitive(bEnable); + m_xSidebarIconSizeLB->set_sensitive(bEnable); + m_xSidebarIconSizeImg->set_visible(!bEnable); + m_xSidebarIconSizeLB->save_value(); + + ToolBoxButtonSize eNotebookbarIconSize = static_cast<ToolBoxButtonSize>(officecfg::Office::Common::Misc::NotebookbarIconSize::get()); + if( eNotebookbarIconSize == ToolBoxButtonSize::DontCare ) + ; // do nothing + else if( eNotebookbarIconSize == ToolBoxButtonSize::Small ) + nNotebookbarSizeLB_InitialSelection = 1; + else if( eNotebookbarIconSize == ToolBoxButtonSize::Large ) + nNotebookbarSizeLB_InitialSelection = 2; + + bEnable = !officecfg::Office::Common::Misc::NotebookbarIconSize::isReadOnly(); + m_xNotebookbarIconSizeLB->set_active(nNotebookbarSizeLB_InitialSelection); + m_xNotebookbarIconSizeLabel->set_sensitive(bEnable); + m_xNotebookbarIconSizeLB->set_sensitive(bEnable); + m_xNotebookbarIconSizeImg->set_visible(!bEnable); + m_xNotebookbarIconSizeLB->save_value(); + + // tdf#153497 set name of automatic icon theme, it may have changed due to "Apply" while this page is visible + UpdateIconThemes(); + + if (aMiscOptions.IconThemeWasSetAutomatically()) { + nStyleLB_InitialSelection = 0; + } + else { + const OUString& selected = SvtMiscOptions::GetIconTheme(); + const vcl::IconThemeInfo& selectedInfo = + vcl::IconThemeInfo::FindIconThemeById(mInstalledIconThemes, selected); + nStyleLB_InitialSelection = m_xIconStyleLB->find_text(selectedInfo.GetDisplayName()); + } + + bEnable = !officecfg::Office::Common::Misc::SymbolStyle::isReadOnly(); + m_xIconStyleLB->set_active(nStyleLB_InitialSelection); + m_xIconStyleLabel->set_sensitive(bEnable); + m_xIconStyleLB->set_sensitive(bEnable); + m_xIconStyleImg->set_visible(!bEnable); + m_xIconStyleLB->save_value(); + + bEnable = !officecfg::Office::Common::Misc::Appearance::isReadOnly(); + m_xAppearanceStyleLB->set_active(officecfg::Office::Common::Misc::Appearance::get()); + m_xAppearanceStyleLabel->set_sensitive(bEnable); + m_xAppearanceStyleLB->set_sensitive(bEnable); + m_xAppearanceStyleImg->set_visible(!bEnable); + m_xAppearanceStyleLB->save_value(); + + // 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 + if(SvtOptionsDrawinglayer::IsAAPossibleOnThisSystem()) + { + m_xUseAntiAliase->set_active(SvtOptionsDrawinglayer::IsAntiAliasing()); + } + else + { + m_xUseAntiAliase->set_active(false); + m_xUseAntiAliase->set_sensitive(false); + m_xUseAntiAliaseImg->set_visible(true); + } + + bEnable = !officecfg::Office::Common::Drawinglayer::AntiAliasing::isReadOnly(); + m_xUseAntiAliase->set_sensitive(bEnable); + m_xUseAntiAliaseImg->set_visible(!bEnable); + m_xUseAntiAliase->save_state(); + } + + m_xUseSkia->set_active(officecfg::Office::Common::VCL::UseSkia::get()); + 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) + if(pCanvasSettings->IsHardwareAccelerationAvailable()) + { + m_xUseHardwareAccell->set_active(pCanvasSettings->IsHardwareAccelerationEnabled()); + m_xUseHardwareAccell->set_sensitive(!pCanvasSettings->IsHardwareAccelerationRO()); + m_xUseHardwareAccellImg->set_visible(pCanvasSettings->IsHardwareAccelerationRO()); + } + else + { + m_xUseHardwareAccell->set_active(false); + m_xUseHardwareAccell->set_sensitive(false); + m_xUseHardwareAccellImg->set_visible(true); + } +#if HAVE_FEATURE_SKIA + m_xUseHardwareAccell->set_sensitive(!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 ) +{ + 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) + { + const OUString* pPatterns = aDateAcceptancePatterns.getConstArray(); + aBuf.append( pPatterns[0]); + for (sal_Int32 i=1; i < nPatterns; ++i) + aBuf.append(";" + pPatterns[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, "cui/ui/optlanguagespage.ui", "OptLanguagesPage", &rSet) + , pLangConfig(new LanguageConfig_Impl) + , m_bDatePatternsValid(false) + , m_xUserInterfaceLB(m_xBuilder->weld_combo_box("userinterface")) + , m_xLocaleSettingFT(m_xBuilder->weld_label("localesettingFT")) + , m_xLocaleSettingLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("localesetting"))) + , m_xLocaleSettingImg(m_xBuilder->weld_widget("locklocalesetting")) + , m_xDecimalSeparatorFT(m_xBuilder->weld_label("label6")) + , m_xDecimalSeparatorCB(m_xBuilder->weld_check_button("decimalseparator")) + , m_xDecimalSeparatorImg(m_xBuilder->weld_widget("lockdecimalseparator")) + , m_xCurrencyFT(m_xBuilder->weld_label("defaultcurrency")) + , m_xCurrencyLB(m_xBuilder->weld_combo_box("currencylb")) + , m_xCurrencyImg(m_xBuilder->weld_widget("lockcurrencylb")) + , m_xDatePatternsFT(m_xBuilder->weld_label("dataaccpatterns")) + , m_xDatePatternsED(m_xBuilder->weld_entry("datepatterns")) + , m_xDatePatternsImg(m_xBuilder->weld_widget("lockdatepatterns")) + , m_xWesternLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("westernlanguage"))) + , m_xWesternLanguageFT(m_xBuilder->weld_label("western")) + , m_xWesternLanguageImg(m_xBuilder->weld_widget("lockwesternlanguage")) + , m_xAsianLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("asianlanguage"))) + , m_xComplexLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("complexlanguage"))) + , m_xCurrentDocCB(m_xBuilder->weld_check_button("currentdoc")) + , m_xAsianSupportCB(m_xBuilder->weld_check_button("asiansupport")) + , m_xAsianSupportImg(m_xBuilder->weld_widget("lockasiansupport")) + , m_xCTLSupportCB(m_xBuilder->weld_check_button("ctlsupport")) + , m_xCTLSupportImg(m_xBuilder->weld_widget("lockctlsupport")) + , m_xIgnoreLanguageChangeCB(m_xBuilder->weld_check_button("ignorelanguagechange")) + , m_xIgnoreLanguageChangeImg(m_xBuilder->weld_widget("lockignorelanguagechange")) +{ + // 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("0", aUILang); + m_xUserInterfaceLB->append_separator(""); + 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("nodepath", 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("nodepath", 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("default", aDefaultCurr); + m_xCurrencyLB->append_separator(""); + + assert(m_xCurrencyLB->find_id("default") != -1); + // all currencies + OUString aTwoSpace( " " ); + 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 ) ); + + Link<weld::Toggleable&,void> aLink( LINK( this, OfaLanguagesTabPage, SupportHdl ) ); + m_xAsianSupportCB->connect_toggled( aLink ); + m_xCTLSupportCB->connect_toggled( aLink ); + + m_bOldAsian = SvtCJKOptions::IsAnyEnabled(); + m_xAsianSupportCB->set_active(m_bOldAsian); + m_xAsianSupportCB->save_state(); + bool bReadonly = SvtCJKOptions::IsAnyReadOnly(); + m_xAsianSupportCB->set_sensitive(!bReadonly); + m_xAsianSupportImg->set_visible(bReadonly); + SupportHdl(*m_xAsianSupportCB); + + m_bOldCtl = SvtCTLOptions::IsCTLFontEnabled(); + m_xCTLSupportCB->set_active(m_bOldCtl); + m_xCTLSupportCB->save_state(); + bReadonly = pLangConfig->aCTLLanguageOptions.IsReadOnly(SvtCTLOptions::E_CTLFONT); + m_xCTLSupportCB->set_sensitive(!bReadonly); + m_xCTLSupportImg->set_visible(bReadonly); + SupportHdl(*m_xCTLSupportCB); + + 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); +} + +static void lcl_Update(std::unique_ptr<SfxVoidItem> pInvalidItems[], std::unique_ptr<SfxBoolItem> pBoolItems[], sal_uInt16 nCount) +{ + SfxViewFrame* pCurrentFrm = SfxViewFrame::Current(); + SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst(); + while(pViewFrm) + { + SfxBindings& rBind = pViewFrm->GetBindings(); + for(sal_uInt16 i = 0; i < nCount; i++) + { + if(pCurrentFrm == pViewFrm) + rBind.InvalidateAll(false); + rBind.SetState( *pInvalidItems[i] ); + rBind.SetState( *pBoolItems[i] ); + } + pViewFrm = SfxViewFrame::GetNext(*pViewFrm); + } +} + +OUString OfaLanguagesTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] + = { "label1", "label4", "label7", "localesettingFT", "defaultcurrency", + "label6", "dataaccpatterns", "label2", "western", "label3" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "decimalseparator", "asiansupport", "ctlsupport", "currentdoc", + "ignorelanguagechange" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.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 + * a) previously it was unchecked and is now checked or + * b) it was already checked but the CTL language has changed + */ + if ( + m_xCTLSupportCB->get_active() && + (m_xCTLSupportCB->get_saved_state() != TRISTATE_TRUE || + 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("nodepath", 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 + + 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 ); + SvtCompatibilityOptions aCompatOpts; + aCompatOpts.SetDefault( SvtCompatibilityEntry::Index::ExpandWordSpace, !bNewCJK ); + } + + 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)); + } + } + + if(m_xAsianSupportCB->get_state_changed_from_saved() ) + { + bool bChecked = m_xAsianSupportCB->get_active(); + SvtCJKOptions::SetAll(bChecked); + + //iterate over all bindings to invalidate vertical text direction + const sal_uInt16 STATE_COUNT = 2; + + std::unique_ptr<SfxBoolItem> pBoolItems[STATE_COUNT]; + pBoolItems[0].reset(new SfxBoolItem(SID_VERTICALTEXT_STATE, false)); + pBoolItems[1].reset(new SfxBoolItem(SID_TEXT_FITTOSIZE_VERTICAL, false)); + + std::unique_ptr<SfxVoidItem> pInvalidItems[STATE_COUNT]; + pInvalidItems[0].reset(new SfxVoidItem(SID_VERTICALTEXT_STATE)); + pInvalidItems[1].reset(new SfxVoidItem(SID_TEXT_FITTOSIZE_VERTICAL)); + + lcl_Update(pInvalidItems, pBoolItems, STATE_COUNT); + } + + if ( m_xCTLSupportCB->get_state_changed_from_saved() ) + { + SvtSearchOptions aOpt; + aOpt.SetIgnoreDiacritics_CTL(true); + aOpt.SetIgnoreKashida_CTL(true); + aOpt.Commit(); + pLangConfig->aCTLLanguageOptions.SetCTLFontEnabled( m_xCTLSupportCB->get_active() ); + + const sal_uInt16 STATE_COUNT = 1; + std::unique_ptr<SfxBoolItem> pBoolItems[STATE_COUNT]; + pBoolItems[0].reset(new SfxBoolItem(SID_CTLFONT_STATE, false)); + std::unique_ptr<SfxVoidItem> pInvalidItems[STATE_COUNT]; + pInvalidItems[0].reset(new SfxVoidItem(SID_CTLFONT_STATE)); + lcl_Update(pInvalidItems, pBoolItems, STATE_COUNT); + } + + 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 ? OUString("default") : 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 ); + + // 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(OfaLanguagesTabPage, SupportHdl, weld::Toggleable&, rBox, void) +{ + bool bCheck = rBox.get_active(); + if ( m_xAsianSupportCB.get() == &rBox ) + { + bool bReadonly = pLangConfig->aLinguConfig.IsReadOnly(u"DefaultLocale_CJK"); + bCheck = ( bCheck && !bReadonly ); + m_xAsianLanguageLB->set_sensitive( bCheck ); + if (rBox.get_sensitive()) + m_bOldAsian = bCheck; + } + else if ( m_xCTLSupportCB.get() == &rBox ) + { + bool bReadonly = pLangConfig->aLinguConfig.IsReadOnly(u"DefaultLocale_CTL"); + bCheck = ( bCheck && !bReadonly ); + m_xComplexLanguageLB->set_sensitive( bCheck ); + if (rBox.get_sensitive()) + m_bOldCtl = bCheck; + } + else + SAL_WARN( "cui.options", "OfaLanguagesTabPage::SupportHdl(): wrong rBox" ); +} + +namespace +{ + void lcl_checkLanguageCheckBox(weld::CheckButton& _rCB, bool _bNewValue, bool _bOldValue) + { + if ( _bNewValue ) + _rCB.set_active(true); + else + _rCB.set_active( _bOldValue ); +// #i15082# do not call save_state() in running dialog... +// _rCB.save_state(); + _rCB.set_sensitive( !_bNewValue ); + } +} + +IMPL_LINK_NOARG(OfaLanguagesTabPage, LocaleSettingHdl, weld::ComboBox&, void) +{ + LanguageType eLang = m_xLocaleSettingLB->get_active_id(); + SvtScriptType nType = SvtLanguageOptions::GetScriptTypeOfLanguage(eLang); + // first check if CTL must be enabled + // #103299# - if CTL font setting is not readonly + if(!pLangConfig->aCTLLanguageOptions.IsReadOnly(SvtCTLOptions::E_CTLFONT)) + { + bool bIsCTLFixed = bool(nType & SvtScriptType::COMPLEX); + lcl_checkLanguageCheckBox(*m_xCTLSupportCB, bIsCTLFixed, m_bOldCtl); + SupportHdl(*m_xCTLSupportCB); + } + // second check if CJK must be enabled + // #103299# - if CJK support is not readonly + if(!SvtCJKOptions::IsAnyReadOnly()) + { + bool bIsCJKFixed = bool(nType & SvtScriptType::ASIAN); + lcl_checkLanguageCheckBox(*m_xAsianSupportCB, bIsCJKFixed, m_bOldAsian); + SupportHdl(*m_xAsianSupportCB); + } + + const NfCurrencyEntry& rCurr = SvNumberFormatter::GetCurrencyEntry( + (eLang == LANGUAGE_USER_SYSTEM_CONFIG) ? MsLangId::getConfiguredSystemLanguage() : eLang); + 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: */ diff --git a/cui/source/options/optgdlg.hxx b/cui/source/options/optgdlg.hxx new file mode 100644 index 0000000000..2c62e569ea --- /dev/null +++ b/cui/source/options/optgdlg.hxx @@ -0,0 +1,226 @@ +/* -*- 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 . + */ +#pragma once +#include <memory> +#include <config_features.h> +#include <sfx2/tabdlg.hxx> +#include <svx/langbox.hxx> + +class CanvasSettings; + +namespace vcl { + class IconThemeInfo; +} + +class OfaMiscTabPage : public SfxTabPage +{ +private: + OUString m_aStrDateInfo; + + std::unique_ptr<weld::CheckButton> m_xExtHelpCB; + std::unique_ptr<weld::Widget> m_xExtHelpImg; + std::unique_ptr<weld::CheckButton> m_xPopUpNoHelpCB; + std::unique_ptr<weld::Widget> m_xPopUpNoHelpImg; + std::unique_ptr<weld::CheckButton> m_xShowTipOfTheDay; + std::unique_ptr<weld::Widget> m_xShowTipOfTheDayImg; + std::unique_ptr<weld::Widget> m_xFileDlgFrame; + std::unique_ptr<weld::Widget> m_xFileDlgROImage; + std::unique_ptr<weld::CheckButton> m_xFileDlgCB; + std::unique_ptr<weld::CheckButton> m_xDocStatusCB; + std::unique_ptr<weld::Widget> m_xDocStatusImg; + std::unique_ptr<weld::Widget> m_xYearFrame; + std::unique_ptr<weld::Label> m_xYearLabel; + std::unique_ptr<weld::SpinButton> m_xYearValueField; + std::unique_ptr<weld::Label> m_xToYearFT; + std::unique_ptr<weld::Widget> m_xYearFrameImg; +#if HAVE_FEATURE_BREAKPAD + std::unique_ptr<weld::Widget> m_xPrivacyFrame; + std::unique_ptr<weld::CheckButton> m_xCrashReport; + std::unique_ptr<weld::Widget> m_xCrashReportImg; +#endif +#if defined(_WIN32) + std::unique_ptr<weld::Widget> m_xQuickStarterFrame; + std::unique_ptr<weld::CheckButton> m_xQuickLaunchCB; + std::unique_ptr<weld::Widget> m_xQuickLaunchImg; + std::unique_ptr<weld::Widget> m_xFileAssocFrame; + std::unique_ptr<weld::Button> m_xFileAssocBtn; + std::unique_ptr<weld::CheckButton> m_xPerformFileExtCheck; + std::unique_ptr<weld::Widget> m_xPerformFileExtImg; +#endif + + DECL_LINK(TwoFigureHdl, weld::SpinButton&, void); +#if defined(_WIN32) + DECL_DLLPRIVATE_STATIC_LINK(OfaMiscTabPage, FileAssocClick, weld::Button&, void); +#endif +protected: + virtual DeactivateRC DeactivatePage( SfxItemSet* pSet ) override; + +public: + OfaMiscTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~OfaMiscTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +class OfaViewTabPage : public SfxTabPage +{ +private: + sal_Int32 nSizeLB_InitialSelection; + sal_Int32 nSidebarSizeLB_InitialSelection; + sal_Int32 nNotebookbarSizeLB_InitialSelection; + sal_Int32 nStyleLB_InitialSelection; + + std::unique_ptr<CanvasSettings> pCanvasSettings; + + std::vector<vcl::IconThemeInfo> mInstalledIconThemes; + + std::unique_ptr<weld::Label> m_xIconSizeLabel; + std::unique_ptr<weld::ComboBox> m_xIconSizeLB; + std::unique_ptr<weld::Widget> m_xIconSizeImg; + std::unique_ptr<weld::Label> m_xSidebarIconSizeLabel; + std::unique_ptr<weld::ComboBox> m_xSidebarIconSizeLB; + std::unique_ptr<weld::Widget> m_xSidebarIconSizeImg; + std::unique_ptr<weld::Label> m_xNotebookbarIconSizeLabel; + std::unique_ptr<weld::ComboBox> m_xNotebookbarIconSizeLB; + std::unique_ptr<weld::Widget> m_xNotebookbarIconSizeImg; + std::unique_ptr<weld::Widget> m_xDarkModeFrame; + std::unique_ptr<weld::Label> m_xAppearanceStyleLabel; + std::unique_ptr<weld::ComboBox> m_xAppearanceStyleLB; + std::unique_ptr<weld::Widget> m_xAppearanceStyleImg; + std::unique_ptr<weld::Label> m_xIconStyleLabel; + std::unique_ptr<weld::ComboBox> m_xIconStyleLB; + std::unique_ptr<weld::Widget> m_xIconStyleImg; + + std::unique_ptr<weld::CheckButton> m_xFontAntiAliasing; + std::unique_ptr<weld::Widget> m_xFontAntiAliasingImg; + std::unique_ptr<weld::Label> m_xAAPointLimitLabel; + std::unique_ptr<weld::Widget> m_xAAPointLimitLabelImg; + std::unique_ptr<weld::MetricSpinButton> m_xAAPointLimit; + + std::unique_ptr<weld::CheckButton> m_xFontShowCB; + std::unique_ptr<weld::Widget> m_xFontShowImg; + + std::unique_ptr<weld::CheckButton> m_xUseHardwareAccell; + std::unique_ptr<weld::Widget> m_xUseHardwareAccellImg; + std::unique_ptr<weld::CheckButton> m_xUseAntiAliase; + std::unique_ptr<weld::Widget> m_xUseAntiAliaseImg; + std::unique_ptr<weld::CheckButton> m_xUseSkia; + std::unique_ptr<weld::Widget> m_xUseSkiaImg; + std::unique_ptr<weld::CheckButton> m_xForceSkiaRaster; + std::unique_ptr<weld::Widget> m_xForceSkiaRasterImg; + + std::unique_ptr<weld::Label> m_xSkiaStatusEnabled; + std::unique_ptr<weld::Label> m_xSkiaStatusDisabled; + std::unique_ptr<weld::Button> m_xSkiaLog; + + std::unique_ptr<weld::Label> m_xMouseMiddleLabel; + std::unique_ptr<weld::ComboBox> m_xMouseMiddleLB; + std::unique_ptr<weld::Widget> m_xMouseMiddleImg; + std::unique_ptr<weld::Button> m_xMoreIcons; + std::unique_ptr<weld::Button> m_xRunGPTests; + + OUString m_sAutoStr; + + DECL_LINK(OnAntialiasingToggled, weld::Toggleable&, void); + DECL_LINK(OnUseSkiaToggled, weld::Toggleable&, void); + DECL_LINK(OnCopySkiaLog, weld::Button&, void); + DECL_STATIC_LINK(OfaViewTabPage, OnMoreIconsClick, weld::Button&, void); + DECL_LINK(OnRunGPTestClick, weld::Button&, void); + void UpdateSkiaStatus(); + void HideSkiaWidgets(); + void UpdateHardwareAccelStatus(); + void UpdateIconThemes(); + +public: + OfaViewTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~OfaViewTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +struct LanguageConfig_Impl; + +class OfaLanguagesTabPage : public SfxTabPage +{ + bool m_bOldAsian; + bool m_bOldCtl; + std::unique_ptr<LanguageConfig_Impl> pLangConfig; + + OUString m_sUserLocaleValue; + OUString m_sSystemDefaultString; + OUString m_sDecimalSeparatorLabel; + + bool m_bDatePatternsValid; + + std::unique_ptr<weld::ComboBox> m_xUserInterfaceLB; + std::unique_ptr<weld::Label> m_xLocaleSettingFT; + std::unique_ptr<SvxLanguageBox> m_xLocaleSettingLB; + std::unique_ptr<weld::Widget> m_xLocaleSettingImg; + std::unique_ptr<weld::Label> m_xDecimalSeparatorFT; + std::unique_ptr<weld::CheckButton> m_xDecimalSeparatorCB; + std::unique_ptr<weld::Widget> m_xDecimalSeparatorImg; + std::unique_ptr<weld::Label> m_xCurrencyFT; + std::unique_ptr<weld::ComboBox> m_xCurrencyLB; + std::unique_ptr<weld::Widget> m_xCurrencyImg; + std::unique_ptr<weld::Label> m_xDatePatternsFT; + std::unique_ptr<weld::Entry> m_xDatePatternsED; + std::unique_ptr<weld::Widget> m_xDatePatternsImg; + + std::unique_ptr<SvxLanguageBox> m_xWesternLanguageLB; + std::unique_ptr<weld::Label> m_xWesternLanguageFT; + std::unique_ptr<weld::Widget> m_xWesternLanguageImg; + std::unique_ptr<SvxLanguageBox> m_xAsianLanguageLB; + std::unique_ptr<SvxLanguageBox> m_xComplexLanguageLB; + std::unique_ptr<weld::CheckButton> m_xCurrentDocCB; + std::unique_ptr<weld::CheckButton> m_xAsianSupportCB; + std::unique_ptr<weld::Widget> m_xAsianSupportImg; + std::unique_ptr<weld::CheckButton> m_xCTLSupportCB; + std::unique_ptr<weld::Widget> m_xCTLSupportImg; + std::unique_ptr<weld::CheckButton> m_xIgnoreLanguageChangeCB; + std::unique_ptr<weld::Widget> m_xIgnoreLanguageChangeImg; + + DECL_LINK(SupportHdl, weld::Toggleable&, void); + DECL_LINK(LocaleSettingHdl, weld::ComboBox&, void); + DECL_LINK(DatePatternsHdl, weld::Entry&, void); + + bool validateDatePatterns( bool& rbModified, OUString& rPatterns ); + +public: + OfaLanguagesTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~OfaLanguagesTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optgenrl.cxx b/cui/source/options/optgenrl.cxx new file mode 100644 index 0000000000..d2cf40244d --- /dev/null +++ b/cui/source/options/optgenrl.cxx @@ -0,0 +1,558 @@ +/* -*- 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 <comphelper/string.hxx> +#include <comphelper/processfactory.hxx> + +#include <config_gpgme.h> +#if HAVE_FEATURE_GPGME +# include <com/sun/star/xml/crypto/GPGSEInitializer.hpp> +# include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp> +#endif + +#include <i18nlangtag/languagetag.hxx> +#include <i18nlangtag/mslangid.hxx> +#include <o3tl/safeint.hxx> +#include <vcl/svapp.hxx> +#include <svl/intitem.hxx> +#include <vcl/settings.hxx> + +#include <officecfg/Office/Common.hxx> +#include <unotools/useroptions.hxx> +#include <cuioptgenrl.hxx> +#include <svx/svxids.hrc> +#include <svx/optgenrl.hxx> + +using namespace css; + +namespace +{ + +// rows +enum RowType +{ + Row_Company, + Row_Name, + Row_Name_Russian, + Row_Name_Eastern, + Row_Street, + Row_Street_Russian, + Row_City, + Row_City_US, + Row_Country, + Row_TitlePos, + Row_Phone, + Row_FaxMail, + + nRowCount +}; + +// language flags +namespace Lang +{ + unsigned const Others = 1; + unsigned const Russian = 2; + unsigned const Eastern = 4; + unsigned const US = 8; + unsigned const All = static_cast<unsigned>(-1); +} + + +// vRowInfo[] -- rows (text + one or more edit boxes) +// The order is the same as in RowType above, which is up to down. + +struct +{ + // id of the lockimage + OUString pLockId; + // id of the text + OUString pTextId; + // language flags (see Lang above): + // which language is this row for? + unsigned nLangFlags; +} +const vRowInfo[] = +{ + { "lockcompanyft", "companyft", Lang::All }, + { "locknameft", "nameft", Lang::All & ~Lang::Russian & ~Lang::Eastern }, + { "lockrusnameft", "rusnameft", Lang::Russian }, + { "lockeastnameft", "eastnameft", Lang::Eastern }, + { "lockstreetft", "streetft", Lang::All & ~Lang::Russian }, + { "lockrusstreetft","russtreetft", Lang::Russian }, + { "lockicityft", "icityft", Lang::All & ~Lang::US }, + { "lockcityft", "cityft", Lang::US }, + { "lockcountryft", "countryft", Lang::All }, + { "locktitleft", "titleft", Lang::All }, + { "lockphoneft", "phoneft", Lang::All }, + { "lockfaxft", "faxft", Lang::All }, +}; + + +// vFieldInfo[] -- edit boxes +// The order is up to down, and then left to right. + +struct +{ + // in which row? + RowType eRow; + // id of the edit box + OUString pEditId; + // id for SvtUserOptions in unotools/useroptions.hxx + UserOptToken nUserOptionsId; + // id for settings the focus (defined in svx/optgenrl.hxx) + EditPosition nGrabFocusId; +} +const vFieldInfo[] = +{ + // Company + { Row_Company, "company", UserOptToken::Company, EditPosition::COMPANY }, + // Name + { Row_Name, "firstname", UserOptToken::FirstName, EditPosition::FIRSTNAME }, + { Row_Name, "lastname", UserOptToken::LastName, EditPosition::LASTNAME }, + { Row_Name, "shortname", UserOptToken::ID, EditPosition::SHORTNAME }, + // Name (russian) + { Row_Name_Russian, "ruslastname", UserOptToken::LastName, EditPosition::LASTNAME }, + { Row_Name_Russian, "rusfirstname", UserOptToken::FirstName, EditPosition::FIRSTNAME }, + { Row_Name_Russian, "rusfathersname", UserOptToken::FathersName, EditPosition::UNKNOWN }, + { Row_Name_Russian, "russhortname", UserOptToken::ID, EditPosition::SHORTNAME }, + // Name (eastern: reversed name ord + { Row_Name_Eastern, "eastlastname", UserOptToken::LastName, EditPosition::LASTNAME }, + { Row_Name_Eastern, "eastfirstname", UserOptToken::FirstName, EditPosition::FIRSTNAME }, + { Row_Name_Eastern, "eastshortname", UserOptToken::ID, EditPosition::SHORTNAME }, + // Street + { Row_Street, "street", UserOptToken::Street, EditPosition::STREET }, + // Street (russian) + { Row_Street_Russian, "russtreet", UserOptToken::Street, EditPosition::STREET }, + { Row_Street_Russian, "apartnum", UserOptToken::Apartment, EditPosition::UNKNOWN }, + // City + { Row_City, "izip", UserOptToken::Zip, EditPosition::PLZ }, + { Row_City, "icity", UserOptToken::City, EditPosition::CITY }, + // City (US) + { Row_City_US, "city", UserOptToken::City, EditPosition::CITY }, + { Row_City_US, "state", UserOptToken::State, EditPosition::STATE }, + { Row_City_US, "zip", UserOptToken::Zip, EditPosition::PLZ }, + // Country + { Row_Country, "country", UserOptToken::Country, EditPosition::COUNTRY }, + // Title/Position + { Row_TitlePos, "title", UserOptToken::Title, EditPosition::TITLE }, + { Row_TitlePos, "position", UserOptToken::Position, EditPosition::POSITION }, + // Phone + { Row_Phone, "home", UserOptToken::TelephoneHome, EditPosition::TELPRIV }, + { Row_Phone, "work", UserOptToken::TelephoneWork, EditPosition::TELCOMPANY }, + // Fax/Mail + { Row_FaxMail, "fax", UserOptToken::Fax, EditPosition::FAX }, + { Row_FaxMail, "email", UserOptToken::Email, EditPosition::EMAIL }, +}; + + +} // namespace + + +// Row + +struct SvxGeneralTabPage::Row +{ + // row lockdown icon + std::unique_ptr<weld::Widget> xLockImg; + // row label + std::unique_ptr<weld::Label> xLabel; + // first and last field in the row (last is exclusive) + unsigned nFirstField, nLastField; + +public: + explicit Row (std::unique_ptr<weld::Widget> xLockImg_, std::unique_ptr<weld::Label> xLabel_) + : xLockImg(std::move(xLockImg_)) + , xLabel(std::move(xLabel_)) + , nFirstField(0) + , nLastField(0) + { + xLabel->show(); + } +}; + + +// Field + +struct SvxGeneralTabPage::Field +{ + // which field is this? (in vFieldInfo[] above) + unsigned iField; + // edit box + std::unique_ptr<weld::Entry> xEdit; + std::unique_ptr<weld::Container> xParent; + +public: + Field (std::unique_ptr<weld::Entry> xEdit_, unsigned iField_) + : iField(iField_) + , xEdit(std::move(xEdit_)) + , xParent(xEdit->weld_parent()) + { + //We want all widgets inside a container, so each row of the toplevel + //grid has another container in it. To avoid adding spacing to these + //empty grids they all default to invisible, so show them if their + //children are visible + xParent->show(); + xEdit->show(); + } +}; + +SvxGeneralTabPage::SvxGeneralTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "cui/ui/optuserpage.ui", "OptUserPage", &rCoreSet) + , m_xUseDataCB(m_xBuilder->weld_check_button("usefordocprop")) + , m_xUseDataImg(m_xBuilder->weld_widget("lockusefordocprop")) + , m_xCryptoFrame(m_xBuilder->weld_widget( "cryptography")) + , m_xSigningKeyLB(m_xBuilder->weld_combo_box("signingkey")) + , m_xSigningKeyFT(m_xBuilder->weld_label("signingkeylabel")) + , m_xSigningKeyImg(m_xBuilder->weld_widget("locksigningkey")) + , m_xEncryptionKeyLB(m_xBuilder->weld_combo_box("encryptionkey")) + , m_xEncryptionKeyFT(m_xBuilder->weld_label("encryptionkeylabel")) + , m_xEncryptionKeyImg(m_xBuilder->weld_widget("lockencryptionkey")) + , m_xEncryptToSelfCB(m_xBuilder->weld_check_button("encrypttoself")) + , m_xEncryptToSelfImg(m_xBuilder->weld_widget("lockencrypttoself")) +{ + InitControls(); +#if HAVE_FEATURE_GPGME + InitCryptography(); +#else + m_xCryptoFrame->hide(); +#endif + + SetExchangeSupport(); // this page needs ExchangeSupport + SetLinks(); +} + +SvxGeneralTabPage::~SvxGeneralTabPage() +{ +} + +// Initializes the titles and the edit boxes, +// according to vRowInfo[] and vFieldInfo[] above. +void SvxGeneralTabPage::InitControls () +{ + // which language bit do we use? (see Lang and vRowInfo[] above) + unsigned LangBit; + LanguageType l = Application::GetSettings().GetUILanguageTag().getLanguageType(); + if (l == LANGUAGE_ENGLISH_US) + LangBit = Lang::US; + else if (l == LANGUAGE_RUSSIAN) + LangBit = Lang::Russian; + else + { + if (MsLangId::isFamilyNameFirst(l)) + LangBit = Lang::Eastern; + else + LangBit = Lang::Others; + } + + // creating rows + unsigned iField = 0; + for (unsigned iRow = 0; iRow != nRowCount; ++iRow) + { + RowType const eRow = static_cast<RowType>(iRow); + // is the row visible? + if (!(vRowInfo[iRow].nLangFlags & LangBit)) + continue; + // creating row + vRows.push_back(std::make_shared<Row>(m_xBuilder->weld_widget(vRowInfo[iRow].pLockId), + m_xBuilder->weld_label(vRowInfo[iRow].pTextId))); + Row& rRow = *vRows.back(); + // fields in the row + static unsigned const nFieldCount = std::size(vFieldInfo); + // skipping other (invisible) rows + while (iField != nFieldCount && vFieldInfo[iField].eRow != eRow) + ++iField; + // fields in the row + rRow.nFirstField = vFields.size(); + for ( ; iField != nFieldCount && vFieldInfo[iField].eRow == eRow; ++iField) + { + // creating edit field + vFields.push_back(std::make_shared<Field>( + m_xBuilder->weld_entry(vFieldInfo[iField].pEditId), iField)); + // "short name" field? + if (vFieldInfo[iField].nUserOptionsId == UserOptToken::ID) + { + nNameRow = vRows.size() - 1; + nShortNameField = vFields.size() - 1; + } + } + rRow.nLastField = vFields.size(); + } +} + +void SvxGeneralTabPage::InitCryptography() +{ +#if HAVE_FEATURE_GPGME + m_xCryptoFrame->show(); + + uno::Reference< xml::crypto::XSEInitializer > xSEInitializer; + try + { + xSEInitializer = xml::crypto::GPGSEInitializer::create( comphelper::getProcessComponentContext() ); + uno::Reference<xml::crypto::XXMLSecurityContext> xSC = xSEInitializer->createSecurityContext( OUString() ); + if (xSC.is()) + { + uno::Reference<xml::crypto::XSecurityEnvironment> xSE = xSC->getSecurityEnvironment(); + uno::Sequence<uno::Reference<security::XCertificate>> xCertificates = xSE->getPersonalCertificates(); + + if (xCertificates.hasElements()) + { + for (auto& xCert : asNonConstRange(xCertificates)) + { + m_xSigningKeyLB->append_text( xCert->getIssuerName()); + m_xEncryptionKeyLB->append_text( xCert->getIssuerName()); + } + } + + //tdf#115015: wrap checkbox text and listboxes if necessary + int nPrefWidth(m_xEncryptToSelfCB->get_preferred_size().Width()); + int nMaxWidth = m_xEncryptToSelfCB->get_approximate_digit_width() * 40; + if (nPrefWidth > nMaxWidth) + { + m_xSigningKeyLB->set_size_request(nMaxWidth, -1); + m_xEncryptionKeyLB->set_size_request(nMaxWidth, -1); + m_xEncryptToSelfCB->set_label_wrap(true); + m_xEncryptToSelfCB->set_size_request(nMaxWidth, -1); + } + } + } + catch ( uno::Exception const & ) + {} +#endif + +} + +void SvxGeneralTabPage::SetLinks () +{ + // link for updating the initials + Link<weld::Entry&,void> aLink = LINK( this, SvxGeneralTabPage, ModifyHdl_Impl ); + Row& rNameRow = *vRows[nNameRow]; + for (unsigned i = rNameRow.nFirstField; i != rNameRow.nLastField - 1; ++i) + vFields[i]->xEdit->connect_changed(aLink); +} + + +std::unique_ptr<SfxTabPage> SvxGeneralTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SvxGeneralTabPage>( pPage, pController, *rAttrSet ); +} + +OUString SvxGeneralTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] + = { "label1", "companyft", "nameft", "rusnameft", + "eastnameft", "streetft", "russtreetft", "icityft", + "cityft", "countryft", "titleft", "phoneft", + "faxft", "cryptographylabel", "signingkeylabel", "encryptionkeylabel" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + sAllStrings += m_xUseDataCB->get_label() + " " + m_xEncryptToSelfCB->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxGeneralTabPage::FillItemSet( SfxItemSet* ) +{ + // remove leading and trailing whitespaces + for (auto const & i: vFields) + i->xEdit->set_text(comphelper::string::strip(i->xEdit->get_text(), ' ')); + + bool bModified = false; + bModified |= GetData_Impl(); + if (m_xUseDataCB->get_active() != officecfg::Office::Common::Save::Document::UseUserData::get()) + { + auto xChanges = comphelper::ConfigurationChanges::create(); + officecfg::Office::Common::Save::Document::UseUserData::set(m_xUseDataCB->get_active(), xChanges); + xChanges->commit(); + bModified = true; + } + return bModified; +} + +void SvxGeneralTabPage::Reset( const SfxItemSet* rSet ) +{ + SetData_Impl(); + + if (rSet->GetItemState(SID_FIELD_GRABFOCUS) == SfxItemState::SET) + { + EditPosition nField = static_cast<EditPosition>(rSet->Get(SID_FIELD_GRABFOCUS).GetValue()); + if (nField != EditPosition::UNKNOWN) + { + for (auto const & i: vFields) + if (nField == vFieldInfo[i->iField].nGrabFocusId) + i->xEdit->grab_focus(); + } + else + vFields.front()->xEdit->grab_focus(); + } + + m_xUseDataCB->set_active(officecfg::Office::Common::Save::Document::UseUserData::get()); +} + + +// ModifyHdl_Impl() +// This handler updates the initials (short name) +// when one of the name fields was updated. +IMPL_LINK( SvxGeneralTabPage, ModifyHdl_Impl, weld::Entry&, rEdit, void ) +{ + // short name field and row + Field& rShortName = *vFields[nShortNameField]; + Row& rNameRow = *vRows[nNameRow]; + // number of initials + unsigned const nInits = rNameRow.nLastField - rNameRow.nFirstField - 1; + // which field was updated? (in rNameRow) + unsigned nField = nInits; + for (unsigned i = 0; i != nInits; ++i) + { + if (vFields[rNameRow.nFirstField + i]->xEdit.get() == &rEdit) + nField = i; + } + // updating the initial + if (!(nField < nInits && rShortName.xEdit->get_sensitive())) + return; + + OUString sShortName = rShortName.xEdit->get_text(); + // clear short name if it contains more characters than the number of initials + if (o3tl::make_unsigned(sShortName.getLength()) > nInits) + { + rShortName.xEdit->set_text(OUString()); + } + while (o3tl::make_unsigned(sShortName.getLength()) < nInits) + sShortName += " "; + OUString sName = rEdit.get_text(); + OUString sLetter = sName.isEmpty() + ? OUString(u' ') : sName.copy(0, 1); + rShortName.xEdit->set_text(sShortName.replaceAt(nField, 1, sLetter).trim()); +} + + +bool SvxGeneralTabPage::GetData_Impl() +{ + // updating + SvtUserOptions aUserOpt; + for (auto const & i: vFields) + aUserOpt.SetToken( + vFieldInfo[i->iField].nUserOptionsId, + i->xEdit->get_text() + ); + + // modified? + bool bModified = false; + for (auto const & i: vFields) + { + if (i->xEdit->get_value_changed_from_saved()) + { + bModified = true; + break; + } + } + +#if HAVE_FEATURE_GPGME + OUString aSK = m_xSigningKeyLB->get_active() == 0 ? OUString() //i.e. no key + : m_xSigningKeyLB->get_active_text(); + OUString aEK = m_xEncryptionKeyLB->get_active() == 0 ? OUString() + : m_xEncryptionKeyLB->get_active_text(); + + aUserOpt.SetToken( UserOptToken::SigningKey, aSK ); + aUserOpt.SetToken( UserOptToken::EncryptionKey, aEK ); + aUserOpt.SetBoolValue( UserOptToken::EncryptToSelf, m_xEncryptToSelfCB->get_active() ); + + bModified |= m_xSigningKeyLB->get_value_changed_from_saved() || + m_xEncryptionKeyLB->get_value_changed_from_saved() || + m_xEncryptToSelfCB->get_state_changed_from_saved(); +#endif + + return bModified; +} + + +void SvxGeneralTabPage::SetData_Impl() +{ + // updating and disabling edit boxes + SvtUserOptions aUserOpt; + for (auto const & i: vRows) + { + Row& rRow = *i; + // the label is enabled if any of its edit fields are enabled + bool bEnableLabel = false; + for (unsigned iField = rRow.nFirstField; iField != rRow.nLastField; ++iField) + { + Field& rField = *vFields[iField]; + // updating content + UserOptToken const nToken = vFieldInfo[rField.iField].nUserOptionsId; + rField.xEdit->set_text(aUserOpt.GetToken(nToken)); + // is enabled? + bool const bEnableEdit = !aUserOpt.IsTokenReadonly(nToken); + rField.xEdit->set_sensitive(bEnableEdit); + bEnableLabel = bEnableLabel || bEnableEdit; + } + rRow.xLabel->set_sensitive(bEnableLabel); + rRow.xLockImg->set_visible(!bEnableLabel); + } + + // saving + for (auto const & i: vFields) + i->xEdit->save_value(); + + //enabling and disabling remaining fields + bool bEnable = !officecfg::Office::Common::Save::Document::UseUserData::isReadOnly(); + m_xUseDataCB->set_sensitive(bEnable); + m_xUseDataImg->set_visible(!bEnable); + +#if HAVE_FEATURE_GPGME + bEnable = !aUserOpt.IsTokenReadonly(UserOptToken::SigningKey); + m_xSigningKeyLB->set_sensitive(bEnable); + m_xSigningKeyFT->set_sensitive(bEnable); + m_xSigningKeyImg->set_visible(!bEnable); + + bEnable = !aUserOpt.IsTokenReadonly(UserOptToken::EncryptionKey); + m_xEncryptionKeyLB->set_sensitive(bEnable); + m_xEncryptionKeyFT->set_sensitive(bEnable); + m_xEncryptionKeyImg->set_visible(!bEnable); + + bEnable = !aUserOpt.IsTokenReadonly(UserOptToken::EncryptToSelf); + m_xEncryptToSelfCB->set_sensitive(bEnable); + m_xEncryptToSelfImg->set_visible(!bEnable); + + OUString aSK = aUserOpt.GetToken(UserOptToken::SigningKey); + aSK.isEmpty() ? m_xSigningKeyLB->set_active( 0 ) //i.e. 'No Key' + : m_xSigningKeyLB->set_active_text( aSK ); + + OUString aEK = aUserOpt.GetToken(UserOptToken::EncryptionKey); + aEK.isEmpty() ? m_xEncryptionKeyLB->set_active( 0 ) //i.e. 'No Key' + : m_xEncryptionKeyLB->set_active_text( aEK ); + + m_xEncryptToSelfCB->set_active( aUserOpt.GetEncryptToSelf() ); +#endif +} + + +DeactivateRC SvxGeneralTabPage::DeactivatePage( SfxItemSet* pSet_ ) +{ + if ( pSet_ ) + FillItemSet( pSet_ ); + return DeactivateRC::LeavePage; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/opthtml.cxx b/cui/source/options/opthtml.cxx new file mode 100644 index 0000000000..6880ec4b2e --- /dev/null +++ b/cui/source/options/opthtml.cxx @@ -0,0 +1,284 @@ +/* -*- 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 <svtools/langtab.hxx> +#include <comphelper/configuration.hxx> +#include <officecfg/Office/Common.hxx> +#include "opthtml.hxx" + + +OfaHtmlTabPage::OfaHtmlTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/opthtmlpage.ui", "OptHtmlPage", &rSet) + , m_xSize1NF(m_xBuilder->weld_spin_button("size1")) + , m_xSize1Img(m_xBuilder->weld_widget("locksize1")) + , m_xSize2NF(m_xBuilder->weld_spin_button("size2")) + , m_xSize2Img(m_xBuilder->weld_widget("locksize2")) + , m_xSize3NF(m_xBuilder->weld_spin_button("size3")) + , m_xSize3Img(m_xBuilder->weld_widget("locksize3")) + , m_xSize4NF(m_xBuilder->weld_spin_button("size4")) + , m_xSize4Img(m_xBuilder->weld_widget("locksize4")) + , m_xSize5NF(m_xBuilder->weld_spin_button("size5")) + , m_xSize5Img(m_xBuilder->weld_widget("locksize5")) + , m_xSize6NF(m_xBuilder->weld_spin_button("size6")) + , m_xSize6Img(m_xBuilder->weld_widget("locksize6")) + , m_xSize7NF(m_xBuilder->weld_spin_button("size7")) + , m_xSize7Img(m_xBuilder->weld_widget("locksize7")) + , m_xNumbersEnglishUSCB(m_xBuilder->weld_check_button("numbersenglishus")) + , m_xNumbersEnglishUSImg(m_xBuilder->weld_widget("locknumbersenglishus")) + , m_xUnknownTagCB(m_xBuilder->weld_check_button("unknowntag")) + , m_xUnknownTagImg(m_xBuilder->weld_widget("lockunknowntag")) + , m_xIgnoreFontNamesCB(m_xBuilder->weld_check_button("ignorefontnames")) + , m_xIgnoreFontNamesImg(m_xBuilder->weld_widget("lockignorefontnames")) + , m_xStarBasicCB(m_xBuilder->weld_check_button("starbasic")) + , m_xStarBasicImg(m_xBuilder->weld_widget("lockstarbasic")) + , m_xStarBasicWarningCB(m_xBuilder->weld_check_button("starbasicwarning")) + , m_xStarBasicWarningImg(m_xBuilder->weld_widget("lockstarbasicwarning")) + , m_xPrintExtensionCB(m_xBuilder->weld_check_button("printextension")) + , m_xPrintExtensionImg(m_xBuilder->weld_widget("lockprintextension")) + , m_xSaveGrfLocalCB(m_xBuilder->weld_check_button("savegrflocal")) + , m_xSaveGrfLocalImg(m_xBuilder->weld_widget("locksavegrflocal")) +{ + // replace placeholder with UI string from language list + OUString aText(m_xNumbersEnglishUSCB->get_label()); + OUString aPlaceholder("%ENGLISHUSLOCALE"); + sal_Int32 nPos; + if ((nPos = aText.indexOf( aPlaceholder)) != -1) + { + const OUString& rStr = SvtLanguageTable::GetLanguageString( LANGUAGE_ENGLISH_US); + if (!rStr.isEmpty()) + { + aText = aText.replaceAt( nPos, aPlaceholder.getLength(), rStr); + m_xNumbersEnglishUSCB->set_label( aText); + } + } + + m_xStarBasicCB->connect_toggled(LINK(this, OfaHtmlTabPage, CheckBoxHdl_Impl)); +} + +OfaHtmlTabPage::~OfaHtmlTabPage() +{ +} + +std::unique_ptr<SfxTabPage> OfaHtmlTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<OfaHtmlTabPage>(pPage, pController, *rAttrSet); +} + +OUString OfaHtmlTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "label3", "size1FT", "size2FT", + "size3FT", "size4FT", "size5FT", "size6FT", "size7FT" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "numbersenglishus", "unknowntag", "ignorefontnames", "starbasic", + "starbasicwarning", "printextension", "savegrflocal" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool OfaHtmlTabPage::FillItemSet( SfxItemSet* ) +{ + std::shared_ptr<comphelper::ConfigurationChanges> xChanges = comphelper::ConfigurationChanges::create(); + if(m_xSize1NF->get_value_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_1::set( + static_cast<sal_uInt16>(m_xSize1NF->get_value()), xChanges); + if(m_xSize2NF->get_value_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_2::set( + static_cast<sal_uInt16>(m_xSize2NF->get_value()), xChanges); + if(m_xSize3NF->get_value_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_3::set( + static_cast<sal_uInt16>(m_xSize3NF->get_value()), xChanges); + if(m_xSize4NF->get_value_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_4::set( + static_cast<sal_uInt16>(m_xSize4NF->get_value()), xChanges); + if(m_xSize5NF->get_value_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_5::set( + static_cast<sal_uInt16>(m_xSize5NF->get_value()), xChanges); + if(m_xSize6NF->get_value_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_6::set( + static_cast<sal_uInt16>(m_xSize6NF->get_value()), xChanges); + if(m_xSize7NF->get_value_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_7::set( + static_cast<sal_uInt16>(m_xSize7NF->get_value()), xChanges); + + if(m_xNumbersEnglishUSCB->get_state_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::NumbersEnglishUS::set( + m_xNumbersEnglishUSCB->get_active(), xChanges); + + if(m_xUnknownTagCB->get_state_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::UnknownTag::set( + m_xUnknownTagCB->get_active(), xChanges); + + if(m_xIgnoreFontNamesCB->get_state_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Import::FontSetting::set( + m_xIgnoreFontNamesCB->get_active(), xChanges); + + if(m_xStarBasicCB->get_state_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Export::Basic::set( + m_xStarBasicCB->get_active(), xChanges); + + if(m_xStarBasicWarningCB->get_state_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Export::Warning::set( + m_xStarBasicWarningCB->get_active(), xChanges); + + if(m_xSaveGrfLocalCB->get_state_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Export::LocalGraphic::set( + m_xSaveGrfLocalCB->get_active(), xChanges); + + if(m_xPrintExtensionCB->get_state_changed_from_saved()) + officecfg::Office::Common::Filter::HTML::Export::PrintLayout::set( + m_xPrintExtensionCB->get_active(), xChanges); + + xChanges->commit(); + return false; +} + +void OfaHtmlTabPage::Reset( const SfxItemSet* ) +{ + m_xSize1NF->set_value(officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_1::get()); + if (officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_1::isReadOnly()) + { + m_xSize1NF->set_sensitive(false); + m_xSize1Img->set_visible(true); + } + + m_xSize2NF->set_value(officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_2::get()); + if (officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_2::isReadOnly()) + { + m_xSize2NF->set_sensitive(false); + m_xSize2Img->set_visible(true); + } + + m_xSize3NF->set_value(officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_3::get()); + if (officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_3::isReadOnly()) + { + m_xSize3NF->set_sensitive(false); + m_xSize3Img->set_visible(true); + } + + m_xSize4NF->set_value(officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_4::get()); + if (officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_4::isReadOnly()) + { + m_xSize4NF->set_sensitive(false); + m_xSize4Img->set_visible(true); + } + + m_xSize5NF->set_value(officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_5::get()); + if (officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_5::isReadOnly()) + { + m_xSize5NF->set_sensitive(false); + m_xSize5Img->set_visible(true); + } + + m_xSize6NF->set_value(officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_6::get()); + if (officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_6::isReadOnly()) + { + m_xSize6NF->set_sensitive(false); + m_xSize6Img->set_visible(true); + } + + m_xSize7NF->set_value(officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_7::get()); + if (officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_7::isReadOnly()) + { + m_xSize7NF->set_sensitive(false); + m_xSize7Img->set_visible(true); + } + + m_xNumbersEnglishUSCB->set_active(officecfg::Office::Common::Filter::HTML::Import::NumbersEnglishUS::get()); + if (officecfg::Office::Common::Filter::HTML::Import::NumbersEnglishUS::isReadOnly()) + { + m_xNumbersEnglishUSCB->set_sensitive(false); + m_xNumbersEnglishUSImg->set_visible(true); + } + + m_xUnknownTagCB->set_active(officecfg::Office::Common::Filter::HTML::Import::UnknownTag::get()); + if (officecfg::Office::Common::Filter::HTML::Import::UnknownTag::isReadOnly()) + { + m_xUnknownTagCB->set_sensitive(false); + m_xUnknownTagImg->set_visible(true); + } + + m_xIgnoreFontNamesCB->set_active(officecfg::Office::Common::Filter::HTML::Import::FontSetting::get()); + if (officecfg::Office::Common::Filter::HTML::Import::FontSetting::isReadOnly()) + { + m_xIgnoreFontNamesCB->set_sensitive(false); + m_xIgnoreFontNamesImg->set_visible(true); + } + + m_xStarBasicCB->set_active(officecfg::Office::Common::Filter::HTML::Export::Basic::get()); + if (officecfg::Office::Common::Filter::HTML::Export::Basic::isReadOnly()) + { + m_xStarBasicCB->set_sensitive(false); + m_xStarBasicImg->set_visible(true); + } + + m_xStarBasicWarningCB->set_active(officecfg::Office::Common::Filter::HTML::Export::Warning::get()); + m_xStarBasicWarningCB->set_sensitive(!m_xStarBasicCB->get_active() && !officecfg::Office::Common::Filter::HTML::Export::Warning::isReadOnly()); + m_xStarBasicWarningImg->set_visible(officecfg::Office::Common::Filter::HTML::Export::Warning::isReadOnly()); + + m_xSaveGrfLocalCB->set_active(officecfg::Office::Common::Filter::HTML::Export::LocalGraphic::get()); + if (officecfg::Office::Common::Filter::HTML::Export::LocalGraphic::isReadOnly()) + { + m_xSaveGrfLocalCB->set_sensitive(false); + m_xSaveGrfLocalImg->set_visible(true); + } + + m_xPrintExtensionCB->set_active(officecfg::Office::Common::Filter::HTML::Export::PrintLayout::get()); + if (officecfg::Office::Common::Filter::HTML::Export::PrintLayout::isReadOnly()) + { + m_xPrintExtensionCB->set_sensitive(false); + m_xPrintExtensionImg->set_visible(true); + } + + m_xPrintExtensionCB->save_state(); + m_xStarBasicCB->save_state(); + m_xStarBasicWarningCB->save_state(); + m_xSaveGrfLocalCB->save_state(); + m_xSize1NF->save_value(); + m_xSize2NF->save_value(); + m_xSize3NF->save_value(); + m_xSize4NF->save_value(); + m_xSize5NF->save_value(); + m_xSize6NF->save_value(); + m_xSize7NF->save_value(); + m_xNumbersEnglishUSCB->save_state(); + m_xUnknownTagCB->save_state(); + m_xIgnoreFontNamesCB->save_state(); +} + +IMPL_LINK(OfaHtmlTabPage, CheckBoxHdl_Impl, weld::Toggleable&, rBox, void) +{ + m_xStarBasicWarningCB->set_sensitive(!rBox.get_active()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/opthtml.hxx b/cui/source/options/opthtml.hxx new file mode 100644 index 0000000000..2f389a7af5 --- /dev/null +++ b/cui/source/options/opthtml.hxx @@ -0,0 +1,75 @@ +/* -*- 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 . + */ +#pragma once + +#include <sfx2/tabdlg.hxx> +#include <svx/txencbox.hxx> + +class OfaHtmlTabPage : public SfxTabPage +{ + + std::unique_ptr<weld::SpinButton> m_xSize1NF; + std::unique_ptr<weld::Widget> m_xSize1Img; + std::unique_ptr<weld::SpinButton> m_xSize2NF; + std::unique_ptr<weld::Widget> m_xSize2Img; + std::unique_ptr<weld::SpinButton> m_xSize3NF; + std::unique_ptr<weld::Widget> m_xSize3Img; + std::unique_ptr<weld::SpinButton> m_xSize4NF; + std::unique_ptr<weld::Widget> m_xSize4Img; + std::unique_ptr<weld::SpinButton> m_xSize5NF; + std::unique_ptr<weld::Widget> m_xSize5Img; + std::unique_ptr<weld::SpinButton> m_xSize6NF; + std::unique_ptr<weld::Widget> m_xSize6Img; + std::unique_ptr<weld::SpinButton> m_xSize7NF; + std::unique_ptr<weld::Widget> m_xSize7Img; + + std::unique_ptr<weld::CheckButton> m_xNumbersEnglishUSCB; + std::unique_ptr<weld::Widget> m_xNumbersEnglishUSImg; + std::unique_ptr<weld::CheckButton> m_xUnknownTagCB; + std::unique_ptr<weld::Widget> m_xUnknownTagImg; + std::unique_ptr<weld::CheckButton> m_xIgnoreFontNamesCB; + std::unique_ptr<weld::Widget> m_xIgnoreFontNamesImg; + + std::unique_ptr<weld::CheckButton> m_xStarBasicCB; + std::unique_ptr<weld::Widget> m_xStarBasicImg; + std::unique_ptr<weld::CheckButton> m_xStarBasicWarningCB; + std::unique_ptr<weld::Widget> m_xStarBasicWarningImg; + std::unique_ptr<weld::CheckButton> m_xPrintExtensionCB; + std::unique_ptr<weld::Widget> m_xPrintExtensionImg; + std::unique_ptr<weld::CheckButton> m_xSaveGrfLocalCB; + std::unique_ptr<weld::Widget> m_xSaveGrfLocalImg; + + DECL_LINK(CheckBoxHdl_Impl, weld::Toggleable&, void); + +public: + OfaHtmlTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~OfaHtmlTabPage() override; + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + +}; + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optinet2.cxx b/cui/source/options/optinet2.cxx new file mode 100644 index 0000000000..083c3e40f7 --- /dev/null +++ b/cui/source/options/optinet2.cxx @@ -0,0 +1,1068 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <officecfg/Inet.hxx> +#include <officecfg/Office/Common.hxx> +#include <officecfg/Office/Security.hxx> +#include <vcl/weld.hxx> +#include <sfx2/filedlghelper.hxx> +#include <vcl/svapp.hxx> +#include <unotools/securityoptions.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <dialmgr.hxx> +#include "optinet2.hxx" +#include <strings.hrc> + +#include <com/sun/star/security/DocumentDigitalSignatures.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <osl/file.hxx> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> + +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/task/PasswordContainer.hpp> +#include <com/sun/star/task/XPasswordContainer2.hpp> +#include "securityoptions.hxx" +#include "webconninfo.hxx" +#include "certpath.hxx" +#include "tsaurls.hxx" + +#include <svtools/restartdialog.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::sfx2; + +namespace { + +bool isValidPort(OUString const & value) { + if (!comphelper::string::isdigitAsciiString(value)) { + return false; + } + auto const n = value.toUInt64(); + if (n > 65535) { + return false; + } + if (n != 0) { + return true; + } + // Overflow in OUString::toUInt64 returns 0, so need to check value contains only zeroes: + return std::u16string_view(value).find_first_not_of(u'0') == std::u16string_view::npos; +} + +} + +IMPL_LINK(SvxProxyTabPage, PortChangedHdl, weld::Entry&, rEdit, void) +{ + if (!isValidPort(rEdit.get_text())) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + CuiResId(RID_CUISTR_OPT_PROXYPORTS))); + xErrorBox->run(); + } +} + +constexpr OUString g_aProxyModePN = u"ooInetProxyType"_ustr; +constexpr OUString g_aHttpProxyPN = u"ooInetHTTPProxyName"_ustr; +constexpr OUString g_aHttpPortPN = u"ooInetHTTPProxyPort"_ustr; +constexpr OUString g_aHttpsProxyPN = u"ooInetHTTPSProxyName"_ustr; +constexpr OUString g_aHttpsPortPN = u"ooInetHTTPSProxyPort"_ustr; +constexpr OUString g_aNoProxyDescPN = u"ooInetNoProxy"_ustr; + +IMPL_STATIC_LINK(SvxProxyTabPage, NumberOnlyTextFilterHdl, OUString&, rTest, bool) +{ + OUStringBuffer sAllowed; + for (sal_Int32 i = 0, nLen = rTest.getLength(); i < nLen; ++i) + { + if (rTest[i] >= '0' && rTest[i] <= '9') + sAllowed.append(rTest[i]); + } + rTest = sAllowed.makeStringAndClear(); + return true; +} + +IMPL_STATIC_LINK(SvxProxyTabPage, NoSpaceTextFilterHdl, OUString&, rTest, bool) +{ + rTest = rTest.replaceAll(" ", ""); + return true; +} + +/********************************************************************/ +/* */ +/* SvxProxyTabPage */ +/* */ +/********************************************************************/ +SvxProxyTabPage::SvxProxyTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optproxypage.ui", "OptProxyPage", &rSet) + , m_xProxyModeFT(m_xBuilder->weld_label("label2")) + , m_xProxyModeLB(m_xBuilder->weld_combo_box("proxymode")) + , m_xProxyModeImg(m_xBuilder->weld_widget("lockproxymode")) + , m_xHttpProxyFT(m_xBuilder->weld_label("httpft")) + , m_xHttpProxyED(m_xBuilder->weld_entry("http")) + , m_xHttpProxyImg(m_xBuilder->weld_widget("lockhttp")) + , m_xHttpPortFT(m_xBuilder->weld_label("httpportft")) + , m_xHttpPortED(m_xBuilder->weld_entry("httpport")) + , m_xHttpPortImg(m_xBuilder->weld_widget("lockhttpport")) + , m_xHttpsProxyFT(m_xBuilder->weld_label("httpsft")) + , m_xHttpsProxyED(m_xBuilder->weld_entry("https")) + , m_xHttpsProxyImg(m_xBuilder->weld_widget("lockhttps")) + , m_xHttpsPortFT(m_xBuilder->weld_label("httpsportft")) + , m_xHttpsPortED(m_xBuilder->weld_entry("httpsport")) + , m_xHttpsPortImg(m_xBuilder->weld_widget("lockhttpsport")) + , m_xNoProxyForFT(m_xBuilder->weld_label("noproxyft")) + , m_xNoProxyForED(m_xBuilder->weld_entry("noproxy")) + , m_xNoProxyForImg(m_xBuilder->weld_widget("locknoproxy")) + , m_xNoProxyDescFT(m_xBuilder->weld_label("noproxydesc")) +{ + m_xHttpProxyED->connect_insert_text(LINK(this, SvxProxyTabPage, NoSpaceTextFilterHdl)); + m_xHttpPortED->connect_insert_text(LINK(this, SvxProxyTabPage, NumberOnlyTextFilterHdl)); + m_xHttpPortED->connect_changed(LINK(this, SvxProxyTabPage, PortChangedHdl)); + m_xHttpsProxyED->connect_insert_text(LINK(this, SvxProxyTabPage, NoSpaceTextFilterHdl)); + m_xHttpsPortED->connect_insert_text(LINK(this, SvxProxyTabPage, NumberOnlyTextFilterHdl)); + m_xHttpsPortED->connect_changed(LINK(this, SvxProxyTabPage, PortChangedHdl)); + + Link<weld::Widget&,void> aLink = LINK( this, SvxProxyTabPage, LoseFocusHdl_Impl ); + m_xHttpPortED->connect_focus_out( aLink ); + m_xHttpsPortED->connect_focus_out( aLink ); + + m_xProxyModeLB->connect_changed(LINK( this, SvxProxyTabPage, ProxyHdl_Impl )); + + Reference< css::lang::XMultiServiceFactory > + xConfigurationProvider( + configuration::theDefaultProvider::get( + comphelper::getProcessComponentContext() ) ); + + beans::NamedValue aProperty; + aProperty.Name = "nodepath"; + aProperty.Value <<= OUString( "org.openoffice.Inet/Settings" ); + + Sequence< Any > aArgumentList{ Any(aProperty) }; + + m_xConfigurationUpdateAccess = xConfigurationProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationUpdateAccess", + aArgumentList ); +} + +SvxProxyTabPage::~SvxProxyTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SvxProxyTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SvxProxyTabPage>(pPage, pController, *rAttrSet); +} + +void SvxProxyTabPage::ReadConfigData_Impl() +{ + sal_Int32 nIntValue = 0; + + std::optional<sal_Int32> x(officecfg::Inet::Settings::ooInetProxyType::get()); + if (x) + { + nIntValue = *x; + m_xProxyModeLB->set_active(nIntValue); + } + + m_xHttpProxyED->set_text( officecfg::Inet::Settings::ooInetHTTPProxyName::get() ); + x = officecfg::Inet::Settings::ooInetHTTPProxyPort::get(); + if (x) + { + nIntValue = *x; + m_xHttpPortED->set_text( OUString::number( nIntValue )); + } + else + m_xHttpPortED->set_text( "" ); + + m_xHttpsProxyED->set_text( officecfg::Inet::Settings::ooInetHTTPSProxyName::get() ); + x = officecfg::Inet::Settings::ooInetHTTPSProxyPort::get(); + if (x) + { + nIntValue = *x; + m_xHttpsPortED->set_text( OUString::number( nIntValue )); + } + else + m_xHttpsPortED->set_text( "" ); + + m_xNoProxyForED->set_text( officecfg::Inet::Settings::ooInetNoProxy::get() ); +} + +void SvxProxyTabPage::ReadConfigDefaults_Impl() +{ + try + { + Reference< beans::XPropertyState > xPropertyState(m_xConfigurationUpdateAccess, UNO_QUERY_THROW); + + sal_Int32 nIntValue = 0; + OUString aStringValue; + + if( xPropertyState->getPropertyDefault(g_aHttpProxyPN) >>= aStringValue ) + { + m_xHttpProxyED->set_text( aStringValue ); + } + + if( xPropertyState->getPropertyDefault(g_aHttpPortPN) >>= nIntValue ) + { + m_xHttpPortED->set_text( OUString::number( nIntValue )); + } + + if( xPropertyState->getPropertyDefault(g_aHttpsProxyPN) >>= aStringValue ) + { + m_xHttpsProxyED->set_text( aStringValue ); + } + + if( xPropertyState->getPropertyDefault(g_aHttpsPortPN) >>= nIntValue ) + { + m_xHttpsPortED->set_text( OUString::number( nIntValue )); + } + + if( xPropertyState->getPropertyDefault(g_aNoProxyDescPN) >>= aStringValue ) + { + m_xNoProxyForED->set_text( aStringValue ); + } + } + catch (const beans::UnknownPropertyException &) + { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } + catch (const css::lang::WrappedTargetException &) + { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } + catch (const RuntimeException &) + { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } +} + +void SvxProxyTabPage::RestoreConfigDefaults_Impl() +{ + try + { + Reference< beans::XPropertyState > xPropertyState(m_xConfigurationUpdateAccess, UNO_QUERY_THROW); + + xPropertyState->setPropertyToDefault(g_aProxyModePN); + xPropertyState->setPropertyToDefault(g_aHttpProxyPN); + xPropertyState->setPropertyToDefault(g_aHttpPortPN); + xPropertyState->setPropertyToDefault(g_aHttpsProxyPN); + xPropertyState->setPropertyToDefault(g_aHttpsPortPN); + xPropertyState->setPropertyToDefault(g_aNoProxyDescPN); + + Reference< util::XChangesBatch > xChangesBatch(m_xConfigurationUpdateAccess, UNO_QUERY_THROW); + xChangesBatch->commitChanges(); + } + catch (const beans::UnknownPropertyException &) + { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } + catch (const css::lang::WrappedTargetException &) + { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } + catch (const RuntimeException &) + { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } +} + +void SvxProxyTabPage::Reset(const SfxItemSet*) +{ + ReadConfigData_Impl(); + + m_xProxyModeLB->save_value(); + m_xHttpProxyED->save_value(); + m_xHttpPortED->save_value(); + m_xHttpsProxyED->save_value(); + m_xHttpsPortED->save_value(); + m_xNoProxyForED->save_value(); + + EnableControls_Impl(); +} + +OUString SvxProxyTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "httpft", "httpsft", + "noproxyft", "httpportft", "httpsportft", "noproxydesc" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxProxyTabPage::FillItemSet(SfxItemSet* ) +{ + bool bModified = false; + + try { + Reference< beans::XPropertySet > xPropertySet(m_xConfigurationUpdateAccess, UNO_QUERY_THROW ); + + sal_Int32 nSelPos = m_xProxyModeLB->get_active(); + if(m_xProxyModeLB->get_value_changed_from_saved()) + { + if( nSelPos == 1 ) + { + RestoreConfigDefaults_Impl(); + return true; + } + + xPropertySet->setPropertyValue(g_aProxyModePN, Any(nSelPos)); + bModified = true; + } + + if(m_xHttpProxyED->get_value_changed_from_saved()) + { + xPropertySet->setPropertyValue( g_aHttpProxyPN, Any(m_xHttpProxyED->get_text())); + bModified = true; + } + + if ( m_xHttpPortED->get_value_changed_from_saved()) + { + xPropertySet->setPropertyValue( g_aHttpPortPN, Any(m_xHttpPortED->get_text().toInt32())); + bModified = true; + } + + if( m_xHttpsProxyED->get_value_changed_from_saved() ) + { + xPropertySet->setPropertyValue( g_aHttpsProxyPN, Any(m_xHttpsProxyED->get_text()) ); + bModified = true; + } + + if ( m_xHttpsPortED->get_value_changed_from_saved() ) + { + xPropertySet->setPropertyValue( g_aHttpsPortPN, Any(m_xHttpsPortED->get_text().toInt32()) ); + bModified = true; + } + + if ( m_xNoProxyForED->get_value_changed_from_saved() ) + { + xPropertySet->setPropertyValue( g_aNoProxyDescPN, Any( m_xNoProxyForED->get_text())); + bModified = true; + } + + Reference< util::XChangesBatch > xChangesBatch(m_xConfigurationUpdateAccess, UNO_QUERY_THROW); + xChangesBatch->commitChanges(); + } + catch (const css::lang::IllegalArgumentException &) { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } + catch (const beans::UnknownPropertyException &) { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } + catch (const beans::PropertyVetoException &) { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } + catch (const css::lang::WrappedTargetException &) { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } + catch (const RuntimeException &) { + TOOLS_WARN_EXCEPTION("cui.options", "" ); + } + + return bModified; +} + +void SvxProxyTabPage::EnableControls_Impl() +{ + bool bEnable = !officecfg::Inet::Settings::ooInetNoProxy::isReadOnly(); + m_xProxyModeFT->set_sensitive(bEnable); + m_xProxyModeLB->set_sensitive(bEnable); + m_xProxyModeImg->set_visible(!bEnable); + + const bool bManualConfig = m_xProxyModeLB->get_active() == 2; + + bEnable = !officecfg::Inet::Settings::ooInetHTTPProxyName::isReadOnly(); + const bool bHTTPProxyNameEnabled = bManualConfig && bEnable; + const bool bHTTPProxyPortEnabled = bManualConfig && bEnable; + m_xHttpProxyFT->set_sensitive(bHTTPProxyNameEnabled); + m_xHttpProxyED->set_sensitive(bHTTPProxyNameEnabled); + m_xHttpProxyImg->set_visible(!bEnable); + m_xHttpPortFT->set_sensitive(bHTTPProxyPortEnabled); + m_xHttpPortED->set_sensitive(bHTTPProxyPortEnabled); + m_xHttpPortImg->set_visible(!bEnable); + + bEnable = !officecfg::Inet::Settings::ooInetHTTPSProxyName::isReadOnly(); + const bool bHTTPSProxyNameEnabled = bManualConfig && bEnable; + const bool bHTTPSProxyPortEnabled = bManualConfig && bEnable; + m_xHttpsProxyFT->set_sensitive(bHTTPSProxyNameEnabled); + m_xHttpsProxyED->set_sensitive(bHTTPSProxyNameEnabled); + m_xHttpsProxyImg->set_visible(!bEnable); + m_xHttpsPortFT->set_sensitive(bHTTPSProxyPortEnabled); + m_xHttpsPortED->set_sensitive(bHTTPSProxyPortEnabled); + m_xHttpsPortImg->set_visible(!bEnable); + + bEnable = !officecfg::Inet::Settings::ooInetNoProxy::isReadOnly(); + const bool bInetNoProxyEnabled = bManualConfig && bEnable; + m_xNoProxyForFT->set_sensitive(bInetNoProxyEnabled); + m_xNoProxyForED->set_sensitive(bInetNoProxyEnabled); + m_xNoProxyForImg->set_visible(!bEnable); + m_xNoProxyDescFT->set_sensitive(bInetNoProxyEnabled); +} + +IMPL_LINK(SvxProxyTabPage, ProxyHdl_Impl, weld::ComboBox&, rBox, void) +{ + sal_Int32 nPos = rBox.get_active(); + + // Restore original system values + if( nPos == 1 ) + { + ReadConfigDefaults_Impl(); + } + + EnableControls_Impl(); +} + +IMPL_STATIC_LINK(SvxProxyTabPage, LoseFocusHdl_Impl, weld::Widget&, rControl, void) +{ + weld::Entry* pEdit = dynamic_cast<weld::Entry*>(&rControl); + if (pEdit && !isValidPort(pEdit->get_text())) + pEdit->set_text(OUString('0')); +} + +/********************************************************************/ +/* */ +/* SvxSecurityTabPage */ +/* */ +/********************************************************************/ +SvxSecurityTabPage::SvxSecurityTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optsecuritypage.ui", "OptSecurityPage", &rSet) + , m_xSecurityOptionsPB(m_xBuilder->weld_button("options")) + , m_xSavePasswordsCB(m_xBuilder->weld_check_button("savepassword")) + , m_xSavePasswordsImg(m_xBuilder->weld_widget("locksavepassword")) + , m_xShowConnectionsPB(m_xBuilder->weld_button("connections")) + , m_xMasterPasswordCB(m_xBuilder->weld_check_button("usemasterpassword")) + , m_xMasterPasswordImg(m_xBuilder->weld_widget("lockusemasterpassword")) + , m_xMasterPasswordFT(m_xBuilder->weld_label("masterpasswordtext")) + , m_xMasterPasswordPB(m_xBuilder->weld_button("masterpassword")) + , m_xMacroSecFrame(m_xBuilder->weld_container("macrosecurity")) + , m_xMacroSecPB(m_xBuilder->weld_button("macro")) + , m_xCertFrame(m_xBuilder->weld_container("certificatepath")) + , m_xCertPathPB(m_xBuilder->weld_button("cert")) + , m_xCertPathImg(m_xBuilder->weld_widget("lockcertipath")) + , m_xCertPathLabel(m_xBuilder->weld_label("label7")) + , m_xTSAURLsFrame(m_xBuilder->weld_container("tsaurls")) + , m_xTSAURLsPB(m_xBuilder->weld_button("tsas")) + , m_xTSAURLsImg(m_xBuilder->weld_widget("locktsas")) + , m_xTSAURLsLabel(m_xBuilder->weld_label("label9")) + , m_xNoPasswordSaveFT(m_xBuilder->weld_label("nopasswordsave")) + , m_xCertMgrPathLB(m_xBuilder->weld_button("browse")) + , m_xParameterEdit(m_xBuilder->weld_entry("parameterfield")) + , m_xCertMgrPathImg(m_xBuilder->weld_widget("lockcertimanager")) + , m_xCertMgrPathLabel(m_xBuilder->weld_label("label11")) +{ + //fdo#65595, we need height-for-width support here, but for now we can + //bodge it + Size aPrefSize(m_xSavePasswordsCB->get_preferred_size()); + int nMaxWidth = m_xSavePasswordsCB->get_approximate_digit_width() * 40; + if (aPrefSize.Width() > nMaxWidth) + { + m_xSavePasswordsCB->set_label_wrap(true); + m_xSavePasswordsCB->set_size_request(nMaxWidth, -1); + } + + m_sPasswordStoringDeactivateStr = m_xNoPasswordSaveFT->get_label(); + + InitControls(); + + m_xSecurityOptionsPB->connect_clicked( LINK( this, SvxSecurityTabPage, SecurityOptionsHdl ) ); + m_xSavePasswordsCB->connect_toggled( LINK( this, SvxSecurityTabPage, SavePasswordHdl ) ); + m_xMasterPasswordPB->connect_clicked( LINK( this, SvxSecurityTabPage, MasterPasswordHdl ) ); + m_xMasterPasswordCB->connect_toggled( LINK( this, SvxSecurityTabPage, MasterPasswordCBHdl ) ); + m_xShowConnectionsPB->connect_clicked( LINK( this, SvxSecurityTabPage, ShowPasswordsHdl ) ); + m_xMacroSecPB->connect_clicked( LINK( this, SvxSecurityTabPage, MacroSecPBHdl ) ); + m_xCertPathPB->connect_clicked( LINK( this, SvxSecurityTabPage, CertPathPBHdl ) ); + m_xTSAURLsPB->connect_clicked( LINK( this, SvxSecurityTabPage, TSAURLsPBHdl ) ); + m_xCertMgrPathLB->connect_clicked( LINK( this, SvxSecurityTabPage, CertMgrPBHdl ) ); + + ActivatePage( rSet ); +} + +IMPL_LINK_NOARG(SvxSecurityTabPage, CertMgrPBHdl, weld::Button&, void) +{ + try + { + FileDialogHelper aHelper(css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, nullptr); + OUString sPath = m_xParameterEdit->get_text(); + if (sPath.isEmpty()) + sPath = "/usr/bin"; + + OUString sUrl; + osl::FileBase::getFileURLFromSystemPath(sPath, sUrl); + aHelper.SetDisplayDirectory(sUrl); + + if (ERRCODE_NONE == aHelper.Execute()) + { + sUrl = aHelper.GetPath(); + if (osl::FileBase::getSystemPathFromFileURL(sUrl, sPath) != osl::FileBase::E_None) + { + sPath.clear(); + } + m_xParameterEdit->set_text(sPath); + } + std::shared_ptr<comphelper::ConfigurationChanges> pBatch( + comphelper::ConfigurationChanges::create()); + OUString sCurCertMgr = m_xParameterEdit->get_text(); + officecfg::Office::Common::Security::Scripting::CertMgrPath::set(sCurCertMgr, pBatch); + pBatch->commit(); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("cui.options", "CertMgrPBHdl"); + } +} + +SvxSecurityTabPage::~SvxSecurityTabPage() +{ +} + +IMPL_LINK_NOARG(SvxSecurityTabPage, SecurityOptionsHdl, weld::Button&, void) +{ + if (!m_xSecOptDlg) + m_xSecOptDlg.reset(new svx::SecurityOptionsDialog(GetFrameWeld())); + m_xSecOptDlg->run(); +} + +IMPL_LINK_NOARG(SvxSecurityTabPage, SavePasswordHdl, weld::Toggleable&, void) +{ + try + { + Reference< task::XPasswordContainer2 > xMasterPasswd( + task::PasswordContainer::create(comphelper::getProcessComponentContext())); + + if ( m_xSavePasswordsCB->get_active() ) + { + bool bOldValue = xMasterPasswd->allowPersistentStoring( true ); + xMasterPasswd->removeMasterPassword(); + + uno::Reference<task::XInteractionHandler> xTmpHandler(task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), + GetDialogController()->getDialog()->GetXWindow())); + + if ( xMasterPasswd->changeMasterPassword(xTmpHandler) ) + { + m_xMasterPasswordPB->set_sensitive(true); + m_xMasterPasswordCB->set_active(true); + m_xMasterPasswordCB->set_sensitive(true); + m_xMasterPasswordFT->set_sensitive(true); + m_xShowConnectionsPB->set_sensitive(true); + } + else + { + xMasterPasswd->allowPersistentStoring( bOldValue ); + m_xSavePasswordsCB->set_active( false ); + } + } + else + { + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + m_sPasswordStoringDeactivateStr)); + xQueryBox->set_default_response(RET_NO); + + sal_uInt16 nRet = xQueryBox->run(); + + if( RET_YES == nRet ) + { + xMasterPasswd->allowPersistentStoring( false ); + m_xMasterPasswordCB->set_active(true); + m_xMasterPasswordPB->set_sensitive( false ); + m_xMasterPasswordCB->set_sensitive( false ); + m_xMasterPasswordFT->set_sensitive( false ); + m_xShowConnectionsPB->set_sensitive( false ); + } + else + { + m_xSavePasswordsCB->set_active(true); + m_xMasterPasswordPB->set_sensitive(true); + m_xShowConnectionsPB->set_sensitive(true); + } + } + } + catch (const Exception&) + { + m_xSavePasswordsCB->set_active( !m_xSavePasswordsCB->get_active() ); + } +} + +IMPL_LINK_NOARG(SvxSecurityTabPage, MasterPasswordHdl, weld::Button&, void) +{ + try + { + Reference< task::XPasswordContainer2 > xMasterPasswd( + task::PasswordContainer::create(comphelper::getProcessComponentContext())); + + if ( xMasterPasswd->isPersistentStoringAllowed() ) + { + uno::Reference<task::XInteractionHandler> xTmpHandler(task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), + GetDialogController()->getDialog()->GetXWindow())); + xMasterPasswd->changeMasterPassword(xTmpHandler); + } + } + catch (const Exception&) + {} +} + +IMPL_LINK_NOARG(SvxSecurityTabPage, MasterPasswordCBHdl, weld::Toggleable&, void) +{ + try + { + Reference< task::XPasswordContainer2 > xMasterPasswd( + task::PasswordContainer::create(comphelper::getProcessComponentContext())); + + uno::Reference<task::XInteractionHandler> xTmpHandler(task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), + GetDialogController()->getDialog()->GetXWindow())); + + if ( m_xMasterPasswordCB->get_active() ) + { + if (xMasterPasswd->isPersistentStoringAllowed() && xMasterPasswd->changeMasterPassword(xTmpHandler)) + { + m_xMasterPasswordPB->set_sensitive(true); + m_xMasterPasswordFT->set_sensitive(true); + } + else + { + m_xMasterPasswordCB->set_active( false ); + m_xMasterPasswordPB->set_sensitive(true); + m_xMasterPasswordFT->set_sensitive(true); + } + } + else + { + if ( xMasterPasswd->isPersistentStoringAllowed() && xMasterPasswd->useDefaultMasterPassword(xTmpHandler) ) + { + m_xMasterPasswordPB->set_sensitive( false ); + m_xMasterPasswordFT->set_sensitive( false ); + } + else + { + m_xMasterPasswordCB->set_active(true); + m_xMasterPasswordPB->set_sensitive(true); + m_xShowConnectionsPB->set_sensitive(true); + } + } + } + catch (const Exception&) + { + m_xSavePasswordsCB->set_active( !m_xSavePasswordsCB->get_active() ); + } +} + +IMPL_LINK_NOARG(SvxSecurityTabPage, ShowPasswordsHdl, weld::Button&, void) +{ + try + { + Reference< task::XPasswordContainer2 > xMasterPasswd( + task::PasswordContainer::create(comphelper::getProcessComponentContext())); + + uno::Reference<task::XInteractionHandler> xTmpHandler(task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), + GetDialogController()->getDialog()->GetXWindow())); + + if ( xMasterPasswd->isPersistentStoringAllowed() && xMasterPasswd->authorizateWithMasterPassword(xTmpHandler) ) + { + svx::WebConnectionInfoDialog aDlg(GetFrameWeld()); + aDlg.run(); + } + } + catch (const Exception&) + {} +} + +IMPL_LINK_NOARG(SvxSecurityTabPage, CertPathPBHdl, weld::Button&, void) +{ + if (!mpCertPathDlg) + mpCertPathDlg.reset(new CertPathDialog(GetFrameWeld())); + mpCertPathDlg->Init(); + + if (mpCertPathDlg->run() == RET_OK && !mpCertPathDlg->isActiveServicePath()) + { + SolarMutexGuard aGuard; + if (svtools::executeRestartDialog(comphelper::getProcessComponentContext(), nullptr, svtools::RESTART_REASON_ADDING_PATH)) + GetDialogController()->response(RET_OK); + } +} + +IMPL_LINK_NOARG(SvxSecurityTabPage, TSAURLsPBHdl, weld::Button&, void) +{ + // Unlike the mpCertPathDlg, we *don't* keep the same dialog object around between + // invocations. Seems clearer to my little brain that way. + TSAURLsDialog aTSAURLsDlg(GetFrameWeld()); + aTSAURLsDlg.run(); +} + +IMPL_LINK_NOARG(SvxSecurityTabPage, MacroSecPBHdl, weld::Button&, void) +{ + try + { + Reference< security::XDocumentDigitalSignatures > xD( + security::DocumentDigitalSignatures::createDefault(comphelper::getProcessComponentContext() ) ); + xD->setParentWindow(GetDialogController()->getDialog()->GetXWindow()); + xD->manageTrustedSources(); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "cui.options", ""); + } +} + +void SvxSecurityTabPage::InitControls() +{ +#ifndef UNX + m_xCertFrame->hide(); +#endif + + m_xMasterPasswordPB->set_sensitive( false ); + m_xMasterPasswordCB->set_sensitive( false ); + m_xMasterPasswordCB->set_active(true); + m_xMasterPasswordFT->set_sensitive( false ); + m_xShowConnectionsPB->set_sensitive( false ); + + // initialize the password saving checkbox + try + { + Reference< task::XPasswordContainer2 > xMasterPasswd( + task::PasswordContainer::create(comphelper::getProcessComponentContext())); + + if ( xMasterPasswd->isPersistentStoringAllowed() ) + { + m_xMasterPasswordCB->set_sensitive(true); + m_xShowConnectionsPB->set_sensitive(true); + m_xSavePasswordsCB->set_active(true); + + if ( xMasterPasswd->isDefaultMasterPasswordUsed() ) + m_xMasterPasswordCB->set_active( false ); + else + { + m_xMasterPasswordPB->set_sensitive(true); + m_xMasterPasswordCB->set_active(true); + m_xMasterPasswordFT->set_sensitive(true); + } + } + + if (officecfg::Office::Common::Passwords::UseStorage::isReadOnly()) + { + m_xSavePasswordsCB->set_sensitive(false); + m_xShowConnectionsPB->set_sensitive(false); + m_xSavePasswordsImg->set_visible(true); + m_xMasterPasswordCB->set_sensitive(false); + m_xMasterPasswordPB->set_sensitive(false); + m_xMasterPasswordImg->set_visible(true); + } + } + catch (const Exception&) + { + m_xSavePasswordsCB->set_sensitive( false ); + } + + try + { + OUString sCurCertMgr = officecfg::Office::Common::Security::Scripting::CertMgrPath::get(); + + if (!sCurCertMgr.isEmpty()) + m_xParameterEdit->set_text(sCurCertMgr); + + bool bEnable = !officecfg::Office::Common::Security::Scripting::CertMgrPath::isReadOnly(); + m_xCertMgrPathLB->set_sensitive(bEnable); + m_xParameterEdit->set_sensitive(bEnable); + m_xCertMgrPathLabel->set_sensitive(bEnable); + m_xCertMgrPathImg->set_visible(!bEnable); + + bEnable = !officecfg::Office::Common::Security::Scripting::TSAURLs::isReadOnly(); + m_xTSAURLsPB->set_sensitive(bEnable); + m_xTSAURLsLabel->set_sensitive(bEnable); + m_xTSAURLsImg->set_visible(!bEnable); + +#ifndef UNX + bEnable = !officecfg::Office::Common::Security::Scripting::CertDir::isReadOnly() || + !officecfg::Office::Common::Security::Scripting::ManualCertDir::isReadOnly(); + m_xCertPathPB->set_sensitive(bEnable); + m_xCertPathLabel->set_sensitive(bEnable); + m_xCertPathImg->set_visible(!bEnable); +#endif + } + catch (const uno::Exception&) + { + } +} + +std::unique_ptr<SfxTabPage> SvxSecurityTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SvxSecurityTabPage>(pPage, pController, *rAttrSet); +} + +void SvxSecurityTabPage::ActivatePage( const SfxItemSet& ) +{ +} + +DeactivateRC SvxSecurityTabPage::DeactivatePage( SfxItemSet* _pSet ) +{ + if( _pSet ) + FillItemSet( _pSet ); + return DeactivateRC::LeavePage; +} + +namespace +{ + bool CheckAndSave( SvtSecurityOptions::EOption _eOpt, const bool _bIsChecked, bool& _rModified ) + { + bool bModified = false; + if ( !SvtSecurityOptions::IsReadOnly( _eOpt ) ) + { + bModified = SvtSecurityOptions::IsOptionSet( _eOpt ) != _bIsChecked; + if ( bModified ) + { + SvtSecurityOptions::SetOption( _eOpt, _bIsChecked ); + _rModified = true; + } + } + + return bModified; + } +} + +OUString SvxSecurityTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label4", "label2", "masterpasswordtext", + "nopasswordsave", "label3", "label5", "label8", + "label7", "label10", "label9", "label12", + "label11" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "savepassword", "usemasterpassword" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + // TODO: Should we exclude button strings from the search? + // button id: "browse" is excluded + OUString buttons[] = { "options", "connections", "masterpassword", "macro", "cert", "tsas" }; + + for (const auto& btn : buttons) + { + if (const auto& pString = m_xBuilder->weld_button(btn)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxSecurityTabPage::FillItemSet( SfxItemSet* ) +{ + bool bModified = false; + + if (m_xSecOptDlg) + { + CheckAndSave( SvtSecurityOptions::EOption::DocWarnSaveOrSend, m_xSecOptDlg->IsSaveOrSendDocsChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::DocWarnSigning, m_xSecOptDlg->IsSignDocsChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::DocWarnPrint, m_xSecOptDlg->IsPrintDocsChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::DocWarnCreatePdf, m_xSecOptDlg->IsCreatePdfChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo, m_xSecOptDlg->IsRemovePersInfoChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::DocWarnKeepRedlineInfo, m_xSecOptDlg->IsRemoveRedlineInfoChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::DocWarnKeepDocUserInfo, m_xSecOptDlg->IsRemoveDocUserInfoChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::DocWarnKeepNoteAuthorDateInfo, m_xSecOptDlg->IsRemoveNoteAuthorInfoChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::DocWarnKeepDocVersionInfo, m_xSecOptDlg->IsRemoveDocVersionInfoChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::DocWarnRecommendPassword, m_xSecOptDlg->IsRecommPasswdChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::CtrlClickHyperlink, m_xSecOptDlg->IsCtrlHyperlinkChecked(), bModified ); + CheckAndSave( SvtSecurityOptions::EOption::BlockUntrustedRefererLinks, m_xSecOptDlg->IsBlockUntrustedRefererLinksChecked(), bModified ); + } + + std::shared_ptr<comphelper::ConfigurationChanges> pBatch( + comphelper::ConfigurationChanges::create()); + if (m_xParameterEdit->get_value_changed_from_saved()) + { + OUString sCurCertMgr = m_xParameterEdit->get_text(); + officecfg::Office::Common::Security::Scripting::CertMgrPath::set(sCurCertMgr, pBatch); + pBatch->commit(); + } + + return bModified; +} + +/*--------------------------------------------------------------------*/ + +void SvxSecurityTabPage::Reset( const SfxItemSet* ) +{ +} + +struct SvxEMailTabPage_Impl +{ + SvxEMailTabPage_Impl(): + sProgram(officecfg::Office::Common::ExternalMailer::Program::get()), + bROProgram( + officecfg::Office::Common::ExternalMailer::Program::isReadOnly()), + bHideContent( + officecfg::Office::Security::HiddenContent::RemoveHiddenContent::get()), + bROHideContent( + officecfg::Office::Security::HiddenContent::RemoveHiddenContent::isReadOnly()) + {} + + OUString sProgram; + bool bROProgram; + bool bHideContent; + bool bROHideContent; +}; + +SvxEMailTabPage::SvxEMailTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage( pPage, pController, "cui/ui/optemailpage.ui", "OptEmailPage", &rSet) + , pImpl(new SvxEMailTabPage_Impl) + , m_xMailContainer(m_xBuilder->weld_container("program")) + , m_xMailerURLFI(m_xBuilder->weld_image("lockemail")) + , m_xMailerURLED(m_xBuilder->weld_entry("url")) + , m_xMailerURLPB(m_xBuilder->weld_button("browse")) + , m_xSuppressHiddenContainer(m_xBuilder->weld_container("suppressHiddenCont")) + , m_xSuppressHiddenFI(m_xBuilder->weld_image("lockSuppressHidden")) + , m_xSuppressHidden(m_xBuilder->weld_check_button("suppressHidden")) + , m_xDefaultFilterFT(m_xBuilder->weld_label("browsetitle")) +{ + m_sDefaultFilterName = m_xDefaultFilterFT->get_label(); + m_xMailerURLPB->connect_clicked( LINK( this, SvxEMailTabPage, FileDialogHdl_Impl ) ); +} + +/* -------------------------------------------------------------------------*/ + +SvxEMailTabPage::~SvxEMailTabPage() +{ +} + +/* -------------------------------------------------------------------------*/ + +std::unique_ptr<SfxTabPage> SvxEMailTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SvxEMailTabPage>(pPage, pController, *rAttrSet); +} + +/* -------------------------------------------------------------------------*/ + +OUString SvxEMailTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "browsetitle", "suppress" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +/* -------------------------------------------------------------------------*/ + +bool SvxEMailTabPage::FillItemSet( SfxItemSet* ) +{ + std::shared_ptr<comphelper::ConfigurationChanges> batch( + comphelper::ConfigurationChanges::create()); + if (!pImpl->bROProgram && m_xMailerURLED->get_value_changed_from_saved()) + { + pImpl->sProgram = m_xMailerURLED->get_text(); + officecfg::Office::Common::ExternalMailer::Program::set( + pImpl->sProgram, batch); + } + if (!pImpl->bROHideContent + && pImpl->bHideContent != m_xSuppressHidden->get_active()) + { + pImpl->bHideContent = m_xSuppressHidden->get_active(); + officecfg::Office::Security::HiddenContent::RemoveHiddenContent::set( + pImpl->bHideContent, batch); + } + batch->commit(); + return false; +} + +/* -------------------------------------------------------------------------*/ + +void SvxEMailTabPage::Reset( const SfxItemSet* ) +{ + m_xMailerURLED->set_sensitive(true); + m_xMailerURLPB->set_sensitive(true); + + if (pImpl->bROProgram) + m_xMailerURLFI->show(); + + m_xMailerURLED->set_text(pImpl->sProgram); + m_xMailerURLED->save_value(); + + m_xMailContainer->set_sensitive(!pImpl->bROProgram); + + if (pImpl->bROHideContent) + m_xSuppressHiddenFI->show(); + + m_xSuppressHidden->set_active(pImpl->bHideContent); + + m_xSuppressHiddenContainer->set_sensitive(!pImpl->bROHideContent); +} + +/* -------------------------------------------------------------------------*/ + +IMPL_LINK_NOARG(SvxEMailTabPage, FileDialogHdl_Impl, weld::Button&, void) +{ + if (pImpl->bROProgram) + return; + + FileDialogHelper aHelper(css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, GetFrameWeld()); + OUString sPath = m_xMailerURLED->get_text(); + if ( sPath.isEmpty() ) + sPath = "/usr/bin"; + + OUString sUrl; + osl::FileBase::getFileURLFromSystemPath(sPath, sUrl); + aHelper.SetDisplayDirectory(sUrl); + aHelper.AddFilter( m_sDefaultFilterName, "*"); + + if ( ERRCODE_NONE == aHelper.Execute() ) + { + sUrl = aHelper.GetPath(); + if (osl::FileBase::getSystemPathFromFileURL(sUrl, sPath) + != osl::FileBase::E_None) + { + sPath.clear(); + } + m_xMailerURLED->set_text(sPath); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optinet2.hxx b/cui/source/options/optinet2.hxx new file mode 100644 index 0000000000..e05a79be02 --- /dev/null +++ b/cui/source/options/optinet2.hxx @@ -0,0 +1,180 @@ +/* -*- 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 . + */ +#pragma once + +#include <memory> +#include <sfx2/tabdlg.hxx> + +namespace svx { + class SecurityOptionsDialog; +} + +// class SvxProxyTabPage ------------------------------------------------- +class SvxProxyTabPage : public SfxTabPage +{ +private: + + std::unique_ptr<weld::Label> m_xProxyModeFT; + std::unique_ptr<weld::ComboBox> m_xProxyModeLB; + std::unique_ptr<weld::Widget> m_xProxyModeImg; + + std::unique_ptr<weld::Label> m_xHttpProxyFT; + std::unique_ptr<weld::Entry> m_xHttpProxyED; + std::unique_ptr<weld::Widget> m_xHttpProxyImg; + std::unique_ptr<weld::Label> m_xHttpPortFT; + std::unique_ptr<weld::Entry> m_xHttpPortED; + std::unique_ptr<weld::Widget> m_xHttpPortImg; + + std::unique_ptr<weld::Label> m_xHttpsProxyFT; + std::unique_ptr<weld::Entry> m_xHttpsProxyED; + std::unique_ptr<weld::Widget> m_xHttpsProxyImg; + std::unique_ptr<weld::Label> m_xHttpsPortFT; + std::unique_ptr<weld::Entry> m_xHttpsPortED; + std::unique_ptr<weld::Widget> m_xHttpsPortImg; + + std::unique_ptr<weld::Label> m_xNoProxyForFT; + std::unique_ptr<weld::Entry> m_xNoProxyForED; + std::unique_ptr<weld::Widget> m_xNoProxyForImg; + std::unique_ptr<weld::Label> m_xNoProxyDescFT; + + css::uno::Reference< css::uno::XInterface > m_xConfigurationUpdateAccess; + + void EnableControls_Impl(); + void ReadConfigData_Impl(); + void ReadConfigDefaults_Impl(); + void RestoreConfigDefaults_Impl(); + + DECL_LINK(PortChangedHdl, weld::Entry&, void); + DECL_STATIC_LINK(SvxProxyTabPage, NumberOnlyTextFilterHdl, OUString&, bool); + DECL_STATIC_LINK(SvxProxyTabPage, NoSpaceTextFilterHdl, OUString&, bool); + DECL_LINK(ProxyHdl_Impl, weld::ComboBox&, void); + DECL_STATIC_LINK(SvxProxyTabPage, LoseFocusHdl_Impl, weld::Widget&, void); + +public: + SvxProxyTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~SvxProxyTabPage() override; + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +// class SvxSecurityTabPage --------------------------------------------- + +class CertPathDialog; +class SvxSecurityTabPage : public SfxTabPage +{ +private: + std::unique_ptr<svx::SecurityOptionsDialog> m_xSecOptDlg; + + std::unique_ptr<CertPathDialog> mpCertPathDlg; + + OUString m_sPasswordStoringDeactivateStr; + + std::unique_ptr<weld::Button> m_xSecurityOptionsPB; + + std::unique_ptr<weld::CheckButton> m_xSavePasswordsCB; + std::unique_ptr<weld::Widget> m_xSavePasswordsImg; + std::unique_ptr<weld::Button> m_xShowConnectionsPB; + + std::unique_ptr<weld::CheckButton> m_xMasterPasswordCB; + std::unique_ptr<weld::Widget> m_xMasterPasswordImg; + std::unique_ptr<weld::Label> m_xMasterPasswordFT; + std::unique_ptr<weld::Button> m_xMasterPasswordPB; + + std::unique_ptr<weld::Container> m_xMacroSecFrame; + std::unique_ptr<weld::Button> m_xMacroSecPB; + + std::unique_ptr<weld::Container> m_xCertFrame; + std::unique_ptr<weld::Button> m_xCertPathPB; + std::unique_ptr<weld::Widget> m_xCertPathImg; + std::unique_ptr<weld::Label> m_xCertPathLabel; + + std::unique_ptr<weld::Container> m_xTSAURLsFrame; + std::unique_ptr<weld::Button> m_xTSAURLsPB; + std::unique_ptr<weld::Widget> m_xTSAURLsImg; + std::unique_ptr<weld::Label> m_xTSAURLsLabel; + + std::unique_ptr<weld::Label> m_xNoPasswordSaveFT; + + std::unique_ptr<weld::Button> m_xCertMgrPathLB; + std::unique_ptr<weld::Entry> m_xParameterEdit; + std::unique_ptr<weld::Widget> m_xCertMgrPathImg; + std::unique_ptr<weld::Label> m_xCertMgrPathLabel; + + DECL_LINK(SecurityOptionsHdl, weld::Button&, void); + DECL_LINK(SavePasswordHdl, weld::Toggleable&, void); + DECL_LINK(MasterPasswordHdl, weld::Button&, void); + DECL_LINK(MasterPasswordCBHdl, weld::Toggleable&, void); + DECL_LINK(ShowPasswordsHdl, weld::Button&, void); + DECL_LINK(MacroSecPBHdl, weld::Button&, void ); + DECL_LINK(CertPathPBHdl, weld::Button&, void ); + DECL_LINK(TSAURLsPBHdl, weld::Button&, void ); + DECL_LINK(CertMgrPBHdl, weld::Button&, void ); + + void InitControls(); + +protected: + virtual void ActivatePage( const SfxItemSet& rSet ) override; + virtual DeactivateRC DeactivatePage( SfxItemSet* pSet ) override; + +public: + SvxSecurityTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + virtual ~SvxSecurityTabPage() override; + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +struct SvxEMailTabPage_Impl; +class SvxEMailTabPage : public SfxTabPage +{ + OUString m_sDefaultFilterName; + + std::unique_ptr<SvxEMailTabPage_Impl> pImpl; + + std::unique_ptr<weld::Container> m_xMailContainer; + std::unique_ptr<weld::Image> m_xMailerURLFI; + std::unique_ptr<weld::Entry> m_xMailerURLED; + std::unique_ptr<weld::Button> m_xMailerURLPB; + std::unique_ptr<weld::Container> m_xSuppressHiddenContainer; + std::unique_ptr<weld::Image> m_xSuppressHiddenFI; + std::unique_ptr<weld::CheckButton> m_xSuppressHidden; + std::unique_ptr<weld::Label> m_xDefaultFilterFT; + + DECL_LINK(FileDialogHdl_Impl, weld::Button&, void); + +public: + SvxEMailTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet ); + virtual ~SvxEMailTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optjava.cxx b/cui/source/options/optjava.cxx new file mode 100644 index 0000000000..6c6d3d07cd --- /dev/null +++ b/cui/source/options/optjava.cxx @@ -0,0 +1,1007 @@ +/* -*- 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 <o3tl/safeint.hxx> +#include <sal/config.h> +#include <sal/log.hxx> + +#include <cassert> +#include <memory> + +#include <config_java.h> + +#include "optaboutconfig.hxx" +#include "optjava.hxx" +#include <treeopt.hxx> +#include <dialmgr.hxx> + +#include <officecfg/Office/Common.hxx> +#include <osl/file.hxx> +#include <rtl/bootstrap.hxx> + +#include <strings.hrc> +#include <vcl/svapp.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <vcl/weld.hxx> +#include <unotools/pathoptions.hxx> +#include <svtools/imagemgr.hxx> +#include <svtools/restartdialog.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/inputdlg.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#if HAVE_FEATURE_JAVA +#include <jvmfwk/framework.hxx> +#endif + +// define ---------------------------------------------------------------- + +#define CLASSPATH_DELIMITER SAL_PATHSEPARATOR + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::uno; + +// class SvxJavaOptionsPage ---------------------------------------------- +SvxJavaOptionsPage::SvxJavaOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optadvancedpage.ui", "OptAdvancedPage", &rSet) + , m_aResetIdle("cui options SvxJavaOptionsPage Reset") + , xDialogListener(new ::svt::DialogClosedListener()) + , m_xJavaEnableCB(m_xBuilder->weld_check_button("javaenabled")) + , m_xJavaList(m_xBuilder->weld_tree_view("javas")) + , m_xJavaPathText(m_xBuilder->weld_label("javapath")) + , m_xAddBtn(m_xBuilder->weld_button("add")) + , m_xParameterBtn(m_xBuilder->weld_button("parameters")) + , m_xClassPathBtn(m_xBuilder->weld_button("classpath")) + , m_xExpertConfigBtn(m_xBuilder->weld_button("expertconfig")) + , m_xExperimentalCB(m_xBuilder->weld_check_button("experimental")) + , m_xExperimentalImg(m_xBuilder->weld_widget("lockexperimental")) + , m_xMacroCB(m_xBuilder->weld_check_button("macrorecording")) + , m_xMacroImg(m_xBuilder->weld_widget("lockmacrorecording")) + , m_xAddDialogText(m_xBuilder->weld_label("selectruntime")) + , m_xJavaFrame(m_xBuilder->weld_widget("javaframe")) +{ + m_sInstallText = m_xJavaPathText->get_label(); + m_sAddDialogText = m_xAddDialogText->get_label(); + + m_xJavaList->set_size_request(m_xJavaList->get_approximate_digit_width() * 30, + m_xJavaList->get_height_rows(8)); + + m_xJavaList->enable_toggle_buttons(weld::ColumnToggleType::Radio); + m_xJavaList->connect_toggled( LINK( this, SvxJavaOptionsPage, CheckHdl_Impl ) ); + m_xJavaList->connect_changed( LINK( this, SvxJavaOptionsPage, SelectHdl_Impl ) ); + + std::vector<int> aWidths + { + m_xJavaList->get_checkbox_column_width(), + o3tl::narrowing<int>(m_xJavaList->get_pixel_size("Sun Microsystems Inc.").Width()) + }; + m_xJavaList->set_column_fixed_widths(aWidths); + + m_xJavaEnableCB->connect_toggled( LINK( this, SvxJavaOptionsPage, EnableHdl_Impl ) ); + m_xAddBtn->connect_clicked( LINK( this, SvxJavaOptionsPage, AddHdl_Impl ) ); + m_xParameterBtn->connect_clicked( LINK( this, SvxJavaOptionsPage, ParameterHdl_Impl ) ); + m_xClassPathBtn->connect_clicked( LINK( this, SvxJavaOptionsPage, ClassPathHdl_Impl ) ); + m_aResetIdle.SetInvokeHandler( LINK( this, SvxJavaOptionsPage, ResetHdl_Impl ) ); + + m_xExpertConfigBtn->connect_clicked( LINK( this, SvxJavaOptionsPage, ExpertConfigHdl_Impl) ); + if (!officecfg::Office::Common::Security::EnableExpertConfiguration::get()) + m_xExpertConfigBtn->set_sensitive(false); + + if (officecfg::Office::Common::Misc::MacroRecorderMode::isReadOnly()) + { + m_xMacroCB->set_sensitive(false); + m_xMacroImg->set_visible(true); + } + + if (officecfg::Office::Common::Misc::ExperimentalMode::isReadOnly()) + { + m_xExperimentalCB->set_sensitive(false); + m_xExperimentalImg->set_visible(true); + } + + xDialogListener->SetDialogClosedLink( LINK( this, SvxJavaOptionsPage, DialogClosedHdl ) ); + + EnableHdl_Impl(*m_xJavaEnableCB); +#if HAVE_FEATURE_JAVA + jfw_lock(); +#else + m_xJavaFrame->set_sensitive(false); +#endif +} + +SvxJavaOptionsPage::~SvxJavaOptionsPage() +{ + ClearJavaInfo(); +#if HAVE_FEATURE_JAVA + m_aAddedInfos.clear(); + + jfw_unlock(); +#endif +} + +IMPL_LINK_NOARG(SvxJavaOptionsPage, EnableHdl_Impl, weld::Toggleable&, void) +{ + bool bEnable = m_xJavaFrame->get_sensitive() && m_xJavaEnableCB->get_active(); + m_xJavaList->set_sensitive(bEnable); +} + +IMPL_LINK(SvxJavaOptionsPage, CheckHdl_Impl, const weld::TreeView::iter_col&, rRowCol, void) +{ + HandleCheckEntry(m_xJavaList->get_iter_index_in_parent(rRowCol.first)); +} + +IMPL_LINK_NOARG(SvxJavaOptionsPage, SelectHdl_Impl, weld::TreeView&, void) +{ + UpdateJavaPathText(); +} + +IMPL_LINK_NOARG(SvxJavaOptionsPage, AddHdl_Impl, weld::Button&, void) +{ + try + { + Reference < XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + xFolderPicker = sfx2::createFolderPicker(xContext, GetFrameWeld()); + + OUString sWorkFolder = SvtPathOptions().GetWorkPath(); + xFolderPicker->setDisplayDirectory( sWorkFolder ); + xFolderPicker->setDescription( m_sAddDialogText ); + + Reference< XAsynchronousExecutableDialog > xAsyncDlg( xFolderPicker, UNO_QUERY ); + if ( xAsyncDlg.is() ) + xAsyncDlg->startExecuteModal( xDialogListener ); + else if ( xFolderPicker.is() && xFolderPicker->execute() == ExecutableDialogResults::OK ) + AddFolder( xFolderPicker->getDirectory() ); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "cui.options", "SvxJavaOptionsPage::AddHdl_Impl()"); + } +} + +IMPL_LINK_NOARG(SvxJavaOptionsPage, ParameterHdl_Impl, weld::Button&, void) +{ +#if HAVE_FEATURE_JAVA + std::vector< OUString > aParameterList; + if (!m_xParamDlg) + { + m_xParamDlg.reset(new SvxJavaParameterDlg(GetFrameWeld())); + javaFrameworkError eErr = jfw_getVMParameters( &m_parParameters ); + if ( JFW_E_NONE == eErr && !m_parParameters.empty() ) + { + aParameterList = m_parParameters; + m_xParamDlg->SetParameters( aParameterList ); + } + } + else + { + aParameterList = m_xParamDlg->GetParameters(); + m_xParamDlg->DisableButtons(); //disable add, edit and remove button when dialog is reopened + } + + if (m_xParamDlg->run() == RET_OK) + { + if ( aParameterList != m_xParamDlg->GetParameters() ) + { + aParameterList = m_xParamDlg->GetParameters(); + if ( jfw_isVMRunning() ) + { + RequestRestart( svtools::RESTART_REASON_ASSIGNING_JAVAPARAMETERS ); + } + } + } + else + m_xParamDlg->SetParameters( aParameterList ); +#else + (void) this; // Silence loplugin:staticmethods +#endif +} + + +IMPL_LINK_NOARG(SvxJavaOptionsPage, ClassPathHdl_Impl, weld::Button&, void) +{ +#if HAVE_FEATURE_JAVA + OUString sClassPath; + + if ( !m_xPathDlg ) + { + m_xPathDlg.reset(new SvxJavaClassPathDlg(GetFrameWeld())); + javaFrameworkError eErr = jfw_getUserClassPath( &m_pClassPath ); + if ( JFW_E_NONE == eErr ) + { + sClassPath = m_pClassPath; + m_xPathDlg->SetClassPath( sClassPath ); + } + } + else + sClassPath = m_xPathDlg->GetClassPath(); + + m_xPathDlg->SetFocus(); + if (m_xPathDlg->run() == RET_OK) + { + + if (m_xPathDlg->GetClassPath() != sClassPath) + { + sClassPath = m_xPathDlg->GetClassPath(); + if ( jfw_isVMRunning() ) + { + RequestRestart( svtools::RESTART_REASON_ASSIGNING_FOLDERS ); + } + } + } + else + m_xPathDlg->SetClassPath( sClassPath ); +#else + (void) this; +#endif +} + + +IMPL_LINK_NOARG(SvxJavaOptionsPage, ResetHdl_Impl, Timer *, void) +{ + LoadJREs(); +} + + +IMPL_LINK_NOARG(SvxJavaOptionsPage, StartFolderPickerHdl, void*, void) +{ + try + { + Reference< XAsynchronousExecutableDialog > xAsyncDlg( xFolderPicker, UNO_QUERY ); + if ( xAsyncDlg.is() ) + xAsyncDlg->startExecuteModal( xDialogListener ); + else if ( xFolderPicker.is() && xFolderPicker->execute() == ExecutableDialogResults::OK ) + AddFolder( xFolderPicker->getDirectory() ); + } + catch ( Exception const & ) + { + TOOLS_WARN_EXCEPTION( "cui.options", "SvxJavaOptionsPage::StartFolderPickerHdl()" ); + } +} + +IMPL_LINK( SvxJavaOptionsPage, DialogClosedHdl, DialogClosedEvent*, pEvt, void ) +{ + if ( RET_OK == pEvt->DialogResult ) + { + DBG_ASSERT( xFolderPicker.is(), "SvxJavaOptionsPage::DialogClosedHdl(): no folder picker" ); + + AddFolder( xFolderPicker->getDirectory() ); + } +} + +IMPL_LINK_NOARG(SvxJavaOptionsPage, ExpertConfigHdl_Impl, weld::Button&, void) +{ + CuiAboutConfigTabPage aExpertConfigDlg(GetFrameWeld()); + { + weld::WaitObject aWait(GetFrameWeld()); + aExpertConfigDlg.Reset();//initialize and reset function + } + + if (RET_OK == aExpertConfigDlg.run()) + { + aExpertConfigDlg.FillItemSet();//save changes if there are any + } +} + +void SvxJavaOptionsPage::ClearJavaInfo() +{ +#if HAVE_FEATURE_JAVA + m_parJavaInfo.clear(); +#else + (void) this; +#endif +} + +void SvxJavaOptionsPage::LoadJREs() +{ +#if HAVE_FEATURE_JAVA + weld::WaitObject aWaitObj(GetFrameWeld()); + javaFrameworkError eErr = jfw_findAllJREs( &m_parJavaInfo ); + if ( JFW_E_NONE == eErr ) + { + for (auto const & pInfo: m_parJavaInfo) + { + AddJRE( pInfo.get() ); + } + } + + for (auto const & pInfo: m_aAddedInfos) + { + AddJRE( pInfo.get() ); + } + + std::unique_ptr<JavaInfo> pSelectedJava; + eErr = jfw_getSelectedJRE( &pSelectedJava ); + if ( !(JFW_E_NONE == eErr && pSelectedJava) ) + return; + + sal_Int32 i = 0; + for (auto const & pCmpInfo: m_parJavaInfo) + { + if ( jfw_areEqualJavaInfo( pCmpInfo.get(), pSelectedJava.get() ) ) + { + HandleCheckEntry(i); + UpdateJavaPathText(); + break; + } + ++i; + } +#else + (void) this; +#endif +} + + +void SvxJavaOptionsPage::AddJRE( JavaInfo const * _pInfo ) +{ +#if HAVE_FEATURE_JAVA + int nPos = m_xJavaList->n_children(); + m_xJavaList->append(); + m_xJavaList->set_toggle(nPos, TRISTATE_FALSE); + m_xJavaList->set_text(nPos, _pInfo->sVendor, 1); + m_xJavaList->set_text(nPos, _pInfo->sVersion, 2); + + INetURLObject aLocObj(_pInfo->sLocation); + OUString sLocation = aLocObj.getFSysPath(FSysStyle::Detect); + m_xJavaList->set_id(nPos, sLocation); +#else + (void) this; + (void)_pInfo; +#endif +} + +void SvxJavaOptionsPage::HandleCheckEntry(int nCheckedRow) +{ + m_xJavaList->select(nCheckedRow); + for (int i = 0, nCount = m_xJavaList->n_children(); i < nCount; ++i) + { + // we have radio button behavior -> so uncheck the other entries + m_xJavaList->set_toggle(i, i == nCheckedRow ? TRISTATE_TRUE : TRISTATE_FALSE); + } +} + +void SvxJavaOptionsPage::UpdateJavaPathText() +{ + assert(m_xJavaList->get_selected_index() != -1); + // set installation directory info + OUString sLocation = m_xJavaList->get_selected_id(); + // tdf#80646 insert LTR mark after label + OUString sInfo = m_sInstallText + u"\u200E" + sLocation; + m_xJavaPathText->set_label(sInfo); +} + +void SvxJavaOptionsPage::AddFolder( const OUString& _rFolder ) +{ +#if HAVE_FEATURE_JAVA + bool bStartAgain = true; + std::unique_ptr<JavaInfo> pInfo; + javaFrameworkError eErr = jfw_getJavaInfoByPath( _rFolder, &pInfo ); + if ( JFW_E_NONE == eErr && pInfo ) + { + sal_Int32 nPos = 0; + bool bFound = false; + for (auto const & pCmpInfo: m_parJavaInfo) + { + if ( jfw_areEqualJavaInfo( pCmpInfo.get(), pInfo.get() ) ) + { + bFound = true; + break; + } + ++nPos; + } + + if ( !bFound ) + { + for (auto const & pCmpInfo: m_aAddedInfos) + { + if ( jfw_areEqualJavaInfo( pCmpInfo.get(), pInfo.get() ) ) + { + bFound = true; + break; + } + ++nPos; + } + } + + if ( !bFound ) + { + jfw_addJRELocation( pInfo->sLocation ); + AddJRE( pInfo.get() ); + m_aAddedInfos.push_back( std::move(pInfo) ); + nPos = m_xJavaList->n_children() - 1; + } + + HandleCheckEntry(nPos); + UpdateJavaPathText(); + bStartAgain = false; + } + else if ( JFW_E_NOT_RECOGNIZED == eErr ) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + CuiResId(RID_CUISTR_JRE_NOT_RECOGNIZED))); + xBox->run(); + } + else if ( JFW_E_FAILED_VERSION == eErr ) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + CuiResId(RID_CUISTR_JRE_FAILED_VERSION))); + xBox->run(); + } + + if ( bStartAgain ) + { + xFolderPicker->setDisplayDirectory( _rFolder ); + Application::PostUserEvent( LINK( this, SvxJavaOptionsPage, StartFolderPickerHdl ) ); + } +#else + (void) this; + (void)_rFolder; +#endif +} + +void SvxJavaOptionsPage::RequestRestart(svtools::RestartReason eReason) +{ + OfaTreeOptionsDialog* pParentDlg(static_cast<OfaTreeOptionsDialog*>(GetDialogController())); + if (pParentDlg) + pParentDlg->SetNeedsRestart(eReason); +} + +std::unique_ptr<SfxTabPage> SvxJavaOptionsPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SvxJavaOptionsPage>(pPage, pController, *rAttrSet); +} + +OUString SvxJavaOptionsPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "javapath", "selectruntime", "label12" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "javaenabled", "experimental", "macrorecording" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + OUString buttons[] = { "add", "parameters", "classpath", "expertconfig" }; + + for (const auto& btn : buttons) + { + if (const auto& pString = m_xBuilder->weld_button(btn)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxJavaOptionsPage::FillItemSet( SfxItemSet* /*rCoreSet*/ ) +{ + bool bModified = false; + + if ( m_xExperimentalCB->get_state_changed_from_saved() ) + { + std::shared_ptr< comphelper::ConfigurationChanges > xChanges( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Misc::ExperimentalMode::set( m_xExperimentalCB->get_active(), xChanges ); + xChanges->commit(); + bModified = true; + RequestRestart( svtools::RESTART_REASON_EXP_FEATURES ); + } + + if ( m_xMacroCB->get_state_changed_from_saved() ) + { + std::shared_ptr< comphelper::ConfigurationChanges > xChanges( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Misc::MacroRecorderMode::set( m_xMacroCB->get_active(), xChanges ); + xChanges->commit(); + bModified = true; + } + +#if HAVE_FEATURE_JAVA + javaFrameworkError eErr = JFW_E_NONE; + if (m_xParamDlg) + { + eErr = jfw_setVMParameters(m_xParamDlg->GetParameters()); + SAL_WARN_IF(JFW_E_NONE != eErr, "cui.options", "SvxJavaOptionsPage::FillItemSet(): error in jfw_setVMParameters"); + bModified = true; + } + + if (m_xPathDlg) + { + OUString sPath(m_xPathDlg->GetClassPath()); + if (m_xPathDlg->GetOldPath() != sPath) + { + eErr = jfw_setUserClassPath( sPath ); + SAL_WARN_IF(JFW_E_NONE != eErr, "cui.options", "SvxJavaOptionsPage::FillItemSet(): error in jfw_setUserClassPath"); + bModified = true; + } + } + + sal_uInt32 nCount = m_xJavaList->n_children(); + for (sal_uInt32 i = 0; i < nCount; ++i) + { + if (m_xJavaList->get_toggle(i) == TRISTATE_TRUE) + { + JavaInfo const * pInfo; + if ( i < m_parJavaInfo.size() ) + pInfo = m_parJavaInfo[i].get(); + else + pInfo = m_aAddedInfos[ i - m_parJavaInfo.size() ].get(); + + std::unique_ptr<JavaInfo> pSelectedJava; + eErr = jfw_getSelectedJRE( &pSelectedJava ); + if ( JFW_E_NONE == eErr || JFW_E_INVALID_SETTINGS == eErr ) + { + if (!pSelectedJava || !jfw_areEqualJavaInfo( pInfo, pSelectedJava.get() ) ) + { + if ( jfw_isVMRunning() || + ( ( pInfo->nRequirements & JFW_REQUIRE_NEEDRESTART ) == JFW_REQUIRE_NEEDRESTART ) ) + { + RequestRestart( svtools::RESTART_REASON_JAVA ); + } + + eErr = jfw_setSelectedJRE( pInfo ); + SAL_WARN_IF(JFW_E_NONE != eErr, "cui.options", "SvxJavaOptionsPage::FillItemSet(): error in jfw_setSelectedJRE"); + bModified = true; + } + } + break; + } + } + + bool bEnabled = false; + eErr = jfw_getEnabled( &bEnabled ); + DBG_ASSERT( JFW_E_NONE == eErr, + "SvxJavaOptionsPage::FillItemSet(): error in jfw_getEnabled" ); + if ( bEnabled != m_xJavaEnableCB->get_active() ) + { + eErr = jfw_setEnabled( m_xJavaEnableCB->get_active() ); + DBG_ASSERT( JFW_E_NONE == eErr, + "SvxJavaOptionsPage::FillItemSet(): error in jfw_setEnabled" ); + bModified = true; + } +#endif + + return bModified; +} + + +void SvxJavaOptionsPage::Reset( const SfxItemSet* /*rSet*/ ) +{ + ClearJavaInfo(); + m_xJavaList->clear(); + +#if HAVE_FEATURE_JAVA + bool bEnabled = false; + javaFrameworkError eErr = jfw_getEnabled( &bEnabled ); + if (eErr == JFW_E_DIRECT_MODE) + { + // direct mode disregards Java settings made here, so gray them out + m_xJavaFrame->set_sensitive(false); + // check whether a usable JRE was set + std::unique_ptr<JavaInfo> pSelectedJava; + eErr = jfw_getSelectedJRE( &pSelectedJava ); + bEnabled = (eErr == JFW_E_NONE); + } + else if ( eErr != JFW_E_NONE ) + bEnabled = false; + m_xJavaEnableCB->set_active(bEnabled); + EnableHdl_Impl(*m_xJavaEnableCB); +#else + m_xJavaEnableCB->set_active(false); + m_xJavaEnableCB->set_sensitive(false); +#endif + + m_xExperimentalCB->set_active( officecfg::Office::Common::Misc::ExperimentalMode::get() ); + m_xExperimentalCB->save_state(); + m_xMacroCB->set_active( officecfg::Office::Common::Misc::MacroRecorderMode::get() ); + m_xMacroCB->save_state(); + + m_aResetIdle.Start(); +} + + +void SvxJavaOptionsPage::FillUserData() +{ + SetUserData( OUString() ); +} + +// class SvxJavaParameterDlg --------------------------------------------- + +SvxJavaParameterDlg::SvxJavaParameterDlg(weld::Window* pParent) + : GenericDialogController(pParent, "cui/ui/javastartparametersdialog.ui", + "JavaStartParameters") + , m_xParameterEdit(m_xBuilder->weld_entry("parameterfield")) + , m_xAssignBtn(m_xBuilder->weld_button("assignbtn")) + , m_xAssignedList(m_xBuilder->weld_tree_view("assignlist")) + , m_xRemoveBtn(m_xBuilder->weld_button("removebtn")) + , m_xEditBtn(m_xBuilder->weld_button("editbtn")) +{ + m_xAssignedList->set_size_request(m_xAssignedList->get_approximate_digit_width() * 54, + m_xAssignedList->get_height_rows(6)); + m_xParameterEdit->connect_changed( LINK( this, SvxJavaParameterDlg, ModifyHdl_Impl ) ); + m_xParameterEdit->connect_activate(LINK(this, SvxJavaParameterDlg, ActivateHdl_Impl)); + m_xAssignBtn->connect_clicked( LINK( this, SvxJavaParameterDlg, AssignHdl_Impl ) ); + m_xRemoveBtn->connect_clicked( LINK( this, SvxJavaParameterDlg, RemoveHdl_Impl ) ); + m_xEditBtn->connect_clicked( LINK( this, SvxJavaParameterDlg, EditHdl_Impl ) ); + m_xAssignedList->connect_changed( LINK( this, SvxJavaParameterDlg, SelectHdl_Impl ) ); + m_xAssignedList->connect_row_activated( LINK( this, SvxJavaParameterDlg, DblClickHdl_Impl ) ); + + ModifyHdl_Impl(*m_xParameterEdit); + EnableEditButton(); + EnableRemoveButton(); +} + +SvxJavaParameterDlg::~SvxJavaParameterDlg() +{ +} + +IMPL_LINK_NOARG(SvxJavaParameterDlg, ModifyHdl_Impl, weld::Entry&, void) +{ + OUString sParam = comphelper::string::strip(m_xParameterEdit->get_text(), ' '); + m_xAssignBtn->set_sensitive(!sParam.isEmpty()); +} + +IMPL_LINK_NOARG(SvxJavaParameterDlg, AssignHdl_Impl, weld::Button&, void) +{ + OUString sParam = comphelper::string::strip(m_xParameterEdit->get_text(), ' '); + if (sParam.isEmpty()) + return; + + int nPos = m_xAssignedList->find_text(sParam); + if (nPos == -1) + { + m_xAssignedList->append_text(sParam); + m_xAssignedList->select(m_xAssignedList->n_children() - 1); + } + else + m_xAssignedList->select(nPos); + m_xParameterEdit->set_text(OUString()); + ModifyHdl_Impl(*m_xParameterEdit); + EnableEditButton(); + EnableRemoveButton(); +} + +IMPL_LINK_NOARG(SvxJavaParameterDlg, ActivateHdl_Impl, weld::Entry&, bool) +{ + if (m_xAssignBtn->get_sensitive()) + { + AssignHdl_Impl(*m_xAssignBtn); + return true; + } + return false; +} + +IMPL_LINK_NOARG(SvxJavaParameterDlg, EditHdl_Impl, weld::Button&, void) +{ + EditParameter(); +} + +IMPL_LINK_NOARG(SvxJavaParameterDlg, SelectHdl_Impl, weld::TreeView&, void) +{ + EnableEditButton(); + EnableRemoveButton(); +} + +IMPL_LINK_NOARG(SvxJavaParameterDlg, DblClickHdl_Impl, weld::TreeView&, bool) +{ + EditParameter(); + return true; +} + +IMPL_LINK_NOARG(SvxJavaParameterDlg, RemoveHdl_Impl, weld::Button&, void) +{ + int nPos = m_xAssignedList->get_selected_index(); + if (nPos != -1) + { + m_xAssignedList->remove(nPos); + int nCount = m_xAssignedList->n_children(); + if (nCount) + { + if (nPos >= nCount) + nPos = nCount - 1; + m_xAssignedList->select(nPos); + } + else + { + DisableEditButton(); + } + } + EnableRemoveButton(); +} + +void SvxJavaParameterDlg::EditParameter() +{ + int nPos = m_xAssignedList->get_selected_index(); + m_xParameterEdit->set_text(OUString()); + + if (nPos == -1) + return; + + InputDialog aParamEditDlg(m_xDialog.get(), CuiResId(RID_CUISTR_JAVA_START_PARAM)); + OUString editableClassPath = m_xAssignedList->get_selected_text(); + aParamEditDlg.SetEntryText(editableClassPath); + aParamEditDlg.HideHelpBtn(); + + if (!aParamEditDlg.run()) + return; + OUString editedClassPath = comphelper::string::strip(aParamEditDlg.GetEntryText(), ' '); + + if ( !editedClassPath.isEmpty() && editableClassPath != editedClassPath ) + { + m_xAssignedList->remove(nPos); + m_xAssignedList->insert_text(nPos, editedClassPath); + m_xAssignedList->select(nPos); + } +} + +short SvxJavaParameterDlg::run() +{ + m_xParameterEdit->grab_focus(); + m_xAssignedList->select(-1); + return GenericDialogController::run(); +} + +std::vector< OUString > SvxJavaParameterDlg::GetParameters() const +{ + int nCount = m_xAssignedList->n_children(); + std::vector< OUString > aParamList; + aParamList.reserve(nCount); + for (int i = 0; i < nCount; ++i) + aParamList.push_back(m_xAssignedList->get_text(i)); + return aParamList; +} + +void SvxJavaParameterDlg::DisableButtons() +{ + DisableAssignButton(); + DisableEditButton(); + DisableRemoveButton(); +} + +void SvxJavaParameterDlg::SetParameters( std::vector< OUString > const & rParams ) +{ + m_xAssignedList->clear(); + for (auto const & sParam: rParams) + { + m_xAssignedList->append_text(sParam); + } + DisableEditButton(); + DisableRemoveButton(); +} + + +// class SvxJavaClassPathDlg --------------------------------------------- + +SvxJavaClassPathDlg::SvxJavaClassPathDlg(weld::Window* pParent) + : GenericDialogController(pParent, "cui/ui/javaclasspathdialog.ui", "JavaClassPath") + , m_xPathList(m_xBuilder->weld_tree_view("paths")) + , m_xAddArchiveBtn(m_xBuilder->weld_button("archive")) + , m_xAddPathBtn(m_xBuilder->weld_button("folder")) + , m_xRemoveBtn(m_xBuilder->weld_button("remove")) +{ + m_xPathList->set_size_request(m_xPathList->get_approximate_digit_width() * 54, + m_xPathList->get_height_rows(8)); + m_xAddArchiveBtn->connect_clicked( LINK( this, SvxJavaClassPathDlg, AddArchiveHdl_Impl ) ); + m_xAddPathBtn->connect_clicked( LINK( this, SvxJavaClassPathDlg, AddPathHdl_Impl ) ); + m_xRemoveBtn->connect_clicked( LINK( this, SvxJavaClassPathDlg, RemoveHdl_Impl ) ); + m_xPathList->connect_changed( LINK( this, SvxJavaClassPathDlg, SelectHdl_Impl ) ); + + // set initial focus to path list + m_xPathList->grab_focus(); +} + +SvxJavaClassPathDlg::~SvxJavaClassPathDlg() +{ +} + +IMPL_LINK_NOARG(SvxJavaClassPathDlg, AddArchiveHdl_Impl, weld::Button&, void) +{ + sfx2::FileDialogHelper aDlg(TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, m_xDialog.get()); + aDlg.SetTitle( CuiResId( RID_CUISTR_ARCHIVE_TITLE ) ); + aDlg.AddFilter( CuiResId( RID_CUISTR_ARCHIVE_HEADLINE ), "*.jar;*.zip" ); + aDlg.SetContext(sfx2::FileDialogHelper::JavaClassPath); + OUString sFolder; + if (m_xPathList->count_selected_rows() > 0) + { + osl::FileBase::getFileURLFromSystemPath(m_xPathList->get_selected_text(), sFolder); + // best effort + } + if (!sFolder.isEmpty()) + aDlg.SetDisplayDirectory( sFolder ); + if ( aDlg.Execute() == ERRCODE_NONE ) + { + OUString sURL = aDlg.GetPath(); + OUString sFile; + if (osl::FileBase::getSystemPathFromFileURL(sURL, sFile) == osl::FileBase::E_None) + { + INetURLObject aURL( sURL ); + if ( !IsPathDuplicate( sFile ) ) + { + m_xPathList->append("", sFile, SvFileInformationManager::GetImageId(aURL)); + m_xPathList->select(m_xPathList->n_children() - 1); + } + else + { + OUString sMsg( CuiResId( RID_CUISTR_MULTIFILE_DBL_ERR ) ); + sMsg = sMsg.replaceFirst( "%1", sFile ); + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, sMsg)); + xBox->run(); + } + } + else + { + OUString sMsg( CuiResId( RID_CUISTR_CANNOTCONVERTURL_ERR ) ); + sMsg = sMsg.replaceFirst( "%1", sURL ); + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, sMsg)); + xBox->run(); + } + } + EnableRemoveButton(); +} + +IMPL_LINK_NOARG(SvxJavaClassPathDlg, AddPathHdl_Impl, weld::Button&, void) +{ + Reference < XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference < XFolderPicker2 > xFolderPicker = sfx2::createFolderPicker(xContext, m_xDialog.get()); + + OUString sOldFolder; + if (m_xPathList->count_selected_rows() > 0) + { + osl::FileBase::getFileURLFromSystemPath(m_xPathList->get_selected_text(), sOldFolder); + // best effort + } + if (sOldFolder.isEmpty()) + sOldFolder = SvtPathOptions().GetWorkPath(); + xFolderPicker->setDisplayDirectory( sOldFolder ); + if ( xFolderPicker->execute() == ExecutableDialogResults::OK ) + { + OUString sFolderURL( xFolderPicker->getDirectory() ); + INetURLObject aURL( sFolderURL ); + OUString sNewFolder; + if (osl::FileBase::getSystemPathFromFileURL(sFolderURL, sNewFolder) + == osl::FileBase::E_None) + { + if ( !IsPathDuplicate( sNewFolder ) ) + { + m_xPathList->append("", sNewFolder, SvFileInformationManager::GetImageId(aURL)); + m_xPathList->select(m_xPathList->n_children() - 1); + } + else + { + OUString sMsg( CuiResId( RID_CUISTR_MULTIFILE_DBL_ERR ) ); + sMsg = sMsg.replaceFirst( "%1", sNewFolder ); + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, sMsg)); + xBox->run(); + } + } + else + { + OUString sMsg( CuiResId( RID_CUISTR_CANNOTCONVERTURL_ERR ) ); + sMsg = sMsg.replaceFirst( "%1", sFolderURL ); + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, sMsg)); + xBox->run(); + } + } + EnableRemoveButton(); +} + +IMPL_LINK_NOARG(SvxJavaClassPathDlg, RemoveHdl_Impl, weld::Button&, void) +{ + int nPos = m_xPathList->get_selected_index(); + if (nPos != -1) + { + m_xPathList->remove(nPos); + int nCount = m_xPathList->n_children(); + if (nCount) + { + if (nPos >= nCount) + nPos = nCount - 1; + m_xPathList->select( nPos ); + } + } + + EnableRemoveButton(); +} + +IMPL_LINK_NOARG(SvxJavaClassPathDlg, SelectHdl_Impl, weld::TreeView&, void) +{ + EnableRemoveButton(); +} + +bool SvxJavaClassPathDlg::IsPathDuplicate( std::u16string_view _rPath ) +{ + bool bRet = false; + int nCount = m_xPathList->n_children(); + for (int i = 0; i < nCount; ++i) + { + if ( m_xPathList->get_text(i) == _rPath ) + { + bRet = true; + break; + } + } + + return bRet; +} + +OUString SvxJavaClassPathDlg::GetClassPath() const +{ + OUStringBuffer sPath; + int nCount = m_xPathList->n_children(); + for (int i = 0; i < nCount; ++i) + { + if (!sPath.isEmpty()) + sPath.append(CLASSPATH_DELIMITER); + sPath.append(m_xPathList->get_text(i)); + } + return sPath.makeStringAndClear(); +} + +#if HAVE_FEATURE_JAVA +void SvxJavaClassPathDlg::SetClassPath( const OUString& _rPath ) +{ + if ( m_sOldPath.isEmpty() ) + m_sOldPath = _rPath; + m_xPathList->clear(); + if (!_rPath.isEmpty()) + { + std::vector paths = jfw_convertUserPathList(_rPath); + for (auto const& path : paths) + { + OUString sURL; + if (path.startsWith("$")) + { + sURL = path; + rtl::Bootstrap::expandMacros(sURL); + } + else + { + osl::FileBase::getFileURLFromSystemPath(path, sURL); + } + INetURLObject aURL( sURL ); + m_xPathList->append("", path, SvFileInformationManager::GetImageId(aURL)); + } + // select first entry + m_xPathList->select(0); + } + SelectHdl_Impl(*m_xPathList); +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optjava.hxx b/cui/source/options/optjava.hxx new file mode 100644 index 0000000000..84422c9030 --- /dev/null +++ b/cui/source/options/optjava.hxx @@ -0,0 +1,212 @@ +/* -*- 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 . + */ + +#pragma once + +#include <config_java.h> + +#include <memory> +#include <vector> +#include <vcl/timer.hxx> +#include <vcl/idle.hxx> +#include <vcl/weld.hxx> +#include <sfx2/tabdlg.hxx> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> +#include <svtools/dialogclosedlistener.hxx> +#include <svtools/restartdialog.hxx> + +// forward --------------------------------------------------------------- + +#if HAVE_FEATURE_JAVA +struct JavaInfo; +#else +typedef void* JavaInfo; +#endif + +class SvxJavaParameterDlg; +class SvxJavaClassPathDlg; +class SvxJavaListBox; +class OfaTreeOptionsDialog; + +// class SvxJavaOptionsPage ---------------------------------------------- + +class SvxJavaOptionsPage : public SfxTabPage +{ +private: +#if HAVE_FEATURE_JAVA + std::vector<std::unique_ptr<JavaInfo>> m_parJavaInfo; + std::vector<OUString> m_parParameters; + OUString m_pClassPath; +#endif + OUString m_sInstallText; + OUString m_sAddDialogText; + Idle m_aResetIdle; + + std::vector<std::unique_ptr<JavaInfo>> m_aAddedInfos; + + rtl::Reference< ::svt::DialogClosedListener > xDialogListener; + css::uno::Reference< css::ui::dialogs::XFolderPicker2 > xFolderPicker; + + std::unique_ptr<weld::CheckButton> m_xJavaEnableCB; + std::unique_ptr<weld::TreeView> m_xJavaList; + std::unique_ptr<weld::Label> m_xJavaPathText; + std::unique_ptr<weld::Button> m_xAddBtn; + std::unique_ptr<weld::Button> m_xParameterBtn; + std::unique_ptr<weld::Button> m_xClassPathBtn; + std::unique_ptr<weld::Button> m_xExpertConfigBtn; + + std::unique_ptr<SvxJavaParameterDlg> m_xParamDlg; + std::unique_ptr<SvxJavaClassPathDlg> m_xPathDlg; + + std::unique_ptr<weld::CheckButton> m_xExperimentalCB; + std::unique_ptr<weld::Widget> m_xExperimentalImg; + std::unique_ptr<weld::CheckButton> m_xMacroCB; + std::unique_ptr<weld::Widget> m_xMacroImg; + + std::unique_ptr<weld::Label> m_xAddDialogText; + + std::unique_ptr<weld::Widget> m_xJavaFrame; + + DECL_LINK(EnableHdl_Impl, weld::Toggleable&, void); + DECL_LINK(CheckHdl_Impl, const weld::TreeView::iter_col&, void); + DECL_LINK(SelectHdl_Impl, weld::TreeView&, void); + DECL_LINK(AddHdl_Impl, weld::Button&, void); + DECL_LINK(ParameterHdl_Impl, weld::Button&, void); + DECL_LINK(ClassPathHdl_Impl, weld::Button&, void); + DECL_LINK(ResetHdl_Impl, Timer *, void); + + DECL_LINK(StartFolderPickerHdl, void *, void); + DECL_LINK(DialogClosedHdl, css::ui::dialogs::DialogClosedEvent*, void); + + DECL_LINK(ExpertConfigHdl_Impl, weld::Button&, void); + + void ClearJavaInfo(); + void LoadJREs(); + void AddJRE( JavaInfo const * _pInfo ); + void HandleCheckEntry(int nCheckedRow); + void UpdateJavaPathText(); + void AddFolder( const OUString& _rFolder ); + void RequestRestart( svtools::RestartReason eReason ); + +public: + SvxJavaOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~SvxJavaOptionsPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + virtual void FillUserData() override; +}; + +// class SvxJavaParameterDlg --------------------------------------------- + +class SvxJavaParameterDlg : public weld::GenericDialogController +{ +private: + std::unique_ptr<weld::Entry> m_xParameterEdit; + std::unique_ptr<weld::Button> m_xAssignBtn; + std::unique_ptr<weld::TreeView> m_xAssignedList; + std::unique_ptr<weld::Button> m_xRemoveBtn; + std::unique_ptr<weld::Button> m_xEditBtn; + + DECL_LINK(ModifyHdl_Impl, weld::Entry&, void); + DECL_LINK(ActivateHdl_Impl, weld::Entry&, bool); + DECL_LINK(AssignHdl_Impl, weld::Button&, void); + DECL_LINK(SelectHdl_Impl, weld::TreeView&, void); + DECL_LINK(DblClickHdl_Impl, weld::TreeView&, bool); + DECL_LINK(RemoveHdl_Impl, weld::Button&, void); + DECL_LINK(EditHdl_Impl, weld::Button&, void); + + void EnableRemoveButton() + { + m_xRemoveBtn->set_sensitive(m_xAssignedList->get_selected_index() != -1); + } + + void EnableEditButton() + { + m_xEditBtn->set_sensitive(m_xAssignedList->get_selected_index() != -1); + } + + void DisableAssignButton() + { + m_xAssignBtn->set_sensitive(false); + } + + void DisableRemoveButton() + { + m_xRemoveBtn->set_sensitive(false); + } + + void DisableEditButton() + { + m_xEditBtn->set_sensitive(false); + } + +public: + explicit SvxJavaParameterDlg(weld::Window* pParent); + virtual ~SvxJavaParameterDlg() override; + + virtual short run() override; + + std::vector< OUString > GetParameters() const; + void SetParameters( std::vector< OUString > const & rParams ); + void DisableButtons(); + void EditParameter(); +}; + +// class SvxJavaClassPathDlg --------------------------------------------- + +class SvxJavaClassPathDlg : public weld::GenericDialogController +{ +private: + std::unique_ptr<weld::TreeView> m_xPathList; + std::unique_ptr<weld::Button> m_xAddArchiveBtn; + std::unique_ptr<weld::Button> m_xAddPathBtn; + std::unique_ptr<weld::Button> m_xRemoveBtn; + + OUString m_sOldPath; + + DECL_LINK(AddArchiveHdl_Impl, weld::Button&, void); + DECL_LINK(AddPathHdl_Impl, weld::Button&, void); + DECL_LINK(RemoveHdl_Impl, weld::Button&, void); + DECL_LINK(SelectHdl_Impl, weld::TreeView&, void); + + bool IsPathDuplicate(std::u16string_view _rPath); + void EnableRemoveButton() + { + m_xRemoveBtn->set_sensitive(m_xPathList->get_selected_index() != -1); + } + +public: + explicit SvxJavaClassPathDlg(weld::Window* pParent); + virtual ~SvxJavaClassPathDlg() override; + + const OUString& GetOldPath() const { return m_sOldPath; } + void SetFocus() { m_xPathList->grab_focus(); } + + OUString GetClassPath() const; +#if HAVE_FEATURE_JAVA + void SetClassPath( const OUString& _rPath ); +#endif +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optjsearch.cxx b/cui/source/options/optjsearch.cxx new file mode 100644 index 0000000000..3f83d602ce --- /dev/null +++ b/cui/source/options/optjsearch.cxx @@ -0,0 +1,397 @@ +/* -*- 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 <tools/debug.hxx> +#include <unotools/searchopt.hxx> +#include <i18nutil/transliteration.hxx> +#include "optjsearch.hxx" + +using namespace com::sun::star::i18n; + + +SvxJSearchOptionsPage::SvxJSearchOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optjsearchpage.ui", "OptJSearchPage", &rSet) + , m_xMatchCase(m_xBuilder->weld_check_button("matchcase")) + , m_xMatchFullHalfWidth(m_xBuilder->weld_check_button("matchfullhalfwidth")) + , m_xMatchHiraganaKatakana(m_xBuilder->weld_check_button("matchhiraganakatakana")) + , m_xMatchContractions(m_xBuilder->weld_check_button("matchcontractions")) + , m_xMatchMinusDashChoon(m_xBuilder->weld_check_button("matchminusdashchoon")) + , m_xMatchRepeatCharMarks(m_xBuilder->weld_check_button("matchrepeatcharmarks")) + , m_xMatchVariantFormKanji(m_xBuilder->weld_check_button("matchvariantformkanji")) + , m_xMatchOldKanaForms(m_xBuilder->weld_check_button("matcholdkanaforms")) + , m_xMatchDiziDuzu(m_xBuilder->weld_check_button("matchdiziduzu")) + , m_xMatchBavaHafa(m_xBuilder->weld_check_button("matchbavahafa")) + , m_xMatchTsithichiDhizi(m_xBuilder->weld_check_button("matchtsithichidhizi")) + , m_xMatchHyuiyuByuvyu(m_xBuilder->weld_check_button("matchhyuiyubyuvyu")) + , m_xMatchSesheZeje(m_xBuilder->weld_check_button("matchseshezeje")) + , m_xMatchIaiya(m_xBuilder->weld_check_button("matchiaiya")) + , m_xMatchKiku(m_xBuilder->weld_check_button("matchkiku")) + , m_xMatchProlongedSoundMark(m_xBuilder->weld_check_button("matchprolongedsoundmark")) + , m_xIgnorePunctuation(m_xBuilder->weld_check_button("ignorepunctuation")) + , m_xIgnoreWhitespace(m_xBuilder->weld_check_button("ignorewhitespace")) + , m_xIgnoreMiddleDot(m_xBuilder->weld_check_button("ignoremiddledot")) + , nTransliterationFlags(TransliterationFlags::NONE) + , bSaveOptions(true) +{ +} + +SvxJSearchOptionsPage::~SvxJSearchOptionsPage() +{ +} + +std::unique_ptr<SfxTabPage> SvxJSearchOptionsPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SvxJSearchOptionsPage>(pPage, pController, *rSet); +} + +void SvxJSearchOptionsPage::SetTransliterationFlags( TransliterationFlags nSettings ) +{ + bool bVal(nSettings & TransliterationFlags::IGNORE_CASE); + m_xMatchCase ->set_active( bVal ); //! treat as equal uppercase/lowercase + bVal = bool(nSettings & TransliterationFlags::IGNORE_WIDTH); + m_xMatchFullHalfWidth ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::IGNORE_KANA); + m_xMatchHiraganaKatakana ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreSize_ja_JP); + m_xMatchContractions ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreMinusSign_ja_JP); + m_xMatchMinusDashChoon ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreIterationMark_ja_JP); + m_xMatchRepeatCharMarks ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreTraditionalKanji_ja_JP); + m_xMatchVariantFormKanji ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreTraditionalKana_ja_JP); + m_xMatchOldKanaForms ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreZiZu_ja_JP); + m_xMatchDiziDuzu ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreBaFa_ja_JP); + m_xMatchBavaHafa ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreTiJi_ja_JP); + m_xMatchTsithichiDhizi ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreHyuByu_ja_JP); + m_xMatchHyuiyuByuvyu ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreSeZe_ja_JP); + m_xMatchSesheZeje ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreIandEfollowedByYa_ja_JP); + m_xMatchIaiya ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreKiKuFollowedBySa_ja_JP); + m_xMatchKiku ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreSeparator_ja_JP); + m_xIgnorePunctuation ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreSpace_ja_JP); + m_xIgnoreWhitespace ->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreProlongedSoundMark_ja_JP); + m_xMatchProlongedSoundMark->set_active( bVal ); + bVal = bool(nSettings & TransliterationFlags::ignoreMiddleDot_ja_JP); + m_xIgnoreMiddleDot ->set_active( bVal ); + + nTransliterationFlags = nSettings; +} + +TransliterationFlags SvxJSearchOptionsPage::GetTransliterationFlags_Impl() +{ + TransliterationFlags nTmp = TransliterationFlags::NONE; + if (m_xMatchCase->get_active()) //! treat as equal uppercase/lowercase + nTmp |= TransliterationFlags::IGNORE_CASE; + if (m_xMatchFullHalfWidth->get_active()) + nTmp |= TransliterationFlags::IGNORE_WIDTH; + if (m_xMatchHiraganaKatakana->get_active()) + nTmp |= TransliterationFlags::IGNORE_KANA; + if (m_xMatchContractions->get_active()) + nTmp |= TransliterationFlags::ignoreSize_ja_JP; + if (m_xMatchMinusDashChoon->get_active()) + nTmp |= TransliterationFlags::ignoreMinusSign_ja_JP; + if (m_xMatchRepeatCharMarks->get_active()) + nTmp |= TransliterationFlags::ignoreIterationMark_ja_JP; + if (m_xMatchVariantFormKanji->get_active()) + nTmp |= TransliterationFlags::ignoreTraditionalKanji_ja_JP; + if (m_xMatchOldKanaForms->get_active()) + nTmp |= TransliterationFlags::ignoreTraditionalKana_ja_JP; + if (m_xMatchDiziDuzu->get_active()) + nTmp |= TransliterationFlags::ignoreZiZu_ja_JP; + if (m_xMatchBavaHafa->get_active()) + nTmp |= TransliterationFlags::ignoreBaFa_ja_JP; + if (m_xMatchTsithichiDhizi->get_active()) + nTmp |= TransliterationFlags::ignoreTiJi_ja_JP; + if (m_xMatchHyuiyuByuvyu->get_active()) + nTmp |= TransliterationFlags::ignoreHyuByu_ja_JP; + if (m_xMatchSesheZeje->get_active()) + nTmp |= TransliterationFlags::ignoreSeZe_ja_JP; + if (m_xMatchIaiya->get_active()) + nTmp |= TransliterationFlags::ignoreIandEfollowedByYa_ja_JP; + if (m_xMatchKiku->get_active()) + nTmp |= TransliterationFlags::ignoreKiKuFollowedBySa_ja_JP; + if (m_xIgnorePunctuation->get_active()) + nTmp |= TransliterationFlags::ignoreSeparator_ja_JP; + if (m_xIgnoreWhitespace->get_active()) + nTmp |= TransliterationFlags::ignoreSpace_ja_JP; + if (m_xMatchProlongedSoundMark->get_active()) + nTmp |= TransliterationFlags::ignoreProlongedSoundMark_ja_JP; + if (m_xIgnoreMiddleDot->get_active()) + nTmp |= TransliterationFlags::ignoreMiddleDot_ja_JP; + + nTransliterationFlags = nTmp; + return nTransliterationFlags; +} + + +void SvxJSearchOptionsPage::Reset( const SfxItemSet* ) +{ + SvtSearchOptions aOpt; + + // read settings from configuration + m_xMatchCase ->set_active(!aOpt.IsMatchCase() ); //! treat as equal uppercase/lowercase + m_xMatchFullHalfWidth ->set_active( aOpt.IsMatchFullHalfWidthForms() ); + m_xMatchHiraganaKatakana ->set_active( aOpt.IsMatchHiraganaKatakana() ); + m_xMatchContractions ->set_active( aOpt.IsMatchContractions() ); + m_xMatchMinusDashChoon ->set_active( aOpt.IsMatchMinusDashChoon() ); + m_xMatchRepeatCharMarks ->set_active( aOpt.IsMatchRepeatCharMarks() ); + m_xMatchVariantFormKanji ->set_active( aOpt.IsMatchVariantFormKanji() ); + m_xMatchOldKanaForms ->set_active( aOpt.IsMatchOldKanaForms() ); + m_xMatchDiziDuzu ->set_active( aOpt.IsMatchDiziDuzu() ); + m_xMatchBavaHafa ->set_active( aOpt.IsMatchBavaHafa() ); + m_xMatchTsithichiDhizi ->set_active( aOpt.IsMatchTsithichiDhizi() ); + m_xMatchHyuiyuByuvyu ->set_active( aOpt.IsMatchHyuiyuByuvyu() ); + m_xMatchSesheZeje ->set_active( aOpt.IsMatchSesheZeje() ); + m_xMatchIaiya ->set_active( aOpt.IsMatchIaiya() ); + m_xMatchKiku ->set_active( aOpt.IsMatchKiku() ); + m_xIgnorePunctuation ->set_active( aOpt.IsIgnorePunctuation() ); + m_xIgnoreWhitespace ->set_active( aOpt.IsIgnoreWhitespace() ); + m_xMatchProlongedSoundMark ->set_active( aOpt.IsIgnoreProlongedSoundMark() ); + m_xIgnoreMiddleDot ->set_active( aOpt.IsIgnoreMiddleDot() ); + + nTransliterationFlags = GetTransliterationFlags_Impl(); + DBG_ASSERT( nTransliterationFlags == aOpt.GetTransliterationFlags(), + "Transliteration settings different" ); + + m_xMatchCase ->save_state(); + m_xMatchFullHalfWidth ->save_state(); + m_xMatchHiraganaKatakana ->save_state(); + m_xMatchContractions ->save_state(); + m_xMatchMinusDashChoon ->save_state(); + m_xMatchRepeatCharMarks ->save_state(); + m_xMatchVariantFormKanji ->save_state(); + m_xMatchOldKanaForms ->save_state(); + m_xMatchDiziDuzu ->save_state(); + m_xMatchBavaHafa ->save_state(); + m_xMatchTsithichiDhizi ->save_state(); + m_xMatchHyuiyuByuvyu ->save_state(); + m_xMatchSesheZeje ->save_state(); + m_xMatchIaiya ->save_state(); + m_xMatchKiku ->save_state(); + m_xIgnorePunctuation ->save_state(); + m_xIgnoreWhitespace ->save_state(); + m_xMatchProlongedSoundMark ->save_state(); + m_xIgnoreMiddleDot ->save_state(); +} + +OUString SvxJSearchOptionsPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "matchcase", + "matchfullhalfwidth", + "matchhiraganakatakana", + "matchcontractions", + "matchminusdashchoon", + "matchrepeatcharmarks", + "matchvariantformkanji", + "matcholdkanaforms", + "ignorepunctuation", + "ignorewhitespace", + "matchdiziduzu", + "matchbavahafa", + "matchtsithichidhizi", + "matchhyuiyubyuvyu", + "matchseshezeje", + "matchiaiya", + "matchkiku", + "matchprolongedsoundmark", + "ignoremiddledot" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxJSearchOptionsPage::FillItemSet( SfxItemSet* ) +{ + TransliterationFlags nOldVal = nTransliterationFlags; + nTransliterationFlags = GetTransliterationFlags_Impl(); + bool bModified = nOldVal != nTransliterationFlags; + + if (!bSaveOptions) + return bModified; + + bModified = false; + SvtSearchOptions aOpt; + bool bNewVal, bChanged; + + bNewVal = m_xMatchCase->get_active(); //! treat as equal uppercase/lowercase + bChanged = m_xMatchCase->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchCase(!bNewVal ); + bModified = true; + } + bNewVal = m_xMatchFullHalfWidth->get_active(); + bChanged = m_xMatchFullHalfWidth->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchFullHalfWidthForms( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchHiraganaKatakana->get_active(); + bChanged = m_xMatchHiraganaKatakana->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchHiraganaKatakana( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchContractions->get_active(); + bChanged = m_xMatchContractions->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchContractions( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchMinusDashChoon->get_active(); + bChanged = m_xMatchMinusDashChoon->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchMinusDashChoon( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchRepeatCharMarks->get_active(); + bChanged = m_xMatchRepeatCharMarks->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchRepeatCharMarks( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchVariantFormKanji->get_active(); + bChanged = m_xMatchVariantFormKanji->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchVariantFormKanji( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchOldKanaForms->get_active(); + bChanged = m_xMatchOldKanaForms->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchOldKanaForms( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchDiziDuzu->get_active(); + bChanged = m_xMatchDiziDuzu->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchDiziDuzu( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchBavaHafa->get_active(); + bChanged = m_xMatchBavaHafa->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchBavaHafa( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchTsithichiDhizi->get_active(); + bChanged = m_xMatchTsithichiDhizi->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchTsithichiDhizi( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchHyuiyuByuvyu->get_active(); + bChanged = m_xMatchHyuiyuByuvyu->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchHyuiyuByuvyu( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchSesheZeje->get_active(); + bChanged = m_xMatchSesheZeje->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchSesheZeje( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchIaiya->get_active(); + bChanged = m_xMatchIaiya->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchIaiya( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchKiku->get_active(); + bChanged = m_xMatchKiku->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetMatchKiku( bNewVal ); + bModified = true; + } + bNewVal = m_xIgnorePunctuation->get_active(); + bChanged = m_xIgnorePunctuation->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetIgnorePunctuation( bNewVal ); + bModified = true; + } + bNewVal = m_xIgnoreWhitespace->get_active(); + bChanged = m_xIgnoreWhitespace->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetIgnoreWhitespace( bNewVal ); + bModified = true; + } + bNewVal = m_xMatchProlongedSoundMark->get_active(); + bChanged = m_xMatchProlongedSoundMark->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetIgnoreProlongedSoundMark( bNewVal ); + bModified = true; + } + bNewVal = m_xIgnoreMiddleDot->get_active(); + bChanged = m_xIgnoreMiddleDot->get_state_changed_from_saved(); + if (bChanged) + { + aOpt.SetIgnoreMiddleDot( bNewVal ); + bModified = true; + } + + if (bModified) + aOpt.Commit(); + + return bModified; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optjsearch.hxx b/cui/source/options/optjsearch.hxx new file mode 100644 index 0000000000..96b7d73f1f --- /dev/null +++ b/cui/source/options/optjsearch.hxx @@ -0,0 +1,73 @@ +/* -*- 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 . + */ + +#pragma once + +#include <i18nutil/transliteration.hxx> +#include <sfx2/tabdlg.hxx> +#include <vcl/weld.hxx> + +class SfxItemSet; + +class SvxJSearchOptionsPage : public SfxTabPage +{ +private: + std::unique_ptr<weld::CheckButton> m_xMatchCase; + std::unique_ptr<weld::CheckButton> m_xMatchFullHalfWidth; + std::unique_ptr<weld::CheckButton> m_xMatchHiraganaKatakana; + std::unique_ptr<weld::CheckButton> m_xMatchContractions; + std::unique_ptr<weld::CheckButton> m_xMatchMinusDashChoon; + std::unique_ptr<weld::CheckButton> m_xMatchRepeatCharMarks; + std::unique_ptr<weld::CheckButton> m_xMatchVariantFormKanji; + std::unique_ptr<weld::CheckButton> m_xMatchOldKanaForms; + std::unique_ptr<weld::CheckButton> m_xMatchDiziDuzu; + std::unique_ptr<weld::CheckButton> m_xMatchBavaHafa; + std::unique_ptr<weld::CheckButton> m_xMatchTsithichiDhizi; + std::unique_ptr<weld::CheckButton> m_xMatchHyuiyuByuvyu; + std::unique_ptr<weld::CheckButton> m_xMatchSesheZeje; + std::unique_ptr<weld::CheckButton> m_xMatchIaiya; + std::unique_ptr<weld::CheckButton> m_xMatchKiku; + std::unique_ptr<weld::CheckButton> m_xMatchProlongedSoundMark; + + std::unique_ptr<weld::CheckButton> m_xIgnorePunctuation; + std::unique_ptr<weld::CheckButton> m_xIgnoreWhitespace; + std::unique_ptr<weld::CheckButton> m_xIgnoreMiddleDot; + + TransliterationFlags nTransliterationFlags; + bool bSaveOptions; + + TransliterationFlags GetTransliterationFlags_Impl(); + +public: + SvxJSearchOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~SvxJSearchOptionsPage() override; + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual OUString GetAllStrings() override; + + virtual void Reset( const SfxItemSet* rSet ) override; + virtual bool FillItemSet( SfxItemSet* rSet ) override; + + void EnableSaveOptions( bool bVal ) { bSaveOptions = bVal; } + + TransliterationFlags GetTransliterationFlags() const { return nTransliterationFlags; } + void SetTransliterationFlags( TransliterationFlags nSettings ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optlanguagetool.cxx b/cui/source/options/optlanguagetool.cxx new file mode 100644 index 0000000000..8c56a40e72 --- /dev/null +++ b/cui/source/options/optlanguagetool.cxx @@ -0,0 +1,161 @@ +/* -*- 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 "optlanguagetool.hxx" +#include <officecfg/Office/Linguistic.hxx> +#include <sal/log.hxx> +#include <dialmgr.hxx> +#include <strings.hrc> + +using LanguageToolCfg = officecfg::Office::Linguistic::GrammarChecking::LanguageTool; +constexpr OUString LANGUAGETOOL_DEFAULT_URL = u"https://api.languagetool.org/v2"_ustr; + +OptLanguageToolTabPage::OptLanguageToolTabPage(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/langtoolconfigpage.ui", "OptLangToolPage", &rSet) + , m_xBaseURLED(m_xBuilder->weld_entry("baseurl")) + , m_xBaseURLImg(m_xBuilder->weld_widget("lockbaseurl")) + , m_xUsernameED(m_xBuilder->weld_entry("username")) + , m_xUsernameImg(m_xBuilder->weld_widget("lockusername")) + , m_xApiKeyED(m_xBuilder->weld_entry("apikey")) + , m_xApiKeyImg(m_xBuilder->weld_widget("lockapikey")) + , m_xRestProtocol(m_xBuilder->weld_entry("restprotocol")) + , m_xRestProtocolImg(m_xBuilder->weld_widget("lockrestprotocol")) + , m_xActivateBox(m_xBuilder->weld_check_button("activate")) + , m_xActivateBoxImg(m_xBuilder->weld_widget("lockactivate")) + , m_xSSLDisableVerificationBox(m_xBuilder->weld_check_button("verifyssl")) + , m_xSSLDisableVerificationBoxImg(m_xBuilder->weld_widget("lockverifyssl")) + , m_xApiSettingsFrame(m_xBuilder->weld_frame("apisettings")) +{ + m_xActivateBox->connect_toggled(LINK(this, OptLanguageToolTabPage, CheckHdl)); + EnableControls(LanguageToolCfg::IsEnabled::get()); + + // tdf#150494 Set default values as placeholder text + m_xBaseURLED->set_placeholder_text(CuiResId(RID_LANGUAGETOOL_LEAVE_EMPTY)); + m_xUsernameED->set_placeholder_text(CuiResId(RID_LANGUAGETOOL_LEAVE_EMPTY)); + m_xApiKeyED->set_placeholder_text(CuiResId(RID_LANGUAGETOOL_LEAVE_EMPTY)); + m_xRestProtocol->set_placeholder_text(CuiResId(RID_LANGUAGETOOL_REST_LEAVE_EMPTY)); +} + +OptLanguageToolTabPage::~OptLanguageToolTabPage() {} + +void OptLanguageToolTabPage::EnableControls(bool bEnable) +{ + if (bEnable != LanguageToolCfg::IsEnabled::get()) + { + auto batch(comphelper::ConfigurationChanges::create()); + LanguageToolCfg::IsEnabled::set(bEnable, batch); + batch->commit(); + } + m_xApiSettingsFrame->set_visible(bEnable); + m_xActivateBox->set_active(bEnable); + m_xActivateBox->set_sensitive(!LanguageToolCfg::IsEnabled::isReadOnly()); + m_xActivateBoxImg->set_visible(LanguageToolCfg::IsEnabled::isReadOnly()); + m_xSSLDisableVerificationBox->set_active(!LanguageToolCfg::SSLCertVerify::get()); + m_xSSLDisableVerificationBox->set_sensitive(!LanguageToolCfg::SSLCertVerify::isReadOnly()); + m_xSSLDisableVerificationBoxImg->set_visible(LanguageToolCfg::SSLCertVerify::isReadOnly()); +} + +IMPL_LINK_NOARG(OptLanguageToolTabPage, CheckHdl, weld::Toggleable&, void) +{ + EnableControls(m_xActivateBox->get_active()); +} + +void OptLanguageToolTabPage::Reset(const SfxItemSet*) +{ + // tdf#150494 If no URL has been set, use the default URL + OUString aBaseURL = LanguageToolCfg::BaseURL::get().value_or(""); + if (aBaseURL.isEmpty()) + m_xBaseURLED->set_text(LANGUAGETOOL_DEFAULT_URL); + else + m_xBaseURLED->set_text(aBaseURL); + + m_xBaseURLED->set_sensitive(!LanguageToolCfg::BaseURL::isReadOnly()); + m_xBaseURLImg->set_visible(LanguageToolCfg::BaseURL::isReadOnly()); + + m_xUsernameED->set_text(LanguageToolCfg::Username::get().value_or("")); + m_xUsernameED->set_sensitive(!LanguageToolCfg::Username::isReadOnly()); + m_xUsernameImg->set_visible(LanguageToolCfg::Username::isReadOnly()); + + m_xApiKeyED->set_text(LanguageToolCfg::ApiKey::get().value_or("")); + m_xApiKeyED->set_sensitive(!LanguageToolCfg::ApiKey::isReadOnly()); + m_xApiKeyImg->set_visible(LanguageToolCfg::ApiKey::isReadOnly()); + + m_xRestProtocol->set_text(LanguageToolCfg::RestProtocol::get().value_or("")); + m_xRestProtocol->set_sensitive(!LanguageToolCfg::RestProtocol::isReadOnly()); + m_xRestProtocolImg->set_visible(LanguageToolCfg::RestProtocol::isReadOnly()); + + m_xSSLDisableVerificationBox->set_active(!LanguageToolCfg::SSLCertVerify::get()); + m_xSSLDisableVerificationBox->set_sensitive(!LanguageToolCfg::SSLCertVerify::isReadOnly()); + m_xSSLDisableVerificationBoxImg->set_visible(LanguageToolCfg::SSLCertVerify::isReadOnly()); +} + +OUString OptLanguageToolTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "langtoolsettings", "disclaimer", "apisettingsheader", "base", + "urldesc", "usernamelbl", "usernamedesc", "apikeylbl", + "apikeydesc", "restlbl", "restdesc" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "activate", "verifyssl" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + if (const auto& pString = m_xBuilder->weld_link_button("policy")) + sAllStrings += pString->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool OptLanguageToolTabPage::FillItemSet(SfxItemSet*) +{ + auto batch(comphelper::ConfigurationChanges::create()); + + // tdf#150494 If no URL has been set, then save the default URL + OUString aBaseURL = m_xBaseURLED->get_text(); + if (aBaseURL.isEmpty()) + LanguageToolCfg::BaseURL::set(LANGUAGETOOL_DEFAULT_URL, batch); + else + LanguageToolCfg::BaseURL::set(aBaseURL, batch); + + LanguageToolCfg::Username::set(m_xUsernameED->get_text(), batch); + LanguageToolCfg::ApiKey::set(m_xApiKeyED->get_text(), batch); + LanguageToolCfg::RestProtocol::set(m_xRestProtocol->get_text(), batch); + LanguageToolCfg::SSLCertVerify::set(!m_xSSLDisableVerificationBox->get_active(), batch); + batch->commit(); + return false; +} + +std::unique_ptr<SfxTabPage> OptLanguageToolTabPage::Create(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<OptLanguageToolTabPage>(pPage, pController, *rAttrSet); +} diff --git a/cui/source/options/optlanguagetool.hxx b/cui/source/options/optlanguagetool.hxx new file mode 100644 index 0000000000..3e3c3e8da0 --- /dev/null +++ b/cui/source/options/optlanguagetool.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ +#pragma once +#include <sfx2/tabdlg.hxx> +#include <rtl/ustring.hxx> + +class OptLanguageToolTabPage : public SfxTabPage +{ +public: + OptLanguageToolTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet); + virtual ~OptLanguageToolTabPage() override; + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet(SfxItemSet* rSet) override; + virtual void Reset(const SfxItemSet* rSet) override; + +private: + std::unique_ptr<weld::Entry> m_xBaseURLED; + std::unique_ptr<weld::Widget> m_xBaseURLImg; + std::unique_ptr<weld::Entry> m_xUsernameED; + std::unique_ptr<weld::Widget> m_xUsernameImg; + std::unique_ptr<weld::Entry> m_xApiKeyED; + std::unique_ptr<weld::Widget> m_xApiKeyImg; + std::unique_ptr<weld::Entry> m_xRestProtocol; + std::unique_ptr<weld::Widget> m_xRestProtocolImg; + std::unique_ptr<weld::CheckButton> m_xActivateBox; + std::unique_ptr<weld::Widget> m_xActivateBoxImg; + std::unique_ptr<weld::CheckButton> m_xSSLDisableVerificationBox; + std::unique_ptr<weld::Widget> m_xSSLDisableVerificationBoxImg; + std::unique_ptr<weld::Frame> m_xApiSettingsFrame; + + void EnableControls(bool bEnable); + + DECL_LINK(CheckHdl, weld::Toggleable&, void); +}; diff --git a/cui/source/options/optlingu.cxx b/cui/source/options/optlingu.cxx new file mode 100644 index 0000000000..de908b9439 --- /dev/null +++ b/cui/source/options/optlingu.cxx @@ -0,0 +1,2070 @@ +/* -*- 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 <utility> +#include <vcl/settings.hxx> +#include <vcl/weld.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <i18nlangtag/mslangid.hxx> +#include <o3tl/safeint.hxx> +#include <officecfg/Office/Security.hxx> +#include <officecfg/Office/Linguistic.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/linguprops.hxx> +#include <editeng/unolingu.hxx> +#include <linguistic/misc.hxx> +#include <sfx2/sfxsids.hrc> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/dispatchcommand.hxx> +#include <comphelper/lok.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/linguistic2/LinguServiceManager.hpp> +#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> +#include <com/sun/star/linguistic2/XSpellChecker.hpp> +#include <com/sun/star/linguistic2/XProofreader.hpp> +#include <com/sun/star/linguistic2/XHyphenator.hpp> +#include <com/sun/star/linguistic2/XThesaurus.hpp> +#include <com/sun/star/linguistic2/XDictionary.hpp> +#include <com/sun/star/linguistic2/XDictionaryList.hpp> +#include <com/sun/star/linguistic2/XLinguProperties.hpp> +#include <com/sun/star/lang/XServiceDisplayName.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <unotools/extendedsecurityoptions.hxx> +#include <svl/eitem.hxx> +#include <vcl/svapp.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> + +#include <svx/svxdlg.hxx> +#include <editeng/optitems.hxx> +#include <optlingu.hxx> +#include <dialmgr.hxx> +#include <strings.hrc> + +#include <ucbhelper/content.hxx> + +#include <set> +#include <vector> +#include <map> + +using namespace ::ucbhelper; +using namespace ::com::sun::star; +using namespace css::lang; +using namespace css::uno; +using namespace css::linguistic2; +using namespace css::beans; + +constexpr OUString cSpell(SN_SPELLCHECKER); +constexpr OUString cGrammar(SN_GRAMMARCHECKER); +constexpr OUString cHyph(SN_HYPHENATOR); +constexpr OUString cThes(SN_THESAURUS); + +// static ---------------------------------------------------------------- + +static sal_Int32 lcl_SeqGetEntryPos( + const Sequence< OUString > &rSeq, std::u16string_view rEntry ) +{ + sal_Int32 i; + sal_Int32 nLen = rSeq.getLength(); + const OUString *pItem = rSeq.getConstArray(); + for (i = 0; i < nLen; ++i) + { + if (rEntry == pItem[i]) + break; + } + return i < nLen ? i : -1; +} + +static bool KillFile_Impl( const OUString& rURL ) +{ + bool bRet = true; + try + { + Content aCnt( rURL, uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() ); + aCnt.executeCommand( "delete", Any( true ) ); + } + catch( ... ) + { + TOOLS_WARN_EXCEPTION( "cui.options", "KillFile" ); + bRet = false; + } + + return bRet; +} + +// 0x 0p 0t 0c nn +// p: 1 -> parent +// t: 1 -> spell, 2 -> hyph, 3 -> thes, 4 -> grammar +// c: 1 -> checked 0 -> unchecked +// n: index + +#define TYPE_SPELL sal_uInt8(1) +#define TYPE_GRAMMAR sal_uInt8(2) +#define TYPE_HYPH sal_uInt8(3) +#define TYPE_THES sal_uInt8(4) + +namespace { + +class ModuleUserData_Impl +{ + bool bParent; + bool bIsChecked; + sal_uInt8 nType; + sal_uInt8 nIndex; + OUString sImplName; + +public: + ModuleUserData_Impl( OUString sImpName, bool bIsParent, bool bChecked, sal_uInt8 nSetType, sal_uInt8 nSetIndex ) : + bParent(bIsParent), + bIsChecked(bChecked), + nType(nSetType), + nIndex(nSetIndex), + sImplName(std::move(sImpName)) + { + } + bool IsParent() const {return bParent;} + sal_uInt8 GetType() const {return nType;} + bool IsChecked() const {return bIsChecked;} + sal_uInt8 GetIndex() const {return nIndex;} + const OUString& GetImplName() const {return sImplName;} + +}; + + +// User for user-dictionaries (XDictionary interface) + +class DicUserData +{ + sal_uInt32 nVal; + +public: + explicit DicUserData(sal_uInt32 nUserData) : nVal( nUserData ) {} + DicUserData( sal_uInt16 nEID, + bool bChecked, bool bEditable, bool bDeletable ); + + sal_uInt32 GetUserData() const { return nVal; } + sal_uInt16 GetEntryId() const { return static_cast<sal_uInt16>(nVal >> 16); } + bool IsChecked() const { return static_cast<bool>((nVal >> 8) & 0x01); } + bool IsDeletable() const { return static_cast<bool>((nVal >> 10) & 0x01); } +}; + +} + +DicUserData::DicUserData( + sal_uInt16 nEID, + bool bChecked, bool bEditable, bool bDeletable ) +{ + DBG_ASSERT( nEID < 65000, "Entry Id out of range" ); + nVal = (static_cast<sal_uInt32>(0xFFFF & nEID) << 16) | + (static_cast<sal_uInt32>(bChecked ? 1 : 0) << 8) | + (static_cast<sal_uInt32>(bEditable ? 1 : 0) << 9) | + (static_cast<sal_uInt32>(bDeletable ? 1 : 0) << 10); +} + +/*-------------------------------------------------- + Entry IDs for options listbox of dialog +--------------------------------------------------*/ + +namespace { + +enum EID_OPTIONS +{ + EID_SPELL_AUTO, + EID_GRAMMAR_AUTO, + EID_CAPITAL_WORDS, + EID_WORDS_WITH_DIGITS, + EID_SPELL_SPECIAL, + EID_NUM_MIN_WORDLEN, + EID_NUM_PRE_BREAK, + EID_NUM_POST_BREAK, + EID_HYPH_AUTO, + EID_HYPH_SPECIAL, + EID_SPELL_CLOSED_COMPOUND, + EID_SPELL_HYPHENATED_COMPOUND +}; + +} + +static OUString lcl_GetPropertyName( EID_OPTIONS eEntryId ) +{ + switch (eEntryId) + { + case EID_SPELL_AUTO: return UPN_IS_SPELL_AUTO; + case EID_GRAMMAR_AUTO: return UPN_IS_GRAMMAR_AUTO; + case EID_CAPITAL_WORDS: return UPN_IS_SPELL_UPPER_CASE; + case EID_SPELL_CLOSED_COMPOUND: return UPN_IS_SPELL_CLOSED_COMPOUND; + case EID_SPELL_HYPHENATED_COMPOUND: return UPN_IS_SPELL_HYPHENATED_COMPOUND; + case EID_WORDS_WITH_DIGITS: return UPN_IS_SPELL_WITH_DIGITS; + case EID_SPELL_SPECIAL: return UPN_IS_SPELL_SPECIAL; + case EID_NUM_MIN_WORDLEN: return UPN_HYPH_MIN_WORD_LENGTH; + case EID_NUM_PRE_BREAK: return UPN_HYPH_MIN_LEADING; + case EID_NUM_POST_BREAK: return UPN_HYPH_MIN_TRAILING; + case EID_HYPH_AUTO: return UPN_IS_HYPH_AUTO; + case EID_HYPH_SPECIAL: return UPN_IS_HYPH_SPECIAL; + default: assert (false); abort(); + } +} + +namespace { + +class OptionsBreakSet : public weld::GenericDialogController +{ + std::unique_ptr<weld::Widget> m_xBeforeFrame; + std::unique_ptr<weld::Widget> m_xAfterFrame; + std::unique_ptr<weld::Widget> m_xMinimalFrame; + std::unique_ptr<weld::SpinButton> m_xBreakNF; + +public: + OptionsBreakSet(weld::Window* pParent, sal_uInt16 nRID) + : GenericDialogController(pParent, "cui/ui/breaknumberoption.ui", "BreakNumberOption") + , m_xBeforeFrame(m_xBuilder->weld_widget("beforeframe")) + , m_xAfterFrame(m_xBuilder->weld_widget("afterframe")) + , m_xMinimalFrame(m_xBuilder->weld_widget("miniframe")) + { + assert(EID_NUM_PRE_BREAK == nRID || EID_NUM_POST_BREAK == nRID || EID_NUM_MIN_WORDLEN == nRID); //unexpected ID + + if (nRID == EID_NUM_PRE_BREAK) + { + m_xBeforeFrame->show(); + m_xBreakNF = m_xBuilder->weld_spin_button("beforebreak"); + } + else if(nRID == EID_NUM_POST_BREAK) + { + m_xAfterFrame->show(); + m_xBreakNF = m_xBuilder->weld_spin_button("afterbreak"); + } + else if(nRID == EID_NUM_MIN_WORDLEN) + { + m_xMinimalFrame->show(); + m_xBreakNF = m_xBuilder->weld_spin_button("wordlength"); + } + } + + weld::SpinButton& GetNumericFld() + { + return *m_xBreakNF; + } +}; + +// class OptionsUserData ------------------------------------------------- + +class OptionsUserData +{ + sal_uInt32 nVal; + +public: + explicit OptionsUserData( sal_uInt32 nUserData ) : nVal( nUserData ) {} + OptionsUserData( sal_uInt16 nEID, + bool bHasNV, sal_uInt16 nNumVal, + bool bCheckable, bool bChecked ); + + sal_uInt32 GetUserData() const { return nVal; } + sal_uInt16 GetEntryId() const { return static_cast<sal_uInt16>(nVal >> 16); } + bool HasNumericValue() const { return static_cast<bool>((nVal >> 10) & 0x01); } + sal_uInt16 GetNumericValue() const { return static_cast<sal_uInt16>(nVal & 0xFF); } + bool IsCheckable() const { return static_cast<bool>((nVal >> 9) & 0x01); } + bool IsModified() const { return static_cast<bool>((nVal >> 11) & 0x01); } + + void SetNumericValue( sal_uInt8 nNumVal ); +}; + +} + +OptionsUserData::OptionsUserData( sal_uInt16 nEID, + bool bHasNV, sal_uInt16 nNumVal, + bool bCheckable, bool bChecked ) +{ + DBG_ASSERT( nEID < 65000, "Entry Id out of range" ); + DBG_ASSERT( nNumVal < 256, "value out of range" ); + nVal = (static_cast<sal_uInt32>(0xFFFF & nEID) << 16) | + (static_cast<sal_uInt32>(bHasNV ? 1 : 0) << 10) | + (static_cast<sal_uInt32>(bCheckable ? 1 : 0) << 9) | + (static_cast<sal_uInt32>(bChecked ? 1 : 0) << 8) | + static_cast<sal_uInt32>(0xFF & nNumVal); +} + +void OptionsUserData::SetNumericValue( sal_uInt8 nNumVal ) +{ + if (HasNumericValue() && (GetNumericValue() != nNumVal)) + { + nVal &= 0xffffff00; + nVal |= nNumVal; + nVal |= sal_uInt32(1) << 11; // mark as modified + } +} + +// ServiceInfo_Impl ---------------------------------------------------- + +namespace { + +struct ServiceInfo_Impl +{ + OUString sDisplayName; + OUString sSpellImplName; + OUString sHyphImplName; + OUString sThesImplName; + OUString sGrammarImplName; + uno::Reference< XSpellChecker > xSpell; + uno::Reference< XHyphenator > xHyph; + uno::Reference< XThesaurus > xThes; + uno::Reference< XProofreader > xGrammar; + bool bConfigured; + + ServiceInfo_Impl() : bConfigured(false) {} +}; + +struct Locale_less +{ + bool operator()(const css::lang::Locale& lhs, const css::lang::Locale& rhs) const + { + if (lhs.Language < rhs.Language) + return true; + if (lhs.Language > rhs.Language) + return false; + if (lhs.Country < rhs.Country) + return true; + if (lhs.Country > rhs.Country) + return false; + return lhs.Variant < rhs.Variant; + } +}; + +} + +typedef std::vector< ServiceInfo_Impl > ServiceInfoArr; +typedef std::map< LanguageType, Sequence< OUString > > LangImplNameTable; + + +// SvxLinguData_Impl ---------------------------------------------------- + +class SvxLinguData_Impl +{ + //contains services and implementation names sorted by implementation names + ServiceInfoArr aDisplayServiceArr; + sal_uInt32 nDisplayServices; + + std::set<Locale, Locale_less> aAllServiceLocales; + LangImplNameTable aCfgSpellTable; + LangImplNameTable aCfgHyphTable; + LangImplNameTable aCfgThesTable; + LangImplNameTable aCfgGrammarTable; + uno::Reference< XLinguServiceManager2 > xLinguSrvcMgr; + + + static bool AddRemove( Sequence< OUString > &rConfigured, + const OUString &rImplName, bool bAdd ); + +public: + SvxLinguData_Impl(); + + uno::Reference<XLinguServiceManager2> & GetManager() { return xLinguSrvcMgr; } + + void SetChecked( const Sequence< OUString > &rConfiguredServices ); + void Reconfigure( std::u16string_view rDisplayName, bool bEnable ); + + const auto& GetAllSupportedLocales() const { return aAllServiceLocales; } + + LangImplNameTable & GetSpellTable() { return aCfgSpellTable; } + LangImplNameTable & GetHyphTable() { return aCfgHyphTable; } + LangImplNameTable & GetThesTable() { return aCfgThesTable; } + LangImplNameTable & GetGrammarTable() { return aCfgGrammarTable; } + + ServiceInfoArr & GetDisplayServiceArray() { return aDisplayServiceArr; } + + const sal_uInt32 & GetDisplayServiceCount() const { return nDisplayServices; } + void SetDisplayServiceCount( sal_uInt32 nVal ) { nDisplayServices = nVal; } + + // returns the list of service implementation names for the specified + // language and service (TYPE_SPELL, TYPE_HYPH, TYPE_THES) sorted in + // the proper order for the SvxEditModulesDlg (the ones from the + // configuration (keeping that order!) first and then the other ones. + // I.e. the ones available but not configured in arbitrary order). + // They available ones may contain names that do not(!) support that + // language. + Sequence< OUString > GetSortedImplNames( LanguageType nLang, sal_uInt8 nType ); + + ServiceInfo_Impl * GetInfoByImplName( std::u16string_view rSvcImplName ); +}; + + +static sal_Int32 lcl_SeqGetIndex( const Sequence< OUString > &rSeq, std::u16string_view rTxt ) +{ + sal_Int32 nRes = -1; + sal_Int32 nLen = rSeq.getLength(); + const OUString *pString = rSeq.getConstArray(); + for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i) + { + if (pString[i] == rTxt) + nRes = i; + } + return nRes; +} + + +Sequence< OUString > SvxLinguData_Impl::GetSortedImplNames( LanguageType nLang, sal_uInt8 nType ) +{ + LangImplNameTable *pTable = nullptr; + switch (nType) + { + case TYPE_SPELL : pTable = &aCfgSpellTable; break; + case TYPE_HYPH : pTable = &aCfgHyphTable; break; + case TYPE_THES : pTable = &aCfgThesTable; break; + case TYPE_GRAMMAR : pTable = &aCfgGrammarTable; break; + } + Sequence< OUString > aRes; + if (!pTable) + { + SAL_WARN( "cui.options", "unknown linguistic type" ); + return aRes; + } + if (pTable->count( nLang )) + aRes = (*pTable)[ nLang ]; // add configured services + sal_Int32 nIdx = aRes.getLength(); + DBG_ASSERT( nDisplayServices >= o3tl::make_unsigned(nIdx), "size mismatch" ); + aRes.realloc( nDisplayServices ); + OUString *pRes = aRes.getArray(); + + // add not configured services + for (sal_uInt32 i = 0; i < nDisplayServices; ++i) + { + const ServiceInfo_Impl &rInfo = aDisplayServiceArr[ i ]; + OUString aImplName; + switch (nType) + { + case TYPE_SPELL : aImplName = rInfo.sSpellImplName; break; + case TYPE_HYPH : aImplName = rInfo.sHyphImplName; break; + case TYPE_THES : aImplName = rInfo.sThesImplName; break; + case TYPE_GRAMMAR : aImplName = rInfo.sGrammarImplName; break; + } + + if (!aImplName.isEmpty() && (lcl_SeqGetIndex( aRes, aImplName) == -1)) // name not yet added + { + DBG_ASSERT( nIdx < aRes.getLength(), "index out of range" ); + if (nIdx < aRes.getLength()) + pRes[ nIdx++ ] = aImplName; + } + } + // don't forget to put aRes back to its actual size just in case you allocated too much + // since all of the names may have already been added + // otherwise you get duplicate entries in the edit dialog + aRes.realloc( nIdx ); + return aRes; +} + + +ServiceInfo_Impl * SvxLinguData_Impl::GetInfoByImplName( std::u16string_view rSvcImplName ) +{ + for (sal_uInt32 i = 0; i < nDisplayServices; ++i) + { + ServiceInfo_Impl &rTmp = aDisplayServiceArr[ i ]; + if (rTmp.sSpellImplName == rSvcImplName || + rTmp.sHyphImplName == rSvcImplName || + rTmp.sThesImplName == rSvcImplName || + rTmp.sGrammarImplName == rSvcImplName) + { + return &rTmp; + } + } + return nullptr; +} + +static void lcl_MergeDisplayArray( + SvxLinguData_Impl &rData, + const ServiceInfo_Impl &rToAdd ) +{ + sal_uInt32 nCnt = 0; + + ServiceInfoArr &rSvcInfoArr = rData.GetDisplayServiceArray(); + sal_uInt32 nEntries = rData.GetDisplayServiceCount(); + + for (sal_uInt32 i = 0; i < nEntries; ++i) + { + ServiceInfo_Impl& rEntry = rSvcInfoArr[i]; + if (rEntry.sDisplayName == rToAdd.sDisplayName) + { + if(rToAdd.xSpell.is()) + { + DBG_ASSERT( !rEntry.xSpell.is() && + rEntry.sSpellImplName.isEmpty(), + "merge conflict" ); + rEntry.sSpellImplName = rToAdd.sSpellImplName; + rEntry.xSpell = rToAdd.xSpell; + } + if(rToAdd.xGrammar.is()) + { + DBG_ASSERT( !rEntry.xGrammar.is() && + rEntry.sGrammarImplName.isEmpty(), + "merge conflict" ); + rEntry.sGrammarImplName = rToAdd.sGrammarImplName; + rEntry.xGrammar = rToAdd.xGrammar; + } + if(rToAdd.xHyph.is()) + { + DBG_ASSERT( !rEntry.xHyph.is() && + rEntry.sHyphImplName.isEmpty(), + "merge conflict" ); + rEntry.sHyphImplName = rToAdd.sHyphImplName; + rEntry.xHyph = rToAdd.xHyph; + } + if(rToAdd.xThes.is()) + { + DBG_ASSERT( !rEntry.xThes.is() && + rEntry.sThesImplName.isEmpty(), + "merge conflict" ); + rEntry.sThesImplName = rToAdd.sThesImplName; + rEntry.xThes = rToAdd.xThes; + } + return ; + } + ++nCnt; + } + rData.GetDisplayServiceArray().push_back( rToAdd ); + rData.SetDisplayServiceCount( nCnt + 1 ); +} + +SvxLinguData_Impl::SvxLinguData_Impl() : + nDisplayServices (0) +{ + uno::Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + xLinguSrvcMgr = LinguServiceManager::create(xContext); + + const Locale& rCurrentLocale = Application::GetSettings().GetUILanguageTag().getLocale(); + Sequence<Any> aArgs + { + Any(LinguMgr::GetLinguPropertySet()), + Any() // second argument has to be empty! + }; + + //read spell checker + const Sequence< OUString > aSpellNames = xLinguSrvcMgr->getAvailableServices( + cSpell, Locale() ); + + for(const OUString& spellName : aSpellNames) + { + ServiceInfo_Impl aInfo; + aInfo.sSpellImplName = spellName; + aInfo.xSpell.set( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sSpellImplName, aArgs, xContext), UNO_QUERY); + + uno::Reference<XServiceDisplayName> xDispName(aInfo.xSpell, UNO_QUERY); + if(xDispName.is()) + aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale ); + + const Sequence< Locale > aLocales( aInfo.xSpell->getLocales() ); + //! suppress display of entries with no supported languages (see feature 110994) + if (aLocales.hasElements()) + { + aAllServiceLocales.insert(aLocales.begin(), aLocales.end()); + lcl_MergeDisplayArray( *this, aInfo ); + } + } + + //read grammar checker + const Sequence< OUString > aGrammarNames = xLinguSrvcMgr->getAvailableServices( + cGrammar, Locale() ); + for(const OUString& grammarName : aGrammarNames) + { + ServiceInfo_Impl aInfo; + aInfo.sGrammarImplName = grammarName; + aInfo.xGrammar.set( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sGrammarImplName, aArgs, xContext), UNO_QUERY); + + uno::Reference<XServiceDisplayName> xDispName(aInfo.xGrammar, UNO_QUERY); + if(xDispName.is()) + aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale ); + + const Sequence< Locale > aLocales( aInfo.xGrammar->getLocales() ); + //! suppress display of entries with no supported languages (see feature 110994) + if (aLocales.hasElements()) + { + aAllServiceLocales.insert(aLocales.begin(), aLocales.end()); + lcl_MergeDisplayArray( *this, aInfo ); + } + } + + //read hyphenator + const Sequence< OUString > aHyphNames = xLinguSrvcMgr->getAvailableServices( + cHyph, Locale() ); + for(const OUString& hyphName : aHyphNames) + { + ServiceInfo_Impl aInfo; + aInfo.sHyphImplName = hyphName; + aInfo.xHyph.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sHyphImplName, aArgs, xContext), UNO_QUERY); + + uno::Reference<XServiceDisplayName> xDispName(aInfo.xHyph, UNO_QUERY); + if(xDispName.is()) + aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale ); + + const Sequence< Locale > aLocales( aInfo.xHyph->getLocales() ); + //! suppress display of entries with no supported languages (see feature 110994) + if (aLocales.hasElements()) + { + aAllServiceLocales.insert(aLocales.begin(), aLocales.end()); + lcl_MergeDisplayArray( *this, aInfo ); + } + } + + //read thesauri + const Sequence< OUString > aThesNames = xLinguSrvcMgr->getAvailableServices( + cThes, Locale() ); + for(const OUString& thesName : aThesNames) + { + ServiceInfo_Impl aInfo; + aInfo.sThesImplName = thesName; + aInfo.xThes.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sThesImplName, aArgs, xContext), UNO_QUERY); + + uno::Reference<XServiceDisplayName> xDispName(aInfo.xThes, UNO_QUERY); + if(xDispName.is()) + aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale ); + + const Sequence< Locale > aLocales( aInfo.xThes->getLocales() ); + //! suppress display of entries with no supported languages (see feature 110994) + if (aLocales.hasElements()) + { + aAllServiceLocales.insert(aLocales.begin(), aLocales.end()); + lcl_MergeDisplayArray( *this, aInfo ); + } + } + + Sequence< OUString > aCfgSvcs; + for(auto const & locale : std::as_const(aAllServiceLocales)) + { + LanguageType nLang = LanguageTag::convertToLanguageType( locale ); + + aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cSpell, locale); + SetChecked( aCfgSvcs ); + if (aCfgSvcs.hasElements()) + aCfgSpellTable[ nLang ] = aCfgSvcs; + + aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cGrammar, locale); + SetChecked( aCfgSvcs ); + if (aCfgSvcs.hasElements()) + aCfgGrammarTable[ nLang ] = aCfgSvcs; + + aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cHyph, locale); + SetChecked( aCfgSvcs ); + if (aCfgSvcs.hasElements()) + aCfgHyphTable[ nLang ] = aCfgSvcs; + + aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cThes, locale); + SetChecked( aCfgSvcs ); + if (aCfgSvcs.hasElements()) + aCfgThesTable[ nLang ] = aCfgSvcs; + } +} + +void SvxLinguData_Impl::SetChecked(const Sequence<OUString>& rConfiguredServices) +{ + for(OUString const & configService : rConfiguredServices) + { + for (sal_uInt32 i = 0; i < nDisplayServices; ++i) + { + ServiceInfo_Impl& rEntry = aDisplayServiceArr[i]; + if (!rEntry.bConfigured) + { + const OUString &rSrvcImplName = configService; + if (!rSrvcImplName.isEmpty() && + (rEntry.sSpellImplName == rSrvcImplName || + rEntry.sGrammarImplName == rSrvcImplName || + rEntry.sHyphImplName == rSrvcImplName || + rEntry.sThesImplName == rSrvcImplName)) + { + rEntry.bConfigured = true; + break; + } + } + } + } +} + +bool SvxLinguData_Impl::AddRemove( + Sequence< OUString > &rConfigured, + const OUString &rImplName, bool bAdd ) +{ + bool bRet = false; // modified? + + sal_Int32 nEntries = rConfigured.getLength(); + sal_Int32 nPos = lcl_SeqGetEntryPos(rConfigured, rImplName); + if (bAdd && nPos < 0) // add new entry + { + rConfigured.realloc( ++nEntries ); + OUString *pConfigured = rConfigured.getArray(); + pConfigured[nEntries - 1] = rImplName; + bRet = true; + } + else if (!bAdd && nPos >= 0) // remove existing entry + { + OUString *pConfigured = rConfigured.getArray(); + for (sal_Int32 i = nPos; i < nEntries - 1; ++i) + pConfigured[i] = pConfigured[i + 1]; + rConfigured.realloc(--nEntries); + bRet = true; + } + + return bRet; +} + + +void SvxLinguData_Impl::Reconfigure( std::u16string_view rDisplayName, bool bEnable ) +{ + DBG_ASSERT( !rDisplayName.empty(), "empty DisplayName" ); + + ServiceInfo_Impl *pInfo = nullptr; + for (sal_uInt32 i = 0; i < nDisplayServices; ++i) + { + ServiceInfo_Impl& rTmp = aDisplayServiceArr[i]; + if (rTmp.sDisplayName == rDisplayName) + { + pInfo = &rTmp; + break; + } + } + DBG_ASSERT( pInfo, "DisplayName entry not found" ); + if (!pInfo) + return; + + pInfo->bConfigured = bEnable; + + Sequence< Locale > aLocales; + const Locale *pLocale = nullptr; + sal_Int32 nLocales = 0; + sal_Int32 i; + + // update configured spellchecker entries + if (pInfo->xSpell.is()) + { + aLocales = pInfo->xSpell->getLocales(); + pLocale = aLocales.getConstArray(); + nLocales = aLocales.getLength(); + for (i = 0; i < nLocales; ++i) + { + LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] ); + if (!aCfgSpellTable.count( nLang ) && bEnable) + aCfgSpellTable[ nLang ] = Sequence< OUString >(); + if (aCfgSpellTable.count( nLang )) + AddRemove( aCfgSpellTable[ nLang ], pInfo->sSpellImplName, bEnable ); + } + } + + // update configured grammar checker entries + if (pInfo->xGrammar.is()) + { + aLocales = pInfo->xGrammar->getLocales(); + pLocale = aLocales.getConstArray(); + nLocales = aLocales.getLength(); + for (i = 0; i < nLocales; ++i) + { + LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] ); + if (!aCfgGrammarTable.count( nLang ) && bEnable) + aCfgGrammarTable[ nLang ] = Sequence< OUString >(); + if (aCfgGrammarTable.count( nLang )) + AddRemove( aCfgGrammarTable[ nLang ], pInfo->sGrammarImplName, bEnable ); + } + } + + // update configured hyphenator entries + if (pInfo->xHyph.is()) + { + aLocales = pInfo->xHyph->getLocales(); + pLocale = aLocales.getConstArray(); + nLocales = aLocales.getLength(); + for (i = 0; i < nLocales; ++i) + { + LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] ); + if (!aCfgHyphTable.count( nLang ) && bEnable) + aCfgHyphTable[ nLang ] = Sequence< OUString >(); + if (aCfgHyphTable.count( nLang )) + AddRemove( aCfgHyphTable[ nLang ], pInfo->sHyphImplName, bEnable ); + } + } + + // update configured spellchecker entries + if (!pInfo->xThes.is()) + return; + + aLocales = pInfo->xThes->getLocales(); + pLocale = aLocales.getConstArray(); + nLocales = aLocales.getLength(); + for (i = 0; i < nLocales; ++i) + { + LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] ); + if (!aCfgThesTable.count( nLang ) && bEnable) + aCfgThesTable[ nLang ] = Sequence< OUString >(); + if (aCfgThesTable.count( nLang )) + AddRemove( aCfgThesTable[ nLang ], pInfo->sThesImplName, bEnable ); + } +} + + +// class SvxLinguTabPage ------------------------------------------------- + +SvxLinguTabPage::SvxLinguTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optlingupage.ui", "OptLinguPage", &rSet) + , sCapitalWords (CuiResId(RID_CUISTR_CAPITAL_WORDS)) + , sWordsWithDigits(CuiResId(RID_CUISTR_WORDS_WITH_DIGITS)) + , sSpellSpecial (CuiResId(RID_CUISTR_SPELL_SPECIAL)) + , sSpellAuto (CuiResId(RID_CUISTR_SPELL_AUTO)) + , sSpellClosedCompound (CuiResId(RID_CUISTR_SPELL_CLOSED_COMPOUND)) + , sSpellHyphenatedCompound (CuiResId(RID_CUISTR_SPELL_HYPHENATED_COMPOUND)) + , sGrammarAuto (CuiResId(RID_CUISTR_GRAMMAR_AUTO)) + , sNumMinWordlen (CuiResId(RID_CUISTR_NUM_MIN_WORDLEN)) + , sNumPreBreak (CuiResId(RID_CUISTR_NUM_PRE_BREAK)) + , sNumPostBreak (CuiResId(RID_CUISTR_NUM_POST_BREAK)) + , sHyphAuto (CuiResId(RID_CUISTR_HYPH_AUTO)) + , sHyphSpecial (CuiResId(RID_CUISTR_HYPH_SPECIAL)) + , nUPN_HYPH_MIN_WORD_LENGTH(-1) + , nUPN_HYPH_MIN_LEADING(-1) + , nUPN_HYPH_MIN_TRAILING(-1) + , m_nDlbClickEventId(nullptr) + , m_xLinguModulesFT(m_xBuilder->weld_label("lingumodulesft")) + , m_xLinguModulesCLB(m_xBuilder->weld_tree_view("lingumodules")) + , m_xLinguModulesEditPB(m_xBuilder->weld_button("lingumodulesedit")) + , m_xLinguDicsFT(m_xBuilder->weld_label("lingudictsft")) + , m_xLinguDicsCLB(m_xBuilder->weld_tree_view("lingudicts")) + , m_xLinguDicsNewPB(m_xBuilder->weld_button("lingudictsnew")) + , m_xLinguDicsEditPB(m_xBuilder->weld_button("lingudictsedit")) + , m_xLinguDicsDelPB(m_xBuilder->weld_button("lingudictsdelete")) + , m_xLinguOptionsCLB(m_xBuilder->weld_tree_view("linguoptions")) + , m_xLinguOptionsEditPB(m_xBuilder->weld_button("linguoptionsedit")) + , m_xMoreDictsBox(m_xBuilder->weld_box("moredictsbox")) + , m_xMoreDictsLink(m_xBuilder->weld_link_button("moredictslink")) +{ + m_xLinguModulesCLB->enable_toggle_buttons(weld::ColumnToggleType::Check); + m_xLinguDicsCLB->enable_toggle_buttons(weld::ColumnToggleType::Check); + m_xLinguOptionsCLB->enable_toggle_buttons(weld::ColumnToggleType::Check); + + m_xLinguModulesCLB->connect_changed( LINK( this, SvxLinguTabPage, SelectHdl_Impl )); + m_xLinguModulesCLB->connect_row_activated(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl)); + m_xLinguModulesCLB->connect_toggled(LINK(this, SvxLinguTabPage, ModulesBoxCheckButtonHdl_Impl)); + + m_xLinguModulesEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl )); + m_xLinguOptionsEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl )); + + m_xLinguDicsCLB->connect_changed( LINK( this, SvxLinguTabPage, SelectHdl_Impl )); + m_xLinguDicsCLB->connect_toggled(LINK(this, SvxLinguTabPage, DicsBoxCheckButtonHdl_Impl)); + + m_xLinguDicsNewPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl )); + m_xLinguDicsEditPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl )); + m_xLinguDicsDelPB->connect_clicked( LINK( this, SvxLinguTabPage, ClickHdl_Impl )); + + m_xLinguOptionsCLB->connect_changed( LINK( this, SvxLinguTabPage, SelectHdl_Impl )); + m_xLinguOptionsCLB->connect_row_activated(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl)); + + m_xMoreDictsLink->connect_activate_link(LINK(this, SvxLinguTabPage, OnLinkClick)); + if (officecfg::Office::Security::Hyperlinks::Open::get() == SvtExtendedSecurityOptions::OPEN_NEVER) + m_xMoreDictsBox->hide(); + + if (comphelper::LibreOfficeKit::isActive()) + { + // hide User-defined Dictionaries part + m_xBuilder->weld_frame("dictsframe")->hide(); + // hide Get more dictionaries URL + icon + m_xMoreDictsBox->hide(); + } + + xProp = LinguMgr::GetLinguPropertySet(); + xDicList.set( LinguMgr::GetDictionaryList() ); + if (xDicList.is()) + { + // keep references to all **currently** available dictionaries, + // since the diclist may get changed meanwhile (e.g. through the API). + // We want the dialog to operate on the same set of dictionaries it + // was started with. + // Also we have to take care to not lose the last reference when + // someone else removes a dictionary from the list. + // removed dics will be replaced by NULL new entries be added to the end + // Thus we may use indices as consistent references. + aDics = xDicList->getDictionaries(); + + UpdateDicBox_Impl(); + } + else + { + m_xLinguDicsFT->set_sensitive(false); + m_xLinguDicsCLB->set_sensitive(false); + m_xLinguDicsNewPB->set_sensitive(false); + m_xLinguDicsEditPB->set_sensitive(false); + m_xLinguDicsDelPB->set_sensitive(false); + } +} + +SvxLinguTabPage::~SvxLinguTabPage() +{ + if (m_nDlbClickEventId) + { + Application::RemoveUserEvent(m_nDlbClickEventId); + m_nDlbClickEventId = nullptr; + } + pLinguData.reset(); +} + +std::unique_ptr<SfxTabPage> SvxLinguTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SvxLinguTabPage>( pPage, pController, *rAttrSet ); +} + +OUString SvxLinguTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "lingumodulesft", "lingudictsft", "label4" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + sAllStrings += m_xMoreDictsLink->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxLinguTabPage::FillItemSet( SfxItemSet* rCoreSet ) +{ + bool bModified = true; // !!!! + + // if not HideGroups was called with GROUP_MODULES... + if (m_xLinguModulesCLB->get_visible()) + { + DBG_ASSERT( pLinguData, "pLinguData not yet initialized" ); + if (!pLinguData) + pLinguData.reset( new SvxLinguData_Impl ); + + // update spellchecker configuration entries + const LangImplNameTable *pTable = &pLinguData->GetSpellTable(); + for (auto const& elem : *pTable) + { + LanguageType nLang = elem.first; + const Sequence< OUString > aImplNames(elem.second); + uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() ); + Locale aLocale( LanguageTag::convertToLocale(nLang) ); + if (xMgr.is()) + xMgr->setConfiguredServices( cSpell, aLocale, aImplNames ); + } + + // update grammar checker configuration entries + pTable = &pLinguData->GetGrammarTable(); + for (auto const& elem : *pTable) + { + LanguageType nLang = elem.first; + const Sequence< OUString > aImplNames(elem.second); + uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() ); + Locale aLocale( LanguageTag::convertToLocale(nLang) ); + if (xMgr.is()) + xMgr->setConfiguredServices( cGrammar, aLocale, aImplNames ); + } + + // update hyphenator configuration entries + pTable = &pLinguData->GetHyphTable(); + for (auto const& elem : *pTable) + { + LanguageType nLang = elem.first; + const Sequence< OUString > aImplNames(elem.second); + uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() ); + Locale aLocale( LanguageTag::convertToLocale(nLang) ); + if (xMgr.is()) + xMgr->setConfiguredServices( cHyph, aLocale, aImplNames ); + } + + // update thesaurus configuration entries + pTable = &pLinguData->GetThesTable(); + for (auto const& elem : *pTable) + { + LanguageType nLang = elem.first; + const Sequence< OUString > aImplNames(elem.second); + uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() ); + Locale aLocale( LanguageTag::convertToLocale(nLang) ); + if (xMgr.is()) + xMgr->setConfiguredServices( cThes, aLocale, aImplNames ); + } + } + + + // activate dictionaries according to checkbox state + + Sequence< OUString > aActiveDics; + sal_Int32 nActiveDics = 0; + int nEntries = m_xLinguDicsCLB->n_children(); + for (int i = 0; i < nEntries; ++i) + { + sal_Int32 nDics = aDics.getLength(); + + aActiveDics.realloc( nDics ); + OUString *pActiveDic = aActiveDics.getArray(); + + DicUserData aData(m_xLinguDicsCLB->get_id(i).toUInt32()); + if (aData.GetEntryId() < nDics) + { + bool bChecked = m_xLinguDicsCLB->get_toggle(i) == TRISTATE_TRUE; + uno::Reference< XDictionary > xDic( aDics.getConstArray()[ i ] ); + if (xDic.is()) + { + if (LinguMgr::GetIgnoreAllList() == xDic) + bChecked = true; + xDic->setActive( bChecked ); + if (bChecked) + pActiveDic[nActiveDics++] = xDic->getName(); + } + } + } + + aActiveDics.realloc( nActiveDics ); + Any aTmp; + aTmp <<= aActiveDics; + SvtLinguConfig aLngCfg; + aLngCfg.SetProperty( UPH_ACTIVE_DICTIONARIES, aTmp ); + + + nEntries = m_xLinguOptionsCLB->n_children(); + for (int j = 0; j < nEntries; ++j) + { + OptionsUserData aData(m_xLinguOptionsCLB->get_id(j).toUInt32()); + OUString aPropName( lcl_GetPropertyName( static_cast<EID_OPTIONS>(aData.GetEntryId()) ) ); + + Any aAny; + if (aData.IsCheckable()) + { + bool bChecked = m_xLinguOptionsCLB->get_toggle(j) == TRISTATE_TRUE; + aAny <<= bChecked; + } + else if (aData.HasNumericValue()) + { + sal_Int16 nVal = aData.GetNumericValue(); + aAny <<= nVal; + } + + if (xProp.is()) + xProp->setPropertyValue( aPropName, aAny ); + aLngCfg.SetProperty( aPropName, aAny ); + } + + OptionsUserData aPreBreakData(m_xLinguOptionsCLB->get_id(EID_NUM_PRE_BREAK).toUInt32()); + OptionsUserData aPostBreakData(m_xLinguOptionsCLB->get_id(EID_NUM_POST_BREAK).toUInt32()); + if ( aPreBreakData.IsModified() || aPostBreakData.IsModified() ) + { + SfxHyphenRegionItem aHyp( SID_ATTR_HYPHENREGION ); + aHyp.GetMinLead() = static_cast<sal_uInt8>(aPreBreakData.GetNumericValue()); + aHyp.GetMinTrail() = static_cast<sal_uInt8>(aPostBreakData.GetNumericValue()); + rCoreSet->Put( aHyp ); + } + + // automatic spell checking + bool bNewAutoCheck = m_xLinguOptionsCLB->get_toggle(EID_SPELL_AUTO) == TRISTATE_TRUE; + const SfxPoolItem* pOld = GetOldItem( *rCoreSet, SID_AUTOSPELL_CHECK ); + if ( !pOld || static_cast<const SfxBoolItem*>(pOld)->GetValue() != bNewAutoCheck ) + { + rCoreSet->Put( SfxBoolItem( SID_AUTOSPELL_CHECK, bNewAutoCheck ) ); + bModified = true; + } + + return bModified; +} + +sal_uInt32 SvxLinguTabPage::GetDicUserData( const uno::Reference< XDictionary > &rxDic, sal_uInt16 nIdx ) +{ + sal_uInt32 nRes = 0; + DBG_ASSERT( rxDic.is(), "dictionary not supplied" ); + if (rxDic.is()) + { + uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY ); + + bool bChecked = rxDic->isActive(); + bool bEditable = !xStor.is() || !xStor->isReadonly(); + bool bDeletable = bEditable; + + nRes = DicUserData( nIdx, + bChecked, bEditable, bDeletable ).GetUserData(); + } + return nRes; +} + + +void SvxLinguTabPage::AddDicBoxEntry( + const uno::Reference< XDictionary > &rxDic, + sal_uInt16 nIdx ) +{ + m_xLinguDicsCLB->freeze(); + + OUString aTxt( ::GetDicInfoStr( rxDic->getName(), + LanguageTag( rxDic->getLocale() ).getLanguageType(), + DictionaryType_NEGATIVE == rxDic->getDictionaryType() ) ); + m_xLinguDicsCLB->append(); // append at end + int nEntry = m_xLinguDicsCLB->n_children() - 1; + DicUserData aData( GetDicUserData( rxDic, nIdx ) ); + m_xLinguDicsCLB->set_id(nEntry, OUString::number(aData.GetUserData())); + m_xLinguDicsCLB->set_toggle(nEntry, aData.IsChecked() ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguDicsCLB->set_text(nEntry, aTxt, 0); // append at end + + m_xLinguDicsCLB->thaw(); +} + +void SvxLinguTabPage::UpdateDicBox_Impl() +{ + m_xLinguDicsCLB->freeze(); + m_xLinguDicsCLB->clear(); + + sal_Int32 nDics = aDics.getLength(); + const uno::Reference< XDictionary > *pDic = aDics.getConstArray(); + for (sal_Int32 i = 0; i < nDics; ++i) + { + const uno::Reference< XDictionary > &rDic = pDic[i]; + if (rDic.is()) + AddDicBoxEntry( rDic, static_cast<sal_uInt16>(i) ); + } + + m_xLinguDicsCLB->thaw(); + if (m_xLinguDicsCLB->n_children()) + { + m_xLinguDicsCLB->select(0); + SelectHdl_Impl(*m_xLinguDicsCLB); + } +} + +void SvxLinguTabPage::UpdateModulesBox_Impl() +{ + if (!pLinguData) + return; + + const ServiceInfoArr &rAllDispSrvcArr = pLinguData->GetDisplayServiceArray(); + const sal_uInt32 nDispSrvcCount = pLinguData->GetDisplayServiceCount(); + + m_xLinguModulesCLB->clear(); + + for (sal_uInt32 i = 0; i < nDispSrvcCount; ++i) + { + const ServiceInfo_Impl &rInfo = rAllDispSrvcArr[i]; + m_xLinguModulesCLB->append(); + m_xLinguModulesCLB->set_id(i, weld::toId(&rInfo)); + m_xLinguModulesCLB->set_toggle(i, rInfo.bConfigured ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguModulesCLB->set_text(i, rInfo.sDisplayName, 0); + } + if (nDispSrvcCount) + { + m_xLinguModulesCLB->select(0); + SelectHdl_Impl(*m_xLinguModulesCLB); + } + m_xLinguModulesEditPB->set_sensitive( nDispSrvcCount > 0 ); +} + +void SvxLinguTabPage::Reset( const SfxItemSet* rSet ) +{ + // if not HideGroups was called with GROUP_MODULES... + if (m_xLinguModulesCLB->get_visible()) + { + if (!pLinguData) + pLinguData.reset( new SvxLinguData_Impl ); + UpdateModulesBox_Impl(); + } + + + // get data from configuration + SvtLinguConfig aLngCfg; + + m_xLinguOptionsCLB->freeze(); + m_xLinguOptionsCLB->clear(); + + sal_Int16 nVal = 0; + bool bVal = false; + sal_uInt32 nUserData = 0; + + m_xLinguOptionsCLB->append(); + int nEntry = 0; + + aLngCfg.GetProperty( UPN_IS_SPELL_AUTO ) >>= bVal; + const SfxPoolItem* pItem = GetItem( *rSet, SID_AUTOSPELL_CHECK ); + if (pItem) + bVal = static_cast<const SfxBoolItem *>(pItem)->GetValue(); + nUserData = OptionsUserData( EID_SPELL_AUTO, false, 0, true, bVal).GetUserData(); + m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguOptionsCLB->set_text(nEntry, sSpellAuto, 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_AUTO)); + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_IS_GRAMMAR_AUTO ) >>= bVal; + nUserData = OptionsUserData( EID_GRAMMAR_AUTO, false, 0, true, bVal).GetUserData(); + m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguOptionsCLB->set_text(nEntry, sGrammarAuto, 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_GRAMMAR_AUTO)); + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_IS_SPELL_UPPER_CASE ) >>= bVal; + nUserData = OptionsUserData( EID_CAPITAL_WORDS, false, 0, true, bVal).GetUserData(); + m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguOptionsCLB->set_text(nEntry, sCapitalWords, 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_UPPER_CASE)); + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_IS_SPELL_WITH_DIGITS ) >>= bVal; + nUserData = OptionsUserData( EID_WORDS_WITH_DIGITS, false, 0, true, bVal).GetUserData(); + m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguOptionsCLB->set_text(nEntry, sWordsWithDigits, 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_WITH_DIGITS)); + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_IS_SPELL_CLOSED_COMPOUND ) >>= bVal; + nUserData = OptionsUserData( EID_SPELL_CLOSED_COMPOUND, false, 0, true, bVal).GetUserData(); + m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguOptionsCLB->set_text(nEntry, sSpellClosedCompound, 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_CLOSED_COMPOUND)); + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_IS_SPELL_HYPHENATED_COMPOUND ) >>= bVal; + nUserData = OptionsUserData( EID_SPELL_HYPHENATED_COMPOUND, false, 0, true, bVal).GetUserData(); + m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguOptionsCLB->set_text(nEntry, sSpellHyphenatedCompound, 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_HYPHENATED_COMPOUND)); + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_IS_SPELL_SPECIAL ) >>= bVal; + nUserData = OptionsUserData( EID_SPELL_SPECIAL, false, 0, true, bVal).GetUserData(); + m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguOptionsCLB->set_text(nEntry, sSpellSpecial, 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_SPELL_SPECIAL)); + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_HYPH_MIN_WORD_LENGTH ) >>= nVal; + nUserData = OptionsUserData( EID_NUM_MIN_WORDLEN, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData(); + m_xLinguOptionsCLB->set_text(nEntry, sNumMinWordlen + " " + OUString::number(nVal), 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_HYPH_MIN_WORD_LENGTH)); + nUPN_HYPH_MIN_WORD_LENGTH = nEntry; + + const SfxHyphenRegionItem *pHyp = nullptr; + if ( rSet->GetItemState( SID_ATTR_HYPHENREGION, false ) == SfxItemState::SET ) + pHyp = & rSet->Get( SID_ATTR_HYPHENREGION ); + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_HYPH_MIN_LEADING ) >>= nVal; + if (pHyp) + nVal = static_cast<sal_Int16>(pHyp->GetMinLead()); + nUserData = OptionsUserData( EID_NUM_PRE_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData(); + m_xLinguOptionsCLB->set_text(nEntry, sNumPreBreak + " " + OUString::number(nVal), 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_HYPH_MIN_LEADING)); + nUPN_HYPH_MIN_LEADING = nEntry; + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_HYPH_MIN_TRAILING ) >>= nVal; + if (pHyp) + nVal = static_cast<sal_Int16>(pHyp->GetMinTrail()); + nUserData = OptionsUserData( EID_NUM_POST_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData(); + m_xLinguOptionsCLB->set_text(nEntry, sNumPostBreak + " " + OUString::number(nVal), 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_HYPH_MIN_TRAILING)); + nUPN_HYPH_MIN_TRAILING = nEntry; + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_IS_HYPH_AUTO ) >>= bVal; + nUserData = OptionsUserData( EID_HYPH_AUTO, false, 0, true, bVal).GetUserData(); + m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguOptionsCLB->set_text(nEntry, sHyphAuto, 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_HYPH_AUTO)); + + m_xLinguOptionsCLB->append(); + ++nEntry; + + aLngCfg.GetProperty( UPN_IS_HYPH_SPECIAL ) >>= bVal; + nUserData = OptionsUserData( EID_HYPH_SPECIAL, false, 0, true, bVal).GetUserData(); + m_xLinguOptionsCLB->set_toggle(nEntry, bVal ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLinguOptionsCLB->set_text(nEntry, sHyphSpecial, 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(nUserData)); + m_xLinguOptionsCLB->set_sensitive(nEntry, !aLngCfg.IsReadOnly(UPN_IS_HYPH_SPECIAL)); + + m_xLinguOptionsCLB->thaw(); + + m_xLinguOptionsCLB->select(0); + SelectHdl_Impl(*m_xLinguOptionsCLB); + + m_xLinguModulesCLB->set_size_request(m_xLinguModulesCLB->get_preferred_size().Width(), + m_xLinguModulesCLB->get_height_rows(3)); + m_xLinguDicsCLB->set_size_request(m_xLinguDicsCLB->get_preferred_size().Width(), + m_xLinguDicsCLB->get_height_rows(5)); + m_xLinguOptionsCLB->set_size_request(m_xLinguOptionsCLB->get_preferred_size().Width(), + m_xLinguOptionsCLB->get_height_rows(5)); + + if (officecfg::Office::Linguistic::General::DictionaryList::ActiveDictionaries::isReadOnly()) + { + m_xLinguDicsFT->set_sensitive(false); + m_xLinguDicsCLB->set_sensitive(false); + m_xLinguDicsNewPB->set_sensitive(false); + m_xLinguDicsEditPB->set_sensitive(false); + m_xLinguDicsDelPB->set_sensitive(false); + } +} + +IMPL_LINK(SvxLinguTabPage, BoxDoubleClickHdl_Impl, weld::TreeView&, rBox, bool) +{ + if (&rBox == m_xLinguModulesCLB.get() && !m_nDlbClickEventId) + { + //! in order to avoid a bug causing a GPF when double clicking + //! on a module entry and exiting the "Edit Modules" dialog + //! after that. + m_nDlbClickEventId = Application::PostUserEvent(LINK(this, SvxLinguTabPage, PostDblClickHdl_Impl)); + } + else if (&rBox == m_xLinguOptionsCLB.get()) + { + ClickHdl_Impl(*m_xLinguOptionsEditPB); + } + return true; +} + +IMPL_LINK_NOARG(SvxLinguTabPage, PostDblClickHdl_Impl, void*, void) +{ + m_nDlbClickEventId = nullptr; + ClickHdl_Impl(*m_xLinguModulesEditPB); +} + +IMPL_LINK(SvxLinguTabPage, ModulesBoxCheckButtonHdl_Impl, const weld::TreeView::iter_col&, rRowCol, void) +{ + if (!pLinguData) + return; + pLinguData->Reconfigure(m_xLinguModulesCLB->get_text(rRowCol.first), + m_xLinguModulesCLB->get_toggle(rRowCol.first) == TRISTATE_TRUE); +} + +IMPL_LINK(SvxLinguTabPage, DicsBoxCheckButtonHdl_Impl, const weld::TreeView::iter_col&, rRowCol, void) +{ + const uno::Reference<XDictionary> &rDic = aDics.getConstArray()[m_xLinguDicsCLB->get_iter_index_in_parent(rRowCol.first)]; + if (LinguMgr::GetIgnoreAllList() == rDic) + m_xLinguDicsCLB->set_toggle(rRowCol.first, TRISTATE_TRUE); +} + +IMPL_LINK(SvxLinguTabPage, ClickHdl_Impl, weld::Button&, rBtn, void) +{ + if (m_xLinguModulesEditPB.get() == &rBtn) + { + if (!pLinguData) + pLinguData.reset( new SvxLinguData_Impl ); + + SvxLinguData_Impl aOldLinguData( *pLinguData ); + SvxEditModulesDlg aDlg(GetFrameWeld(), *pLinguData); + if (aDlg.run() != RET_OK) + *pLinguData = aOldLinguData; + + // evaluate new status of 'bConfigured' flag + sal_uInt32 nLen = pLinguData->GetDisplayServiceCount(); + for (sal_uInt32 i = 0; i < nLen; ++i) + pLinguData->GetDisplayServiceArray()[i].bConfigured = false; + for (const auto& locale : pLinguData->GetAllSupportedLocales()) + { + LanguageType nLang = LanguageTag::convertToLanguageType(locale); + if (pLinguData->GetSpellTable().count( nLang )) + pLinguData->SetChecked( pLinguData->GetSpellTable()[ nLang ] ); + if (pLinguData->GetGrammarTable().count( nLang )) + pLinguData->SetChecked( pLinguData->GetGrammarTable()[ nLang ] ); + if (pLinguData->GetHyphTable().count( nLang )) + pLinguData->SetChecked( pLinguData->GetHyphTable()[ nLang ] ); + if (pLinguData->GetThesTable().count( nLang )) + pLinguData->SetChecked( pLinguData->GetThesTable()[ nLang ] ); + } + + // show new status of modules + UpdateModulesBox_Impl(); + } + else if (m_xLinguDicsNewPB.get() == &rBtn) + { + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractSvxNewDictionaryDialog> aDlg(pFact->CreateSvxNewDictionaryDialog(GetFrameWeld())); + uno::Reference< XDictionary > xNewDic; + if ( aDlg->Execute() == RET_OK ) + xNewDic = aDlg->GetNewDictionary(); + if ( xNewDic.is() ) + { + // add new dics to the end + sal_Int32 nLen = aDics.getLength(); + aDics.realloc( nLen + 1 ); + + aDics.getArray()[ nLen ] = xNewDic; + + AddDicBoxEntry( xNewDic, static_cast<sal_uInt16>(nLen) ); + } + } + else if (m_xLinguDicsEditPB.get() == &rBtn) + { + int nEntry = m_xLinguDicsCLB->get_selected_index(); + if (nEntry != -1) + { + DicUserData aData(m_xLinguDicsCLB->get_id(nEntry).toUInt32()); + sal_uInt16 nDicPos = aData.GetEntryId(); + sal_Int32 nDics = aDics.getLength(); + if (nDicPos < nDics) + { + uno::Reference< XDictionary > xDic = aDics.getConstArray()[ nDicPos ]; + if (xDic.is()) + { + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> aDlg(pFact->CreateSvxEditDictionaryDialog(GetFrameWeld(), xDic->getName())); + aDlg->Execute(); + } + } + } + } + else if (m_xLinguDicsDelPB.get() == &rBtn) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "cui/ui/querydeletedictionarydialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteDictionaryDialog")); + if (RET_NO == xQuery->run()) + return; + + int nEntry = m_xLinguDicsCLB->get_selected_index(); + if (nEntry != -1) + { + DicUserData aData(m_xLinguDicsCLB->get_id(nEntry).toUInt32()); + sal_uInt16 nDicPos = aData.GetEntryId(); + sal_Int32 nDics = aDics.getLength(); + if (nDicPos < nDics) + { + uno::Reference< XDictionary > xDic = aDics.getConstArray()[ nDicPos ]; + if (xDic.is()) + { + if (LinguMgr::GetIgnoreAllList() == xDic) + xDic->clear(); + else + { + if (xDicList.is()) + xDicList->removeDictionary( xDic ); + + uno::Reference< frame::XStorable > xStor( xDic, UNO_QUERY ); + if ( xStor->hasLocation() && !xStor->isReadonly() ) + { + OUString sURL = xStor->getLocation(); + INetURLObject aObj(sURL); + DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File, + "non-file URLs cannot be deleted" ); + if ( aObj.GetProtocol() == INetProtocol::File ) + { + KillFile_Impl( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + } + } + + aDics.getArray()[ nDicPos ] = nullptr; + + // remove entry from checklistbox + int nCnt = m_xLinguDicsCLB->n_children(); + for (int i = 0; i < nCnt; ++i) + { + DicUserData aDicData(m_xLinguDicsCLB->get_id(i).toUInt32()); + if (aDicData.GetEntryId() == nDicPos ) + { + m_xLinguDicsCLB->remove(i); + break; + } + } + DBG_ASSERT( nCnt > m_xLinguDicsCLB->n_children(), + "remove failed ?"); + } + } + } + } + } + else if (m_xLinguOptionsEditPB.get() == &rBtn) + { + int nEntry = m_xLinguOptionsCLB->get_selected_index(); + DBG_ASSERT(nEntry != -1, "no entry selected"); + if (nEntry != -1) + { + OptionsUserData aData(m_xLinguOptionsCLB->get_id(nEntry).toUInt32()); + if (aData.HasNumericValue()) + { + sal_uInt16 nRID = aData.GetEntryId(); + OptionsBreakSet aDlg(GetFrameWeld(), nRID); + aDlg.GetNumericFld().set_value(aData.GetNumericValue()); + if (RET_OK == aDlg.run()) + { + int nVal = aDlg.GetNumericFld().get_value(); + if (-1 != nVal && aData.GetNumericValue() != nVal) + { + aData.SetNumericValue( static_cast<sal_uInt8>(nVal) ); //! sets IsModified ! + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(aData.GetUserData())); + if (nEntry == nUPN_HYPH_MIN_WORD_LENGTH) + m_xLinguOptionsCLB->set_text(nEntry, sNumMinWordlen + " " + OUString::number(nVal), 0); + else if (nEntry == nUPN_HYPH_MIN_LEADING) + m_xLinguOptionsCLB->set_text(nEntry, sNumPreBreak + " " + OUString::number(nVal), 0); + else if (nEntry == nUPN_HYPH_MIN_TRAILING) + m_xLinguOptionsCLB->set_text(nEntry, sNumPostBreak + " " + OUString::number(nVal), 0); + m_xLinguOptionsCLB->set_id(nEntry, OUString::number(aData.GetUserData())); + } + } + } + } + } + else + { + SAL_WARN("cui.options", "rBtn unexpected value"); + } +} + +IMPL_LINK(SvxLinguTabPage, SelectHdl_Impl, weld::TreeView&, rBox, void) +{ + if (m_xLinguModulesCLB.get() == &rBox) + { + } + else if (m_xLinguDicsCLB.get() == &rBox) + { + int nEntry = rBox.get_selected_index(); + if (nEntry != -1) + { + DicUserData aData(rBox.get_id(nEntry).toUInt32()); + + // always allow to edit (i.e. at least view the content of the dictionary) + m_xLinguDicsEditPB->set_sensitive( true ); + m_xLinguDicsDelPB->set_sensitive( aData.IsDeletable() ); + } + } + else if (m_xLinguOptionsCLB.get() == &rBox) + { + int nEntry = rBox.get_selected_index(); + if (nEntry != -1) + { + OptionsUserData aData(rBox.get_id(nEntry).toUInt32()); + m_xLinguOptionsEditPB->set_sensitive( aData.HasNumericValue() ); + } + } + else + { + SAL_WARN("cui.options", "rBtn unexpected value"); + } +} + +void SvxLinguTabPage::HideGroups( sal_uInt16 nGrp ) +{ + if ( 0 != ( GROUP_MODULES & nGrp ) ) + { + m_xLinguModulesFT->hide(); + m_xLinguModulesCLB->hide(); + m_xLinguModulesEditPB->hide(); + + if (officecfg::Office::Security::Hyperlinks::Open::get() != SvtExtendedSecurityOptions::OPEN_NEVER && + !comphelper::LibreOfficeKit::isActive()) + { + m_xMoreDictsBox->show(); + } + } +} + +IMPL_STATIC_LINK_NOARG(SvxLinguTabPage, OnLinkClick, weld::LinkButton&, bool) +{ + comphelper::dispatchCommand(".uno:MoreDictionaries", {}); + return true; +} + +SvxEditModulesDlg::SvxEditModulesDlg(weld::Window* pParent, SvxLinguData_Impl& rData) + : GenericDialogController(pParent, "cui/ui/editmodulesdialog.ui", "EditModulesDialog") + , sSpell(CuiResId(RID_CUISTR_SPELL)) + , sHyph(CuiResId(RID_CUISTR_HYPH)) + , sThes(CuiResId(RID_CUISTR_THES)) + , sGrammar(CuiResId(RID_CUISTR_GRAMMAR)) + , rLinguData(rData) + , m_xModulesCLB(m_xBuilder->weld_tree_view("lingudicts")) + , m_xPrioUpPB(m_xBuilder->weld_button("up")) + , m_xPrioDownPB(m_xBuilder->weld_button("down")) + , m_xBackPB(m_xBuilder->weld_button("back")) + , m_xMoreDictsLink(m_xBuilder->weld_link_button("moredictslink")) + , m_xClosePB(m_xBuilder->weld_button("close")) + , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("language"))) +{ + m_xModulesCLB->set_size_request(m_xModulesCLB->get_approximate_digit_width() * 40, + m_xModulesCLB->get_height_rows(12)); + + m_xModulesCLB->enable_toggle_buttons(weld::ColumnToggleType::Check); + + pDefaultLinguData.reset( new SvxLinguData_Impl( rLinguData ) ); + + m_xModulesCLB->connect_changed( LINK( this, SvxEditModulesDlg, SelectHdl_Impl )); + m_xModulesCLB->connect_toggled(LINK(this, SvxEditModulesDlg, BoxCheckButtonHdl_Impl)); + + m_xClosePB->connect_clicked( LINK( this, SvxEditModulesDlg, ClickHdl_Impl )); + m_xPrioUpPB->connect_clicked( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl )); + m_xPrioDownPB->connect_clicked( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl )); + m_xBackPB->connect_clicked( LINK( this, SvxEditModulesDlg, BackHdl_Impl )); + // in case of not installed language modules + m_xPrioUpPB->set_sensitive( false ); + m_xPrioDownPB->set_sensitive( false ); + + m_xMoreDictsLink->connect_activate_link(LINK(this, SvxEditModulesDlg, OnLinkClick)); + if (officecfg::Office::Security::Hyperlinks::Open::get() == SvtExtendedSecurityOptions::OPEN_NEVER) + m_xMoreDictsLink->hide(); + + // set that we want the checkbox shown if spellchecking is available + m_xLanguageLB->SetLanguageList(SvxLanguageListFlags::EMPTY, false, false, true); + + //fill language box + const auto& rLoc = rLinguData.GetAllSupportedLocales(); + std::vector<LanguageType> aLanguages; + aLanguages.reserve(rLoc.size()); + std::transform(rLoc.begin(), rLoc.end(), std::back_inserter(aLanguages), + [](Locale const& locale) { return LanguageTag::convertToLanguageType(locale); }); + m_xLanguageLB->InsertLanguages(aLanguages); + LanguageType eSysLang = MsLangId::getConfiguredSystemLanguage(); + m_xLanguageLB->set_active_id( eSysLang ); + if (m_xLanguageLB->get_active_id() != eSysLang) + m_xLanguageLB->set_active(0); + + css::uno::Reference < css::uno::XComponentContext > xContext(::comphelper::getProcessComponentContext()); + m_xReadWriteAccess = css::configuration::ReadWriteAccess::create(xContext, "*"); + + m_xLanguageLB->connect_changed( LINK( this, SvxEditModulesDlg, LangSelectListBoxHdl_Impl )); + LangSelectHdl_Impl(m_xLanguageLB.get()); +} + +SvxEditModulesDlg::~SvxEditModulesDlg() +{ + for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i) + delete weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i)); +} + +IMPL_LINK( SvxEditModulesDlg, SelectHdl_Impl, weld::TreeView&, rBox, void ) +{ + int nCurPos = rBox.get_selected_index(); + if (nCurPos == -1) + return; + + bool bDisableUp = true; + bool bDisableDown = true; + ModuleUserData_Impl* pData = weld::fromId<ModuleUserData_Impl*>(rBox.get_id(nCurPos)); + if (!pData->IsParent() && pData->GetType() != TYPE_HYPH) + { + if (nCurPos < rBox.n_children() - 1) + { + bDisableDown = weld::fromId<ModuleUserData_Impl*>(rBox.get_id(nCurPos + 1))->IsParent(); + } + if (nCurPos > 1) + { + bDisableUp = weld::fromId<ModuleUserData_Impl*>(rBox.get_id(nCurPos - 1))->IsParent(); + } + } + m_xPrioUpPB->set_sensitive(!bDisableUp); + m_xPrioDownPB->set_sensitive(!bDisableDown); +} + +IMPL_LINK( SvxEditModulesDlg, BoxCheckButtonHdl_Impl, const weld::TreeView::iter_col&, rRowCol, void ) +{ + ModuleUserData_Impl* pData = weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(rRowCol.first)); + if (pData->IsParent() || pData->GetType() != TYPE_HYPH) + return; + + // make hyphenator checkboxes function as radio-buttons + // (at most one box may be checked) + auto nPos = m_xModulesCLB->get_iter_index_in_parent(rRowCol.first); + for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i) + { + pData = weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i)); + if (!pData->IsParent() && pData->GetType() == TYPE_HYPH && i != nPos) + { + m_xModulesCLB->set_toggle(i, TRISTATE_FALSE); + } + } +} + +IMPL_LINK_NOARG(SvxEditModulesDlg, LangSelectListBoxHdl_Impl, weld::ComboBox&, void) +{ + LangSelectHdl_Impl(m_xLanguageLB.get()); +} + +void SvxEditModulesDlg::LangSelectHdl_Impl(const SvxLanguageBox* pBox) +{ + LanguageType eCurLanguage = m_xLanguageLB->get_active_id(); + static Locale aLastLocale; + Locale aCurLocale( LanguageTag::convertToLocale( eCurLanguage)); + + if (pBox) + { + // save old probably changed settings + // before switching to new language entries + + LanguageType nLang = LanguageTag::convertToLanguageType( aLastLocale ); + + sal_Int32 nStart = 0, nLocalIndex = 0; + Sequence< OUString > aChange; + bool bChanged = false; + for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i) + { + ModuleUserData_Impl* pData = weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i)); + if (pData->IsParent()) + { + if (bChanged) + { + LangImplNameTable *pTable = nullptr; + sal_uInt8 nType = pData->GetType(); + switch (nType - 1) + { + case TYPE_SPELL : pTable = &rLinguData.GetSpellTable(); break; + case TYPE_GRAMMAR : pTable = &rLinguData.GetGrammarTable(); break; + case TYPE_HYPH : pTable = &rLinguData.GetHyphTable(); break; + case TYPE_THES : pTable = &rLinguData.GetThesTable(); break; + } + if (pTable) + { + aChange.realloc(nStart); + (*pTable)[ nLang ] = aChange; + } + } + nLocalIndex = nStart = 0; + aChange.realloc(nEntryCount); + bChanged = false; + } + else + { + OUString* pChange = aChange.getArray(); + pChange[nStart] = pData->GetImplName(); + bChanged |= pData->GetIndex() != nLocalIndex || + static_cast<TriState>(pData->IsChecked()) != m_xModulesCLB->get_toggle(i); + if (m_xModulesCLB->get_toggle(i)) + nStart++; + ++nLocalIndex; + } + } + if(bChanged) + { + aChange.realloc(nStart); + rLinguData.GetThesTable()[ nLang ] = aChange; + } + } + + for (int i = 0, nEntryCount = m_xModulesCLB->n_children(); i < nEntryCount; ++i) + delete weld::fromId<ModuleUserData_Impl*>(m_xModulesCLB->get_id(i)); + m_xModulesCLB->clear(); + + // display entries for new selected language + + if (LANGUAGE_DONTKNOW != eCurLanguage) + { + sal_Int32 n; + ServiceInfo_Impl* pInfo; + bool bReadOnly = false; + + int nRow = 0; + // spellchecker entries + + ModuleUserData_Impl* pUserData = new ModuleUserData_Impl( + OUString(), true, false, TYPE_SPELL, 0 ); + OUString sId(weld::toId(pUserData)); + m_xModulesCLB->append(nullptr); + m_xModulesCLB->set_id(nRow, sId); + m_xModulesCLB->set_text(nRow, sSpell, 0); + m_xModulesCLB->set_text_emphasis(nRow, true, 0); + ++nRow; + + OUString aLangNodeName = LanguageTag::convertToBcp47(aCurLocale); + OUString aConfigPath = officecfg::Office::Linguistic::ServiceManager::path() + "/SpellCheckerList/" + aLangNodeName; + if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath)) + { + css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath); + bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0; + } + + Sequence< OUString > aNames( rLinguData.GetSortedImplNames( eCurLanguage, TYPE_SPELL ) ); + const OUString *pName = aNames.getConstArray(); + sal_Int32 nNames = aNames.getLength(); + sal_Int32 nLocalIndex = 0; // index relative to parent + for (n = 0; n < nNames; ++n) + { + OUString aImplName; + bool bIsSuppLang = false; + + pInfo = rLinguData.GetInfoByImplName( pName[n] ); + if (pInfo) + { + bIsSuppLang = pInfo->xSpell.is() && + pInfo->xSpell->hasLocale( aCurLocale ); + aImplName = pInfo->sSpellImplName; + } + if (!aImplName.isEmpty() && bIsSuppLang) + { + OUString aTxt( pInfo->sDisplayName ); + + LangImplNameTable &rTable = rLinguData.GetSpellTable(); + const bool bHasLang = rTable.count( eCurLanguage ); + if (!bHasLang) + { + SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported + } + const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0; + pUserData = new ModuleUserData_Impl( aImplName, false, + bCheck, TYPE_SPELL, static_cast<sal_uInt8>(nLocalIndex++) ); + sId = weld::toId(pUserData); + + m_xModulesCLB->append(nullptr); + m_xModulesCLB->set_id(nRow, sId); + m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xModulesCLB->set_text(nRow, aTxt, 0); + m_xModulesCLB->set_text_emphasis(nRow, false, 0); + m_xModulesCLB->set_sensitive(nRow, !bReadOnly); + ++nRow; + } + } + + // grammar checker entries + + pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_GRAMMAR, 0 ); + sId = weld::toId(pUserData); + m_xModulesCLB->append(nullptr); + m_xModulesCLB->set_id(nRow, sId); + m_xModulesCLB->set_text(nRow, sGrammar, 0); + m_xModulesCLB->set_text_emphasis(nRow, true, 0); + ++nRow; + + aConfigPath = officecfg::Office::Linguistic::ServiceManager::path() + "/GrammarCheckerList/" + aLangNodeName; + if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath)) + { + css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath); + bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0; + } + + aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_GRAMMAR ); + pName = aNames.getConstArray(); + nNames = aNames.getLength(); + nLocalIndex = 0; + for (n = 0; n < nNames; ++n) + { + OUString aImplName; + bool bIsSuppLang = false; + + pInfo = rLinguData.GetInfoByImplName( pName[n] ); + if (pInfo) + { + bIsSuppLang = pInfo->xGrammar.is() && + pInfo->xGrammar->hasLocale( aCurLocale ); + aImplName = pInfo->sGrammarImplName; + } + if (!aImplName.isEmpty() && bIsSuppLang) + { + OUString aTxt( pInfo->sDisplayName ); + + LangImplNameTable &rTable = rLinguData.GetGrammarTable(); + const bool bHasLang = rTable.count( eCurLanguage ); + if (!bHasLang) + { + SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported + } + const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0; + pUserData = new ModuleUserData_Impl( aImplName, false, + bCheck, TYPE_GRAMMAR, static_cast<sal_uInt8>(nLocalIndex++) ); + + sId = weld::toId(pUserData); + + m_xModulesCLB->append(nullptr); + m_xModulesCLB->set_id(nRow, sId); + m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xModulesCLB->set_text(nRow, aTxt, 0); + m_xModulesCLB->set_text_emphasis(nRow, false, 0); + m_xModulesCLB->set_sensitive(nRow, !bReadOnly); + ++nRow; + } + } + + // hyphenator entries + + pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_HYPH, 0 ); + sId = weld::toId(pUserData); + m_xModulesCLB->append(nullptr); + m_xModulesCLB->set_id(nRow, sId); + m_xModulesCLB->set_text(nRow, sHyph, 0); + m_xModulesCLB->set_text_emphasis(nRow, true, 0); + ++nRow; + + aConfigPath = officecfg::Office::Linguistic::ServiceManager::path() + "/HyphenatorList/" + aLangNodeName; + if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath)) + { + css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath); + bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0; + } + + aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_HYPH ); + pName = aNames.getConstArray(); + nNames = aNames.getLength(); + nLocalIndex = 0; + for (n = 0; n < nNames; ++n) + { + OUString aImplName; + bool bIsSuppLang = false; + + pInfo = rLinguData.GetInfoByImplName( pName[n] ); + if (pInfo) + { + bIsSuppLang = pInfo->xHyph.is() && + pInfo->xHyph->hasLocale( aCurLocale ); + aImplName = pInfo->sHyphImplName; + } + if (!aImplName.isEmpty() && bIsSuppLang) + { + OUString aTxt( pInfo->sDisplayName ); + + LangImplNameTable &rTable = rLinguData.GetHyphTable(); + const bool bHasLang = rTable.count( eCurLanguage ); + if (!bHasLang) + { + SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported + } + const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0; + pUserData = new ModuleUserData_Impl( aImplName, false, + bCheck, TYPE_HYPH, static_cast<sal_uInt8>(nLocalIndex++) ); + sId = weld::toId(pUserData); + + m_xModulesCLB->append(nullptr); + m_xModulesCLB->set_id(nRow, sId); + m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xModulesCLB->set_text(nRow, aTxt, 0); + m_xModulesCLB->set_text_emphasis(nRow, false, 0); + m_xModulesCLB->set_sensitive(nRow, !bReadOnly); + ++nRow; + } + } + + // thesaurus entries + + pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_THES, 0 ); + sId = weld::toId(pUserData); + m_xModulesCLB->append(nullptr); + m_xModulesCLB->set_id(nRow, sId); + m_xModulesCLB->set_text(nRow, sThes, 0); + m_xModulesCLB->set_text_emphasis(nRow, true, 0); + ++nRow; + + aConfigPath = officecfg::Office::Linguistic::ServiceManager::path() + "/ThesaurusList/" + aLangNodeName; + if (m_xReadWriteAccess->hasPropertyByHierarchicalName(aConfigPath)) + { + css::beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(aConfigPath); + bReadOnly = (aProperty.Attributes & css::beans::PropertyAttribute::READONLY) != 0; + } + + aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_THES ); + pName = aNames.getConstArray(); + nNames = aNames.getLength(); + nLocalIndex = 0; + for (n = 0; n < nNames; ++n) + { + OUString aImplName; + bool bIsSuppLang = false; + + pInfo = rLinguData.GetInfoByImplName( pName[n] ); + if (pInfo) + { + bIsSuppLang = pInfo->xThes.is() && + pInfo->xThes->hasLocale( aCurLocale ); + aImplName = pInfo->sThesImplName; + } + if (!aImplName.isEmpty() && bIsSuppLang) + { + OUString aTxt( pInfo->sDisplayName ); + + LangImplNameTable &rTable = rLinguData.GetThesTable(); + const bool bHasLang = rTable.count( eCurLanguage ); + if (!bHasLang) + { + SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported + } + const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0; + pUserData = new ModuleUserData_Impl( aImplName, false, + bCheck, TYPE_THES, static_cast<sal_uInt8>(nLocalIndex++) ); + sId = weld::toId(pUserData); + + m_xModulesCLB->append(nullptr); + m_xModulesCLB->set_id(nRow, sId); + m_xModulesCLB->set_toggle(nRow, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xModulesCLB->set_text(nRow, aTxt, 0); + m_xModulesCLB->set_text_emphasis(nRow, false, 0); + m_xModulesCLB->set_sensitive(nRow, !bReadOnly); + ++nRow; + } + } + } + aLastLocale = aCurLocale; +} + +IMPL_LINK( SvxEditModulesDlg, UpDownHdl_Impl, weld::Button&, rBtn, void ) +{ + bool bUp = m_xPrioUpPB.get() == &rBtn; + int nCurPos = m_xModulesCLB->get_selected_index(); + if (nCurPos == -1) + return; + + m_xModulesCLB->freeze(); + + OUString sId(m_xModulesCLB->get_id(nCurPos)); + OUString sStr(m_xModulesCLB->get_text(nCurPos)); + bool bIsChecked = m_xModulesCLB->get_toggle(nCurPos); + + m_xModulesCLB->remove(nCurPos); + + int nDestPos = bUp ? nCurPos - 1 : nCurPos + 1; + + m_xModulesCLB->insert_text(nDestPos, sStr); + m_xModulesCLB->set_id(nDestPos, sId); + m_xModulesCLB->set_toggle(nDestPos, bIsChecked ? TRISTATE_TRUE : TRISTATE_FALSE); + + m_xModulesCLB->thaw(); + + m_xModulesCLB->select(nDestPos); + SelectHdl_Impl(*m_xModulesCLB); +} + +IMPL_LINK_NOARG(SvxEditModulesDlg, ClickHdl_Impl, weld::Button&, void) +{ + // store language config + LangSelectHdl_Impl(m_xLanguageLB.get()); + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(SvxEditModulesDlg, BackHdl_Impl, weld::Button&, void) +{ + rLinguData = *pDefaultLinguData; + LangSelectHdl_Impl(nullptr); +} + +IMPL_STATIC_LINK_NOARG(SvxEditModulesDlg, OnLinkClick, weld::LinkButton&, bool) +{ + comphelper::dispatchCommand(".uno:MoreDictionaries", {}); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optopencl.cxx b/cui/source/options/optopencl.cxx new file mode 100644 index 0000000000..129cbc1b01 --- /dev/null +++ b/cui/source/options/optopencl.cxx @@ -0,0 +1,107 @@ +/* -*- 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 <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <opencl/openclconfig.hxx> +#include <opencl/openclwrapper.hxx> +#include <officecfg/Office/Common.hxx> +#include <svtools/restartdialog.hxx> + +#include "optopencl.hxx" + +SvxOpenCLTabPage::SvxOpenCLTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optopenclpage.ui", "OptOpenCLPage", &rSet) + , maConfig(OpenCLConfig::get()) + , mxUseOpenCL(m_xBuilder->weld_check_button("useopencl")) + , mxUseOpenImg(m_xBuilder->weld_widget("lockuseopencl")) + , mxOclUsed(m_xBuilder->weld_label("openclused")) + , mxOclNotUsed(m_xBuilder->weld_label("openclnotused")) +{ + mxUseOpenCL->set_active(maConfig.mbUseOpenCL); + mxUseOpenCL->set_sensitive(!officecfg::Office::Common::Misc::UseOpenCL::isReadOnly()); + mxUseOpenImg->set_visible(officecfg::Office::Common::Misc::UseOpenCL::isReadOnly()); + + bool bCLUsed = openclwrapper::GPUEnv::isOpenCLEnabled(); + mxOclUsed->set_visible(bCLUsed); + mxOclNotUsed->set_visible(!bCLUsed); +} + +SvxOpenCLTabPage::~SvxOpenCLTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SvxOpenCLTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SvxOpenCLTabPage>(pPage, pController, *rAttrSet); +} + +OUString SvxOpenCLTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "openclnotused", "openclused" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + sAllStrings += mxUseOpenCL->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxOpenCLTabPage::FillItemSet( SfxItemSet* ) +{ + bool bModified = false; + std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); + + if (mxUseOpenCL->get_state_changed_from_saved()) + maConfig.mbUseOpenCL = mxUseOpenCL->get_active(); + + if (maConfig != OpenCLConfig::get()) + { + maConfig.set(); + bModified = true; + } + + if (bModified) + { + batch->commit(); + SolarMutexGuard aGuard; + if (svtools::executeRestartDialog(comphelper::getProcessComponentContext(), nullptr, + svtools::RESTART_REASON_OPENCL)) + GetDialogController()->response(RET_OK); + } + + return bModified; +} + +void SvxOpenCLTabPage::Reset( const SfxItemSet* ) +{ + maConfig = OpenCLConfig::get(); + + mxUseOpenCL->set_active(maConfig.mbUseOpenCL); + mxUseOpenImg->set_visible(officecfg::Office::Common::Misc::UseOpenCL::isReadOnly()); + mxUseOpenCL->save_state(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optopencl.hxx b/cui/source/options/optopencl.hxx new file mode 100644 index 0000000000..e6414245da --- /dev/null +++ b/cui/source/options/optopencl.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ +#pragma once + +#include <opencl/openclconfig.hxx> +#include <sfx2/tabdlg.hxx> + +class SvxOpenCLTabPage : public SfxTabPage +{ +private: + OpenCLConfig maConfig; + + std::unique_ptr<weld::CheckButton> mxUseOpenCL; + std::unique_ptr<weld::Widget> mxUseOpenImg; + std::unique_ptr<weld::Label> mxOclUsed; + std::unique_ptr<weld::Label> mxOclNotUsed; + +public: + SvxOpenCLTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet ); + virtual ~SvxOpenCLTabPage() override; + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optpath.cxx b/cui/source/options/optpath.cxx new file mode 100644 index 0000000000..7832c26007 --- /dev/null +++ b/cui/source/options/optpath.cxx @@ -0,0 +1,705 @@ +/* -*- 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 <svx/svxdlg.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/app.hxx> +#include <tools/urlobj.hxx> +#include <unotools/defaultoptions.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/moduleoptions.hxx> +#include <unotools/viewoptions.hxx> + +#include <bitmaps.hlst> +#include <dialmgr.hxx> +#include <optpath.hxx> +#include <strings.hrc> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/util/thePathSettings.hpp> +#include <comphelper/diagnose_ex.hxx> +#include <sal/log.hxx> +#include <o3tl/string_view.hxx> + +using namespace css; +using namespace css::beans; +using namespace css::lang; +using namespace css::ui::dialogs; +using namespace css::uno; +using namespace svx; + +// define ---------------------------------------------------------------- + +constexpr OUStringLiteral POSTFIX_INTERNAL = u"_internal"; +constexpr OUString POSTFIX_USER = u"_user"_ustr; +constexpr OUString POSTFIX_WRITABLE = u"_writable"_ustr; +constexpr OUStringLiteral VAR_ONE = u"%1"; +constexpr OUStringLiteral IODLG_CONFIGNAME = u"FilePicker_Save"; + +// struct OptPath_Impl --------------------------------------------------- + +struct OptPath_Impl +{ + OUString m_sMultiPathDlg; + Reference< css::util::XPathSettings > m_xPathSettings; + + OptPath_Impl() + : m_sMultiPathDlg(CuiResId(RID_CUISTR_EDIT_PATHS)) + { + } +}; + +namespace { + +struct PathUserData_Impl +{ + SvtPathOptions::Paths nRealId; + bool bItemStateSet; + OUString sUserPath; + OUString sWritablePath; + bool bReadOnly; + + explicit PathUserData_Impl(SvtPathOptions::Paths nId) + : nRealId(nId) + , bItemStateSet(false) + , bReadOnly(false) + { + } +}; + +struct Handle2CfgNameMapping_Impl +{ + SvtPathOptions::Paths m_nHandle; + const char* m_pCfgName; +}; + +} + +Handle2CfgNameMapping_Impl const Hdl2CfgMap_Impl[] = +{ + { SvtPathOptions::Paths::AutoCorrect, "AutoCorrect" }, + { SvtPathOptions::Paths::AutoText, "AutoText" }, + { SvtPathOptions::Paths::Backup, "Backup" }, + { SvtPathOptions::Paths::Gallery, "Gallery" }, + { SvtPathOptions::Paths::Graphic, "Graphic" }, + { SvtPathOptions::Paths::Temp, "Temp" }, + { SvtPathOptions::Paths::Template, "Template" }, + { SvtPathOptions::Paths::Work, "Work" }, + { SvtPathOptions::Paths::Dictionary, "Dictionary" }, + { SvtPathOptions::Paths::Classification, "Classification" }, +#if OSL_DEBUG_LEVEL > 1 + { SvtPathOptions::Paths::Linguistic, "Linguistic" }, +#endif + { SvtPathOptions::Paths::LAST, nullptr } +}; + +static OUString getCfgName_Impl( SvtPathOptions::Paths _nHandle ) +{ + OUString sCfgName; + sal_uInt16 nIndex = 0; + while ( Hdl2CfgMap_Impl[ nIndex ].m_nHandle != SvtPathOptions::Paths::LAST ) + { + if ( Hdl2CfgMap_Impl[ nIndex ].m_nHandle == _nHandle ) + { + // config name found + sCfgName = OUString::createFromAscii( Hdl2CfgMap_Impl[ nIndex ].m_pCfgName ); + break; + } + ++nIndex; + } + + return sCfgName; +} + +#define MULTIPATH_DELIMITER ';' + +static OUString Convert_Impl( std::u16string_view rValue ) +{ + if (rValue.empty()) + return OUString(); + + sal_Int32 nPos = 0; + OUStringBuffer aReturn; + for (;;) + { + OUString aValue( o3tl::getToken(rValue, 0, MULTIPATH_DELIMITER, nPos ) ); + INetURLObject aObj( aValue ); + if ( aObj.GetProtocol() == INetProtocol::File ) + aReturn.append(aObj.PathToFileName()); + if ( nPos < 0 ) + break; + aReturn.append(MULTIPATH_DELIMITER); + } + + return aReturn.makeStringAndClear(); +} + +// functions ------------------------------------------------------------- + +static bool IsMultiPath_Impl( const SvtPathOptions::Paths nIndex ) +{ +#if OSL_DEBUG_LEVEL > 1 + return ( SvtPathOptions::Paths::AutoCorrect == nIndex || + SvtPathOptions::Paths::AutoText == nIndex || + SvtPathOptions::Paths::Basic == nIndex || + SvtPathOptions::Paths::Gallery == nIndex || + SvtPathOptions::Paths::Template == nIndex ); +#else + return ( SvtPathOptions::Paths::AutoCorrect == nIndex || + SvtPathOptions::Paths::AutoText == nIndex || + SvtPathOptions::Paths::Basic == nIndex || + SvtPathOptions::Paths::Gallery == nIndex || + SvtPathOptions::Paths::Template == nIndex || + SvtPathOptions::Paths::Linguistic == nIndex || + SvtPathOptions::Paths::Dictionary == nIndex ); +#endif +} + +// class SvxPathTabPage -------------------------------------------------- + +SvxPathTabPage::SvxPathTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage( pPage, pController, "cui/ui/optpathspage.ui", "OptPathsPage", &rSet) + , pImpl(new OptPath_Impl) + , xDialogListener ( new ::svt::DialogClosedListener() ) + , m_xStandardBtn(m_xBuilder->weld_button("default")) + , m_xPathBtn(m_xBuilder->weld_button("edit")) + , m_xPathBox(m_xBuilder->weld_tree_view("paths")) +{ + m_xStandardBtn->connect_clicked(LINK(this, SvxPathTabPage, StandardHdl_Impl)); + m_xPathBtn->connect_clicked( LINK( this, SvxPathTabPage, PathHdl_Impl ) ); + + m_xPathBox->set_size_request(m_xPathBox->get_approximate_digit_width() * 60, + m_xPathBox->get_height_rows(20)); + + m_xPathBox->connect_row_activated( LINK( this, SvxPathTabPage, DoubleClickPathHdl_Impl ) ); + m_xPathBox->connect_column_clicked(LINK(this, SvxPathTabPage, HeaderBarClick)); + m_xPathBox->connect_changed( LINK( this, SvxPathTabPage, PathSelect_Impl ) ); + m_xPathBox->set_selection_mode(SelectionMode::Multiple); + + xDialogListener->SetDialogClosedLink( LINK( this, SvxPathTabPage, DialogClosedHdl ) ); +} + +IMPL_LINK(SvxPathTabPage, HeaderBarClick, int, nColumn, void) +{ + bool bSortAtoZ = !m_xPathBox->get_sort_order(); + m_xPathBox->set_sort_order(bSortAtoZ); + m_xPathBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn); +} + +SvxPathTabPage::~SvxPathTabPage() +{ + for (int i = 0, nEntryCount = m_xPathBox->n_children(); i < nEntryCount; ++i) + delete weld::fromId<PathUserData_Impl*>(m_xPathBox->get_id(i)); +} + +std::unique_ptr<SfxTabPage> SvxPathTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SvxPathTabPage>( pPage, pController, *rAttrSet ); +} + +OUString SvxPathTabPage::GetAllStrings() +{ + OUString sAllStrings; + if (const auto& pString = m_xBuilder->weld_label("label1")) + sAllStrings += pString->get_label() + " "; + return sAllStrings.replaceAll("_", ""); +} + +bool SvxPathTabPage::FillItemSet( SfxItemSet* ) +{ + for (int i = 0, nEntryCount = m_xPathBox->n_children(); i < nEntryCount; ++i) + { + PathUserData_Impl* pPathImpl = weld::fromId<PathUserData_Impl*>(m_xPathBox->get_id(i)); + SvtPathOptions::Paths nRealId = pPathImpl->nRealId; + if (pPathImpl->bItemStateSet ) + SetPathList( nRealId, pPathImpl->sUserPath, pPathImpl->sWritablePath ); + } + return true; +} + +void SvxPathTabPage::Reset( const SfxItemSet* ) +{ + m_xPathBox->clear(); + m_xPathBox->make_unsorted(); + + std::unique_ptr<weld::TreeIter> xIter = m_xPathBox->make_iterator(); + for( sal_uInt16 i = 0; i <= sal_uInt16(SvtPathOptions::Paths::Classification); ++i ) + { + // only writer uses autotext + if ( static_cast<SvtPathOptions::Paths>(i) == SvtPathOptions::Paths::AutoText + && !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) + continue; + + TranslateId pId; + + switch (static_cast<SvtPathOptions::Paths>(i)) + { + case SvtPathOptions::Paths::AutoCorrect: + pId = RID_CUISTR_KEY_AUTOCORRECT_DIR; + break; + case SvtPathOptions::Paths::AutoText: + pId = RID_CUISTR_KEY_GLOSSARY_PATH; + break; + case SvtPathOptions::Paths::Backup: + pId = RID_CUISTR_KEY_BACKUP_PATH; + break; + case SvtPathOptions::Paths::Gallery: + pId = RID_CUISTR_KEY_GALLERY_DIR; + break; + case SvtPathOptions::Paths::Graphic: + pId = RID_CUISTR_KEY_GRAPHICS_PATH; + break; + case SvtPathOptions::Paths::Temp: + pId = RID_CUISTR_KEY_TEMP_PATH; + break; + case SvtPathOptions::Paths::Template: + pId = RID_CUISTR_KEY_TEMPLATE_PATH; + break; + case SvtPathOptions::Paths::Dictionary: + pId = RID_CUISTR_KEY_DICTIONARY_PATH; + break; + case SvtPathOptions::Paths::Classification: + pId = RID_CUISTR_KEY_CLASSIFICATION_PATH; + break; +#if OSL_DEBUG_LEVEL > 1 + case SvtPathOptions::Paths::Linguistic: + pId = RID_CUISTR_KEY_LINGUISTIC_DIR; + break; +#endif + case SvtPathOptions::Paths::Work: + pId = RID_CUISTR_KEY_WORK_PATH; + break; + default: break; + } + + if (pId) + { + m_xPathBox->append(xIter.get()); + + OUString aStr(CuiResId(pId)); + m_xPathBox->set_text(*xIter, aStr, 0); + + OUString sInternal, sUser, sWritable; + bool bReadOnly = false; + GetPathList( static_cast<SvtPathOptions::Paths>(i), sInternal, sUser, sWritable, bReadOnly ); + + if (bReadOnly) + m_xPathBox->set_image(*xIter, RID_SVXBMP_LOCK); + + OUString sTmpPath = sUser; + if ( !sTmpPath.isEmpty() && !sWritable.isEmpty() ) + sTmpPath += OUStringChar(MULTIPATH_DELIMITER); + sTmpPath += sWritable; + const OUString aValue = Convert_Impl( sTmpPath ); + + m_xPathBox->set_text(*xIter, aValue, 1); + + const OUString aValueInternal = Convert_Impl( sInternal ); + + m_xPathBox->set_text(*xIter, aValueInternal, 2); + + m_xPathBox->set_sensitive(*xIter, !bReadOnly, 0); + m_xPathBox->set_sensitive(*xIter, !bReadOnly, 1); + m_xPathBox->set_sensitive(*xIter, !bReadOnly, 2); + + PathUserData_Impl* pPathImpl = new PathUserData_Impl(static_cast<SvtPathOptions::Paths>(i)); + pPathImpl->sUserPath = sUser; + pPathImpl->sWritablePath = sWritable; + pPathImpl->bReadOnly = bReadOnly; + + OUString sId = weld::toId(pPathImpl); + m_xPathBox->set_id(*xIter, sId); + } + } + + m_xPathBox->columns_autosize(); + m_xPathBox->make_sorted(); + PathSelect_Impl(*m_xPathBox); +} + +IMPL_LINK_NOARG(SvxPathTabPage, PathSelect_Impl, weld::TreeView&, void) +{ + bool bEnable = false; + int nEntry = m_xPathBox->get_selected_index(); + if (nEntry != -1) + { + PathUserData_Impl* pPathImpl = weld::fromId<PathUserData_Impl*>(m_xPathBox->get_id(nEntry)); + bEnable = !pPathImpl->bReadOnly; + } + sal_uInt16 nSelCount = m_xPathBox->count_selected_rows(); + m_xPathBtn->set_sensitive(1 == nSelCount && bEnable); + m_xStandardBtn->set_sensitive(nSelCount > 0 && bEnable); +} + +IMPL_LINK_NOARG(SvxPathTabPage, StandardHdl_Impl, weld::Button&, void) +{ + m_xPathBox->selected_foreach([this](weld::TreeIter& rEntry){ + PathUserData_Impl* pPathImpl = weld::fromId<PathUserData_Impl*>(m_xPathBox->get_id(rEntry)); + OUString aOldPath = SvtDefaultOptions::GetDefaultPath( pPathImpl->nRealId ); + + if ( !aOldPath.isEmpty() ) + { + OUString sInternal, sUser, sWritable, sTemp; + bool bReadOnly = false; + GetPathList( pPathImpl->nRealId, sInternal, sUser, sWritable, bReadOnly ); + + sal_Int32 nOldPos = 0; + do + { + bool bFound = false; + const std::u16string_view sOnePath = o3tl::getToken(aOldPath, 0, MULTIPATH_DELIMITER, nOldPos ); + if ( !sInternal.isEmpty() ) + { + sal_Int32 nInternalPos = 0; + do + { + if ( o3tl::getToken(sInternal, 0, MULTIPATH_DELIMITER, nInternalPos ) == sOnePath ) + bFound = true; + } + while ( !bFound && nInternalPos >= 0 ); + } + if ( !bFound ) + { + if ( !sTemp.isEmpty() ) + sTemp += OUStringChar(MULTIPATH_DELIMITER); + sTemp += sOnePath; + } + } + while ( nOldPos >= 0 ); + + OUString sWritablePath; + OUStringBuffer sUserPath; + if ( !sTemp.isEmpty() ) + { + sal_Int32 nNextPos = 0; + for (;;) + { + const OUString sToken = sTemp.getToken( 0, MULTIPATH_DELIMITER, nNextPos ); + if ( nNextPos<0 ) + { + // Last token need a different handling + sWritablePath = sToken; + break; + } + if ( !sUserPath.isEmpty() ) + sUserPath.append(MULTIPATH_DELIMITER); + sUserPath.append(sToken); + } + } + m_xPathBox->set_text(rEntry, Convert_Impl(sTemp), 1); + pPathImpl->bItemStateSet = true; + pPathImpl->sUserPath = sUserPath.makeStringAndClear(); + pPathImpl->sWritablePath = sWritablePath; + } + return false; + }); +} + +void SvxPathTabPage::ChangeCurrentEntry( const OUString& _rFolder ) +{ + int nEntry = m_xPathBox->get_cursor_index(); + if (nEntry == -1) + { + SAL_WARN( "cui.options", "SvxPathTabPage::ChangeCurrentEntry(): no entry" ); + return; + } + + OUString sInternal, sUser, sWritable; + PathUserData_Impl* pPathImpl = weld::fromId<PathUserData_Impl*>(m_xPathBox->get_id(nEntry)); + bool bReadOnly = false; + GetPathList( pPathImpl->nRealId, sInternal, sUser, sWritable, bReadOnly ); + sUser = pPathImpl->sUserPath; + sWritable = pPathImpl->sWritablePath; + + // old path is a URL? + INetURLObject aObj( sWritable ); + bool bURL = ( aObj.GetProtocol() != INetProtocol::NotValid ); + INetURLObject aNewObj( _rFolder ); + aNewObj.removeFinalSlash(); + + // then the new path also a URL else system path + OUString sNewPathStr = bURL ? _rFolder : aNewObj.getFSysPath( FSysStyle::Detect ); + + bool bChanged = +#ifdef UNX +// Unix is case sensitive + ( sNewPathStr != sWritable ); +#else + !sNewPathStr.equalsIgnoreAsciiCase( sWritable ); +#endif + + if ( !bChanged ) + return; + + m_xPathBox->set_text(nEntry, Convert_Impl(sNewPathStr), 1); + pPathImpl->bItemStateSet = true; + pPathImpl->sWritablePath = sNewPathStr; + if ( SvtPathOptions::Paths::Work == pPathImpl->nRealId ) + { + // Remove view options entry so the new work path + // will be used for the next open dialog. + SvtViewOptions aDlgOpt( EViewType::Dialog, IODLG_CONFIGNAME ); + aDlgOpt.Delete(); + // Reset also last used dir in the sfx application instance + SfxApplication *pSfxApp = SfxGetpApp(); + pSfxApp->ResetLastDir(); + } +} + +IMPL_LINK_NOARG(SvxPathTabPage, DoubleClickPathHdl_Impl, weld::TreeView&, bool) +{ + PathHdl_Impl(*m_xPathBtn); + return true; +} + +IMPL_LINK_NOARG(SvxPathTabPage, PathHdl_Impl, weld::Button&, void) +{ + int nEntry = m_xPathBox->get_cursor_index(); + PathUserData_Impl* pPathImpl = nEntry != -1 ? weld::fromId<PathUserData_Impl*>(m_xPathBox->get_id(nEntry)) : nullptr; + if (!pPathImpl || pPathImpl->bReadOnly) + return; + + SvtPathOptions::Paths nPos = pPathImpl->nRealId; + OUString sInternal, sUser, sWritable; + bool bPickFile = false; + bool bReadOnly = false; + GetPathList( pPathImpl->nRealId, sInternal, sUser, sWritable, bReadOnly ); + sUser = pPathImpl->sUserPath; + sWritable = pPathImpl->sWritablePath; + bPickFile = pPathImpl->nRealId == SvtPathOptions::Paths::Classification; + + if (IsMultiPath_Impl(nPos)) + { + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractSvxMultiPathDialog> pMultiDlg( + pFact->CreateSvxMultiPathDialog(GetFrameWeld())); + + OUString sPath( sUser ); + if ( !sPath.isEmpty() ) + sPath += OUStringChar(MULTIPATH_DELIMITER); + sPath += sWritable; + pMultiDlg->SetPath( sPath ); + + const OUString sPathName = m_xPathBox->get_text(nEntry, 0); + const OUString sNewTitle = pImpl->m_sMultiPathDlg.replaceFirst( VAR_ONE, sPathName ); + pMultiDlg->SetTitle( sNewTitle ); + + if (pMultiDlg->Execute() == RET_OK) + { + sUser.clear(); + sWritable.clear(); + OUString sFullPath; + OUString sNewPath = pMultiDlg->GetPath(); + if ( !sNewPath.isEmpty() ) + { + sal_Int32 nNextPos = 0; + for (;;) + { + const OUString sToken(sNewPath.getToken( 0, MULTIPATH_DELIMITER, nNextPos )); + if ( nNextPos<0 ) + { + // Last token need a different handling + sWritable = sToken; + break; + } + if ( !sUser.isEmpty() ) + sUser += OUStringChar(MULTIPATH_DELIMITER); + sUser += sToken; + } + sFullPath = sUser; + if ( !sFullPath.isEmpty() ) + sFullPath += OUStringChar(MULTIPATH_DELIMITER); + sFullPath += sWritable; + } + + m_xPathBox->set_text(nEntry, Convert_Impl(sFullPath), 1); + // save modified flag + pPathImpl->bItemStateSet = true; + pPathImpl->sUserPath = sUser; + pPathImpl->sWritablePath = sWritable; + } + } + else if (!bPickFile) + { + try + { + Reference < XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + xFolderPicker = sfx2::createFolderPicker(xContext, GetFrameWeld()); + + INetURLObject aURL( sWritable, INetProtocol::File ); + xFolderPicker->setDisplayDirectory( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + + Reference< XAsynchronousExecutableDialog > xAsyncDlg( xFolderPicker, UNO_QUERY ); + if ( xAsyncDlg.is() ) + xAsyncDlg->startExecuteModal( xDialogListener ); + else + { + short nRet = xFolderPicker->execute(); + if (ExecutableDialogResults::OK != nRet) + return; + + OUString sFolder(xFolderPicker->getDirectory()); + ChangeCurrentEntry(sFolder); + } + } + catch( Exception const & ) + { + TOOLS_WARN_EXCEPTION( "cui.options", "SvxPathTabPage::PathHdl_Impl: exception from folder picker" ); + } + } + else + { + try + { + sfx2::FileDialogHelper aHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, GetFrameWeld()); + uno::Reference<ui::dialogs::XFilePicker3> xFilePicker = aHelper.GetFilePicker(); + xFilePicker->appendFilter(OUString(), "*.xml"); + if (xFilePicker->execute() == ui::dialogs::ExecutableDialogResults::OK) + { + uno::Sequence<OUString> aPathSeq(xFilePicker->getSelectedFiles()); + ChangeCurrentEntry(aPathSeq[0]); + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("cui.options", "exception from file picker"); + } + } +} + +IMPL_LINK( SvxPathTabPage, DialogClosedHdl, DialogClosedEvent*, pEvt, void ) +{ + if (RET_OK == pEvt->DialogResult) + { + assert(xFolderPicker.is() && "SvxPathTabPage::DialogClosedHdl(): no folder picker"); + OUString sURL = xFolderPicker->getDirectory(); + ChangeCurrentEntry( sURL ); + } +} + +void SvxPathTabPage::GetPathList( + SvtPathOptions::Paths _nPathHandle, OUString& _rInternalPath, + OUString& _rUserPath, OUString& _rWritablePath, bool& _rReadOnly ) +{ + OUString sCfgName = getCfgName_Impl( _nPathHandle ); + + try + { + // load PathSettings service if necessary + if ( !pImpl->m_xPathSettings.is() ) + { + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + pImpl->m_xPathSettings = css::util::thePathSettings::get( xContext ); + } + + // load internal paths + Any aAny = pImpl->m_xPathSettings->getPropertyValue( + sCfgName + POSTFIX_INTERNAL); + Sequence< OUString > aPathSeq; + if ( aAny >>= aPathSeq ) + { + tools::Long i, nCount = aPathSeq.getLength(); + const OUString* pPaths = aPathSeq.getConstArray(); + + for ( i = 0; i < nCount; ++i ) + { + if ( !_rInternalPath.isEmpty() ) + _rInternalPath += ";"; + _rInternalPath += pPaths[i]; + } + } + // load user paths + aAny = pImpl->m_xPathSettings->getPropertyValue( + sCfgName + POSTFIX_USER); + if ( aAny >>= aPathSeq ) + { + tools::Long i, nCount = aPathSeq.getLength(); + const OUString* pPaths = aPathSeq.getConstArray(); + + for ( i = 0; i < nCount; ++i ) + { + if ( !_rUserPath.isEmpty() ) + _rUserPath += ";"; + _rUserPath += pPaths[i]; + } + } + // then the writable path + aAny = pImpl->m_xPathSettings->getPropertyValue( + sCfgName + POSTFIX_WRITABLE); + OUString sWritablePath; + if ( aAny >>= sWritablePath ) + _rWritablePath = sWritablePath; + + // and the readonly flag + Reference< XPropertySetInfo > xInfo = pImpl->m_xPathSettings->getPropertySetInfo(); + Property aProp = xInfo->getPropertyByName(sCfgName); + _rReadOnly = ( ( aProp.Attributes & PropertyAttribute::READONLY ) == PropertyAttribute::READONLY ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "cui.options", "SvxPathTabPage::GetPathList()" ); + } +} + + +void SvxPathTabPage::SetPathList( + SvtPathOptions::Paths _nPathHandle, std::u16string_view _rUserPath, const OUString& _rWritablePath ) +{ + OUString sCfgName = getCfgName_Impl( _nPathHandle ); + + try + { + // load PathSettings service if necessary + if ( !pImpl->m_xPathSettings.is() ) + { + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + pImpl->m_xPathSettings = css::util::thePathSettings::get( xContext ); + } + + // save user paths + const sal_Int32 nCount = comphelper::string::getTokenCount(_rUserPath, MULTIPATH_DELIMITER); + Sequence< OUString > aPathSeq( nCount ); + OUString* pArray = aPathSeq.getArray(); + sal_Int32 nPos = 0; + for ( sal_Int32 i = 0; i < nCount; ++i ) + pArray[i] = o3tl::getToken(_rUserPath, 0, MULTIPATH_DELIMITER, nPos ); + Any aValue( aPathSeq ); + pImpl->m_xPathSettings->setPropertyValue( + sCfgName + POSTFIX_USER, aValue); + + // then the writable path + aValue <<= _rWritablePath; + pImpl->m_xPathSettings->setPropertyValue( + sCfgName + POSTFIX_WRITABLE, aValue); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("cui.options", ""); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optsave.cxx b/cui/source/options/optsave.cxx new file mode 100644 index 0000000000..4c292a75ac --- /dev/null +++ b/cui/source/options/optsave.cxx @@ -0,0 +1,740 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <o3tl/string_view.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <dialmgr.hxx> +#include "optsave.hxx" +#include <strings.hrc> +#include <treeopt.hxx> +#include <officecfg/Office/Common.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/moduleoptions.hxx> +#include <unotools/saveopt.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XContainerQuery.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <sfx2/sfxsids.hrc> +#include <sfx2/docfilt.hxx> +#include <unotools/optionsdlg.hxx> +#include <osl/diagnose.h> +#include <comphelper/diagnose_ex.hxx> +#include <officecfg/Office/Recovery.hxx> +#include <unotools/confignode.hxx> + +#include <sfx2/fcontnr.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::util; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace comphelper; + +#define CFG_PAGE_AND_GROUP u"General", u"LoadSave" + + +struct SvxSaveTabPage_Impl +{ + Reference< XNameContainer > xFact; + std::vector< OUString > aFilterArr[APP_COUNT]; + std::vector< bool > aODFArr[APP_COUNT]; + std::vector< OUString > aUIFilterArr[APP_COUNT]; + OUString aDefaultArr[APP_COUNT]; + bool aDefaultReadonlyArr[APP_COUNT]; + bool bInitialized; + + SvxSaveTabPage_Impl(); +}; + +SvxSaveTabPage_Impl::SvxSaveTabPage_Impl() : bInitialized( false ) +{ +} + +// class SvxSaveTabPage -------------------------------------------------- + +SvxSaveTabPage::SvxSaveTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage( pPage, pController, "cui/ui/optsavepage.ui", "OptSavePage", &rCoreSet ) + , pImpl(new SvxSaveTabPage_Impl) + , m_xLoadViewPosAnyUserCB(m_xBuilder->weld_check_button("load_anyuser")) + , m_xLoadViewPosAnyUserImg(m_xBuilder->weld_widget("lockload_anyuser")) + , m_xLoadUserSettingsCB(m_xBuilder->weld_check_button("load_settings")) + , m_xLoadUserSettingsImg(m_xBuilder->weld_widget("lockload_settings")) + , m_xLoadDocPrinterCB(m_xBuilder->weld_check_button("load_docprinter")) + , m_xLoadDocPrinterImg(m_xBuilder->weld_widget("lockload_docprinter")) + , m_xDocInfoCB(m_xBuilder->weld_check_button("docinfo")) + , m_xDocInfoImg(m_xBuilder->weld_widget("lockdocinfo")) + , m_xBackupCB(m_xBuilder->weld_check_button("backup")) + , m_xBackupImg(m_xBuilder->weld_widget("lockbackup")) + , m_xBackupIntoDocumentFolderCB(m_xBuilder->weld_check_button("backupintodocumentfolder")) + , m_xBackupIntoDocumentFolderImg(m_xBuilder->weld_widget("lockbackupintodoc")) + , m_xAutoSaveCB(m_xBuilder->weld_check_button("autosave")) + , m_xAutoSaveImg(m_xBuilder->weld_widget("lockautosave")) + , m_xAutoSaveEdit(m_xBuilder->weld_spin_button("autosave_spin")) + , m_xMinuteFT(m_xBuilder->weld_label("autosave_mins")) + , m_xUserAutoSaveCB(m_xBuilder->weld_check_button("userautosave")) + , m_xUserAutoSaveImg(m_xBuilder->weld_widget("lockuserautosave")) + , m_xRelativeFsysCB(m_xBuilder->weld_check_button("relative_fsys")) + , m_xRelativeFsysImg(m_xBuilder->weld_widget("lockrelative_fsys")) + , m_xRelativeInetCB(m_xBuilder->weld_check_button("relative_inet")) + , m_xRelativeInetImg(m_xBuilder->weld_widget("lockrelative_inet")) + , m_xODFVersionLB(m_xBuilder->weld_combo_box("odfversion")) + , m_xODFVersionFT(m_xBuilder->weld_label("label5")) + , m_xODFVersionImg(m_xBuilder->weld_widget("lockodfversion")) + , m_xWarnAlienFormatCB(m_xBuilder->weld_check_button("warnalienformat")) + , m_xWarnAlienFormatImg(m_xBuilder->weld_widget("lockwarnalienformat")) + , m_xDocTypeLB(m_xBuilder->weld_combo_box("doctype")) + , m_xSaveAsFT(m_xBuilder->weld_label("saveas_label")) + , m_xSaveAsLB(m_xBuilder->weld_combo_box("saveas")) + , m_xODFWarningFI(m_xBuilder->weld_widget("odfwarning_image")) + , m_xODFWarningFT(m_xBuilder->weld_label("odfwarning_label")) +{ + m_xAutoSaveEdit->set_max_length(2); + m_xBackupIntoDocumentFolderCB->set_accessible_description(CuiResId(RID_CUISTR_A11Y_DESC_BACKUP)); + + m_xODFVersionLB->set_id(0, OUString::number(SvtSaveOptions::ODFVER_011)); // 1.0/1.1 + m_xODFVersionLB->set_id(1, OUString::number(SvtSaveOptions::ODFVER_012)); // 1.2 + m_xODFVersionLB->set_id(2, OUString::number(SvtSaveOptions::ODFVER_012_EXT_COMPAT)); // 1.2 Extended (compatibility mode) + m_xODFVersionLB->set_id(3, OUString::number(SvtSaveOptions::ODFVER_012_EXTENDED)); // 1.2 Extended + m_xODFVersionLB->set_id(4, OUString::number(SvtSaveOptions::ODFVER_013)); // 1.3 + m_xODFVersionLB->set_id(5, OUString::number(SvtSaveOptions::ODFVER_LATEST)); // 1.3 Extended (recommended) + + auto aFilterClassesNode = utl::OConfigurationTreeRoot::createWithComponentContext( + comphelper::getProcessComponentContext(), + "org.openoffice.Office.UI/FilterClassification/GlobalFilters/Classes", + -1, + utl::OConfigurationTreeRoot::CM_READONLY + ); + + m_xDocTypeLB->append(OUString::number(APP_WRITER), aFilterClassesNode.getNodeValue("com.sun.star.text.TextDocument/DisplayName").get<OUString>()); + m_xDocTypeLB->append(OUString::number(APP_WRITER_WEB), aFilterClassesNode.getNodeValue("com.sun.star.text.WebDocument/DisplayName").get<OUString>()); + m_xDocTypeLB->append(OUString::number(APP_WRITER_GLOBAL), aFilterClassesNode.getNodeValue("com.sun.star.text.GlobalDocument/DisplayName").get<OUString>()); + m_xDocTypeLB->append(OUString::number(APP_CALC), aFilterClassesNode.getNodeValue("com.sun.star.sheet.SpreadsheetDocument/DisplayName").get<OUString>()); + m_xDocTypeLB->append(OUString::number(APP_IMPRESS), aFilterClassesNode.getNodeValue("com.sun.star.presentation.PresentationDocument/DisplayName").get<OUString>()); + m_xDocTypeLB->append(OUString::number(APP_DRAW), aFilterClassesNode.getNodeValue("com.sun.star.drawing.DrawingDocument/DisplayName").get<OUString>()); + m_xDocTypeLB->append(OUString::number(APP_MATH), aFilterClassesNode.getNodeValue("com.sun.star.formula.FormulaProperties/DisplayName").get<OUString>()); + + m_xAutoSaveCB->connect_toggled( LINK( this, SvxSaveTabPage, AutoClickHdl_Impl ) ); + m_xBackupCB->connect_toggled(LINK(this, SvxSaveTabPage, BackupClickHdl_Impl)); + + SvtModuleOptions aModuleOpt; + if ( !aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::MATH ) ) + { + m_xSaveAsLB->remove_id(OUString::number(APP_MATH)); + m_xDocTypeLB->remove_id(OUString::number(APP_MATH)); + } + else + { + pImpl->aDefaultArr[APP_MATH] = aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::MATH); + pImpl->aDefaultReadonlyArr[APP_MATH] = aModuleOpt.IsDefaultFilterReadonly(SvtModuleOptions::EFactory::MATH); + } + + if ( !aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) ) + { + m_xSaveAsLB->remove_id(OUString::number(APP_DRAW)); + m_xDocTypeLB->remove_id(OUString::number(APP_DRAW)); + } + else + { + pImpl->aDefaultArr[APP_DRAW] = aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::DRAW); + pImpl->aDefaultReadonlyArr[APP_DRAW] = aModuleOpt.IsDefaultFilterReadonly(SvtModuleOptions::EFactory::DRAW); + } + + if ( !aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) ) + { + m_xSaveAsLB->remove_id(OUString::number(APP_IMPRESS)); + m_xDocTypeLB->remove_id(OUString::number(APP_IMPRESS)); + } + else + { + pImpl->aDefaultArr[APP_IMPRESS] = aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::IMPRESS); + pImpl->aDefaultReadonlyArr[APP_IMPRESS] = aModuleOpt.IsDefaultFilterReadonly(SvtModuleOptions::EFactory::IMPRESS); + } + + if ( !aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) ) + { + m_xSaveAsLB->remove_id(OUString::number(APP_CALC)); + m_xDocTypeLB->remove_id(OUString::number(APP_CALC)); + } + else + { + pImpl->aDefaultArr[APP_CALC] = aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::CALC); + pImpl->aDefaultReadonlyArr[APP_CALC] = aModuleOpt.IsDefaultFilterReadonly(SvtModuleOptions::EFactory::CALC); + } + + if ( !aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) + { + m_xSaveAsLB->remove_id(OUString::number(APP_WRITER)); + m_xSaveAsLB->remove_id(OUString::number(APP_WRITER_WEB)); + m_xSaveAsLB->remove_id(OUString::number(APP_WRITER_GLOBAL)); + m_xDocTypeLB->remove_id(OUString::number(APP_WRITER)); + m_xDocTypeLB->remove_id(OUString::number(APP_WRITER_WEB)); + m_xDocTypeLB->remove_id(OUString::number(APP_WRITER_GLOBAL)); + } + else + { + pImpl->aDefaultArr[APP_WRITER] = aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::WRITER); + pImpl->aDefaultArr[APP_WRITER_WEB] = aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::WRITERWEB); + pImpl->aDefaultArr[APP_WRITER_GLOBAL] = aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::WRITERGLOBAL); + pImpl->aDefaultReadonlyArr[APP_WRITER] = aModuleOpt.IsDefaultFilterReadonly(SvtModuleOptions::EFactory::WRITER); + pImpl->aDefaultReadonlyArr[APP_WRITER_WEB] = aModuleOpt.IsDefaultFilterReadonly(SvtModuleOptions::EFactory::WRITERWEB); + pImpl->aDefaultReadonlyArr[APP_WRITER_GLOBAL] = aModuleOpt.IsDefaultFilterReadonly(SvtModuleOptions::EFactory::WRITERGLOBAL); + } + + Link<weld::ComboBox&,void> aLink = LINK( this, SvxSaveTabPage, ODFVersionHdl_Impl ); + m_xODFVersionLB->connect_changed( aLink ); + aLink = LINK( this, SvxSaveTabPage, FilterHdl_Impl ); + m_xDocTypeLB->connect_changed( aLink ); + m_xSaveAsLB->connect_changed( aLink ); + + DetectHiddenControls(); +} + +SvxSaveTabPage::~SvxSaveTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SvxSaveTabPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SvxSaveTabPage>(pPage, pController, *rAttrSet); +} + +void SvxSaveTabPage::DetectHiddenControls() +{ + SvtOptionsDialogOptions aOptionsDlgOpt; + + if ( aOptionsDlgOpt.IsOptionHidden( u"Backup", CFG_PAGE_AND_GROUP ) ) + { + // hide controls of "Backup" + m_xBackupCB->hide(); + m_xBackupIntoDocumentFolderCB->hide(); + } + + if ( aOptionsDlgOpt.IsOptionHidden( u"AutoSave", CFG_PAGE_AND_GROUP ) ) + { + // hide controls of "AutoSave" + m_xAutoSaveCB->hide(); + m_xAutoSaveEdit->hide(); + m_xMinuteFT->hide(); + } + + if ( aOptionsDlgOpt.IsOptionHidden( u"UserAutoSave", CFG_PAGE_AND_GROUP ) ) + { + // hide controls of "UserAutoSave" + m_xUserAutoSaveCB->hide(); + } + +} + +OUString SvxSaveTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label2", "autosave_mins", "label3", + "label5", "label6", "saveas_label", "odfwarning_label" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] + = { "load_settings", "load_docprinter", "load_anyuser", "autosave", + "userautosave", "docinfo", "backup", "backupintodocumentfolder", + "relative_fsys", "relative_inet", "warnalienformat" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxSaveTabPage::FillItemSet( SfxItemSet* rSet ) +{ + auto xChanges = comphelper::ConfigurationChanges::create(); + bool bModified = false; + if (m_xLoadViewPosAnyUserCB->get_state_changed_from_saved()) + { + officecfg::Office::Common::Load::ViewPositionForAnyUser::set(m_xLoadViewPosAnyUserCB->get_active(), xChanges); + } + if(m_xLoadUserSettingsCB->get_state_changed_from_saved()) + officecfg::Office::Common::Load::UserDefinedSettings::set(m_xLoadUserSettingsCB->get_active(), xChanges); + + if ( m_xLoadDocPrinterCB->get_state_changed_from_saved() ) + officecfg::Office::Common::Save::Document::LoadPrinter::set(m_xLoadDocPrinterCB->get_active(), xChanges); + + if ( m_xODFVersionLB->get_value_changed_from_saved() ) + { + sal_Int32 nVersion = m_xODFVersionLB->get_active_id().toInt32(); + SetODFDefaultVersion( SvtSaveOptions::ODFDefaultVersion( nVersion ), xChanges ); + } + + if ( m_xDocInfoCB->get_state_changed_from_saved() ) + { + rSet->Put( SfxBoolItem( SID_ATTR_DOCINFO, + m_xDocInfoCB->get_active() ) ); + bModified = true; + } + + if ( m_xBackupCB->get_sensitive() && m_xBackupCB->get_state_changed_from_saved() ) + { + rSet->Put( SfxBoolItem( SID_ATTR_BACKUP, m_xBackupCB->get_active() ) ); + bModified = true; + } + + if (m_xBackupIntoDocumentFolderCB->get_sensitive() + && m_xBackupIntoDocumentFolderCB->get_state_changed_from_saved()) + { + rSet->Put( + SfxBoolItem(SID_ATTR_BACKUP_BESIDE_ORIGINAL, m_xBackupIntoDocumentFolderCB->get_active())); + bModified = true; + } + + if ( m_xAutoSaveCB->get_state_changed_from_saved() ) + { + rSet->Put( SfxBoolItem( SID_ATTR_AUTOSAVE, + m_xAutoSaveCB->get_active() ) ); + bModified = true; + } + if ( m_xWarnAlienFormatCB->get_state_changed_from_saved() ) + { + rSet->Put( SfxBoolItem( SID_ATTR_WARNALIENFORMAT, + m_xWarnAlienFormatCB->get_active() ) ); + bModified = true; + } + + if ( m_xAutoSaveEdit->get_value_changed_from_saved() ) + { + rSet->Put( SfxUInt16Item( SID_ATTR_AUTOSAVEMINUTE, + static_cast<sal_uInt16>(m_xAutoSaveEdit->get_value()) ) ); + bModified = true; + } + + if ( m_xUserAutoSaveCB->get_state_changed_from_saved() ) + { + rSet->Put( SfxBoolItem( SID_ATTR_USERAUTOSAVE, + m_xUserAutoSaveCB->get_active() ) ); + bModified = true; + } + // save relatively + if ( m_xRelativeFsysCB->get_state_changed_from_saved() ) + { + rSet->Put( SfxBoolItem( SID_SAVEREL_FSYS, + m_xRelativeFsysCB->get_active() ) ); + bModified = true; + } + + if ( m_xRelativeInetCB->get_state_changed_from_saved() ) + { + rSet->Put( SfxBoolItem( SID_SAVEREL_INET, + m_xRelativeInetCB->get_active() ) ); + bModified = true; + } + + SvtModuleOptions aModuleOpt; + if(!pImpl->aDefaultArr[APP_MATH].isEmpty() && + pImpl->aDefaultArr[APP_MATH] != aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::MATH)) + aModuleOpt.SetFactoryDefaultFilter(SvtModuleOptions::EFactory::MATH, pImpl->aDefaultArr[APP_MATH]); + + if( !pImpl->aDefaultArr[APP_DRAW].isEmpty() && + pImpl->aDefaultArr[APP_DRAW] != aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::DRAW)) + aModuleOpt.SetFactoryDefaultFilter(SvtModuleOptions::EFactory::DRAW, pImpl->aDefaultArr[APP_DRAW]); + + if(!pImpl->aDefaultArr[APP_IMPRESS].isEmpty() && + pImpl->aDefaultArr[APP_IMPRESS] != aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::IMPRESS)) + aModuleOpt.SetFactoryDefaultFilter(SvtModuleOptions::EFactory::IMPRESS, pImpl->aDefaultArr[APP_IMPRESS]); + + if(!pImpl->aDefaultArr[APP_CALC].isEmpty() && + pImpl->aDefaultArr[APP_CALC] != aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::CALC)) + aModuleOpt.SetFactoryDefaultFilter(SvtModuleOptions::EFactory::CALC, pImpl->aDefaultArr[APP_CALC]); + + if(!pImpl->aDefaultArr[APP_WRITER].isEmpty() && + pImpl->aDefaultArr[APP_WRITER] != aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::WRITER)) + aModuleOpt.SetFactoryDefaultFilter(SvtModuleOptions::EFactory::WRITER, pImpl->aDefaultArr[APP_WRITER]); + + if(!pImpl->aDefaultArr[APP_WRITER_WEB].isEmpty() && + pImpl->aDefaultArr[APP_WRITER_WEB] != aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::WRITERWEB)) + aModuleOpt.SetFactoryDefaultFilter(SvtModuleOptions::EFactory::WRITERWEB, pImpl->aDefaultArr[APP_WRITER_WEB]); + + if(!pImpl->aDefaultArr[APP_WRITER_GLOBAL].isEmpty() && + pImpl->aDefaultArr[APP_WRITER_GLOBAL] != aModuleOpt.GetFactoryDefaultFilter(SvtModuleOptions::EFactory::WRITERGLOBAL)) + aModuleOpt.SetFactoryDefaultFilter(SvtModuleOptions::EFactory::WRITERGLOBAL, pImpl->aDefaultArr[APP_WRITER_GLOBAL]); + + xChanges->commit(); + return bModified; +} + +static bool isODFFormat( std::u16string_view sFilter ) +{ + static const char* aODFFormats[] = + { + "writer8", + "writer8_template", + "writerglobal8", + "writerglobal8_writer", + "calc8", + "calc8_template", + "draw8", + "draw8_template", + "impress8", + "impress8_template", + "impress8_draw", + "chart8", + "math8", + nullptr + }; + + bool bRet = false; + int i = 0; + while ( aODFFormats[i] != nullptr ) + { + if ( o3tl::equalsAscii( sFilter, aODFFormats[i++] ) ) + { + bRet = true; + break; + } + } + + return bRet; +} + +void SvxSaveTabPage::Reset( const SfxItemSet* ) +{ + m_xLoadViewPosAnyUserCB->set_active(officecfg::Office::Common::Load::ViewPositionForAnyUser::get()); + m_xLoadViewPosAnyUserCB->save_state(); + m_xLoadViewPosAnyUserCB->set_sensitive(!officecfg::Office::Common::Load::ViewPositionForAnyUser::isReadOnly()); + m_xLoadViewPosAnyUserImg->set_visible(officecfg::Office::Common::Load::ViewPositionForAnyUser::isReadOnly()); + + m_xLoadUserSettingsCB->set_active(officecfg::Office::Common::Load::UserDefinedSettings::get()); + m_xLoadUserSettingsCB->save_state(); + m_xLoadUserSettingsCB->set_sensitive(!officecfg::Office::Common::Load::UserDefinedSettings::isReadOnly()); + m_xLoadUserSettingsImg->set_visible(officecfg::Office::Common::Load::UserDefinedSettings::isReadOnly()); + + m_xLoadDocPrinterCB->set_active( officecfg::Office::Common::Save::Document::LoadPrinter::get() ); + m_xLoadDocPrinterCB->save_state(); + m_xLoadDocPrinterCB->set_sensitive(!officecfg::Office::Common::Save::Document::LoadPrinter::isReadOnly()); + m_xLoadDocPrinterImg->set_visible(officecfg::Office::Common::Save::Document::LoadPrinter::isReadOnly()); + + if ( !pImpl->bInitialized ) + { + try + { + Reference< XMultiServiceFactory > xMSF = comphelper::getProcessServiceFactory(); + pImpl->xFact.set(xMSF->createInstance("com.sun.star.document.FilterFactory"), UNO_QUERY); + + DBG_ASSERT(pImpl->xFact.is(), "service com.sun.star.document.FilterFactory unavailable"); + Reference< XContainerQuery > xQuery(pImpl->xFact, UNO_QUERY); + if(xQuery.is()) + { + for (sal_Int32 n = 0, nEntryCount = m_xDocTypeLB->get_count(); n < nEntryCount; ++n) + { + unsigned int nData = m_xDocTypeLB->get_id(n).toUInt32(); + OUString sCommand = "getSortedFilterList():module=%1:iflags=" + + OUString::number(static_cast<int>(SfxFilterFlags::IMPORT|SfxFilterFlags::EXPORT)) + + ":eflags=" + + OUString::number(static_cast<int>(SfxFilterFlags::NOTINFILEDLG)); + OUString sReplace; + switch(nData) + { + case APP_WRITER : sReplace = "com.sun.star.text.TextDocument"; break; + case APP_WRITER_WEB : sReplace = "com.sun.star.text.WebDocument"; break; + case APP_WRITER_GLOBAL : sReplace = "com.sun.star.text.GlobalDocument"; break; + case APP_CALC : sReplace = "com.sun.star.sheet.SpreadsheetDocument";break; + case APP_IMPRESS : sReplace = "com.sun.star.presentation.PresentationDocument";break; + case APP_DRAW : sReplace = "com.sun.star.drawing.DrawingDocument";break; + case APP_MATH : sReplace = "com.sun.star.formula.FormulaProperties";break; + default: SAL_WARN("cui.options", "illegal user data"); + } + sCommand = sCommand.replaceFirst("%1", sReplace); + Reference< XEnumeration > xList = xQuery->createSubSetEnumerationByQuery(sCommand); + std::vector< OUString > lList; + std::vector<bool> lODFList; + while(xList->hasMoreElements()) + { + SequenceAsHashMap aFilter(xList->nextElement()); + OUString sFilter = aFilter.getUnpackedValueOrDefault("Name",OUString()); + if (!sFilter.isEmpty()) + { + lList.push_back(sFilter); + lODFList.push_back( isODFFormat( sFilter ) ); + } + } + pImpl->aFilterArr[nData] = lList; + pImpl->aODFArr[nData] = lODFList; + } + } + OUString sModule = OfaTreeOptionsDialog::getCurrentFactory_Impl(GetFrame()); + sal_Int32 docId = 0; + if (sModule == "com.sun.star.text.TextDocument") + docId = APP_WRITER; + else if (sModule == "com.sun.star.text.WebDocument") + docId = APP_WRITER_WEB; + else if (sModule == "com.sun.star.text.GlobalDocument") + docId = APP_WRITER_GLOBAL; + else if (sModule == "com.sun.star.sheet.SpreadsheetDocument") + docId = APP_CALC; + else if (sModule == "com.sun.star.presentation.PresentationDocument") + docId = APP_IMPRESS; + else if (sModule == "com.sun.star.drawing.DrawingDocument") + docId = APP_DRAW; + else if (sModule == "com.sun.star.formula.FormulaProperties") + docId = APP_MATH; + m_xDocTypeLB->set_active_id(OUString::number(docId)); + FilterHdl_Impl(*m_xDocTypeLB); + } + catch(Exception const &) + { + TOOLS_WARN_EXCEPTION( "cui.options", "exception in FilterFactory access" ); + } + + pImpl->bInitialized = true; + } + + m_xDocInfoCB->set_active(officecfg::Office::Common::Save::Document::EditProperty::get()); + m_xDocInfoCB->set_sensitive(!officecfg::Office::Common::Save::Document::EditProperty::isReadOnly()); + m_xDocInfoImg->set_visible(officecfg::Office::Common::Save::Document::EditProperty::isReadOnly()); + + m_xBackupCB->set_active(officecfg::Office::Common::Save::Document::CreateBackup::get()); + m_xBackupCB->set_sensitive(!officecfg::Office::Common::Save::Document::CreateBackup::isReadOnly()); + m_xBackupImg->set_visible(officecfg::Office::Common::Save::Document::CreateBackup::isReadOnly()); + + m_xBackupIntoDocumentFolderCB->set_active( + officecfg::Office::Common::Save::Document::BackupIntoDocumentFolder::get()); + m_xBackupIntoDocumentFolderCB->set_sensitive( + !officecfg::Office::Common::Save::Document::BackupIntoDocumentFolder::isReadOnly() + && m_xBackupCB->get_active()); + m_xBackupIntoDocumentFolderImg->set_visible( + officecfg::Office::Common::Save::Document::BackupIntoDocumentFolder::isReadOnly()); + + m_xAutoSaveCB->set_active(officecfg::Office::Recovery::AutoSave::Enabled::get()); + m_xAutoSaveCB->set_sensitive(!officecfg::Office::Recovery::AutoSave::Enabled::isReadOnly()); + m_xAutoSaveImg->set_visible(officecfg::Office::Recovery::AutoSave::Enabled::isReadOnly()); + + m_xUserAutoSaveCB->set_active(officecfg::Office::Recovery::AutoSave::UserAutoSaveEnabled::get()); + m_xUserAutoSaveCB->set_sensitive(!officecfg::Office::Recovery::AutoSave::UserAutoSaveEnabled::isReadOnly()); + m_xUserAutoSaveImg->set_visible(officecfg::Office::Recovery::AutoSave::UserAutoSaveEnabled::isReadOnly()); + + m_xWarnAlienFormatCB->set_active(officecfg::Office::Common::Save::Document::WarnAlienFormat::get()); + m_xWarnAlienFormatCB->set_sensitive(!officecfg::Office::Common::Save::Document::WarnAlienFormat::isReadOnly()); + m_xWarnAlienFormatImg->set_visible(officecfg::Office::Common::Save::Document::WarnAlienFormat::isReadOnly()); + + m_xAutoSaveEdit->set_value(officecfg::Office::Recovery::AutoSave::TimeIntervall::get()); + m_xAutoSaveEdit->set_sensitive(!officecfg::Office::Recovery::AutoSave::TimeIntervall::isReadOnly()); + + // save relatively + m_xRelativeFsysCB->set_active(officecfg::Office::Common::Save::URL::FileSystem::get()); + m_xRelativeFsysCB->set_sensitive(!officecfg::Office::Common::Save::URL::FileSystem::isReadOnly()); + m_xRelativeFsysImg->set_visible(officecfg::Office::Common::Save::URL::FileSystem::isReadOnly()); + + m_xRelativeInetCB->set_active(officecfg::Office::Common::Save::URL::Internet::get()); + m_xRelativeInetCB->set_sensitive(!officecfg::Office::Common::Save::URL::Internet::isReadOnly()); + m_xRelativeInetImg->set_visible(officecfg::Office::Common::Save::URL::Internet::isReadOnly()); + + sal_Int32 nDefaultVersion = GetODFDefaultVersion(); + m_xODFVersionLB->set_active_id(OUString::number(nDefaultVersion)); + m_xODFVersionLB->set_sensitive(!officecfg::Office::Common::Save::ODF::DefaultVersion::isReadOnly()); + m_xODFVersionFT->set_sensitive(!officecfg::Office::Common::Save::ODF::DefaultVersion::isReadOnly()); + m_xODFVersionImg->set_visible(officecfg::Office::Common::Save::ODF::DefaultVersion::isReadOnly()); + + AutoClickHdl_Impl(*m_xAutoSaveCB); + ODFVersionHdl_Impl(*m_xODFVersionLB); + + m_xDocInfoCB->save_state(); + m_xBackupCB->save_state(); + m_xBackupIntoDocumentFolderCB->save_state(); + m_xWarnAlienFormatCB->save_state(); + m_xAutoSaveCB->save_state(); + m_xAutoSaveEdit->save_value(); + + m_xUserAutoSaveCB->save_state(); + + m_xRelativeFsysCB->save_state(); + m_xRelativeInetCB->save_state(); + m_xODFVersionLB->save_value(); +} + +IMPL_LINK(SvxSaveTabPage, AutoClickHdl_Impl, weld::Toggleable&, rBox, void) +{ + if (&rBox != m_xAutoSaveCB.get()) + return; + + if (m_xAutoSaveCB->get_active()) + { + m_xAutoSaveEdit->set_sensitive(!officecfg::Office::Recovery::AutoSave::Enabled::isReadOnly()); + m_xMinuteFT->set_sensitive(!officecfg::Office::Recovery::AutoSave::Enabled::isReadOnly()); + m_xUserAutoSaveCB->set_sensitive(!officecfg::Office::Recovery::AutoSave::UserAutoSaveEnabled::isReadOnly()); + } + else + { + m_xAutoSaveEdit->set_sensitive(false); + m_xMinuteFT->set_sensitive(false); + m_xUserAutoSaveCB->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(SvxSaveTabPage, BackupClickHdl_Impl, weld::Toggleable&, void) +{ + m_xBackupIntoDocumentFolderCB->set_sensitive(m_xBackupCB->get_active() && + !officecfg::Office::Common::Save::Document::BackupIntoDocumentFolder::isReadOnly()); +} + +static OUString lcl_ExtracUIName(const Sequence<PropertyValue> &rProperties, std::u16string_view rExtension) +{ + OUString sName; + const PropertyValue* pPropVal = rProperties.getConstArray(); + const PropertyValue* const pEnd = pPropVal + rProperties.getLength(); + for( ; pPropVal != pEnd; pPropVal++ ) + { + const OUString &rName = pPropVal->Name; + if (rName == "UIName") + { + OUString sUIName; + if ( ( pPropVal->Value >>= sUIName ) && sUIName.getLength() ) + { + if (!rExtension.empty()) + { + return sUIName + " (" + rExtension + ")"; + } + else + { + return sUIName; + } + } + } + else if (rName == "Name") + { + pPropVal->Value >>= sName; + } + } + + OSL_ENSURE( false, "Filter without UIName!" ); + + return sName; +} + +IMPL_LINK( SvxSaveTabPage, FilterHdl_Impl, weld::ComboBox&, rBox, void ) +{ + const int nCurPos = m_xDocTypeLB->get_active(); + + int nData = -1; + if (nCurPos < APP_COUNT) + nData = m_xDocTypeLB->get_id(nCurPos).toInt32(); + + if ( nData >= 0 && nData < APP_COUNT ) + { + if(m_xDocTypeLB.get() == &rBox) + { + m_xSaveAsLB->clear(); + auto & rFilters = pImpl->aFilterArr[nData]; + if(pImpl->aUIFilterArr[nData].empty()) + { + pImpl->aUIFilterArr[nData].resize(pImpl->aFilterArr[nData].size()); + auto & rUIFilters = pImpl->aUIFilterArr[nData]; + for(size_t nFilter = 0; nFilter < pImpl->aFilterArr[nData].size(); nFilter++) + { + Any aProps = pImpl->xFact->getByName(rFilters[nFilter]); + // get the extension of the filter + OUString extension; + SfxFilterMatcher matcher; + std::shared_ptr<const SfxFilter> pFilter = matcher.GetFilter4FilterName(rFilters[nFilter]); + if (pFilter) + { + extension = pFilter->GetWildcard().getGlob().getToken(0, ';'); + } + Sequence<PropertyValue> aProperties; + aProps >>= aProperties; + rUIFilters[nFilter] = lcl_ExtracUIName(aProperties, extension); + } + } + auto const & rUIFilters = pImpl->aUIFilterArr[nData]; + OUString sSelect; + for(size_t i = 0; i < pImpl->aUIFilterArr[nData].size(); i++) + { + OUString sId; + if (pImpl->aODFArr[nData][i]) + sId = weld::toId(pImpl.get()); + m_xSaveAsLB->append(sId, rUIFilters[i]); + if (rFilters[i] == pImpl->aDefaultArr[nData]) + sSelect = rUIFilters[i]; + } + if (!sSelect.isEmpty()) + { + m_xSaveAsLB->set_active_text(sSelect); + } + + m_xSaveAsFT->set_sensitive(!pImpl->aDefaultReadonlyArr[nData]); + m_xSaveAsLB->set_sensitive(!pImpl->aDefaultReadonlyArr[nData]); + } + else + { + OUString sSelect = rBox.get_active_text(); + auto const & rFilters = pImpl->aFilterArr[nData]; + auto const & rUIFilters = pImpl->aUIFilterArr[nData]; + for(size_t i = 0; i < pImpl->aUIFilterArr[nData].size(); i++) + if(rUIFilters[i] == sSelect) + { + sSelect = rFilters[i]; + break; + } + + pImpl->aDefaultArr[nData] = sSelect; + } + } + + ODFVersionHdl_Impl( *m_xSaveAsLB ); +} + +IMPL_LINK_NOARG(SvxSaveTabPage, ODFVersionHdl_Impl, weld::ComboBox&, void) +{ + sal_Int32 nVersion = m_xODFVersionLB->get_active_id().toInt32(); + bool bShown = SvtSaveOptions::ODFDefaultVersion(nVersion) != SvtSaveOptions::ODFVER_LATEST; + if ( bShown ) + { + bool bHasODFFormat = false; + const int nCount = m_xSaveAsLB->get_count(); + for (int i = 0; i < nCount; ++i ) + { + if ( m_xSaveAsLB->get_id(i).toInt64() != 0 ) + { + bHasODFFormat = true; + break; + } + } + + bShown = !bHasODFFormat + || ( m_xSaveAsLB->get_active_id().toInt64() != 0); + } + + m_xODFWarningFI->set_visible(bShown); + m_xODFWarningFT->set_visible(bShown); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optsave.hxx b/cui/source/options/optsave.hxx new file mode 100644 index 0000000000..cb6d63a7e8 --- /dev/null +++ b/cui/source/options/optsave.hxx @@ -0,0 +1,96 @@ +/* -*- 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 . + */ +#pragma once + +#include <memory> +#include <sfx2/tabdlg.hxx> + +#define APP_WRITER 0 +#define APP_WRITER_WEB 1 +#define APP_WRITER_GLOBAL 2 +#define APP_CALC 3 +#define APP_IMPRESS 4 +#define APP_DRAW 5 +#define APP_MATH 6 +#define APP_COUNT 7 + +namespace com::sun::star::beans { struct PropertyValue; } + +// class SvxSaveTabPage -------------------------------------------------- + +struct SvxSaveTabPage_Impl; + +class SvxSaveTabPage : public SfxTabPage +{ +private: + std::unique_ptr<SvxSaveTabPage_Impl> pImpl; + + std::unique_ptr<weld::CheckButton> m_xLoadViewPosAnyUserCB; + std::unique_ptr<weld::Widget> m_xLoadViewPosAnyUserImg; + std::unique_ptr<weld::CheckButton> m_xLoadUserSettingsCB; + std::unique_ptr<weld::Widget> m_xLoadUserSettingsImg; + std::unique_ptr<weld::CheckButton> m_xLoadDocPrinterCB; + std::unique_ptr<weld::Widget> m_xLoadDocPrinterImg; + std::unique_ptr<weld::CheckButton> m_xDocInfoCB; + std::unique_ptr<weld::Widget> m_xDocInfoImg; + std::unique_ptr<weld::CheckButton> m_xBackupCB; + std::unique_ptr<weld::Widget> m_xBackupImg; + std::unique_ptr<weld::CheckButton> m_xBackupIntoDocumentFolderCB; + std::unique_ptr<weld::Widget> m_xBackupIntoDocumentFolderImg; + std::unique_ptr<weld::CheckButton> m_xAutoSaveCB; + std::unique_ptr<weld::Widget> m_xAutoSaveImg; + std::unique_ptr<weld::SpinButton> m_xAutoSaveEdit; + std::unique_ptr<weld::Label> m_xMinuteFT; + std::unique_ptr<weld::CheckButton> m_xUserAutoSaveCB; + std::unique_ptr<weld::Widget> m_xUserAutoSaveImg; + std::unique_ptr<weld::CheckButton> m_xRelativeFsysCB; + std::unique_ptr<weld::Widget> m_xRelativeFsysImg; + std::unique_ptr<weld::CheckButton> m_xRelativeInetCB; + std::unique_ptr<weld::Widget> m_xRelativeInetImg; + std::unique_ptr<weld::ComboBox> m_xODFVersionLB; + std::unique_ptr<weld::Label> m_xODFVersionFT; + std::unique_ptr<weld::Widget> m_xODFVersionImg; + std::unique_ptr<weld::CheckButton> m_xWarnAlienFormatCB; + std::unique_ptr<weld::Widget> m_xWarnAlienFormatImg; + std::unique_ptr<weld::ComboBox> m_xDocTypeLB; + std::unique_ptr<weld::Label> m_xSaveAsFT; + std::unique_ptr<weld::ComboBox> m_xSaveAsLB; + std::unique_ptr<weld::Widget> m_xODFWarningFI; + std::unique_ptr<weld::Label> m_xODFWarningFT; + + DECL_LINK( AutoClickHdl_Impl, weld::Toggleable&, void ); + DECL_LINK(BackupClickHdl_Impl, weld::Toggleable&, void); + DECL_LINK( FilterHdl_Impl, weld::ComboBox&, void ); + DECL_LINK(ODFVersionHdl_Impl, weld::ComboBox&, void ); + + void DetectHiddenControls(); + +public: + SvxSaveTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~SvxSaveTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optupdt.cxx b/cui/source/options/optupdt.cxx new file mode 100644 index 0000000000..e3b855b15d --- /dev/null +++ b/cui/source/options/optupdt.cxx @@ -0,0 +1,516 @@ +/* -*- 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 <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <svl/numformat.hxx> +#include <svl/zforlist.hxx> +#include "optupdt.hxx" +#include <comphelper/processfactory.hxx> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <com/sun/star/deployment/UpdateInformationProvider.hpp> +#include <com/sun/star/ucb/XWebDAVCommandEnvironment.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/setup/UpdateCheck.hpp> +#include <com/sun/star/setup/UpdateCheckConfig.hpp> +#include <com/sun/star/configuration/ReadWriteAccess.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <sfx2/filedlghelper.hxx> +#include <officecfg/Office/Common.hxx> +#include <officecfg/Office/Update.hxx> +#include <osl/file.hxx> +#include <osl/security.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <unotools/configmgr.hxx> + +using namespace ::css; + +SvxOnlineUpdateTabPage::SvxOnlineUpdateTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/optonlineupdatepage.ui", "OptOnlineUpdatePage", &rSet) + , m_showTraditionalOnlineUpdate(isTraditionalOnlineUpdateAvailable()) + , m_showMarOnlineUpdate(isMarOnlineUpdateAvailable()) + , m_xNeverChecked(m_xBuilder->weld_label("neverchecked")) + , m_xAutoCheckCheckBox(m_xBuilder->weld_check_button("autocheck")) + , m_xAutoCheckImg(m_xBuilder->weld_widget("lockautocheck")) + , m_xEveryDayButton(m_xBuilder->weld_radio_button("everyday")) + , m_xEveryWeekButton(m_xBuilder->weld_radio_button("everyweek")) + , m_xEveryMonthButton(m_xBuilder->weld_radio_button("everymonth")) + , m_xCheckIntervalImg(m_xBuilder->weld_widget("lockcheckinterval")) + , m_xCheckNowButton(m_xBuilder->weld_button("checknow")) + , m_xAutoDownloadCheckBox(m_xBuilder->weld_check_button("autodownload")) + , m_xAutoDownloadImg(m_xBuilder->weld_widget("lockautodownload")) + , m_xDestPathLabel(m_xBuilder->weld_label("destpathlabel")) + , m_xDestPath(m_xBuilder->weld_label("destpath")) + , m_xChangePathButton(m_xBuilder->weld_button("changepath")) + , m_xLastChecked(m_xBuilder->weld_label("lastchecked")) + , m_xExtrasCheckBox(m_xBuilder->weld_check_button("extrabits")) + , m_xExtrasImg(m_xBuilder->weld_widget("lockextrabits")) + , m_xUserAgentLabel(m_xBuilder->weld_label("useragent")) + , m_xPrivacyPolicyButton(m_xBuilder->weld_link_button("btnPrivacyPolicy")) + , m_xBox2(m_xBuilder->weld_box("box2")) + , m_xFrameDest(m_xBuilder->weld_frame("frameDest")) + , m_xFrameAgent(m_xBuilder->weld_frame("frameAgent")) + , m_xMar(m_xBuilder->weld_frame("frameMar")) + , m_xEnableMar(m_xBuilder->weld_check_button("enableMar")) +{ + if (m_showTraditionalOnlineUpdate) { + m_aNeverChecked = m_xNeverChecked->get_label(); + + m_xAutoCheckCheckBox->connect_toggled( LINK( this, SvxOnlineUpdateTabPage, AutoCheckHdl_Impl ) ); + m_xExtrasCheckBox->connect_toggled( LINK( this, SvxOnlineUpdateTabPage, ExtrasCheckHdl_Impl ) ); + m_xCheckNowButton->connect_clicked( LINK( this, SvxOnlineUpdateTabPage, CheckNowHdl_Impl ) ); + m_xChangePathButton->connect_clicked( LINK( this, SvxOnlineUpdateTabPage, FileDialogHdl_Impl ) ); + m_xPrivacyPolicyButton->set_uri( + officecfg::Office::Common::Menus::PrivacyPolicyURL::get() + + "?type=updatecheck&LOvers=" + utl::ConfigManager::getProductVersion() + + "&LOlocale=" + LanguageTag(utl::ConfigManager::getUILocale()).getBcp47()); + + + uno::Reference < uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + + m_xUpdateAccess = setup::UpdateCheckConfig::create( xContext ); + m_xReadWriteAccess = css::configuration::ReadWriteAccess::create(xContext, "*"); + + bool bDownloadSupported = false; + m_xUpdateAccess->getByName( "DownloadSupported" ) >>= bDownloadSupported; + + m_xAutoDownloadCheckBox->set_visible(bDownloadSupported); + m_xDestPathLabel->set_visible(bDownloadSupported); + m_xDestPath->set_visible(bDownloadSupported); + m_xChangePathButton->set_visible(bDownloadSupported); + + m_aLastCheckedTemplate = m_xLastChecked->get_label(); + + UpdateLastCheckedText(); + UpdateUserAgent(); + } else { + m_xAutoCheckCheckBox->hide(); + m_xEveryDayButton->hide(); + m_xEveryWeekButton->hide(); + m_xEveryMonthButton->hide(); + m_xCheckNowButton->hide(); + m_xBox2->hide(); + m_xAutoCheckImg->hide(); + m_xCheckIntervalImg->hide(); + m_xFrameDest->hide(); + m_xFrameAgent->hide(); + m_xPrivacyPolicyButton->hide(); + } + + if (m_showMarOnlineUpdate) { + m_xMar->show(); + m_xEnableMar->set_sensitive(!officecfg::Office::Update::Update::Enabled::isReadOnly()); + } else { + m_xMar->hide(); + } +} + +SvxOnlineUpdateTabPage::~SvxOnlineUpdateTabPage() +{ +} + +void SvxOnlineUpdateTabPage::UpdateLastCheckedText() +{ + OUString aText; + sal_Int64 lastChecked = 0; + + m_xUpdateAccess->getByName("LastCheck") >>= lastChecked; + + if( lastChecked == 0 ) // never checked + { + aText = m_aNeverChecked; + } + else + { + TimeValue lastCheckedTV; + oslDateTime lastCheckedDT; + + Date aDate( Date::EMPTY ); + tools::Time aTime( tools::Time::EMPTY ); + + lastCheckedTV.Seconds = static_cast<sal_uInt32>(lastChecked); + osl_getLocalTimeFromSystemTime( &lastCheckedTV, &lastCheckedTV ); + + if ( osl_getDateTimeFromTimeValue( &lastCheckedTV, &lastCheckedDT ) ) + { + aDate = Date( lastCheckedDT.Day, lastCheckedDT.Month, lastCheckedDT.Year ); + aTime = ::tools::Time( lastCheckedDT.Hours, lastCheckedDT.Minutes ); + } + + LanguageType eUILang = Application::GetSettings().GetUILanguageTag().getLanguageType(); + std::optional<SvNumberFormatter> pNumberFormatter( std::in_place, ::comphelper::getProcessComponentContext(), eUILang ); + const Color* pColor = nullptr; + const Date& rNullDate = pNumberFormatter->GetNullDate(); + sal_uInt32 nFormat = pNumberFormatter->GetStandardFormat( SvNumFormatType::DATE, eUILang ); + + OUString aDateStr; + pNumberFormatter->GetOutputString( aDate - rNullDate, nFormat, aDateStr, &pColor ); + + nFormat = pNumberFormatter->GetStandardFormat( SvNumFormatType::TIME, eUILang ); + OUString aTimeStr; + pNumberFormatter->GetOutputString( aTime.GetTimeInDays(), nFormat, aTimeStr, &pColor ); + + pNumberFormatter.reset(); + + aText = m_aLastCheckedTemplate; + sal_Int32 nIndex = aText.indexOf( "%DATE%" ); + if ( nIndex != -1 ) + aText = aText.replaceAt( nIndex, 6, aDateStr ); + + nIndex = aText.indexOf( "%TIME%" ); + if ( nIndex != -1 ) + aText = aText.replaceAt( nIndex, 6, aTimeStr ); + } + + m_xLastChecked->set_label(aText); +} + +void SvxOnlineUpdateTabPage::UpdateUserAgent() +{ + try { + uno::Reference< ucb::XWebDAVCommandEnvironment > xDav( + css::deployment::UpdateInformationProvider::create( + ::comphelper::getProcessComponentContext() ), + css::uno::UNO_QUERY_THROW ); + + OUString aPseudoURL = "useragent:normal"; + if( m_xExtrasCheckBox->get_active() ) + aPseudoURL = "useragent:extended"; + const uno::Sequence< beans::StringPair > aHeaders + = xDav->getUserRequestHeaders( aPseudoURL, ucb::WebDAVHTTPMethod(0) ); + + for (const css::beans::StringPair & aHeader : aHeaders) + { + if ( aHeader.First == "User-Agent" ) + { + OUString aText = aHeader.Second; + aText = aText.replaceAll(";", ";\n"); + aText = aText.replaceAll("(", "\n("); + m_xUserAgentLabel->set_label(aText); + break; + } + } + } catch (const uno::Exception &) { + TOOLS_WARN_EXCEPTION( "cui.options", "Unexpected exception fetching User Agent" ); + } +} + +std::unique_ptr<SfxTabPage> SvxOnlineUpdateTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SvxOnlineUpdateTabPage>( pPage, pController, *rAttrSet ); +} + +OUString SvxOnlineUpdateTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "lastchecked", "neverchecked", "labeldest", + "destpathlabel", "labelagent", "useragent_label", "useragent_changed" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "autocheck", "autodownload", "extrabits" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + OUString radioButton[] = { "everyday", "everyweek", "everymonth" }; + + for (const auto& radio : radioButton) + { + if (const auto& pString = m_xBuilder->weld_radio_button(radio)) + sAllStrings += pString->get_label() + " "; + } + + // some buttons are not included + sAllStrings += m_xPrivacyPolicyButton->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxOnlineUpdateTabPage::FillItemSet( SfxItemSet* ) +{ + bool bModified = false; + + if (m_showTraditionalOnlineUpdate) { + bool bValue; + sal_Int64 nValue; + + if( m_xAutoCheckCheckBox->get_state_changed_from_saved() ) + { + bValue = m_xAutoCheckCheckBox->get_active(); + m_xUpdateAccess->replaceByName( "AutoCheckEnabled", uno::Any( bValue ) ); + bModified = true; + } + + nValue = 0; + if( m_xEveryDayButton->get_active() ) + { + if( !m_xEveryDayButton->get_saved_state() ) + nValue = 86400; + } + else if( m_xEveryWeekButton->get_active() ) + { + if( !m_xEveryWeekButton->get_saved_state() ) + nValue = 604800; + } + else if( m_xEveryMonthButton->get_active() ) + { + if( !m_xEveryMonthButton->get_saved_state() ) + nValue = 2592000; + } + + if( nValue > 0 ) + { + m_xUpdateAccess->replaceByName( "CheckInterval", uno::Any( nValue ) ); + bModified = true; + } + + if( m_xAutoDownloadCheckBox->get_state_changed_from_saved() ) + { + bValue = m_xAutoDownloadCheckBox->get_active(); + m_xUpdateAccess->replaceByName( "AutoDownloadEnabled", uno::Any( bValue ) ); + bModified = true; + } + + OUString sValue, aURL; + m_xUpdateAccess->getByName( "DownloadDestination" ) >>= sValue; + + if( ( osl::FileBase::E_None == osl::FileBase::getFileURLFromSystemPath(m_xDestPath->get_label(), aURL) ) && + ( aURL != sValue ) ) + { + m_xUpdateAccess->replaceByName( "DownloadDestination", uno::Any( aURL ) ); + bModified = true; + } + + if( m_xExtrasCheckBox->get_state_changed_from_saved() ) + { + bValue = m_xExtrasCheckBox->get_active(); + m_xUpdateAccess->replaceByName( "ExtendedUserAgent", uno::Any( bValue ) ); + bModified = true; + } + + uno::Reference< util::XChangesBatch > xChangesBatch(m_xUpdateAccess, uno::UNO_QUERY); + if( xChangesBatch.is() && xChangesBatch->hasPendingChanges() ) + xChangesBatch->commitChanges(); + } + + if (m_showMarOnlineUpdate && m_xEnableMar->get_state_changed_from_saved()) { + auto batch(comphelper::ConfigurationChanges::create()); + officecfg::Office::Update::Update::Enabled::set(m_xEnableMar->get_active(), batch); + batch->commit(); + bModified = true; + } + + return bModified; +} + +void SvxOnlineUpdateTabPage::Reset( const SfxItemSet* ) +{ + if (m_showTraditionalOnlineUpdate) { + bool bValue = false; + m_xUpdateAccess->getByName( "AutoCheckEnabled" ) >>= bValue; + beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName("/org.openoffice.Office.Jobs/Jobs/org.openoffice.Office.Jobs:Job['UpdateCheck']/Arguments/AutoCheckEnabled"); + bool bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0; + + m_xAutoCheckCheckBox->set_active(bValue); + m_xAutoCheckCheckBox->set_sensitive(!bReadOnly); + m_xAutoCheckImg->set_visible(bReadOnly); + + sal_Int64 nValue = 0; + m_xUpdateAccess->getByName( "CheckInterval" ) >>= nValue; + aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName("/org.openoffice.Office.Jobs/Jobs/org.openoffice.Office.Jobs:Job['UpdateCheck']/Arguments/CheckInterval"); + bool bReadOnly2 = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0; + m_xEveryDayButton->set_sensitive(bValue && !(bReadOnly || bReadOnly2)); + m_xEveryWeekButton->set_sensitive(bValue && !(bReadOnly || bReadOnly2)); + m_xEveryMonthButton->set_sensitive(bValue && !(bReadOnly || bReadOnly2)); + m_xCheckIntervalImg->set_visible(bReadOnly2); + + if( nValue == 86400 ) + m_xEveryDayButton->set_active(true); + else if( nValue == 604800 ) + m_xEveryWeekButton->set_active(true); + else + m_xEveryMonthButton->set_active(true); + + m_xAutoCheckCheckBox->save_state(); + m_xEveryDayButton->save_state(); + m_xEveryWeekButton->save_state(); + m_xEveryMonthButton->save_state(); + + m_xUpdateAccess->getByName( "AutoDownloadEnabled" ) >>= bValue; + aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName("/org.openoffice.Office.Jobs/Jobs/org.openoffice.Office.Jobs:Job['UpdateCheck']/Arguments/AutoDownloadEnabled"); + bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0; + m_xAutoDownloadCheckBox->set_active(bValue); + m_xAutoDownloadCheckBox->set_sensitive(!bReadOnly); + m_xAutoDownloadImg->set_visible(bReadOnly); + m_xDestPathLabel->set_sensitive(true); + m_xDestPath->set_sensitive(true); + + OUString sValue, aPath; + m_xUpdateAccess->getByName( "DownloadDestination" ) >>= sValue; + aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName("/org.openoffice.Office.Jobs/Jobs/org.openoffice.Office.Jobs:Job['UpdateCheck']/Arguments/DownloadDestination"); + bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0; + m_xChangePathButton->set_sensitive(!bReadOnly); + + if( osl::FileBase::E_None == osl::FileBase::getSystemPathFromFileURL(sValue, aPath) ) + m_xDestPath->set_label(aPath); + + m_xUpdateAccess->getByName( "ExtendedUserAgent" ) >>= bValue; + aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName("/org.openoffice.Office.Jobs/Jobs/org.openoffice.Office.Jobs:Job['UpdateCheck']/Arguments/ExtendedUserAgent"); + bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0; + m_xExtrasCheckBox->set_active(bValue); + m_xExtrasCheckBox->set_sensitive(!bReadOnly); + m_xExtrasImg->set_visible(bReadOnly); + m_xExtrasCheckBox->save_state(); + UpdateUserAgent(); + + m_xAutoDownloadCheckBox->save_state(); + } + + if (m_showMarOnlineUpdate) { + m_xEnableMar->set_active(officecfg::Office::Update::Update::Enabled::get()); + m_xEnableMar->save_state(); + } +} + +void SvxOnlineUpdateTabPage::FillUserData() +{ +} + +IMPL_LINK(SvxOnlineUpdateTabPage, AutoCheckHdl_Impl, weld::Toggleable&, rBox, void) +{ + bool bEnabled = rBox.get_active(); + beans::Property aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName("/org.openoffice.Office.Jobs/Jobs/org.openoffice.Office.Jobs:Job['UpdateCheck']/Arguments/CheckInterval"); + bool bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0; + m_xEveryDayButton->set_sensitive(bEnabled && !bReadOnly); + m_xEveryWeekButton->set_sensitive(bEnabled && !bReadOnly); + m_xEveryMonthButton->set_sensitive(bEnabled && !bReadOnly); + m_xCheckIntervalImg->set_visible(bReadOnly); +} + +IMPL_LINK_NOARG(SvxOnlineUpdateTabPage, ExtrasCheckHdl_Impl, weld::Toggleable&, void) +{ + UpdateUserAgent(); +} + +IMPL_LINK_NOARG(SvxOnlineUpdateTabPage, FileDialogHdl_Impl, weld::Button&, void) +{ + uno::Reference < uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + uno::Reference < ui::dialogs::XFolderPicker2 > xFolderPicker = sfx2::createFolderPicker(xContext, GetFrameWeld()); + + OUString aURL; + if( osl::FileBase::E_None != osl::FileBase::getFileURLFromSystemPath(m_xDestPath->get_label(), aURL) ) + osl::Security().getHomeDir(aURL); + + xFolderPicker->setDisplayDirectory( aURL ); + sal_Int16 nRet = xFolderPicker->execute(); + + if ( ui::dialogs::ExecutableDialogResults::OK == nRet ) + { + OUString aFolder; + if( osl::FileBase::E_None == osl::FileBase::getSystemPathFromFileURL(xFolderPicker->getDirectory(), aFolder)) + m_xDestPath->set_label(aFolder); + } +} + +IMPL_LINK_NOARG(SvxOnlineUpdateTabPage, CheckNowHdl_Impl, weld::Button&, void) +{ + uno::Reference < uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() ); + + try + { + uno::Reference< lang::XMultiServiceFactory > xConfigProvider( + css::configuration::theDefaultProvider::get( xContext ) ); + + beans::NamedValue aProperty; + aProperty.Name = "nodepath"; + aProperty.Value <<= OUString("org.openoffice.Office.Addons/AddonUI/OfficeHelp/UpdateCheckJob"); + + uno::Sequence< uno::Any > aArgumentList{ uno::Any(aProperty) }; + + uno::Reference< container::XNameAccess > xNameAccess( + xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", aArgumentList ), + uno::UNO_QUERY_THROW ); + + util::URL aURL; + xNameAccess->getByName("URL") >>= aURL.Complete; + + uno::Reference < util::XURLTransformer > xTransformer( util::URLTransformer::create( xContext ) ); + + xTransformer->parseStrict(aURL); + + uno::Reference < frame::XDesktop2 > xDesktop = frame::Desktop::create( xContext ); + + uno::Reference< frame::XDispatchProvider > xDispatchProvider( + xDesktop->getCurrentFrame(), uno::UNO_QUERY ); + + uno::Reference< frame::XDispatch > xDispatch; + if( xDispatchProvider.is() ) + xDispatch = xDispatchProvider->queryDispatch(aURL, OUString(), 0); + + if( xDispatch.is() ) + xDispatch->dispatch(aURL, uno::Sequence< beans::PropertyValue > ()); + + UpdateLastCheckedText(); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("cui.options", "Caught exception, thread terminated"); + } +} + +bool SvxOnlineUpdateTabPage::isTraditionalOnlineUpdateAvailable() { + try + { + css::uno::Reference < css::uno::XInterface > xService( setup::UpdateCheck::create( ::comphelper::getProcessComponentContext() ) ); + if( xService.is() ) + return true; + } + catch ( css::uno::DeploymentException& ) + { + } + return false; +} + +bool SvxOnlineUpdateTabPage::isMarOnlineUpdateAvailable() { +#if HAVE_FEATURE_UPDATE_MAR + return officecfg::Office::Common::Misc::ExperimentalMode::get(); +#else + return false; +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/optupdt.hxx b/cui/source/options/optupdt.hxx new file mode 100644 index 0000000000..48113c8079 --- /dev/null +++ b/cui/source/options/optupdt.hxx @@ -0,0 +1,87 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sfx2/tabdlg.hxx> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/configuration/XReadWriteAccess.hpp> + +// class SvxPathTabPage -------------------------------------------------- + +class SvxOnlineUpdateTabPage : public SfxTabPage +{ +private: + bool m_showTraditionalOnlineUpdate; + bool m_showMarOnlineUpdate; + + OUString m_aNeverChecked; + OUString m_aLastCheckedTemplate; + + css::uno::Reference< css::container::XNameReplace > m_xUpdateAccess; + css::uno::Reference<css::configuration::XReadWriteAccess> m_xReadWriteAccess; + + std::unique_ptr<weld::Label> m_xNeverChecked; + std::unique_ptr<weld::CheckButton> m_xAutoCheckCheckBox; + std::unique_ptr<weld::Widget> m_xAutoCheckImg; + std::unique_ptr<weld::RadioButton> m_xEveryDayButton; + std::unique_ptr<weld::RadioButton> m_xEveryWeekButton; + std::unique_ptr<weld::RadioButton> m_xEveryMonthButton; + std::unique_ptr<weld::Widget> m_xCheckIntervalImg; + std::unique_ptr<weld::Button> m_xCheckNowButton; + std::unique_ptr<weld::CheckButton> m_xAutoDownloadCheckBox; + std::unique_ptr<weld::Widget> m_xAutoDownloadImg; + std::unique_ptr<weld::Label> m_xDestPathLabel; + std::unique_ptr<weld::Label> m_xDestPath; + std::unique_ptr<weld::Button> m_xChangePathButton; + std::unique_ptr<weld::Label> m_xLastChecked; + std::unique_ptr<weld::CheckButton> m_xExtrasCheckBox; + std::unique_ptr<weld::Widget> m_xExtrasImg; + std::unique_ptr<weld::Label> m_xUserAgentLabel; + std::unique_ptr<weld::LinkButton> m_xPrivacyPolicyButton; + std::unique_ptr<weld::Box> m_xBox2; + std::unique_ptr<weld::Frame> m_xFrameDest; + std::unique_ptr<weld::Frame> m_xFrameAgent; + std::unique_ptr<weld::Frame> m_xMar; + std::unique_ptr<weld::CheckButton> m_xEnableMar; + + DECL_LINK(FileDialogHdl_Impl, weld::Button&, void); + DECL_LINK(CheckNowHdl_Impl, weld::Button&, void); + DECL_LINK(AutoCheckHdl_Impl, weld::Toggleable&, void); + DECL_LINK(ExtrasCheckHdl_Impl, weld::Toggleable&, void); + + void UpdateLastCheckedText(); + void UpdateUserAgent(); + +public: + SvxOnlineUpdateTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet ); + virtual ~SvxOnlineUpdateTabPage() override; + + virtual OUString GetAllStrings() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + virtual void FillUserData() override; + + static bool isTraditionalOnlineUpdateAvailable(); + static bool isMarOnlineUpdateAvailable(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/personalization.cxx b/cui/source/options/personalization.cxx new file mode 100644 index 0000000000..657344d60c --- /dev/null +++ b/cui/source/options/personalization.cxx @@ -0,0 +1,200 @@ +/* -*- 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/. + */ + +#include <config_folders.h> + +#include "personalization.hxx" + +#include <dialmgr.hxx> + +#include <comphelper/processfactory.hxx> +#include <officecfg/Office/Common.hxx> +#include <rtl/bootstrap.hxx> +#include <tools/urlobj.hxx> +#include <tools/stream.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/virdev.hxx> +#include <personas.hrc> + +using namespace com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +// persona +SvxPersonalizationTabPage::SvxPersonalizationTabPage(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/personalization_tab.ui", "PersonalizationTabPage", + &rSet) + , m_xNoPersona(m_xBuilder->weld_radio_button("no_persona")) + , m_xPersonaImg(m_xBuilder->weld_widget("lockpersona")) + , m_xDefaultPersona(m_xBuilder->weld_radio_button("default_persona")) + , m_xContentGrid(m_xBuilder->weld_container("gridpersonasetting")) +{ + for (sal_uInt32 i = 0; i < MAX_DEFAULT_PERSONAS; ++i) + { + OUString sDefaultId("default" + OUString::number(i)); + m_vDefaultPersonaImages[i] = m_xBuilder->weld_toggle_button(sDefaultId); + m_vDefaultPersonaImages[i]->connect_clicked( + LINK(this, SvxPersonalizationTabPage, DefaultPersona)); + } + + LoadDefaultImages(); +} + +SvxPersonalizationTabPage::~SvxPersonalizationTabPage() {} + +std::unique_ptr<SfxTabPage> SvxPersonalizationTabPage::Create(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet* rSet) +{ + return std::make_unique<SvxPersonalizationTabPage>(pPage, pController, *rSet); +} + +OUString SvxPersonalizationTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString radioButton[] = { "no_persona", "default_persona" }; + + for (const auto& radio : radioButton) + { + if (const auto& pString = m_xBuilder->weld_radio_button(radio)) + sAllStrings += pString->get_label() + " "; + } + + if (const auto& pString = m_xBuilder->weld_label("personas_label")) + sAllStrings += pString->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SvxPersonalizationTabPage::FillItemSet(SfxItemSet*) +{ + // persona + OUString aPersona("default"); + if (m_xNoPersona->get_active()) + aPersona = "no"; + + bool bModified = false; + if (aPersona != officecfg::Office::Common::Misc::Persona::get() + || m_aPersonaSettings != officecfg::Office::Common::Misc::PersonaSettings::get()) + { + bModified = true; + } + + // write + std::shared_ptr<comphelper::ConfigurationChanges> batch( + comphelper::ConfigurationChanges::create()); + if (aPersona == "no") + m_aPersonaSettings.clear(); + officecfg::Office::Common::Misc::Persona::set(aPersona, batch); + officecfg::Office::Common::Misc::PersonaSettings::set(m_aPersonaSettings, batch); + batch->commit(); + + if (bModified) + { + // broadcast the change + DataChangedEvent aDataChanged(DataChangedEventType::SETTINGS, nullptr, + AllSettingsFlags::STYLE); + Application::NotifyAllWindows(aDataChanged); + } + + return bModified; +} + +void SvxPersonalizationTabPage::Reset(const SfxItemSet*) +{ + // persona + OUString aPersona = officecfg::Office::Common::Misc::Persona::get(); + m_aPersonaSettings = officecfg::Office::Common::Misc::PersonaSettings::get(); + + if (aPersona == "no") + m_xNoPersona->set_active(true); + else + m_xDefaultPersona->set_active(true); + + if (officecfg::Office::Common::Misc::Persona::isReadOnly()) + { + m_xNoPersona->set_sensitive(false); + m_xDefaultPersona->set_sensitive(false); + m_xPersonaImg->set_visible(true); + } + + if (officecfg::Office::Common::Misc::PersonaSettings::isReadOnly()) + m_xContentGrid->set_sensitive(false); +} + +void SvxPersonalizationTabPage::LoadDefaultImages() +{ + // Load the pre saved personas + + OUString gallery = "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/gallery/personas/"; + rtl::Bootstrap::expandMacros(gallery); + OUString aPersonasList = gallery + "personas_list.txt"; + SvFileStream aStream(aPersonasList, StreamMode::READ); + GraphicFilter aFilter; + Graphic aGraphic; + sal_Int32 nIndex = 0; + bool foundOne = false; + + OStringBuffer aLine; + int nLineNumberFilePersona = 0; + while (aStream.IsOpen() && !aStream.eof() && nIndex < MAX_DEFAULT_PERSONAS) + { + OUString aPersonaSetting, aPreviewFile, aName; + sal_Int32 nParseIndex = 0; + + aStream.ReadLine(aLine); + aPersonaSetting = OStringToOUString(aLine, RTL_TEXTENCODING_UTF8); + aName = CuiResId(RID_PERSONAS_COLOR[nLineNumberFilePersona].first); + aPreviewFile = aPersonaSetting.getToken(2, ';', nParseIndex); + + if (aPreviewFile.isEmpty()) + break; + + m_vDefaultPersonaSettings.push_back(aPersonaSetting); + + INetURLObject aURLObj(rtl::Concat2View(gallery + aPreviewFile)); + aFilter.ImportGraphic(aGraphic, aURLObj); + + Size aSize(aGraphic.GetSizePixel()); + aSize.setWidth(aSize.Width() / 4); + aSize.setHeight(aSize.Height() / 1.5); + ScopedVclPtr<VirtualDevice> xVirDev + = m_vDefaultPersonaImages[nIndex]->create_virtual_device(); + xVirDev->SetOutputSizePixel(aSize); + aGraphic.Draw(*xVirDev, Point(0, 0)); + m_vDefaultPersonaImages[nIndex]->set_image(xVirDev.get()); + xVirDev.disposeAndClear(); + + m_vDefaultPersonaImages[nIndex]->set_tooltip_text(aName); + m_vDefaultPersonaImages[nIndex++]->show(); + foundOne = true; + ++nLineNumberFilePersona; + } + + m_xDefaultPersona->set_sensitive(foundOne); +} + +IMPL_LINK(SvxPersonalizationTabPage, DefaultPersona, weld::Button&, rButton, void) +{ + m_xDefaultPersona->set_active(true); + for (sal_Int32 nIndex = 0; nIndex < MAX_DEFAULT_PERSONAS; ++nIndex) + { + if (&rButton == m_vDefaultPersonaImages[nIndex].get()) + m_aPersonaSettings = m_vDefaultPersonaSettings[nIndex]; + else + m_vDefaultPersonaImages[nIndex]->set_active(false); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/personalization.hxx b/cui/source/options/personalization.hxx new file mode 100644 index 0000000000..786b22c7d7 --- /dev/null +++ b/cui/source/options/personalization.hxx @@ -0,0 +1,66 @@ +/* -*- 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/. + */ + +#pragma once + +#include <sfx2/tabdlg.hxx> +#include <vector> + +#define MAX_DEFAULT_PERSONAS 6 // Maximum number of default personas + +class SvxPersonalizationTabPage : public SfxTabPage +{ +private: + std::unique_ptr<weld::RadioButton> m_xNoPersona; ///< Just the default look, without any bitmap + std::unique_ptr<weld::Widget> m_xPersonaImg; + std::unique_ptr<weld::RadioButton> m_xDefaultPersona; ///< Use the built-in bitmap + std::unique_ptr<weld::Container> m_xContentGrid; + std::unique_ptr<weld::ToggleButton> m_vDefaultPersonaImages + [MAX_DEFAULT_PERSONAS]; ///< Buttons to show the default persona images + OUString m_aPersonaSettings; ///< Header and footer images + color to be set in the settings. + + std::vector<OUString> m_vDefaultPersonaSettings; + +public: + SvxPersonalizationTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet); + virtual ~SvxPersonalizationTabPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual OUString GetAllStrings() override; + + /// Apply the settings ([OK] button). + virtual bool FillItemSet(SfxItemSet* rSet) override; + + /// Reset to default settings ([Revert] button). + virtual void Reset(const SfxItemSet* rSet) override; + + /* + * Loads the default personas from the shared personas directory + * which resides in the shared gallery. + * There needs to be a separate subdirectory for each default persona, + * which includes the preview, header, and footer images. + * And there needs to be a personas_list.txt file in the personas directory + * which keeps the index/info of the default personas, one persona per line. + * A line should look like this: + * persona_slug;Persona Name;subdir/preview.jpg;subdir/header.jpg;subdir/footer.jpg;#textcolor + * (It is recommended to keep the subdir name the same as the slug) + * Example line: + * abstract;Abstract;abstract/preview.jpg;abstract/Header2.jpg;abstract/Footer2.jpg;#ffffff + */ + void LoadDefaultImages(); + +private: + /// Handle the default Persona selection + DECL_LINK(DefaultPersona, weld::Button&, void); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/sdbcdriverenum.cxx b/cui/source/options/sdbcdriverenum.cxx new file mode 100644 index 0000000000..0ddd7f8f9f --- /dev/null +++ b/cui/source/options/sdbcdriverenum.cxx @@ -0,0 +1,99 @@ +/* -*- 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 "sdbcdriverenum.hxx" +#include <comphelper/processfactory.hxx> +#include <osl/diagnose.h> +#include <comphelper/diagnose_ex.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbc/DriverManager.hpp> + + +namespace offapp +{ + + + using namespace css::uno; + using namespace css::lang; + using namespace css::container; + using namespace css::sdbc; + + class ODriverEnumerationImpl + { + protected: + std::vector< OUString > m_aImplNames; + + public: + ODriverEnumerationImpl(); + + const std::vector< OUString >& getDriverImplNames() const { return m_aImplNames; } + }; + + + ODriverEnumerationImpl::ODriverEnumerationImpl() + { + try + { + Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + Reference< XDriverManager2 > xEnumAccess = DriverManager::create( xContext ); + + Reference< XEnumeration > xEnumDrivers = xEnumAccess->createEnumeration(); + OSL_ENSURE(xEnumDrivers.is(), "ODriverEnumerationImpl::ODriverEnumerationImpl: invalid enumeration object!"); + + Reference< XServiceInfo > xDriverSI; + while (xEnumDrivers->hasMoreElements()) + { + xEnumDrivers->nextElement() >>= xDriverSI; + OSL_ENSURE(xDriverSI.is(), "ODriverEnumerationImpl::ODriverEnumerationImpl: driver without service info!"); + if (xDriverSI.is()) + m_aImplNames.push_back(xDriverSI->getImplementationName()); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "cui.options", "ODriverEnumerationImpl::ODriverEnumerationImpl: caught an exception while enumerating the drivers!"); + } + } + + ODriverEnumeration::ODriverEnumeration() noexcept + :m_pImpl(new ODriverEnumerationImpl) + { + } + + + ODriverEnumeration::~ODriverEnumeration() noexcept + { + } + + + ODriverEnumeration::const_iterator ODriverEnumeration::begin() const noexcept + { + return m_pImpl->getDriverImplNames().begin(); + } + + + ODriverEnumeration::const_iterator ODriverEnumeration::end() const noexcept + { + return m_pImpl->getDriverImplNames().end(); + } + +} // namespace offapp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/sdbcdriverenum.hxx b/cui/source/options/sdbcdriverenum.hxx new file mode 100644 index 0000000000..852648893f --- /dev/null +++ b/cui/source/options/sdbcdriverenum.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#pragma once + +#include <rtl/ustring.hxx> + +#include <vector> +#include <memory> + + +namespace offapp +{ + + class ODriverEnumerationImpl; + /** simple class for accessing SDBC drivers registered within the office + <p>Rather small, introduced to not contaminate other instances with the + exception handling (code-size-bloating) implementations here. + </p> + */ + class ODriverEnumeration + { + private: + std::unique_ptr<ODriverEnumerationImpl> m_pImpl; + + public: + ODriverEnumeration() noexcept; + ~ODriverEnumeration() noexcept; + typedef std::vector< OUString >::const_iterator const_iterator; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + }; + + +} // namespace offapp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/securityoptions.cxx b/cui/source/options/securityoptions.cxx new file mode 100644 index 0000000000..d583f62618 --- /dev/null +++ b/cui/source/options/securityoptions.cxx @@ -0,0 +1,118 @@ +/* -*- 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 <unotools/securityoptions.hxx> +#include "securityoptions.hxx" + +namespace +{ + bool enableAndSet(SvtSecurityOptions::EOption eOption, + weld::CheckButton& rCheckBox, weld::Widget& rFixedImage) + { + bool bEnable = !SvtSecurityOptions::IsReadOnly(eOption); + rCheckBox.set_sensitive(bEnable); + rFixedImage.set_visible(!bEnable); + rCheckBox.set_active(SvtSecurityOptions::IsOptionSet(eOption)); + return bEnable; + } +} + +namespace svx +{ + +SecurityOptionsDialog::SecurityOptionsDialog(weld::Window* pParent) + : GenericDialogController(pParent, "cui/ui/securityoptionsdialog.ui", "SecurityOptionsDialog") + , m_xSaveOrSendDocsCB(m_xBuilder->weld_check_button("savesenddocs")) + , m_xSaveOrSendDocsImg(m_xBuilder->weld_widget("locksavesenddocs")) + , m_xSignDocsCB(m_xBuilder->weld_check_button("whensigning")) + , m_xSignDocsImg(m_xBuilder->weld_widget("lockwhensigning")) + , m_xPrintDocsCB(m_xBuilder->weld_check_button("whenprinting")) + , m_xPrintDocsImg(m_xBuilder->weld_widget("lockwhenprinting")) + , m_xCreatePdfCB(m_xBuilder->weld_check_button("whenpdf")) + , m_xCreatePdfImg(m_xBuilder->weld_widget("lockwhenpdf")) + , m_xRemovePersInfoCB(m_xBuilder->weld_check_button("removepersonal")) + , m_xRemovePersInfoImg(m_xBuilder->weld_widget("lockremovepersonal")) + , m_xRecommPasswdCB(m_xBuilder->weld_check_button("password")) + , m_xRecommPasswdImg(m_xBuilder->weld_widget("lockpassword")) + , m_xCtrlHyperlinkCB(m_xBuilder->weld_check_button("ctrlclick")) + , m_xCtrlHyperlinkImg(m_xBuilder->weld_widget("lockctrlclick")) + , m_xBlockUntrustedRefererLinksCB(m_xBuilder->weld_check_button("blockuntrusted")) + , m_xBlockUntrustedRefererLinksImg(m_xBuilder->weld_widget("lockblockuntrusted")) + , m_xRedlineinfoCB(m_xBuilder->weld_check_button("redlineinfo")) + , m_xRedlineinfoImg(m_xBuilder->weld_widget("lockredlineinfo")) + , m_xDocPropertiesCB(m_xBuilder->weld_check_button("docproperties")) + , m_xDocPropertiesImg(m_xBuilder->weld_widget("lockdocproperties")) + , m_xNoteAuthorCB(m_xBuilder->weld_check_button("noteauthor")) + , m_xNoteAuthorImg(m_xBuilder->weld_widget("locknoteauthor")) + , m_xDocumentVersionCB(m_xBuilder->weld_check_button("documentversion")) + , m_xDocumentVersionImg(m_xBuilder->weld_widget("lockdocumentversion")) +{ + m_xRemovePersInfoCB->connect_toggled(LINK(this, SecurityOptionsDialog, ShowPersonalInfosToggle)); + init(); +} + +IMPL_LINK_NOARG(SecurityOptionsDialog, ShowPersonalInfosToggle, weld::Toggleable&, void) +{ + changeKeepSecurityInfosEnabled(); +} + +void SecurityOptionsDialog::init() +{ + enableAndSet(SvtSecurityOptions::EOption::DocWarnSaveOrSend, *m_xSaveOrSendDocsCB, + *m_xSaveOrSendDocsImg); + enableAndSet(SvtSecurityOptions::EOption::DocWarnSigning, *m_xSignDocsCB, + *m_xSignDocsImg); + enableAndSet(SvtSecurityOptions::EOption::DocWarnPrint, *m_xPrintDocsCB, + *m_xPrintDocsImg); + enableAndSet(SvtSecurityOptions::EOption::DocWarnCreatePdf, *m_xCreatePdfCB, + *m_xCreatePdfImg); + enableAndSet(SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo, *m_xRemovePersInfoCB, + *m_xRemovePersInfoImg); + enableAndSet(SvtSecurityOptions::EOption::DocWarnKeepRedlineInfo, *m_xRedlineinfoCB, + *m_xRedlineinfoImg); + enableAndSet(SvtSecurityOptions::EOption::DocWarnKeepDocUserInfo, *m_xDocPropertiesCB, + *m_xDocPropertiesImg); + enableAndSet(SvtSecurityOptions::EOption::DocWarnKeepNoteAuthorDateInfo, *m_xNoteAuthorCB, + *m_xNoteAuthorImg); + enableAndSet(SvtSecurityOptions::EOption::DocWarnKeepDocVersionInfo, *m_xDocumentVersionCB, + *m_xDocumentVersionImg); + enableAndSet(SvtSecurityOptions::EOption::DocWarnRecommendPassword, *m_xRecommPasswdCB, + *m_xRecommPasswdImg); + enableAndSet(SvtSecurityOptions::EOption::CtrlClickHyperlink, *m_xCtrlHyperlinkCB, + *m_xCtrlHyperlinkImg); + enableAndSet(SvtSecurityOptions::EOption::BlockUntrustedRefererLinks, *m_xBlockUntrustedRefererLinksCB, + *m_xBlockUntrustedRefererLinksImg); + + if (!SvtSecurityOptions::IsReadOnly(SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo)) + changeKeepSecurityInfosEnabled(); +} + +void SecurityOptionsDialog::changeKeepSecurityInfosEnabled() +{ + bool bEnable = m_xRemovePersInfoCB->get_active(); + m_xRedlineinfoCB->set_sensitive(bEnable); + m_xDocPropertiesCB->set_sensitive(bEnable); + m_xNoteAuthorCB->set_sensitive(bEnable); + m_xDocumentVersionCB->set_sensitive(bEnable); +} + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/securityoptions.hxx b/cui/source/options/securityoptions.hxx new file mode 100644 index 0000000000..7884ccfbd3 --- /dev/null +++ b/cui/source/options/securityoptions.hxx @@ -0,0 +1,79 @@ +/* -*- 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 . + */ +#pragma once + +#include <vcl/weld.hxx> + +namespace svx +{ + class SecurityOptionsDialog : public weld::GenericDialogController + { + private: + std::unique_ptr<weld::CheckButton> m_xSaveOrSendDocsCB; + std::unique_ptr<weld::Widget> m_xSaveOrSendDocsImg; + std::unique_ptr<weld::CheckButton> m_xSignDocsCB; + std::unique_ptr<weld::Widget> m_xSignDocsImg; + std::unique_ptr<weld::CheckButton> m_xPrintDocsCB; + std::unique_ptr<weld::Widget> m_xPrintDocsImg; + std::unique_ptr<weld::CheckButton> m_xCreatePdfCB; + std::unique_ptr<weld::Widget> m_xCreatePdfImg; + + std::unique_ptr<weld::CheckButton> m_xRemovePersInfoCB; + std::unique_ptr<weld::Widget> m_xRemovePersInfoImg; + std::unique_ptr<weld::CheckButton> m_xRecommPasswdCB; + std::unique_ptr<weld::Widget> m_xRecommPasswdImg; + std::unique_ptr<weld::CheckButton> m_xCtrlHyperlinkCB; + std::unique_ptr<weld::Widget> m_xCtrlHyperlinkImg; + std::unique_ptr<weld::CheckButton> m_xBlockUntrustedRefererLinksCB; + std::unique_ptr<weld::Widget> m_xBlockUntrustedRefererLinksImg; + + std::unique_ptr<weld::CheckButton> m_xRedlineinfoCB; + std::unique_ptr<weld::Widget> m_xRedlineinfoImg; + std::unique_ptr<weld::CheckButton> m_xDocPropertiesCB; + std::unique_ptr<weld::Widget> m_xDocPropertiesImg; + std::unique_ptr<weld::CheckButton> m_xNoteAuthorCB; + std::unique_ptr<weld::Widget> m_xNoteAuthorImg; + std::unique_ptr<weld::CheckButton> m_xDocumentVersionCB; + std::unique_ptr<weld::Widget> m_xDocumentVersionImg; + + public: + SecurityOptionsDialog(weld::Window* pParent); + + void init(); + + bool IsSaveOrSendDocsChecked() const { return m_xSaveOrSendDocsCB->get_active(); } + bool IsSignDocsChecked() const { return m_xSignDocsCB->get_active(); } + bool IsPrintDocsChecked() const { return m_xPrintDocsCB->get_active(); } + bool IsCreatePdfChecked() const { return m_xCreatePdfCB->get_active(); } + bool IsRemovePersInfoChecked() const { return m_xRemovePersInfoCB->get_active(); } + bool IsRemoveRedlineInfoChecked() const { return m_xRedlineinfoCB->get_active(); } + bool IsRemoveDocUserInfoChecked() const { return m_xDocPropertiesCB->get_active(); } + bool IsRemoveNoteAuthorInfoChecked() const { return m_xNoteAuthorCB->get_active(); } + bool IsRemoveDocVersionInfoChecked() const { return m_xDocumentVersionCB->get_active(); } + bool IsRecommPasswdChecked() const { return m_xRecommPasswdCB->get_active(); } + bool IsCtrlHyperlinkChecked() const { return m_xCtrlHyperlinkCB->get_active(); } + bool IsBlockUntrustedRefererLinksChecked() const { return m_xBlockUntrustedRefererLinksCB->get_active(); } + + DECL_LINK(ShowPersonalInfosToggle, weld::Toggleable&, void); + + void changeKeepSecurityInfosEnabled(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/treeopt.cxx b/cui/source/options/treeopt.cxx new file mode 100644 index 0000000000..d8fe793e10 --- /dev/null +++ b/cui/source/options/treeopt.cxx @@ -0,0 +1,2748 @@ +/* -*- 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 "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 "optcolor.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 "personalization.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 <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::beans; +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::get(); + 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_PERSONALIZATION: fnCreate = &SvxPersonalizationTabPage::Create; break; +#endif + case RID_SVXPAGE_COLORCONFIG: fnCreate = &SvxColorOptionsTabPage::Create; break; + 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 +{ + const char* m_pGroupName; + const char* m_pPageName; + sal_uInt16 m_nPageId; +}; + +} + +OptionsMapping_Impl const OptionsMap_Impl[] = +{ +// GROUP PAGE PAGE-ID + { "ProductName", nullptr, SID_GENERAL_OPTIONS }, + { "ProductName", "UserData", RID_SFXPAGE_GENERAL }, + { "ProductName", "General", OFA_TP_MISC }, + { "ProductName", "View", OFA_TP_VIEW }, + { "ProductName", "Print", RID_SFXPAGE_PRINTOPTIONS }, + { "ProductName", "Paths", RID_SFXPAGE_PATH }, + { "ProductName", "Fonts", RID_SVX_FONT_SUBSTITUTION }, + { "ProductName", "Security", RID_SVXPAGE_INET_SECURITY }, + { "ProductName", "Personalization", RID_SVXPAGE_PERSONALIZATION }, + { "ProductName", "Appearance", RID_SVXPAGE_COLORCONFIG }, + { "ProductName", "Accessibility", RID_SVXPAGE_ACCESSIBILITYCONFIG }, + { "ProductName", "Java", RID_SVXPAGE_OPTIONS_JAVA }, + { "ProductName", "BasicIDEOptions", RID_SVXPAGE_BASICIDE_OPTIONS }, + { "ProductName", "OnlineUpdate", RID_SVXPAGE_ONLINEUPDATE }, + { "LanguageSettings", nullptr, SID_LANGUAGE_OPTIONS }, + { "LanguageSettings", "Languages", OFA_TP_LANGUAGES }, + { "LanguageSettings", "WritingAids", RID_SFXPAGE_LINGU }, + { "LanguageSettings", "SearchingInJapanese", RID_SVXPAGE_JSEARCH_OPTIONS }, + { "LanguageSettings", "AsianLayout", RID_SVXPAGE_ASIAN_LAYOUT }, + { "LanguageSettings", "ComplexTextLayout", RID_SVXPAGE_OPTIONS_CTL }, + { "Internet", nullptr, SID_INET_DLG }, + { "Internet", "Proxy", RID_SVXPAGE_INET_PROXY }, + { "Internet", "Email", RID_SVXPAGE_INET_MAIL }, + { "LoadSave", nullptr, SID_FILTER_DLG }, + { "LoadSave", "General", RID_SFXPAGE_SAVE }, + { "LoadSave", "VBAProperties", SID_OPTFILTER_MSOFFICE }, + { "LoadSave", "MicrosoftOffice", RID_OFAPAGE_MSFILTEROPT2 }, + { "LoadSave", "HTMLCompatibility", RID_OFAPAGE_HTMLOPT }, + { "Writer", nullptr, SID_SW_EDITOPTIONS }, + { "Writer", "General", RID_SW_TP_OPTLOAD_PAGE }, + { "Writer", "View", RID_SW_TP_CONTENT_OPT }, + { "Writer", "FormattingAids", RID_SW_TP_OPTSHDWCRSR }, + { "Writer", "Grid", RID_SVXPAGE_GRID }, + { "Writer", "BasicFontsWestern", RID_SW_TP_STD_FONT }, + { "Writer", "BasicFontsAsian", RID_SW_TP_STD_FONT_CJK }, + { "Writer", "BasicFontsCTL", RID_SW_TP_STD_FONT_CTL }, + { "Writer", "Print", RID_SW_TP_OPTPRINT_PAGE }, + { "Writer", "Table", RID_SW_TP_OPTTABLE_PAGE }, + { "Writer", "Changes", RID_SW_TP_REDLINE_OPT }, + { "Writer", "Comparison", RID_SW_TP_COMPARISON_OPT }, + { "Writer", "Compatibility", RID_SW_TP_OPTCOMPATIBILITY_PAGE }, + { "Writer", "AutoCaption", RID_SW_TP_OPTCAPTION_PAGE }, + { "Writer", "MailMerge", RID_SW_TP_MAILCONFIG }, + { "WriterWeb", nullptr, SID_SW_ONLINEOPTIONS }, + { "WriterWeb", "View", RID_SW_TP_HTML_CONTENT_OPT }, + { "WriterWeb", "FormattingAids", RID_SW_TP_HTML_OPTSHDWCRSR }, + { "WriterWeb", "Grid", RID_SW_TP_HTML_OPTGRID_PAGE }, + { "WriterWeb", "Print", RID_SW_TP_HTML_OPTPRINT_PAGE }, + { "WriterWeb", "Table", RID_SW_TP_HTML_OPTTABLE_PAGE }, + { "WriterWeb", "Background", RID_SW_TP_BACKGROUND }, + { "Math", nullptr, SID_SM_EDITOPTIONS }, + { "Math", "Settings", SID_SM_TP_PRINTOPTIONS }, + { "Calc", nullptr, SID_SC_EDITOPTIONS }, + { "Calc", "General", SID_SC_TP_LAYOUT }, + { "Calc", "View", SID_SC_TP_CONTENT }, + { "Calc", "Calculate", SID_SC_TP_CALC }, + { "Calc", "Formula", SID_SC_TP_FORMULA }, + { "Calc", "SortLists", SID_SC_TP_USERLISTS }, + { "Calc", "Changes", SID_SC_TP_CHANGES }, + { "Calc", "Compatibility", SID_SC_TP_COMPATIBILITY }, + { "Calc", "Grid", SID_SC_TP_GRID }, + { "Calc", "Print", RID_SC_TP_PRINT }, + { "Impress", nullptr, SID_SD_EDITOPTIONS }, + { "Impress", "General", SID_SI_TP_MISC }, + { "Impress", "View", SID_SI_TP_CONTENTS }, + { "Impress", "Grid", SID_SI_TP_SNAP }, + { "Impress", "Print", SID_SI_TP_PRINT }, + { "Draw", nullptr, SID_SD_GRAPHIC_OPTIONS }, + { "Draw", "General", SID_SD_TP_MISC }, + { "Draw", "View", SID_SD_TP_CONTENTS }, + { "Draw", "Grid", SID_SD_TP_SNAP }, + { "Draw", "Print", SID_SD_TP_PRINT }, + { "Charts", nullptr, SID_SCH_EDITOPTIONS }, + { "Charts", "DefaultColors", RID_OPTPAGE_CHART_DEFCOLORS }, + { "Base", nullptr, SID_SB_STARBASEOPTIONS }, + { "Base", "Connections", SID_SB_CONNECTIONPOOLING }, + { "Base", "Databases", SID_SB_DBREGISTEROPTIONS }, + { nullptr, nullptr, 0 } +}; + +static bool lcl_getStringFromID( sal_uInt16 _nPageId, OUString& _rGroupName, OUString& _rPageName ) +{ + bool bRet = false; + + sal_uInt16 nIdx = 0; + while ( OptionsMap_Impl[nIdx].m_pGroupName != nullptr ) + { + if ( _nPageId == OptionsMap_Impl[nIdx].m_nPageId ) + { + bRet = true; + _rGroupName = OUString::createFromAscii( OptionsMap_Impl[nIdx].m_pGroupName ); + if ( OptionsMap_Impl[nIdx].m_pPageName != nullptr ) + _rPageName = OUString::createFromAscii( OptionsMap_Impl[nIdx].m_pPageName ); + break; + } + ++nIdx; + } + + 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, "cui/ui/optionsdialog.ui", "OptionsDialog") + , xOkPB(m_xBuilder->weld_button("ok")) + , xApplyPB(m_xBuilder->weld_button("apply")) + , xBackPB(m_xBuilder->weld_button("revert")) + , xTreeLB(m_xBuilder->weld_tree_view("pages")) + , xTabBox(m_xBuilder->weld_container("box")) + , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry")) + , 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() * 82, xTreeLB->get_height_rows(30)); +#if HAVE_FEATURE_GPGME + // tdf#115015: make enough space for crypto settings (approx. 14 text edits + padding) + aSize.setHeight((weld::GetMinimumEditHeight() + 6) * 14); +#endif + 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_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(); +} + +OfaTreeOptionsDialog::~OfaTreeOptionsDialog() +{ + 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(); +} + +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) +{ + // initializeFirstNDialog() can take a long time, show wait cursor and disable input + std::unique_ptr<weld::WaitObject> xWait(m_pParent ? new weld::WaitObject(m_pParent) : nullptr); + + // Pause redraw + xTreeLB->freeze(); + + if (bIsFirtsInitialize) + { + m_xSearchEdit->freeze(); + xTreeLB->hide(); + + initializeFirstNDialog(); + + 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(); +} + +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::initializeFirstNDialog(sal_Int16 nNumberOfNode) +{ + std::unique_ptr<weld::TreeIter> xEntry; + sal_Int16 nCount = 0; + + 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); + } + } + + /* if nNumberOfNode is -1 (which is the default value if no parameter provided), + this function will initialize all dialogs since nCount always greater than -1 */ + if (nCount == nNumberOfNode) + break; + + ++nCount; + 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(); + + // initializeFirstNDialog() can take a long time, show wait cursor + std::unique_ptr<weld::WaitObject> xWait(m_pParent ? new weld::WaitObject(m_pParent) : nullptr); + + /* initialize first 25 dialogs which are almost half of the dialogs + in a row while Options dialog opens. then clear&reselect to avoid UI test failures. */ + initializeFirstNDialog(25); + clearOptionsDialog(); + 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, + 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(), SID_ATTR_LANGUAGE); + + aState = pDispatch->QueryState(SID_ATTR_CHAR_CJK_LANGUAGE, aResult); + if(SfxItemState::DEFAULT <= aState) + pRet->Put(*aResult.getItem(), SID_ATTR_CHAR_CJK_LANGUAGE); + + aState = pDispatch->QueryState(SID_ATTR_CHAR_CTL_LANGUAGE, aResult); + if(SfxItemState::DEFAULT <= aState) + pRet->Put(*aResult.getItem(), SID_ATTR_CHAR_CTL_LANGUAGE); + + 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; + + 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 ); + } + } +} + +OUString OfaTreeOptionsDialog::getCurrentFactory_Impl( const Reference< XFrame >& _xFrame ) +{ + OUString sIdentifier; + Reference < XFrame > xCurrentFrame( _xFrame ); + Reference < XModuleManager2 > xModuleManager = ModuleManager::create(::comphelper::getProcessComponentContext()); + if ( !xCurrentFrame.is() ) + { + Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() ); + xCurrentFrame = xDesktop->getCurrentFrame(); + } + + if ( xCurrentFrame.is() ) + { + try + { + sIdentifier = xModuleManager->identify( xCurrentFrame ); + } + catch ( css::frame::UnknownModuleException& ) + { + SAL_INFO( "cui.options", "unknown module" ); + } + catch ( Exception const & ) + { + TOOLS_WARN_EXCEPTION( "cui.options", "getActiveModule_Impl(): exception of XModuleManager::identify()" ); + } + } + + return sIdentifier; +} + +void OfaTreeOptionsDialog::generalOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + if ( !lcl_isOptionHidden( SID_GENERAL_OPTIONS, aOptionsDlgOpt ) ) + { + setGroupName(u"ProductName", CuiResId(SID_GENERAL_OPTIONS_RES[0].first)); + nGroup = AddGroup(CuiResId(SID_GENERAL_OPTIONS_RES[0].first), nullptr, nullptr, SID_GENERAL_OPTIONS ); + const sal_uInt16 nEnd = static_cast<sal_uInt16>(std::size(SID_GENERAL_OPTIONS_RES)); + + for (sal_uInt16 i = 1; i < nEnd; ++i) + { + OUString sNewTitle = CuiResId(SID_GENERAL_OPTIONS_RES[i].first); + nPageId = SID_GENERAL_OPTIONS_RES[i].second; + if ( lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + continue; + + // Disable Online Update page if neither mode is available + if( RID_SVXPAGE_ONLINEUPDATE == nPageId + && !(SvxOnlineUpdateTabPage::isTraditionalOnlineUpdateAvailable() + || SvxOnlineUpdateTabPage::isMarOnlineUpdateAvailable()) ) + { + continue; + } + + // Disable Basic IDE options, if experimental features are not enabled + if( RID_SVXPAGE_BASICIDE_OPTIONS == nPageId ) + { + if( ! officecfg::Office::Common::Misc::ExperimentalMode::get() ) + continue; + } + + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, sNewTitle, nGroup); + } + else + AddTabPage(nPageId, sNewTitle, nGroup); + } + } +} + +void OfaTreeOptionsDialog::loadAndSaveOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + if ( !lcl_isOptionHidden( SID_FILTER_DLG, aOptionsDlgOpt ) ) + { + setGroupName( u"LoadSave", CuiResId(SID_FILTER_DLG_RES[0].first) ); + nGroup = AddGroup( CuiResId(SID_FILTER_DLG_RES[0].first), nullptr, nullptr, SID_FILTER_DLG ); + for ( size_t i = 1; i < std::size(SID_FILTER_DLG_RES); ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_FILTER_DLG_RES[i].second); + if ( !lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + { + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_FILTER_DLG_RES[i].first), nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_FILTER_DLG_RES[i].first), nGroup); + } + } + } +} + +void OfaTreeOptionsDialog::languageOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + SvtCTLOptions aCTLLanguageOptions; + if ( !lcl_isOptionHidden( SID_LANGUAGE_OPTIONS, aOptionsDlgOpt ) ) + { + setGroupName(u"LanguageSettings", CuiResId(SID_LANGUAGE_OPTIONS_RES[0].first)); + nGroup = AddGroup(CuiResId(SID_LANGUAGE_OPTIONS_RES[0].first), nullptr, nullptr, SID_LANGUAGE_OPTIONS ); + for (size_t i = 1; i < std::size(SID_LANGUAGE_OPTIONS_RES); ++i) + { + nPageId = static_cast<sal_uInt16>(SID_LANGUAGE_OPTIONS_RES[i].second); + if ( lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + continue; + + // Disable DeepL translation settings, if experimental mode is not enabled + if( RID_SVXPAGE_DEEPL_OPTIONS == nPageId ) + { + if( ! officecfg::Office::Common::Misc::ExperimentalMode::get() ) + continue; + } + + if ( ( RID_SVXPAGE_JSEARCH_OPTIONS != nPageId || SvtCJKOptions::IsJapaneseFindEnabled() ) && + ( RID_SVXPAGE_ASIAN_LAYOUT != nPageId || SvtCJKOptions::IsAsianTypographyEnabled() ) && + ( RID_SVXPAGE_OPTIONS_CTL != nPageId || SvtCTLOptions::IsCTLFontEnabled() ) ) + { + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_LANGUAGE_OPTIONS_RES[i].first), nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_LANGUAGE_OPTIONS_RES[i].first), nGroup); + } + } + } +} + +void OfaTreeOptionsDialog::writerOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + OUString aFactory = getCurrentFactory_Impl( m_xFrame ); + DBG_ASSERT( GetModuleIdentifier( m_xFrame ) == aFactory, "S H I T!!!" ); + + SvtModuleOptions aModuleOpt; + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) + { + // text document + if ( aFactory == "com.sun.star.text.TextDocument" + || aFactory == "com.sun.star.text.WebDocument" + || aFactory == "com.sun.star.text.GlobalDocument" ) + { + SfxModule* pSwMod = SfxApplication::GetModule(SfxToolsModule::Writer); + if ( !lcl_isOptionHidden( SID_SW_EDITOPTIONS, aOptionsDlgOpt ) ) + { + if ( aFactory == "com.sun.star.text.WebDocument" ) + setGroupName( u"WriterWeb", CuiResId(SID_SW_EDITOPTIONS_RES[0].first) ); + else + setGroupName( u"Writer", CuiResId(SID_SW_EDITOPTIONS_RES[0].first) ); + nGroup = AddGroup(CuiResId(SID_SW_EDITOPTIONS_RES[0].first), pSwMod, pSwMod, SID_SW_EDITOPTIONS ); + SvtCTLOptions aCTLLanguageOptions; + for ( size_t i = 1; i < std::size(SID_SW_EDITOPTIONS_RES); ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_SW_EDITOPTIONS_RES[i].second); + if ( lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + continue; + if ( ( RID_SW_TP_STD_FONT_CJK != nPageId || SvtCJKOptions::IsCJKFontEnabled() ) && + ( RID_SW_TP_STD_FONT_CTL != nPageId || SvtCTLOptions::IsCTLFontEnabled() ) && + ( RID_SW_TP_MAILCONFIG != nPageId || MailMergeCfgIsEmailSupported() ) ) + { + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_SW_EDITOPTIONS_RES[i].first), + nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_SW_EDITOPTIONS_RES[i].first), nGroup); + } + } +#ifdef DBG_UTIL + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), RID_SW_TP_OPTTEST_PAGE) + != vPageId.end()) + AddTabPage(RID_SW_TP_OPTTEST_PAGE, "Internal Test", nGroup); + } + else + AddTabPage(RID_SW_TP_OPTTEST_PAGE, "Internal Test", nGroup); +#endif + } + } + } +} + +void OfaTreeOptionsDialog::writerWebOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + OUString aFactory = getCurrentFactory_Impl( m_xFrame ); + DBG_ASSERT( GetModuleIdentifier( m_xFrame ) == aFactory, "S H I T!!!" ); + + SvtModuleOptions aModuleOpt; + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) + { + // text document + if ( aFactory == "com.sun.star.text.TextDocument" + || aFactory == "com.sun.star.text.WebDocument" + || aFactory == "com.sun.star.text.GlobalDocument" ) + { + SfxModule* pSwMod = SfxApplication::GetModule(SfxToolsModule::Writer); + + // HTML documents + if ( !lcl_isOptionHidden( SID_SW_ONLINEOPTIONS, aOptionsDlgOpt ) ) + { + nGroup = AddGroup(CuiResId(SID_SW_ONLINEOPTIONS_RES[0].first), pSwMod, pSwMod, SID_SW_ONLINEOPTIONS ); + for( size_t i = 1; i < std::size(SID_SW_ONLINEOPTIONS_RES); ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_SW_ONLINEOPTIONS_RES[i].second); + if ( !lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + { + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_SW_ONLINEOPTIONS_RES[i].first), + nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_SW_ONLINEOPTIONS_RES[i].first), + nGroup); + } + } +#ifdef DBG_UTIL + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), RID_SW_TP_OPTTEST_PAGE) + != vPageId.end()) + AddTabPage(RID_SW_TP_OPTTEST_PAGE, "Internal Test", nGroup); + } + else + AddTabPage(RID_SW_TP_OPTTEST_PAGE, "Internal Test", nGroup); +#endif + } + } + } +} + +void OfaTreeOptionsDialog::calcOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + OUString aFactory = getCurrentFactory_Impl( m_xFrame ); + DBG_ASSERT( GetModuleIdentifier( m_xFrame ) == aFactory, "S H I T!!!" ); + + SvtModuleOptions aModuleOpt; + // Calc options + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) ) + { + if ( aFactory == "com.sun.star.sheet.SpreadsheetDocument" ) + { + if ( !lcl_isOptionHidden( SID_SC_EDITOPTIONS, aOptionsDlgOpt ) ) + { + SfxModule* pScMod = SfxApplication::GetModule( SfxToolsModule::Calc ); + setGroupName( u"Calc", CuiResId(SID_SC_EDITOPTIONS_RES[0].first) ); + nGroup = AddGroup( CuiResId(SID_SC_EDITOPTIONS_RES[0].first), pScMod, pScMod, SID_SC_EDITOPTIONS ); + const sal_uInt16 nCount = static_cast<sal_uInt16>(std::size(SID_SC_EDITOPTIONS_RES)); + for ( sal_uInt16 i = 1; i < nCount; ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_SC_EDITOPTIONS_RES[i].second); + if ( lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + continue; + + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_SC_EDITOPTIONS_RES[i].first), nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_SC_EDITOPTIONS_RES[i].first), nGroup); + } + } + } + } +} + +void OfaTreeOptionsDialog::impressOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + OUString aFactory = getCurrentFactory_Impl( m_xFrame ); + DBG_ASSERT( GetModuleIdentifier( m_xFrame ) == aFactory, "S H I T!!!" ); + SvtModuleOptions aModuleOpt; + + // Impress options + SfxModule* pSdMod = SfxApplication::GetModule( SfxToolsModule::Draw ); + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) ) + { + if ( aFactory == "com.sun.star.presentation.PresentationDocument" ) + { + if ( !lcl_isOptionHidden( SID_SD_EDITOPTIONS, aOptionsDlgOpt ) ) + { + setGroupName( u"Impress", CuiResId(SID_SD_EDITOPTIONS_RES[0].first) ); + nGroup = AddGroup( CuiResId(SID_SD_EDITOPTIONS_RES[0].first), pSdMod, pSdMod, SID_SD_EDITOPTIONS ); + const sal_uInt16 nCount = static_cast<sal_uInt16>(std::size(SID_SD_EDITOPTIONS_RES)); + for ( sal_uInt16 i = 1; i < nCount; ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_SD_EDITOPTIONS_RES[i].second); + if ( lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + continue; + + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_SD_EDITOPTIONS_RES[i].first), nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_SD_EDITOPTIONS_RES[i].first), nGroup); + } + } + } + } +} + +void OfaTreeOptionsDialog::drawOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + OUString aFactory = getCurrentFactory_Impl( m_xFrame ); + DBG_ASSERT( GetModuleIdentifier( m_xFrame ) == aFactory, "S H I T!!!" ); + SvtModuleOptions aModuleOpt; + + // Draw options + SfxModule* pSdMod = SfxApplication::GetModule(SfxToolsModule::Draw); + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) ) + { + if ( aFactory == "com.sun.star.drawing.DrawingDocument" ) + { + if ( !lcl_isOptionHidden( SID_SD_GRAPHIC_OPTIONS, aOptionsDlgOpt ) ) + { + setGroupName( u"Draw", CuiResId(SID_SD_GRAPHIC_OPTIONS_RES[0].first) ); + nGroup = AddGroup( CuiResId(SID_SD_GRAPHIC_OPTIONS_RES[0].first), pSdMod, pSdMod, SID_SD_GRAPHIC_OPTIONS ); + const sal_uInt16 nCount = static_cast<sal_uInt16>(std::size(SID_SD_GRAPHIC_OPTIONS_RES)); + for ( sal_uInt16 i = 1; i < nCount; ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_SD_GRAPHIC_OPTIONS_RES[i].second); + if ( lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + continue; + + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_SD_GRAPHIC_OPTIONS_RES[i].first), + nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_SD_GRAPHIC_OPTIONS_RES[i].first), nGroup); + } + } + } + } +} + +void OfaTreeOptionsDialog::mathOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + OUString aFactory = getCurrentFactory_Impl( m_xFrame ); + DBG_ASSERT( GetModuleIdentifier( m_xFrame ) == aFactory, "S H I T!!!" ); + SvtModuleOptions aModuleOpt; + + // Math options + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::MATH ) ) + { + if ( aFactory == "com.sun.star.formula.FormulaProperties" ) + { + if ( !lcl_isOptionHidden( SID_SM_EDITOPTIONS, aOptionsDlgOpt ) ) + { + SfxModule* pSmMod = SfxApplication::GetModule(SfxToolsModule::Math); + setGroupName( u"Math", CuiResId(SID_SM_EDITOPTIONS_RES[0].first) ); + nGroup = AddGroup(CuiResId(SID_SM_EDITOPTIONS_RES[0].first), pSmMod, pSmMod, SID_SM_EDITOPTIONS ); + for ( size_t i = 1; i < std::size(SID_SM_EDITOPTIONS_RES); ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_SM_EDITOPTIONS_RES[i].second); + if ( !lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + { + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_SM_EDITOPTIONS_RES[i].first), + nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_SM_EDITOPTIONS_RES[i].first), nGroup); + } + } + } + } + } +} + +void OfaTreeOptionsDialog::databaseOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + SvtModuleOptions aModuleOpt; + + // Database - needed only if there is an application which integrates with databases + if ( !lcl_isOptionHidden( SID_SB_STARBASEOPTIONS, aOptionsDlgOpt ) && + ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) + || aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) + || aModuleOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) + ) ) + { + setGroupName( u"Base", CuiResId(SID_SB_STARBASEOPTIONS_RES[0].first) ); + nGroup = AddGroup( CuiResId(SID_SB_STARBASEOPTIONS_RES[0].first), nullptr, nullptr, SID_SB_STARBASEOPTIONS ); + for ( size_t i = 1; i < std::size(SID_SB_STARBASEOPTIONS_RES); ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_SB_STARBASEOPTIONS_RES[i].second); + if ( !lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + { + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_SB_STARBASEOPTIONS_RES[i].first), nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_SB_STARBASEOPTIONS_RES[i].first), nGroup); + } + } + } +} + +void OfaTreeOptionsDialog::chartOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + if ( !lcl_isOptionHidden( SID_SCH_EDITOPTIONS, aOptionsDlgOpt ) ) + { + setGroupName( u"Charts", CuiResId(SID_SCH_EDITOPTIONS_RES[0].first) ); + nGroup = AddGroup( CuiResId(SID_SCH_EDITOPTIONS_RES[0].first), nullptr, nullptr, SID_SCH_EDITOPTIONS ); + for ( size_t i = 1; i < std::size(SID_SCH_EDITOPTIONS_RES); ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_SCH_EDITOPTIONS_RES[i].second); + if ( !lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + { + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_SCH_EDITOPTIONS_RES[i].first), nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_SCH_EDITOPTIONS_RES[i].first), nGroup); + } + } + } +} + +void OfaTreeOptionsDialog::internetOptions(const std::vector<sal_uInt16>& vPageId) +{ + sal_uInt16 nGroup = 0; + SvtOptionsDialogOptions aOptionsDlgOpt; + sal_uInt16 nPageId = 0; + + if ( lcl_isOptionHidden( SID_INET_DLG, aOptionsDlgOpt ) ) + return; + + setGroupName(u"Internet", CuiResId(SID_INET_DLG_RES[0].first)); + nGroup = AddGroup(CuiResId(SID_INET_DLG_RES[0].first), nullptr, nullptr, SID_INET_DLG ); + + for ( size_t i = 1; i < std::size(SID_INET_DLG_RES); ++i ) + { + nPageId = static_cast<sal_uInt16>(SID_INET_DLG_RES[i].second); + if ( lcl_isOptionHidden( nPageId, aOptionsDlgOpt ) ) + continue; +#if defined(_WIN32) + // Disable E-mail tab-page on Windows + if ( nPageId == RID_SVXPAGE_INET_MAIL ) + continue; +#endif + if (vPageId.size() != 0) + { + if (std::find(vPageId.begin(), vPageId.end(), nPageId) != vPageId.end()) + AddTabPage(nPageId, CuiResId(SID_INET_DLG_RES[i].first), nGroup); + } + else + AddTabPage(nPageId, CuiResId(SID_INET_DLG_RES[i].first), nGroup); + } +} + +void OfaTreeOptionsDialog::Initialize(const Reference<XFrame>& _xFrame) +{ + m_xFrame = _xFrame; + + // %PRODUCTNAME options + generalOptions(); + + // Load and Save options + loadAndSaveOptions(); + + // Language options + languageOptions(); + + // Writer and Writer/Web options + writerOptions(); + writerWebOptions(); + + // Calc options + calcOptions(); + + // Impress options + impressOptions(); + + // Draw options + drawOptions(); + + // Math options + mathOptions(); + + // Database - needed only if there is an application which integrates with databases + databaseOptions(); + + // Chart options (always installed and active) + chartOptions(); + + // Internet options + internetOptions(); + + // store Options Dialogs with their page names and strings + // in order to use them when searching + storeOptionsTree(); +} + +static bool isNodeActive( OptionsNode const * pNode, Module* pModule ) +{ + if ( !pNode ) + return false; + + // Node for all modules active? + if ( pNode->m_bAllModules ) + return true; + + // OOo-Nodes (Writer, Calc, Impress...) are active if node is already inserted + if ( !getGroupName( pNode->m_sId, false ).isEmpty() ) + return true; + + // no module -> not active + if ( !pModule ) + return false; + + // search node in active module + if ( pModule->m_bActive ) + { + for (auto const& j : pModule->m_aNodeList) + if ( j->m_sId == pNode->m_sId ) + return true; + } + return false; +} + +void OfaTreeOptionsDialog::LoadExtensionOptions( std::u16string_view rExtensionId ) +{ + std::unique_ptr<Module> pModule; + + // when called by Tools - Options then load nodes of active module + if ( rExtensionId.empty() ) + { + pModule = LoadModule( GetModuleIdentifier( Reference< XFrame >() ) ); + } + + VectorOfNodes aNodeList = LoadNodes( pModule.get(), rExtensionId ); + InsertNodes( aNodeList ); +} + +OUString OfaTreeOptionsDialog::GetModuleIdentifier( const Reference< XFrame >& rFrame ) +{ + OUString sModule; + Reference < XFrame > xCurrentFrame( rFrame ); + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + Reference < XModuleManager2 > xModuleManager = ModuleManager::create(xContext); + + if ( !xCurrentFrame.is() ) + { + Reference < XDesktop2 > xDesktop = Desktop::create( xContext ); + xCurrentFrame = xDesktop->getCurrentFrame(); + } + + if ( xCurrentFrame.is() ) + { + try + { + sModule = xModuleManager->identify( xCurrentFrame ); + } + catch ( css::frame::UnknownModuleException& ) + { + SAL_INFO( "cui.options", "unknown module" ); + } + catch ( Exception const & ) + { + TOOLS_WARN_EXCEPTION( "cui.options", "OfaTreeOptionsDialog::GetModuleIdentifier(): exception of XModuleManager::identify()"); + } + } + return sModule; +} + +std::unique_ptr<Module> OfaTreeOptionsDialog::LoadModule( + std::u16string_view rModuleIdentifier ) +{ + std::unique_ptr<Module> pModule; + Reference< XNameAccess > xSet( + officecfg::Office::OptionsDialog::Modules::get()); + + const Sequence< OUString > seqNames = xSet->getElementNames(); + for ( const OUString& rModule : seqNames ) + { + if ( rModuleIdentifier == rModule ) + { + // current active module found + pModule.reset(new Module); + pModule->m_bActive = true; + + Reference< XNameAccess > xModAccess; + xSet->getByName( rModule ) >>= xModAccess; + if ( xModAccess.is() ) + { + // load the nodes of this module + Reference< XNameAccess > xNodeAccess; + xModAccess->getByName( "Nodes" ) >>= xNodeAccess; + if ( xNodeAccess.is() ) + { + const Sequence< OUString > xTemp = xNodeAccess->getElementNames(); + Reference< XNameAccess > xAccess; + sal_Int32 nIndex = -1; + for ( const OUString& rNode : xTemp) + { + xNodeAccess->getByName( rNode ) >>= xAccess; + if ( xAccess.is() ) + { + xAccess->getByName( "Index" ) >>= nIndex; + if ( nIndex < 0 ) + // append nodes with index < 0 + pModule->m_aNodeList.push_back( + std::unique_ptr<OrderedEntry>(new OrderedEntry(nIndex, rNode))); + else + { + // search position of the node + std::vector<OrderedEntry *>::size_type y = 0; + for ( ; y < pModule->m_aNodeList.size(); ++y ) + { + sal_Int32 nNodeIdx = pModule->m_aNodeList[y]->m_nIndex; + if ( nNodeIdx < 0 || nNodeIdx > nIndex ) + break; + } + // and insert the node on this position + pModule->m_aNodeList.insert( + pModule->m_aNodeList.begin() + y, + std::unique_ptr<OrderedEntry>(new OrderedEntry( nIndex, rNode )) ); + } + } + } + } + } + break; + } + } + return pModule; +} + +VectorOfNodes OfaTreeOptionsDialog::LoadNodes( + Module* pModule, std::u16string_view rExtensionId) +{ + VectorOfNodes aOutNodeList; + + Reference< XNameAccess > xSet( + officecfg::Office::OptionsDialog::Nodes::get()); + VectorOfNodes aNodeList; + const Sequence< OUString > seqNames = xSet->getElementNames(); + + for ( OUString const & sGroupName : seqNames ) + { + Reference< XNameAccess > xNodeAccess; + xSet->getByName( sGroupName ) >>= xNodeAccess; + + if ( xNodeAccess.is() ) + { + OUString sNodeId, sLabel, sPageURL; + bool bAllModules = false; + + sNodeId = sGroupName; + xNodeAccess->getByName( "Label" ) >>= sLabel; + xNodeAccess->getByName( "OptionsPage" ) >>= sPageURL; + xNodeAccess->getByName( "AllModules" ) >>= bAllModules; + + if ( sLabel.isEmpty() ) + sLabel = sGroupName; + OUString sTemp = getGroupName( sLabel, !rExtensionId.empty() ); + if ( !sTemp.isEmpty() ) + sLabel = sTemp; + std::unique_ptr<OptionsNode> pNode(new OptionsNode(sNodeId, sLabel, bAllModules)); + + if ( rExtensionId.empty() && !isNodeActive( pNode.get(), pModule ) ) + { + continue; + } + + Reference< XNameAccess > xLeavesSet; + xNodeAccess->getByName( "Leaves" ) >>= xLeavesSet; + if ( xLeavesSet.is() ) + { + const Sequence< OUString > seqLeaves = xLeavesSet->getElementNames(); + for ( OUString const & leafName : seqLeaves ) + { + Reference< XNameAccess > xLeaveAccess; + xLeavesSet->getByName( leafName ) >>= xLeaveAccess; + + if ( xLeaveAccess.is() ) + { + OUString sId, sLeafLabel, sEventHdl, sLeafURL, sLeafGrpId; + sal_Int32 nLeafGrpIdx = 0; + + xLeaveAccess->getByName( "Id" ) >>= sId; + xLeaveAccess->getByName( "Label" ) >>= sLeafLabel; + xLeaveAccess->getByName( "OptionsPage" ) >>= sLeafURL; + xLeaveAccess->getByName( "EventHandlerService" ) >>= sEventHdl; + xLeaveAccess->getByName( "GroupId" ) >>= sLeafGrpId; + xLeaveAccess->getByName( "GroupIndex" ) >>= nLeafGrpIdx; + + if ( rExtensionId.empty() || sId == rExtensionId ) + { + std::unique_ptr<OptionsLeaf> pLeaf(new OptionsLeaf( + sLeafLabel, sLeafURL, sEventHdl, sLeafGrpId, nLeafGrpIdx )); + + if ( !sLeafGrpId.isEmpty() ) + { + bool bAlreadyOpened = false; + if ( !pNode->m_aGroupedLeaves.empty() ) + { + for (auto & rGroup : pNode->m_aGroupedLeaves) + { + if ( !rGroup.empty() && + rGroup[0]->m_sGroupId == sLeafGrpId ) + { + std::vector<std::unique_ptr<OptionsLeaf>>::size_type l = 0; + for ( ; l < rGroup.size(); ++l ) + { + if ( rGroup[l]->m_nGroupIndex >= nLeafGrpIdx ) + break; + } + rGroup.insert( rGroup.begin() + l, std::move(pLeaf) ); + bAlreadyOpened = true; + break; + } + } + } + if ( !bAlreadyOpened ) + { + std::vector< std::unique_ptr<OptionsLeaf> > aGroupedLeaves; + aGroupedLeaves.push_back( std::move(pLeaf) ); + pNode->m_aGroupedLeaves.push_back( std::move(aGroupedLeaves) ); + } + } + else + pNode->m_aLeaves.push_back( std::move(pLeaf) ); + } + } + } + } + + // do not insert nodes without leaves + if ( !pNode->m_aLeaves.empty() || !pNode->m_aGroupedLeaves.empty() ) + { + pModule ? aNodeList.push_back( std::move(pNode) ) : aOutNodeList.push_back( std::move(pNode) ); + } + } + } + + if ( pModule && !aNodeList.empty() ) + { + for ( auto const & i: pModule->m_aNodeList ) + { + OUString sNodeId = i->m_sId; + for ( auto j = aNodeList.begin(); j != aNodeList.end(); ++j ) + { + if ( (*j)->m_sId == sNodeId ) + { + aOutNodeList.push_back( std::move(*j) ); + aNodeList.erase( j ); + break; + } + } + } + + for ( auto & i: aNodeList ) + aOutNodeList.push_back( std::move(i) ); + } + return aOutNodeList; +} + +static sal_uInt16 lcl_getGroupId( std::u16string_view rGroupName, const weld::TreeView& rTreeLB ) +{ + sal_uInt16 nRet = 0; + + std::unique_ptr<weld::TreeIter> xEntry = rTreeLB.make_iterator(); + bool bEntry = rTreeLB.get_iter_first(*xEntry); + while (bEntry) + { + if (!rTreeLB.get_iter_depth(*xEntry)) + { + OUString sTemp(rTreeLB.get_text(*xEntry)); + if (sTemp == rGroupName) + return nRet; + nRet++; + } + bEntry = rTreeLB.iter_next(*xEntry); + } + + return USHRT_MAX; +} + +static void lcl_insertLeaf( + OfaTreeOptionsDialog* pDlg, OptionsNode const * pNode, OptionsLeaf const * pLeaf, const weld::TreeView& rTreeLB ) +{ + sal_uInt16 nGrpId = lcl_getGroupId( pNode->m_sLabel, rTreeLB ); + if ( USHRT_MAX == nGrpId ) + { + sal_uInt16 nNodeGrpId = getGroupNodeId( pNode->m_sId ); + nGrpId = pDlg->AddGroup( pNode->m_sLabel, nullptr, nullptr, nNodeGrpId ); + } + OptionsPageInfo* pInfo = pDlg->AddTabPage( 0, pLeaf->m_sLabel, nGrpId ); + pInfo->m_sPageURL = pLeaf->m_sPageURL; + pInfo->m_sEventHdl = pLeaf->m_sEventHdl; +} + +void OfaTreeOptionsDialog::InsertNodes( const VectorOfNodes& rNodeList ) +{ + for (auto const& node : rNodeList) + { + if ( !node->m_aLeaves.empty() || !node->m_aGroupedLeaves.empty() ) + { + for ( auto const & j: node->m_aGroupedLeaves ) + { + for ( size_t k = 0; k < j.size(); ++k ) + { + lcl_insertLeaf( this, node.get(), j[k].get(), *xTreeLB ); + } + } + + for ( auto const & j: node->m_aLeaves ) + { + lcl_insertLeaf( this, node.get(), j.get(), *xTreeLB ); + } + } + } +} + +void OfaTreeOptionsDialog::SetNeedsRestart( svtools::RestartReason eReason) +{ + bNeedsRestart = true; + eRestartReason = eReason; +} + +short OfaTreeOptionsDialog::run() +{ + std::unique_ptr< SvxDicListChgClamp > pClamp; + if ( !bIsFromExtensionManager ) + { + // collect all DictionaryList Events while the dialog is executed + Reference<css::linguistic2::XSearchableDictionaryList> xDictionaryList(LinguMgr::GetDictionaryList()); + pClamp.reset( new SvxDicListChgClamp( xDictionaryList ) ); + } + + return SfxOkDialogController::run(); +} + +// class ExtensionsTabPage ----------------------------------------------- +ExtensionsTabPage::ExtensionsTabPage( + weld::Container* pParent, OUString aPageURL, + OUString aEvtHdl, const Reference< awt::XContainerWindowProvider >& rProvider ) + : m_pContainer(pParent) + , m_sPageURL(std::move(aPageURL)) + , m_sEventHdl(std::move(aEvtHdl)) + , m_xWinProvider(rProvider) +{ +} + +ExtensionsTabPage::~ExtensionsTabPage() +{ + Hide(); + DeactivatePage(); + + if ( m_xPage.is() ) + { + try + { + m_xPage->dispose(); + } + catch (const Exception&) + { + } + m_xPage.clear(); + } + + if ( m_xPageParent.is() ) + { + try + { + m_xPageParent->dispose(); + } + catch (const Exception&) + { + } + m_xPageParent.clear(); + } +} + +void ExtensionsTabPage::CreateDialogWithHandler() +{ + try + { + bool bWithHandler = !m_sEventHdl.isEmpty(); + if ( bWithHandler ) + { + Reference < XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() ); + m_xEventHdl.set( xFactory->createInstance( m_sEventHdl ), UNO_QUERY ); + } + + if ( !bWithHandler || m_xEventHdl.is() ) + { + m_xPageParent = m_pContainer->CreateChildFrame(); + Reference<awt::XWindowPeer> xParent(m_xPageParent, UNO_QUERY); + m_xPage = + m_xWinProvider->createContainerWindow( + m_sPageURL, OUString(), xParent, m_xEventHdl ); + + Reference< awt::XControl > xPageControl( m_xPage, UNO_QUERY ); + if ( xPageControl.is() ) + { + Reference< awt::XWindowPeer > xWinPeer( xPageControl->getPeer() ); + if ( xWinPeer.is() ) + { + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWinPeer ); + if ( pWindow ) + pWindow->SetStyle( pWindow->GetStyle() | WB_DIALOGCONTROL | WB_CHILDDLGCTRL ); + } + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "cui.options", "ExtensionsTabPage::CreateDialogWithHandler(): exception of XDialogProvider2::createDialogWithHandler()"); + } +} + +bool ExtensionsTabPage::DispatchAction( const OUString& rAction ) +{ + bool bRet = false; + if ( m_xEventHdl.is() ) + { + try + { + bRet = m_xEventHdl->callHandlerMethod( m_xPage, Any( rAction ), "external_event" ); + } + catch ( Exception const & ) + { + TOOLS_WARN_EXCEPTION( "cui.options", "ExtensionsTabPage::DispatchAction(): exception of XDialogEventHandler::callHandlerMethod()" ); + } + } + return bRet; +} + +void ExtensionsTabPage::Show() +{ + if (!m_xPageParent.is()) + return; + + VclPtr<vcl::Window> xPageParent = VCLUnoHelper::GetWindow(m_xPageParent); + if (xPageParent) + { + // NoActivate otherwise setVisible will call Window::Show which will grab + // focus to the page by default + xPageParent->Show(true, ShowFlags::NoActivate); + } + + m_xPageParent->setVisible(true); +} + +void ExtensionsTabPage::Hide() +{ + if (!m_xPageParent.is()) + return; + m_xPageParent->setVisible(false); +} + +void ExtensionsTabPage::ActivatePage() +{ + if ( !m_xPage.is() ) + { + CreateDialogWithHandler(); + + if ( m_xPage.is() ) + { + auto aWindowRect = m_xPageParent->getPosSize(); + m_xPage->setPosSize(0, 0, aWindowRect.Width, aWindowRect.Height, awt::PosSize::POSSIZE); + if ( !m_sEventHdl.isEmpty() ) + DispatchAction( "initialize" ); + } + } + + if ( m_xPage.is() ) + { + m_xPage->setVisible( true ); + } +} + +void ExtensionsTabPage::DeactivatePage() +{ + if ( m_xPage.is() ) + m_xPage->setVisible( false ); +} + +void ExtensionsTabPage::ResetPage() +{ + DispatchAction( "back" ); + ActivatePage(); +} + +void ExtensionsTabPage::SavePage() +{ + DispatchAction( "ok" ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/treeopthelper.cxx b/cui/source/options/treeopthelper.cxx new file mode 100644 index 0000000000..e486dbb5ea --- /dev/null +++ b/cui/source/options/treeopthelper.cxx @@ -0,0 +1,184 @@ +/* -*- 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 <fstream> +#include <treeopt.hxx> + +#include <treeopt.hrc> +#include <helpids.h> +#include <svx/dialogs.hrc> +#include <svx/svxids.hrc> + +namespace +{ +struct PageIdToFileNameMap_Impl +{ + sal_uInt16 m_nPageId; + OUString m_sContent; +}; +} + +static PageIdToFileNameMap_Impl FileMap_Impl[] = { + + // { PAGE-ID, CONTENT }, + + // ProductName, SID_GENERAL_OPTIONS + { RID_SFXPAGE_GENERAL, "" }, // UserData + + { OFA_TP_MISC, "" }, // General + + { OFA_TP_VIEW, "" }, // View + + { RID_SFXPAGE_PRINTOPTIONS, "" }, // Print + + { RID_SFXPAGE_PATH, "" }, // Paths + + { RID_SVX_FONT_SUBSTITUTION, "" }, // Fonts + + { RID_SVXPAGE_INET_SECURITY, "" }, // Security + + { RID_SVXPAGE_PERSONALIZATION, "" }, // Personalization + { RID_SVXPAGE_COLORCONFIG, "" }, // ApplicationColors + { RID_SVXPAGE_ACCESSIBILITYCONFIG, "" }, // Accessibility + { RID_SVXPAGE_OPTIONS_JAVA, "" }, // Java + { RID_SVXPAGE_BASICIDE_OPTIONS, "" }, // BasicIDEOptions + { RID_SVXPAGE_ONLINEUPDATE, "" }, // OnlineUpdate + { RID_SVXPAGE_OPENCL, "" }, // OpenCL + + // LanguageSettings, SID_LANGUAGE_OPTIONS + { OFA_TP_LANGUAGES, "" }, // Languages + { RID_SFXPAGE_LINGU, "" }, // WritingAids + { RID_SVXPAGE_JSEARCH_OPTIONS, "" }, // SearchingInJapanese + { RID_SVXPAGE_ASIAN_LAYOUT, "" }, // AsianLayout + { RID_SVXPAGE_OPTIONS_CTL, "" }, // ComplexTextLayout + { RID_SVXPAGE_LANGTOOL_OPTIONS, "" }, // LanguageTool Server + { RID_SVXPAGE_DEEPL_OPTIONS, "" }, // DeepL Server + + // Internet, SID_INET_DLG + { RID_SVXPAGE_INET_PROXY, "" }, // Proxy + { RID_SVXPAGE_INET_MAIL, "" }, // Email + + // Load/Save, SID_FILTER_DLG + { RID_SFXPAGE_SAVE, "" }, // General + { SID_OPTFILTER_MSOFFICE, "" }, // VBA Properties + { RID_OFAPAGE_MSFILTEROPT2, "" }, // Microsoft Office + { RID_OFAPAGE_HTMLOPT, "" }, // HTML Compatibility + + // Writer, SID_SW_EDITOPTIONS + { RID_SW_TP_OPTLOAD_PAGE, "" }, // General + { RID_SW_TP_CONTENT_OPT, "" }, // View + { RID_SW_TP_OPTSHDWCRSR, "" }, // FormattingAids + { RID_SVXPAGE_GRID, "" }, // Grid + { RID_SW_TP_STD_FONT, "" }, // BasicFontsWestern + { RID_SW_TP_STD_FONT_CJK, "" }, // BasicFontsAsian + { RID_SW_TP_STD_FONT_CTL, "" }, // BasicFontsCTL + { RID_SW_TP_OPTPRINT_PAGE, "" }, // Print + { RID_SW_TP_OPTTABLE_PAGE, "" }, // Table + { RID_SW_TP_REDLINE_OPT, "" }, // Changes + { RID_SW_TP_COMPARISON_OPT, "" }, // Comparison + { RID_SW_TP_OPTCOMPATIBILITY_PAGE, "" }, // Compatibility + { RID_SW_TP_OPTCAPTION_PAGE, "" }, // AutoCaption + { RID_SW_TP_MAILCONFIG, "" }, // MailMerge + { RID_SW_TP_OPTTEST_PAGE, "" }, // Internal Test (only in dev build) + + // WriterWeb, SID_SW_ONLINEOPTIONS + { RID_SW_TP_HTML_CONTENT_OPT, "" }, // View + { RID_SW_TP_HTML_OPTSHDWCRSR, "" }, // FormattingAids + { RID_SW_TP_HTML_OPTGRID_PAGE, "" }, // Grid + { RID_SW_TP_HTML_OPTPRINT_PAGE, "" }, // Print + { RID_SW_TP_HTML_OPTTABLE_PAGE, "" }, // Table + { RID_SW_TP_BACKGROUND, "" }, // Background + { RID_SW_TP_OPTTEST_PAGE, "" }, // Internal Test (only in dev build) + + // Math, SID_SM_EDITOPTIONS + { SID_SM_TP_PRINTOPTIONS, "" }, // Settings + + // Calc, SID_SC_EDITOPTIONS + { SID_SC_TP_LAYOUT, "" }, // General + { RID_SC_TP_DEFAULTS, "" }, // Defaults + { SID_SC_TP_CONTENT, "" }, // View + { SID_SC_TP_CALC, "" }, // Calculate + { SID_SC_TP_FORMULA, "" }, // Formula + { SID_SC_TP_USERLISTS, "" }, // SortLists + { SID_SC_TP_CHANGES, "" }, // Changes + { SID_SC_TP_COMPATIBILITY, "" }, // Compatibility + { SID_SC_TP_GRID, "" }, // Grid + { RID_SC_TP_PRINT, "" }, // Print + + // Impress, SID_SD_EDITOPTIONS + { SID_SI_TP_MISC, "" }, // General + { SID_SI_TP_CONTENTS, "" }, // View + { SID_SI_TP_SNAP, "" }, // Grid + { SID_SI_TP_PRINT, "" }, // Print + + // Draw, SID_SD_GRAPHIC_OPTIONS + { SID_SD_TP_MISC, "" }, // General + { SID_SD_TP_CONTENTS, "" }, // View + { SID_SD_TP_SNAP, "" }, // Grid + { SID_SD_TP_PRINT, "" }, // Print + + // Charts, SID_SCH_EDITOPTIONS + { RID_OPTPAGE_CHART_DEFCOLORS, "" }, // DefaultColor + + // Base, SID_SB_STARBASEOPTIONS + { SID_SB_CONNECTIONPOOLING, "" }, // Connections + { SID_SB_DBREGISTEROPTIONS, "" } // Databases +}; + +void TreeOptHelper::storeStringsOfDialog(sal_uInt16 nPageId, const OUString& sPageStrings) +{ + for (PageIdToFileNameMap_Impl& rEntry : FileMap_Impl) + { + if (rEntry.m_nPageId == nPageId) + { + rEntry.m_sContent = sPageStrings.replaceAll("~", ""); + break; + } + } +} + +/* +return the strings of: +- labels, +- check buttons, +- radio buttons, +- toggle buttons, +- link buttons, +- buttons + +TODO: +- accessible-names +- accessible-descriptions +- tooltip-texts +*/ +OUString TreeOptHelper::getStringsFromDialog(sal_uInt16 nPageId) +{ + if (nPageId == 0) + return OUString(); + + for (PageIdToFileNameMap_Impl& rEntry : FileMap_Impl) + { + if (rEntry.m_nPageId == nPageId) + return rEntry.m_sContent; + } + + return OUString(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/tsaurls.cxx b/cui/source/options/tsaurls.cxx new file mode 100644 index 0000000000..b33c76c58d --- /dev/null +++ b/cui/source/options/tsaurls.cxx @@ -0,0 +1,128 @@ +/* -*- 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/. + */ + +#include <officecfg/Office/Common.hxx> +#include <svx/svxdlg.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include "tsaurls.hxx" + +using namespace ::com::sun::star; + +TSAURLsDialog::TSAURLsDialog(weld::Window* pParent) + : GenericDialogController(pParent, "cui/ui/tsaurldialog.ui", "TSAURLDialog") + , m_xAddBtn(m_xBuilder->weld_button("add")) + , m_xDeleteBtn(m_xBuilder->weld_button("delete")) + , m_xOKBtn(m_xBuilder->weld_button("ok")) + , m_xURLListBox(m_xBuilder->weld_tree_view("urls")) + , m_xEnterAUrl(m_xBuilder->weld_label("enteraurl")) +{ + m_xURLListBox->set_size_request(m_xURLListBox->get_approximate_digit_width() * 28, + m_xURLListBox->get_height_rows(8)); + m_xOKBtn->set_sensitive(false); + + m_xAddBtn->connect_clicked(LINK(this, TSAURLsDialog, AddHdl_Impl)); + m_xDeleteBtn->connect_clicked(LINK(this, TSAURLsDialog, DeleteHdl_Impl)); + m_xOKBtn->connect_clicked(LINK(this, TSAURLsDialog, OKHdl_Impl)); + m_xURLListBox->connect_changed(LINK(this, TSAURLsDialog, SelectHdl)); + + try + { + std::optional<css::uno::Sequence<OUString>> aUserSetTSAURLs( + officecfg::Office::Common::Security::Scripting::TSAURLs::get()); + if (aUserSetTSAURLs) + { + const css::uno::Sequence<OUString>& rUserSetTSAURLs = *aUserSetTSAURLs; + for (auto const& userSetTSAURL : rUserSetTSAURLs) + { + AddTSAURL(userSetTSAURL); + } + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("cui.options", "TSAURLsDialog::TSAURLsDialog()"); + } + + if (m_xURLListBox->get_selected_index() == -1) + { + m_xDeleteBtn->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(TSAURLsDialog, OKHdl_Impl, weld::Button&, void) +{ + std::shared_ptr<comphelper::ConfigurationChanges> batch( + comphelper::ConfigurationChanges::create()); + + officecfg::Office::Common::Security::Scripting::TSAURLs::set( + comphelper::containerToSequence(m_aURLs), batch); + batch->commit(); + + m_xDialog->response(RET_OK); +} + +TSAURLsDialog::~TSAURLsDialog() {} + +void TSAURLsDialog::AddTSAURL(const OUString& rURL) +{ + m_aURLs.insert(rURL); + + m_xURLListBox->freeze(); + m_xURLListBox->clear(); + + for (auto const& url : m_aURLs) + { + m_xURLListBox->append_text(url); + } + + m_xURLListBox->thaw(); +} + +IMPL_LINK_NOARG(TSAURLsDialog, AddHdl_Impl, weld::Button&, void) +{ + OUString aURL; + OUString aDesc(m_xEnterAUrl->get_label()); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractSvxNameDialog> pDlg( + pFact->CreateSvxNameDialog(m_xDialog.get(), aURL, aDesc)); + + if (pDlg->Execute() == RET_OK) + { + pDlg->GetName(aURL); + AddTSAURL(aURL); + m_xOKBtn->set_sensitive(true); + } + m_xURLListBox->unselect_all(); + // After operations in a ListBox we have nothing selected + m_xDeleteBtn->set_sensitive(false); +} + +IMPL_LINK_NOARG(TSAURLsDialog, SelectHdl, weld::TreeView&, void) +{ + m_xDeleteBtn->set_sensitive(true); +} + +IMPL_LINK_NOARG(TSAURLsDialog, DeleteHdl_Impl, weld::Button&, void) +{ + int nSel = m_xURLListBox->get_selected_index(); + if (nSel == -1) + return; + + m_aURLs.erase(m_xURLListBox->get_text(nSel)); + m_xURLListBox->remove(nSel); + m_xURLListBox->unselect_all(); + // After operations in a ListBox we have nothing selected + m_xDeleteBtn->set_sensitive(false); + m_xOKBtn->set_sensitive(true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/tsaurls.hxx b/cui/source/options/tsaurls.hxx new file mode 100644 index 0000000000..8fb1d04907 --- /dev/null +++ b/cui/source/options/tsaurls.hxx @@ -0,0 +1,41 @@ +/* -*- 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/. + */ + +#pragma once + +#include <vcl/weld.hxx> + +#include <set> + +class TSAURLsDialog : public weld::GenericDialogController +{ +private: + std::unique_ptr<weld::Button> m_xAddBtn; + std::unique_ptr<weld::Button> m_xDeleteBtn; + std::unique_ptr<weld::Button> m_xOKBtn; + std::unique_ptr<weld::TreeView> m_xURLListBox; + std::unique_ptr<weld::Label> m_xEnterAUrl; + + DECL_LINK(AddHdl_Impl, weld::Button&, void); + DECL_LINK(DeleteHdl_Impl, weld::Button&, void); + DECL_LINK(OKHdl_Impl, weld::Button&, void); + // After operations in a TreeView we have nothing selected + // Is Selected element handler for the TreeView + DECL_LINK(SelectHdl, weld::TreeView&, void); + + std::set<OUString> m_aURLs; + + void AddTSAURL(const OUString& rURL); + +public: + explicit TSAURLsDialog(weld::Window* pParent); + virtual ~TSAURLsDialog() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/webconninfo.cxx b/cui/source/options/webconninfo.cxx new file mode 100644 index 0000000000..d9acbd18f5 --- /dev/null +++ b/cui/source/options/webconninfo.cxx @@ -0,0 +1,229 @@ +/* -*- 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 <o3tl/safeint.hxx> +#include "webconninfo.hxx" +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/task/PasswordContainer.hpp> +#include <com/sun/star/task/UrlRecord.hpp> +#include <com/sun/star/task/XPasswordContainer2.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/docpasswordrequest.hxx> + +using namespace ::com::sun::star; + + +namespace svx +{ + +// class WebConnectionInfoDialog ----------------------------------------- + +WebConnectionInfoDialog::WebConnectionInfoDialog(weld::Window* pParent) + : GenericDialogController(pParent, "cui/ui/storedwebconnectiondialog.ui", "StoredWebConnectionDialog") + , m_nPos( -1 ) + , m_xRemoveBtn(m_xBuilder->weld_button("remove")) + , m_xRemoveAllBtn(m_xBuilder->weld_button("removeall")) + , m_xChangeBtn(m_xBuilder->weld_button("change")) + , m_xPasswordsLB(m_xBuilder->weld_tree_view("logins")) +{ + std::vector<int> aWidths + { + o3tl::narrowing<int>(m_xPasswordsLB->get_approximate_digit_width() * 50) + }; + m_xPasswordsLB->set_column_fixed_widths(aWidths); + m_xPasswordsLB->set_size_request(m_xPasswordsLB->get_approximate_digit_width() * 70, + m_xPasswordsLB->get_height_rows(8)); + + m_xPasswordsLB->connect_column_clicked(LINK(this, WebConnectionInfoDialog, HeaderBarClickedHdl)); + + FillPasswordList(); + + m_xRemoveBtn->connect_clicked( LINK( this, WebConnectionInfoDialog, RemovePasswordHdl ) ); + m_xRemoveAllBtn->connect_clicked( LINK( this, WebConnectionInfoDialog, RemoveAllPasswordsHdl ) ); + m_xChangeBtn->connect_clicked( LINK( this, WebConnectionInfoDialog, ChangePasswordHdl ) ); + m_xPasswordsLB->connect_changed( LINK( this, WebConnectionInfoDialog, EntrySelectedHdl ) ); + + m_xRemoveBtn->set_sensitive( false ); + m_xChangeBtn->set_sensitive( false ); + + m_xPasswordsLB->make_sorted(); +} + +WebConnectionInfoDialog::~WebConnectionInfoDialog() +{ +} + +IMPL_LINK(WebConnectionInfoDialog, HeaderBarClickedHdl, int, nColumn, void) +{ + if (nColumn == 0) // only the first column is sorted + { + m_xPasswordsLB->set_sort_order(!m_xPasswordsLB->get_sort_order()); + } +} + +void WebConnectionInfoDialog::FillPasswordList() +{ + try + { + uno::Reference< task::XPasswordContainer2 > xMasterPasswd( + task::PasswordContainer::create(comphelper::getProcessComponentContext())); + + if ( xMasterPasswd->isPersistentStoringAllowed() ) + { + uno::Reference< task::XInteractionHandler > xInteractionHandler = + task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), nullptr); + + const uno::Sequence< task::UrlRecord > aURLEntries = xMasterPasswd->getAllPersistent( xInteractionHandler ); + sal_Int32 nCount = 0; + for ( task::UrlRecord const & urlEntry : aURLEntries ) + { + for ( auto const & user : urlEntry.UserList ) + { + m_xPasswordsLB->append(OUString::number(nCount), urlEntry.Url); + m_xPasswordsLB->set_text(nCount, user.UserName, 1); + ++nCount; + } + } + + // remember pos of first url container entry. + m_nPos = nCount; + + const uno::Sequence< OUString > aUrls + = xMasterPasswd->getUrls( true /* OnlyPersistent */ ); + + for ( OUString const & url : aUrls ) + { + m_xPasswordsLB->append(OUString::number(nCount), url); + m_xPasswordsLB->set_text(nCount, "*"); + ++nCount; + } + } + } + catch( uno::Exception& ) + {} +} + + +IMPL_LINK_NOARG(WebConnectionInfoDialog, RemovePasswordHdl, weld::Button&, void) +{ + try + { + int nEntry = m_xPasswordsLB->get_selected_index(); + if (nEntry != -1) + { + OUString aURL = m_xPasswordsLB->get_text(nEntry, 0); + OUString aUserName = m_xPasswordsLB->get_text(nEntry, 1); + + uno::Reference< task::XPasswordContainer2 > xPasswdContainer( + task::PasswordContainer::create(comphelper::getProcessComponentContext())); + + int nPos = m_xPasswordsLB->get_id(nEntry).toInt32(); + if ( nPos < m_nPos ) + { + xPasswdContainer->removePersistent( aURL, aUserName ); + } + else + { + xPasswdContainer->removeUrl( aURL ); + } + + m_xPasswordsLB->remove(nEntry); + } + } + catch( uno::Exception& ) + {} +} + +IMPL_LINK_NOARG(WebConnectionInfoDialog, RemoveAllPasswordsHdl, weld::Button&, void) +{ + try + { + uno::Reference< task::XPasswordContainer2 > xPasswdContainer( + task::PasswordContainer::create(comphelper::getProcessComponentContext())); + + // should the master password be requested before? + xPasswdContainer->removeAllPersistent(); + + const uno::Sequence< OUString > aUrls + = xPasswdContainer->getUrls( true /* OnlyPersistent */ ); + for ( OUString const & url : aUrls ) + xPasswdContainer->removeUrl( url ); + + m_xPasswordsLB->clear(); + } + catch( uno::Exception& ) + {} +} + +IMPL_LINK_NOARG(WebConnectionInfoDialog, ChangePasswordHdl, weld::Button&, void) +{ + try + { + int nEntry = m_xPasswordsLB->get_selected_index(); + if (nEntry != -1) + { + OUString aURL = m_xPasswordsLB->get_text(nEntry, 0); + OUString aUserName = m_xPasswordsLB->get_text(nEntry, 1); + + rtl::Reference<::comphelper::SimplePasswordRequest> pPasswordRequest + = new ::comphelper::SimplePasswordRequest; + + uno::Reference< task::XInteractionHandler > xInteractionHandler = + task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), m_xDialog->GetXWindow()); + xInteractionHandler->handle( pPasswordRequest ); + + if ( pPasswordRequest->isPassword() ) + { + OUString aNewPass = pPasswordRequest->getPassword(); + uno::Sequence<OUString> aPasswd { aNewPass }; + + uno::Reference< task::XPasswordContainer2 > xPasswdContainer( + task::PasswordContainer::create(comphelper::getProcessComponentContext())); + xPasswdContainer->addPersistent( + aURL, aUserName, aPasswd, xInteractionHandler ); + } + } + } + catch( uno::Exception& ) + {} +} + + +IMPL_LINK_NOARG(WebConnectionInfoDialog, EntrySelectedHdl, weld::TreeView&, void) +{ + int nEntry = m_xPasswordsLB->get_selected_index(); + if (nEntry == -1) + { + m_xRemoveBtn->set_sensitive(false); + m_xChangeBtn->set_sensitive(false); + } + else + { + m_xRemoveBtn->set_sensitive(true); + + // url container entries (-> use system credentials) have + // no password + int nPos = m_xPasswordsLB->get_id(nEntry).toInt32(); + m_xChangeBtn->set_sensitive(nPos < m_nPos); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/webconninfo.hxx b/cui/source/options/webconninfo.hxx new file mode 100644 index 0000000000..6c52d21631 --- /dev/null +++ b/cui/source/options/webconninfo.hxx @@ -0,0 +1,51 @@ +/* + * 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 . + */ +#pragma once + +#include <vcl/weld.hxx> + +namespace svx +{ + class WebConnectionInfoDialog : public weld::GenericDialogController + { + private: + sal_Int32 m_nPos; + + std::unique_ptr<weld::Button> m_xRemoveBtn; + std::unique_ptr<weld::Button> m_xRemoveAllBtn; + std::unique_ptr<weld::Button> m_xChangeBtn; + std::unique_ptr<weld::TreeView> m_xPasswordsLB; + + DECL_LINK( HeaderBarClickedHdl, int, void ); + DECL_LINK( RemovePasswordHdl, weld::Button&, void ); + DECL_LINK( RemoveAllPasswordsHdl, weld::Button&, void ); + DECL_LINK( ChangePasswordHdl, weld::Button&, void ); + DECL_LINK( EntrySelectedHdl, weld::TreeView&, void ); + + void FillPasswordList(); + + public: + explicit WebConnectionInfoDialog(weld::Window* pParent); + virtual ~WebConnectionInfoDialog() override; + }; + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |