Rebased ref, commits from common ancestor: commit fe2d708d32cf04bb3da22fdbd9806fb8b5b8f7d7 Author: Mert Tumer <mert.tu...@collabora.com> AuthorDate: Tue Jul 5 12:03:27 2022 +0300 Commit: Mert Tumer <mert.tu...@collabora.com> CommitDate: Tue Jul 12 14:06:04 2022 +0300
wip translate Signed-off-by: Mert Tumer <mert.tu...@collabora.com> diff --git a/include/svx/svxids.hrc b/include/svx/svxids.hrc index 573f036128c8..f8e162a973a6 100644 --- a/include/svx/svxids.hrc +++ b/include/svx/svxids.hrc @@ -570,7 +570,7 @@ class SdrAngleItem; #define SID_FM_FILECONTROL ( SID_SVX_START + 605 ) //( SID_SVX_START + 606 ) is used by SID_DRAWTBX_REDACTED_EXPORT #define SID_FM_NAVIGATIONBAR ( SID_SVX_START + 607 ) -//FREE +#define SID_FM_TRANSLATE ( SID_SVX_START + 608 ) //FREE #define SID_FM_DELETEROWS ( SID_SVX_START + 610 ) //FREE diff --git a/include/vcl/unohelp3.hxx b/include/vcl/unohelp3.hxx new file mode 100644 index 000000000000..2d3bfb4e5f28 --- /dev/null +++ b/include/vcl/unohelp3.hxx @@ -0,0 +1,53 @@ +/* -*- 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 <com/sun/star/datatransfer/XTransferable.hpp> +#include <cppuhelper/weak.hxx> +#include <rtl/ustring.hxx> +#include <osl/mutex.hxx> +#include <vcl/dllapi.h> +#include <vcl/IDialogRenderable.hxx> + +namespace vcl::unohelper { + + class VCL_DLLPUBLIC HtmlTransferable final : + public css::datatransfer::XTransferable, + public ::cppu::OWeakObject + { + private: + OString data; + + public: + HtmlTransferable( OString sData ); + virtual ~HtmlTransferable() override; + + // css::uno::XInterface + css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + void SAL_CALL acquire() noexcept override { OWeakObject::acquire(); } + void SAL_CALL release() noexcept override { OWeakObject::release(); } + + // css::datatransfer::XTransferable + css::uno::Any SAL_CALL getTransferData( const css::datatransfer::DataFlavor& aFlavor ) override; + css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) override; + sal_Bool SAL_CALL isDataFlavorSupported( const css::datatransfer::DataFlavor& aFlavor ) override; + }; + +} // namespace vcl::unohelper diff --git a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu index 37996759a90d..2f82b9f1711f 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu @@ -1333,6 +1333,14 @@ <value>1</value> </prop> </node> + <node oor:name=".uno:Translate" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Translate Page...</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> <node oor:name=".uno:FormatColumns" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">Co~lumns...</value> diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi index 9ab00de7e881..6b5fb5021370 100644 --- a/svx/sdi/svx.sdi +++ b/svx/sdi/svx.sdi @@ -1596,6 +1596,22 @@ SfxBoolItem NavigationBar SID_FM_NAVIGATIONBAR GroupId = SfxGroupId::Controls; ] +SfxBoolItem Translate SID_FM_TRANSLATE +[ + AutoUpdate = FALSE, + FastCall = TRUE, + ReadOnlyDoc = FALSE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = FALSE, + MenuConfig = FALSE, + ToolBoxConfig = FALSE, + GroupId = SfxGroupId::Format; +] + SfxBoolItem Combobox SID_INSERT_COMBOBOX diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk index a49d53d0509f..5408e28b867a 100644 --- a/sw/Library_sw.mk +++ b/sw/Library_sw.mk @@ -91,6 +91,7 @@ $(eval $(call gb_Library_use_externals,sw,\ icuuc \ icu_headers \ libxml2 \ + curl \ )) $(eval $(call gb_Library_add_exception_objects,sw,\ diff --git a/sw/Library_swui.mk b/sw/Library_swui.mk index 4c1d9614f56c..f4cd9cbf5432 100644 --- a/sw/Library_swui.mk +++ b/sw/Library_swui.mk @@ -150,6 +150,7 @@ $(eval $(call gb_Library_add_exception_objects,swui,\ sw/source/ui/misc/pgfnote \ sw/source/ui/misc/pggrid \ sw/source/ui/misc/srtdlg \ + sw/source/ui/misc/translatelangselect \ sw/source/ui/misc/swmodalredlineacceptdlg \ sw/source/ui/misc/titlepage \ sw/source/ui/table/colwd \ diff --git a/sw/UIConfig_swriter.mk b/sw/UIConfig_swriter.mk index 73abd66dee9b..7d2fc662ae22 100644 --- a/sw/UIConfig_swriter.mk +++ b/sw/UIConfig_swriter.mk @@ -178,6 +178,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/swriter,\ sw/uiconfig/swriter/ui/insertautotextdialog \ sw/uiconfig/swriter/ui/insertbookmark \ sw/uiconfig/swriter/ui/insertbreak \ + sw/uiconfig/swriter/ui/translationdialog \ sw/uiconfig/swriter/ui/insertcaption \ sw/uiconfig/swriter/ui/insertdbcolumnsdialog \ sw/uiconfig/swriter/ui/insertfootnote \ diff --git a/sw/inc/swabstdlg.hxx b/sw/inc/swabstdlg.hxx index 0963de35da21..19d12a736e66 100644 --- a/sw/inc/swabstdlg.hxx +++ b/sw/inc/swabstdlg.hxx @@ -375,6 +375,18 @@ public: virtual sal_uInt16 GetRestartPage() const = 0; }; +class SwLanguageListItem; + +class AbstractSwTranslateLangSelectDlg +{ +protected: + virtual ~AbstractSwTranslateLangSelectDlg() = default; +public: + virtual std::shared_ptr<weld::DialogController> getDialogController() = 0; + virtual std::optional<SwLanguageListItem> GetSelectedLanguage() = 0; +}; + + class SwAbstractDialogFactory { public: @@ -398,6 +410,7 @@ public: CreateSwContentControlListItemDlg(weld::Window* pParent, SwContentControlListItem& rItem) = 0; virtual std::shared_ptr<AbstractSwBreakDlg> CreateSwBreakDlg(weld::Window *pParent, SwWrtShell &rSh) = 0; + virtual std::shared_ptr<AbstractSwTranslateLangSelectDlg> CreateSwTranslateLangSelectDlg(weld::Window *pParent) = 0; virtual VclPtr<VclAbstractDialog> CreateSwChangeDBDlg(SwView& rVw) = 0; virtual VclPtr<SfxAbstractTabDialog> CreateSwCharDlg(weld::Window* pParent, SwView& pVw, const SfxItemSet& rCoreSet, SwCharDlgMode nDialogMode, const OUString* pFormatStr = nullptr) = 0; diff --git a/sw/sdi/_textsh.sdi b/sw/sdi/_textsh.sdi index 84750b937715..128591f1673d 100644 --- a/sw/sdi/_textsh.sdi +++ b/sw/sdi/_textsh.sdi @@ -1796,5 +1796,11 @@ interface BaseText StateMethod = GetState ; ] + SID_FM_TRANSLATE + [ + ExecMethod = Execute ; + StateMethod = GetState ; + ] + } // end of interface text diff --git a/sw/source/ui/dialog/swdlgfact.cxx b/sw/source/ui/dialog/swdlgfact.cxx index 17f0ed1d3a03..b89321133188 100644 --- a/sw/source/ui/dialog/swdlgfact.cxx +++ b/sw/source/ui/dialog/swdlgfact.cxx @@ -90,6 +90,7 @@ #include <uiborder.hxx> #include <mmresultdialogs.hxx> #include <formatlinebreak.hxx> +#include <translatelangselect.hxx> using namespace ::com::sun::star; using namespace css::frame; @@ -802,6 +803,12 @@ sal_uInt16 AbstractMailMergeWizard_Impl::GetRestartPage() const return m_xDlg->GetRestartPage(); } +std::optional<SwLanguageListItem> AbstractSwTranslateLangSelectDlg_Impl::GetSelectedLanguage() +{ + SwTranslateLangSelectDlg* pDlg = dynamic_cast<SwTranslateLangSelectDlg*>(m_xDlg.get()); + return pDlg->GetSelectedLanguage(); +} + VclPtr<AbstractSwInsertAbstractDlg> SwAbstractDialogFactory_Impl::CreateSwInsertAbstractDlg(weld::Window* pParent) { return VclPtr<AbstractSwInsertAbstractDlg_Impl>::Create(std::make_unique<SwInsertAbstractDlg>(pParent)); @@ -861,6 +868,11 @@ std::shared_ptr<AbstractSwBreakDlg> SwAbstractDialogFactory_Impl::CreateSwBreakD return std::make_shared<AbstractSwBreakDlg_Impl>(std::make_unique<SwBreakDlg>(pParent, rSh)); } +std::shared_ptr<AbstractSwTranslateLangSelectDlg> SwAbstractDialogFactory_Impl::CreateSwTranslateLangSelectDlg(weld::Window* pParent) +{ + return std::make_shared<AbstractSwTranslateLangSelectDlg_Impl>(std::make_unique<SwTranslateLangSelectDlg>(pParent)); +} + VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwChangeDBDlg(SwView& rVw) { #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS diff --git a/sw/source/ui/dialog/swdlgfact.hxx b/sw/source/ui/dialog/swdlgfact.hxx index 8690d9db8129..7e7615ef9220 100644 --- a/sw/source/ui/dialog/swdlgfact.hxx +++ b/sw/source/ui/dialog/swdlgfact.hxx @@ -187,6 +187,19 @@ public: virtual std::shared_ptr<weld::DialogController> getDialogController() override { return m_xDlg; } }; +class AbstractSwTranslateLangSelectDlg_Impl : public AbstractSwTranslateLangSelectDlg +{ + std::shared_ptr<weld::DialogController> m_xDlg; +public: + explicit AbstractSwTranslateLangSelectDlg_Impl(std::shared_ptr<weld::DialogController> p) + : m_xDlg(std::move(p)) + { + } + + virtual std::shared_ptr<weld::DialogController> getDialogController() override { return m_xDlg; } + virtual std::optional<SwLanguageListItem> GetSelectedLanguage() override; +}; + class AbstractSwTableWidthDlg_Impl : public VclAbstractDialog { std::unique_ptr<SwTableWidthDlg> m_xDlg; @@ -684,6 +697,7 @@ public: SwContentControlListItem& rItem) override; virtual std::shared_ptr<AbstractSwBreakDlg> CreateSwBreakDlg(weld::Window *pParent, SwWrtShell &rSh) override; + virtual std::shared_ptr<AbstractSwTranslateLangSelectDlg> CreateSwTranslateLangSelectDlg(weld::Window *pParent) override; virtual VclPtr<VclAbstractDialog> CreateSwChangeDBDlg(SwView& rVw) override; virtual VclPtr<SfxAbstractTabDialog> CreateSwCharDlg(weld::Window* pParent, SwView& pVw, const SfxItemSet& rCoreSet, SwCharDlgMode nDialogMode, const OUString* pFormatStr = nullptr) override; diff --git a/sw/source/ui/misc/translatelangselect.cxx b/sw/source/ui/misc/translatelangselect.cxx new file mode 100644 index 000000000000..9a05e6c738f3 --- /dev/null +++ b/sw/source/ui/misc/translatelangselect.cxx @@ -0,0 +1,110 @@ +/* -*- 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 <osl/diagnose.h> + +#include <uitool.hxx> +#include <swtypes.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <viewopt.hxx> +#include <translatelangselect.hxx> +#include <pagedesc.hxx> +#include <poolfmt.hxx> +#include <sal/log.hxx> + +int SwTranslateLangSelectDlg::selectedLangIdx = -1; +SwTranslateLangSelectDlg::SwTranslateLangSelectDlg(weld::Window *pParent) + : GenericDialogController(pParent, "modules/swriter/ui/translationdialog.ui", "LanguageSelectDialog") + , m_xLanguageListBox(m_xBuilder->weld_combo_box("combobox1")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) + , m_xBtnTranslate(m_xBuilder->weld_button("translate")) + , m_xLanguageVec( + { + SwLanguageListItem("BG", "Bulgarian"), + SwLanguageListItem("CS", "Czech"), + SwLanguageListItem("DA", "Danish"), + SwLanguageListItem("DE", "German"), + SwLanguageListItem("EL", "Greek"), + SwLanguageListItem("EN-GB", "English (British)"), + SwLanguageListItem("EN-US", "English (American)"), + SwLanguageListItem("ET", "Estonian"), + SwLanguageListItem("FI", "Finnish"), + SwLanguageListItem("FR", "French"), + SwLanguageListItem("HU", "Hungarian"), + SwLanguageListItem("ID", "Indonesian"), + SwLanguageListItem("IT", "Italian"), + SwLanguageListItem("JA", "Japanese"), + SwLanguageListItem("LT", "Lithuanian"), + SwLanguageListItem("LV", "Dutch"), + SwLanguageListItem("PL", "Polish"), + SwLanguageListItem("PT-BR", "Portuguese (Brazilian)"), + SwLanguageListItem("PT-PT", "Portuguese (European)"), + SwLanguageListItem("RO", "Romanian"), + SwLanguageListItem("RU", "Russian"), + SwLanguageListItem("SK", "Slovak"), + SwLanguageListItem("SL", "Slovenian"), + SwLanguageListItem("SV", "Swedish"), + SwLanguageListItem("TR", "Turkish"), + SwLanguageListItem("ZH", "Chinese (simplified)"), + }) +{ + m_xLanguageListBox->connect_changed(LINK(this, SwTranslateLangSelectDlg, LangSelectHdl)); + m_xBtnCancel->connect_clicked(LINK(this, SwTranslateLangSelectDlg, LangSelectCancelHdl)); + m_xBtnTranslate->connect_clicked(LINK(this, SwTranslateLangSelectDlg, LangSelectTranslateHdl)); + for (const auto& item : m_xLanguageVec) + { + m_xLanguageListBox->append_text(OStringToOUString(item.getName(), RTL_TEXTENCODING_UTF8)); + } + + if (SwTranslateLangSelectDlg::selectedLangIdx != -1) + { + m_xLanguageListBox->set_active(SwTranslateLangSelectDlg::selectedLangIdx); + } +} + +std::optional<SwLanguageListItem> SwTranslateLangSelectDlg::GetSelectedLanguage() +{ + if (SwTranslateLangSelectDlg::selectedLangIdx != -1) + { + return m_xLanguageVec.at(SwTranslateLangSelectDlg::selectedLangIdx); + } + + return {}; +} + + +IMPL_LINK(SwTranslateLangSelectDlg, LangSelectHdl, weld::ComboBox&, rBox, void) +{ + const auto selected = m_xLanguageListBox->get_active(); + SwTranslateLangSelectDlg::selectedLangIdx = selected; +} + +IMPL_LINK(SwTranslateLangSelectDlg, LangSelectCancelHdl, weld::Button&, rButton, void) +{ + m_xDialog->response(RET_CANCEL); +} + +IMPL_LINK(SwTranslateLangSelectDlg, LangSelectTranslateHdl, weld::Button&, rButton, void) +{ + m_xDialog->response(RET_OK); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/inc/translatelangselect.hxx b/sw/source/uibase/inc/translatelangselect.hxx new file mode 100644 index 000000000000..84e5669b7fcb --- /dev/null +++ b/sw/source/uibase/inc/translatelangselect.hxx @@ -0,0 +1,58 @@ + +/* -*- 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 <rtl/string.h> +#include <vector> +#include <optional> +//class SwWrtShell; + +class SwLanguageListItem final +{ +public: + SwLanguageListItem(const OString& sLanguage, const OString& sName) : m_sLanguage(sLanguage), m_sName(sName) {} + const OString& getLanguage() const { return m_sLanguage; } + const OString& getName() const { return m_sName; } + +private: + const OString m_sLanguage; + const OString m_sName; +}; + +class SwTranslateLangSelectDlg final : public weld::GenericDialogController +{ +public: + static int selectedLangIdx; + SwTranslateLangSelectDlg(weld::Window* pParent/*, SwWrtShell& rSh*/); + std::optional<SwLanguageListItem> GetSelectedLanguage(); + +private: + std::unique_ptr<weld::ComboBox> m_xLanguageListBox; + std::unique_ptr<weld::Button> m_xBtnCancel; + std::unique_ptr<weld::Button> m_xBtnTranslate; + std::vector<SwLanguageListItem> m_xLanguageVec; + + DECL_LINK(LangSelectHdl, weld::ComboBox&, void ); + DECL_LINK(LangSelectCancelHdl, weld::Button&, void ); + DECL_LINK(LangSelectTranslateHdl, weld::Button&, void ); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx index 8d7c07e104ca..c38f321edc2b 100644 --- a/sw/source/uibase/shells/textsh1.cxx +++ b/sw/source/uibase/shells/textsh1.cxx @@ -35,6 +35,7 @@ #include <sfx2/bindings.hxx> #include <sfx2/viewfrm.hxx> #include <vcl/unohelp2.hxx> +#include <vcl/unohelp3.hxx> #include <vcl/weld.hxx> #include <sfx2/request.hxx> #include <svl/eitem.hxx> @@ -78,6 +79,8 @@ #include <editeng/acorrcfg.hxx> #include <swabstdlg.hxx> #include <sfx2/sfxdlg.hxx> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> #include <com/sun/star/container/XNameContainer.hpp> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> @@ -103,6 +106,13 @@ #include <bookmark.hxx> #include <linguistic/misc.hxx> #include <authfld.hxx> +#include <unoparagraph.hxx> +#include <ndtxt.hxx> +#include <shellio.hxx> +#include <curl/curl.h> +#include <boost/property_tree/ptree.hpp> +#include <boost/property_tree/json_parser.hpp> +#include <translatelangselect.hxx> using namespace ::com::sun::star; using namespace com::sun::star::beans; @@ -1503,6 +1513,118 @@ void SwTextShell::Execute(SfxRequest &rReq) } } break; + case SID_FM_TRANSLATE: + { + // get url and auth_key from some config + // suply args + // if no args received, bring up language selection dialog + // improve blockingness + progressbar etc + + auto replacePara = [&rWrtSh](const OString& res, SwNodeOffset nodeIndex, const OString& targetLang) { + // curl deepl + std::unique_ptr<CURL, std::function<void(CURL*)>> curl(curl_easy_init(), + [](CURL* p) { curl_easy_cleanup(p); }); + curl_easy_setopt(curl.get(), CURLOPT_URL, "https://api-free.deepl.com/v2/translate?tag_handling=html"); + curl_easy_setopt(curl.get(), CURLOPT_FAILONERROR, 1L); + std::string response_body; + curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, +[](void *buffer, size_t size, size_t nmemb, void *userp) -> size_t + { + if (!userp) + return 0; + std::string* response = static_cast<std::string*>(userp); + size_t real_size = size * nmemb; + response->append(static_cast<char*>(buffer), real_size); + return real_size; + }); + curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, static_cast<void*>(&response_body)); + OString aPostData("auth_key=&target_lang="+targetLang+"&text=" + OString(curl_easy_escape(curl.get(), res.getStr(), res.getLength()))); + curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, aPostData.getStr()); + CURLcode cc = curl_easy_perform(curl.get()); + if (cc != CURLE_OK) + { + SAL_WARN("deepl", "CURL request returned with error: " << static_cast<sal_Int32>(cc)); + return; + } + tools::Long nStatusCode; + curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &nStatusCode); + if (nStatusCode != 200) + { + SAL_WARN("deepl", "CURL request returned with status code: " << nStatusCode); + return; + } + // parse the response + boost::property_tree::ptree root; + std::stringstream aStream(response_body.data()); + boost::property_tree::read_json(aStream, root); + boost::property_tree::ptree& translations = root.get_child("translations"); + size_t size = translations.size(); + if (size <= 0) + { + SAL_WARN("deepl", "request returned no translations"); + } + // take the first one + const boost::property_tree::ptree& translation = translations.begin()->second; + const std::string text = translation.get<std::string>("text"); + OString translatedData(text); + rtl::Reference<vcl::unohelper::HtmlTransferable> pHtmlTransferable = new vcl::unohelper::HtmlTransferable( translatedData ); + if ( pHtmlTransferable.is() ) + { + TransferableDataHelper aDataHelper( pHtmlTransferable ); + if( aDataHelper.GetXTransferable().is() && SwTransferable::IsPasteSpecial( rWrtSh, aDataHelper ) ) + { + std::shared_ptr<SwPaM> cursor = Writer::NewUnoCursor(*rWrtSh.GetDoc(), nodeIndex, nodeIndex); + rWrtSh.SetSelection(*cursor); + SwTransferable::Paste(rWrtSh, aDataHelper); + rWrtSh.KillSelection(nullptr, false); + } + } + }; + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + std::shared_ptr<AbstractSwTranslateLangSelectDlg> pAbstractDialog(pFact->CreateSwTranslateLangSelectDlg(GetView().GetFrameWeld())); + std::shared_ptr<weld::DialogController> pDialogController(pAbstractDialog->getDialogController()); + weld::DialogController::runAsync(pDialogController, [&rWrtSh, replacePara, pAbstractDialog] (sal_Int32 nResult) { + if (nResult != RET_OK) + { + return; + } + auto languageItem = pAbstractDialog->GetSelectedLanguage(); + if (!languageItem.has_value()) + { + return; + } + const OString targetLang = languageItem->getLanguage(); + OString aResult; + auto const& pNodes = rWrtSh.GetNodes(); + WriterRef xWrt; + GetHTMLWriter( OUString("NoLineLimit,SkipHeaderFooter"), OUString(), xWrt ); + SwNode* pNode = nullptr; + for (SwNodeOffset n(0); ; ++n) + { + if (n >= rWrtSh.GetNodes().Count()) + break; + + if (!pNodes[n]) + break; + + pNode = pNodes[n]; + if (pNode->IsTextNode()) + { + if (pNode->GetTextNode()->GetText() == "") + continue; + auto cursor = Writer::NewUnoCursor(*rWrtSh.GetDoc(), pNode->GetIndex(), pNode->GetIndex()); + SvMemoryStream aMemoryStream; + SwWriter aWriter(aMemoryStream, *cursor); + ErrCode nError = aWriter.Write(xWrt); + aResult = OString(static_cast<const char*>(aMemoryStream.GetData()), aMemoryStream.GetSize()); + // replace <p> with <scan> to avoid newlines on paste, hacky but no other option + aResult = aResult.replaceAll("<p", "<span"); + aResult = aResult.replaceAll("</p>", "</span>"); + replacePara(aResult, pNode->GetIndex(), targetLang); + } + } + }); + } + break; case SID_SPELLCHECK_IGNORE: { SwPaM *pPaM = rWrtSh.GetCursor(); diff --git a/sw/uiconfig/sglobal/menubar/menubar.xml b/sw/uiconfig/sglobal/menubar/menubar.xml index 38f6708c1a55..709c492df4f3 100644 --- a/sw/uiconfig/sglobal/menubar/menubar.xml +++ b/sw/uiconfig/sglobal/menubar/menubar.xml @@ -446,6 +446,7 @@ <menu:menuseparator/> <menu:menuitem menu:id=".uno:PageDialog"/> <menu:menuitem menu:id=".uno:TitlePageDialog" menu:style="text"/> + <menu:menuitem menu:id=".uno:Translate" menu:style="text"/> <menu:menuitem menu:id=".uno:FormatAllNotes" menu:style="text"/> <menu:menuitem menu:id=".uno:RubyDialog" menu:style="text"/> <menu:menuitem menu:id=".uno:FormatColumns" menu:style="text"/> diff --git a/sw/uiconfig/swform/menubar/menubar.xml b/sw/uiconfig/swform/menubar/menubar.xml index 0969d09e6ef6..861cded1a732 100644 --- a/sw/uiconfig/swform/menubar/menubar.xml +++ b/sw/uiconfig/swform/menubar/menubar.xml @@ -396,6 +396,7 @@ <menu:menuseparator/> <menu:menuitem menu:id=".uno:PageDialog"/> <menu:menuitem menu:id=".uno:TitlePageDialog" menu:style="text"/> + <menu:menuitem menu:id=".uno:Translate" menu:style="text"/> <menu:menuitem menu:id=".uno:FormatAllNotes" menu:style="text"/> <menu:menuitem menu:id=".uno:RubyDialog" menu:style="text"/> <menu:menuitem menu:id=".uno:FormatColumns" menu:style="text"/> diff --git a/sw/uiconfig/swriter/menubar/menubar.xml b/sw/uiconfig/swriter/menubar/menubar.xml index 3f257b9f0ebf..4658564da415 100644 --- a/sw/uiconfig/swriter/menubar/menubar.xml +++ b/sw/uiconfig/swriter/menubar/menubar.xml @@ -457,6 +457,7 @@ <menu:menuseparator/> <menu:menuitem menu:id=".uno:PageDialog"/> <menu:menuitem menu:id=".uno:TitlePageDialog"/> + <menu:menuitem menu:id=".uno:Translate"/> <menu:menuitem menu:id=".uno:FormatAllNotes" menu:style="text"/> <menu:menuitem menu:id=".uno:RubyDialog" menu:style="text"/> <menu:menuitem menu:id=".uno:FormatColumns"/> diff --git a/sw/uiconfig/swriter/ui/translationdialog.ui b/sw/uiconfig/swriter/ui/translationdialog.ui new file mode 100644 index 000000000000..70a594201e60 --- /dev/null +++ b/sw/uiconfig/swriter/ui/translationdialog.ui @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.2 --> +<interface domain="sw"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkDialog" id="LanguageSelectDialog"> + <property name="can_focus">False</property> + <property name="title" translatable="yes">Language Selection</property> + <property name="type_hint">dialog</property> + <child type="titlebar"> + <placeholder/> + </child> + <child internal-child="vbox"> + <object class="GtkBox" id="box1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="action-area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="cancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="translate"> + <property name="label">gtk-apply</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_homogeneous">True</property> + <property name="column_homogeneous">True</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Select language to translate</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">combobox1</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="combobox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 90d432ee559b..8f3e41c57d81 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -408,6 +408,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/app/svmain \ vcl/source/app/timer \ vcl/source/app/unohelp2 \ + vcl/source/app/unohelp3 \ vcl/source/app/unohelp \ vcl/source/app/vclevent \ vcl/source/app/watchdog \ diff --git a/vcl/source/app/unohelp3.cxx b/vcl/source/app/unohelp3.cxx new file mode 100644 index 000000000000..0910de84e64d --- /dev/null +++ b/vcl/source/app/unohelp3.cxx @@ -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 . + */ + +#include <sal/log.hxx> +#include <vcl/unohelp3.hxx> +#include <sot/exchange.hxx> +#include <sot/formats.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> +#include <cppuhelper/queryinterface.hxx> +#include <boost/property_tree/json_parser.hpp> + +using namespace ::com::sun::star; + +namespace vcl::unohelper { + + HtmlTransferable::HtmlTransferable( OString sData ) : data( sData ) + { + } + + HtmlTransferable::~HtmlTransferable() + { + } + + // css::uno::XInterface + uno::Any HtmlTransferable::queryInterface( const uno::Type & rType ) + { + uno::Any aRet = ::cppu::queryInterface( rType, static_cast< datatransfer::XTransferable* >(this) ); + return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType )); + } + + // css::datatransfer::XTransferable + uno::Any HtmlTransferable::getTransferData( const datatransfer::DataFlavor& rFlavor ) + { + SotClipboardFormatId nT = SotExchange::GetFormat( rFlavor ); + if ( nT != SotClipboardFormatId::HTML ) + { + throw datatransfer::UnsupportedFlavorException(); + } + size_t size = data.getLength(); + uno::Sequence<sal_Int8> sData(size); + std::memcpy(sData.getArray(), data.getStr(), size); + return uno::Any(sData); + } + + uno::Sequence< datatransfer::DataFlavor > HtmlTransferable::getTransferDataFlavors( ) + { + uno::Sequence< datatransfer::DataFlavor > aDataFlavors(1); + auto ref = aDataFlavors.getArray()[0]; + ref.MimeType = "text/html"; + ref.DataType = cppu::UnoType< uno::Sequence<sal_Int8> >::get(); + SotExchange::GetFormatDataFlavor( SotClipboardFormatId::HTML, aDataFlavors.getArray()[0] ); + return aDataFlavors; + } + + sal_Bool HtmlTransferable::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) + { + SotClipboardFormatId nT = SotExchange::GetFormat( rFlavor ); + return ( nT == SotClipboardFormatId::HTML ); + } + +} // namespace vcl::unohelper commit cf4b670229eb8b555dde848ef53108cb2a4ee89b Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Jul 4 13:05:08 2022 +0200 Commit: Gökay ŞATIR <gokaysa...@collabora.com> CommitDate: Tue Jul 5 11:35:28 2022 +0200 sw content control, picture, lok: fix change of placeholder after insert Commit c769c369c87a46ec877b7eefee27988044a2798f (sw content controls: fix picture placeholders, 2022-07-01) fixed picture placeholders on the desktop, but left the LOK case still broken. This is a problem since picture placeholders are protected (which is wanted), and these only allow SID_CHANGE_PICTURE, not SID_INSERT_GRAPHIC. Fix the problem by adapting SwXTextDocument::executeContentControlEvent() to dispatch SID_CHANGE_PICTURE (and not SID_INSERT_GRAPHIC), but do keep the slot ID of the argument as SID_INSERT_GRAPHIC, since SwView::InsertGraphicDlg() looks for a non-interactive URL as SID_INSERT_GRAPHIC even if we're changing an image, not inserting a new one. This means that LOK clients can't use SID_INSERT_GRAPHIC to change picture placeholders, they have to go via SwXTextDocument::executeContentControlEvent(), which is what gtktiledviewer does already. (cherry picked from commit 4002a399af823055b6ba59db18ded1caba4969c9) Change-Id: Ica42939f6564da3d59396a4b302be826d3968f8d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136808 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Gökay ŞATIR <gokaysa...@collabora.com> diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx index 1d68e037d949..8f9b28e01dec 100644 --- a/sw/source/uibase/uno/unotxdoc.cxx +++ b/sw/source/uibase/uno/unotxdoc.cxx @@ -3428,7 +3428,7 @@ void SwXTextDocument::executeContentControlEvent(const StringMap& rArguments) // The current placeholder is selected, so this will replace, not insert. SfxStringItem aItem(SID_INSERT_GRAPHIC, it->second); - pView->GetViewFrame()->GetDispatcher()->ExecuteList(SID_INSERT_GRAPHIC, + pView->GetViewFrame()->GetDispatcher()->ExecuteList(SID_CHANGE_PICTURE, SfxCallMode::SYNCHRON, { &aItem }); } else if (it->second == "date") commit 3a7a58d8b86bffed074bee56ad96fd3e673ef040 Author: Mert Tumer <mert.tu...@collabora.com> AuthorDate: Mon Jul 4 19:52:49 2022 +0300 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Tue Jul 5 11:28:39 2022 +0200 Added option to disable ssl verification for languagetool This will allow to use self-signed certificates with local run languagetool APIs Signed-off-by: Mert Tumer <mert.tu...@collabora.com> Change-Id: I2bda575fa6174dfc0f6c24da45267ee732643db6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136811 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Andras Timar <andras.ti...@collabora.com> diff --git a/cui/source/options/optlanguagetool.cxx b/cui/source/options/optlanguagetool.cxx index 38807bc337d3..fc7a42536051 100644 --- a/cui/source/options/optlanguagetool.cxx +++ b/cui/source/options/optlanguagetool.cxx @@ -29,6 +29,7 @@ OptLanguageToolTabPage::OptLanguageToolTabPage(weld::Container* pPage, , m_xUsernameED(m_xBuilder->weld_entry("username")) , m_xApiKeyED(m_xBuilder->weld_entry("apikey")) , m_xActivateBox(m_xBuilder->weld_check_button("activate")) + , m_xSSLDisableVerificationBox(m_xBuilder->weld_check_button("verifyssl")) , m_xApiSettingsFrame(m_xBuilder->weld_frame("apisettings")) { m_xActivateBox->connect_toggled(LINK(this, OptLanguageToolTabPage, CheckHdl)); @@ -44,6 +45,7 @@ void OptLanguageToolTabPage::EnableControls(bool bEnable) rLanguageOpts.setEnabled(bEnable); m_xApiSettingsFrame->set_visible(bEnable); m_xActivateBox->set_active(bEnable); + m_xSSLDisableVerificationBox->set_active(rLanguageOpts.getSSLVerification() != true); } IMPL_LINK_NOARG(OptLanguageToolTabPage, CheckHdl, weld::Toggleable&, void) @@ -57,6 +59,7 @@ void OptLanguageToolTabPage::Reset(const SfxItemSet*) m_xBaseURLED->set_text(rLanguageOpts.getBaseURL()); m_xUsernameED->set_text(rLanguageOpts.getUsername()); m_xApiKeyED->set_text(rLanguageOpts.getApiKey()); + m_xSSLDisableVerificationBox->set_active(rLanguageOpts.getSSLVerification() != true); } bool OptLanguageToolTabPage::FillItemSet(SfxItemSet*) @@ -65,6 +68,7 @@ bool OptLanguageToolTabPage::FillItemSet(SfxItemSet*) rLanguageOpts.setBaseURL(m_xBaseURLED->get_text()); rLanguageOpts.setUsername(m_xUsernameED->get_text()); rLanguageOpts.setApiKey(m_xApiKeyED->get_text()); + rLanguageOpts.setSSLVerification(m_xSSLDisableVerificationBox->get_active() != true); return false; } diff --git a/cui/source/options/optlanguagetool.hxx b/cui/source/options/optlanguagetool.hxx index 46a60ecbe103..85e0238b0318 100644 --- a/cui/source/options/optlanguagetool.hxx +++ b/cui/source/options/optlanguagetool.hxx @@ -36,6 +36,7 @@ private: std::unique_ptr<weld::Entry> m_xUsernameED; std::unique_ptr<weld::Entry> m_xApiKeyED; std::unique_ptr<weld::CheckButton> m_xActivateBox; + std::unique_ptr<weld::CheckButton> m_xSSLDisableVerificationBox; std::unique_ptr<weld::Frame> m_xApiSettingsFrame; void EnableControls(bool bEnable); diff --git a/cui/uiconfig/ui/langtoolconfigpage.ui b/cui/uiconfig/ui/langtoolconfigpage.ui index 7b822325e3f1..237040fa76b7 100644 --- a/cui/uiconfig/ui/langtoolconfigpage.ui +++ b/cui/uiconfig/ui/langtoolconfigpage.ui @@ -76,16 +76,130 @@ <object class="GtkGrid" id="grid1"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="row_spacing">5</property> - <property name="column_spacing">12</property> <child> - <object class="GtkLabel" id="base"> + <object class="GtkGrid" id="grid2"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes" context="langtoolconfigpage|base">Base URL:</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">baseurl</property> + <property name="row_spacing">5</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="base"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes" context="langtoolconfigpage|base">Base URL:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">baseurl</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="baseurl"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="usernamelbl"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes" context="langtoolconfigpage|usernamelbl">User name:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">username</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="apikeylbl"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes" context="langtoolconfigpage|apikeylbl">API key:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">apikey</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="username"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="apikey"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="urldesc"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes" context="langtoolconfigpage|urldesc">Please use the base URL e.g. without "/check" at the end.</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="usernamedesc"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes" context="langtoolconfigpage|usernamedesc">Your LanguageTool account's username for premium usage.</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="apikeydesc"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes" context="langtoolconfigpage|apikeydesc">Your LanguageTool account's api key for premium usage.</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">5</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> </object> <packing> <property name="left_attach">0</property> @@ -93,109 +207,20 @@ </packing> </child> <child> - <object class="GtkEntry" id="baseurl"> + <object class="GtkCheckButton" id="verifyssl"> + <property name="label" translatable="yes" context="langtoolconfigpage|verifyssl">Disable SSL Certificate Verification</property> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="hexpand">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="usernamelbl"> - <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="receives_default">False</property> <property name="halign">start</property> - <property name="label" translatable="yes" context="langtoolconfigpage|usernamelbl">User name:</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">username</property> + <property name="margin_top">5</property> + <property name="draw_indicator">True</property> </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">2</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="apikeylbl"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes" context="langtoolconfigpage|apikeylbl">API key:</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">apikey</property> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">4</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="username"> - <property name="visible">True</property> - <property name="can_focus">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">2</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="apikey"> - <property name="visible">True</property> - <property name="can_focus">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">4</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="urldesc"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes" context="langtoolconfigpage|urldesc">Please use the base URL e.g. without "/check" at the end.</property> - </object> - <packing> - <property name="left_attach">1</property> <property name="top_attach">1</property> </packing> </child> - <child> - <object class="GtkLabel" id="usernamedesc"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes" context="langtoolconfigpage|usernamedesc">Your LanguageTool account's username for premium usage.</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">3</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="apikeydesc"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes" context="langtoolconfigpage|apikeydesc">Your LanguageTool account's api key for premium usage.</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">5</property> - </packing> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> </object> </child> <child type="label"> diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 5b4434b75e22..07276ebd1eea 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -6568,9 +6568,11 @@ void setLanguageToolConfig() const char* pBaseUrlString = ::getenv("LANGUAGETOOL_BASEURL"); const char* pUsername = ::getenv("LANGUAGETOOL_USERNAME"); const char* pApikey = ::getenv("LANGUAGETOOL_APIKEY"); + const char* pSSLVerification = ::getenv("LANGUAGETOOL_SSL_VERIFICATION"); if (pEnabled && pBaseUrlString) { OUString aEnabled = OStringToOUString(pEnabled, RTL_TEXTENCODING_UTF8); + OUString aSSLVerification = OStringToOUString(pSSLVerification, RTL_TEXTENCODING_UTF8); if (aEnabled != "true") return; OUString aBaseUrl = OStringToOUString(pBaseUrlString, RTL_TEXTENCODING_UTF8); @@ -6579,6 +6581,7 @@ void setLanguageToolConfig() SvxLanguageToolOptions& rLanguageOpts = SvxLanguageToolOptions::Get(); rLanguageOpts.setBaseURL(aBaseUrl); rLanguageOpts.setEnabled(true); + rLanguageOpts.setSSLVerification(aSSLVerification == "true"); if (pUsername && pApikey) { OUString aUsername = OStringToOUString(pUsername, RTL_TEXTENCODING_UTF8); diff --git a/include/svtools/languagetoolcfg.hxx b/include/svtools/languagetoolcfg.hxx index 7578ad6ba281..3f30c4bd94a8 100644 --- a/include/svtools/languagetoolcfg.hxx +++ b/include/svtools/languagetoolcfg.hxx @@ -51,6 +51,9 @@ public: bool getEnabled() const; void setEnabled(bool enabled); + bool getSSLVerification() const; + void setSSLVerification(bool enabled); + private: std::unique_ptr<LanguageToolOptions_Impl> pImpl; void Load(const css::uno::Sequence<OUString>& rPropertyNames); diff --git a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx index 5479e67e82c4..da0d133a6965 100644 --- a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx +++ b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx @@ -41,6 +41,7 @@ #include <com/sun/star/uno/Any.hxx> #include <unotools/lingucfg.hxx> #include <osl/mutex.hxx> +#include <sal/log.hxx> using namespace osl; using namespace com::sun::star; @@ -332,8 +333,12 @@ std::string LanguageToolGrammarChecker::makeHttpRequest(std::string_view aURL, H curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, static_cast<void*>(&response_body)); - curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, false); - curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, false); + // allow unknown or self-signed certificates + if (rLanguageOpts.getSSLVerification() == false) + { + curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, false); + } curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, CURL_TIMEOUT); if (method == HTTP_METHOD::HTTP_POST) @@ -350,8 +355,11 @@ std::string LanguageToolGrammarChecker::makeHttpRequest(std::string_view aURL, H } } - /*CURLcode cc = */ - curl_easy_perform(curl.get()); + CURLcode cc = curl_easy_perform(curl.get()); + if (cc != CURLE_OK) + { + SAL_WARN("languagetool", "CURL request returned with error: " << static_cast<sal_Int32>(cc)); + } curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &nStatusCode); return response_body; } diff --git a/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs b/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs index 8a9239e570f4..a3fc5f1296c8 100644 --- a/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs @@ -435,6 +435,13 @@ </info> <value>false</value> </prop> + <prop oor:name="SSLCertVerify" oor:type="xs:boolean" oor:nillable="false"> + <info> + <desc>Enable or disable SSL certificate verification for HTTPS requests</desc> + <label>API SSL verification control</label> + </info> + <value>true</value> + </prop> </group> </group> <group oor:name="Hyphenation"> diff --git a/svtools/source/config/languagetoolcfg.cxx b/svtools/source/config/languagetoolcfg.cxx index 9f81c8e787f1..3f48010141db 100644 --- a/svtools/source/config/languagetoolcfg.cxx +++ b/svtools/source/config/languagetoolcfg.cxx @@ -32,6 +32,7 @@ struct LanguageToolOptions_Impl OUString sUsername; OUString sApiKey; bool bEnabled; + bool bSSLCertVerificatrionEnabled; }; const Sequence<OUString>& SvxLanguageToolOptions::GetPropertyNames() @@ -41,6 +42,7 @@ const Sequence<OUString>& SvxLanguageToolOptions::GetPropertyNames() "LanguageTool/Username", "LanguageTool/ApiKey", "LanguageTool/IsEnabled", + "LanguageTool/SSLCertVerify", }; return aNames; } @@ -75,6 +77,14 @@ void SvxLanguageToolOptions::setApiKey(const OUString& rVal) bool SvxLanguageToolOptions::getEnabled() const { return pImpl->bEnabled; } +bool SvxLanguageToolOptions::getSSLVerification() const { return pImpl->bSSLCertVerificatrionEnabled; } + +void SvxLanguageToolOptions::setSSLVerification(bool bEnabled) +{ + pImpl->bSSLCertVerificatrionEnabled = bEnabled; + SetModified(); +} + void SvxLanguageToolOptions::setEnabled(bool bEnabled) { pImpl->bEnabled = bEnabled; @@ -129,6 +139,9 @@ void SvxLanguageToolOptions::Load(const css::uno::Sequence<OUString>& aNames) case 3: pValues[nProp] >>= pImpl->bEnabled; break; + case 4: + pValues[nProp] >>= pImpl->bSSLCertVerificatrionEnabled; + break; default: break; } @@ -156,6 +169,9 @@ void SvxLanguageToolOptions::ImplCommit() case 3: pValues[nProp] <<= pImpl->bEnabled; break; + case 4: + pValues[nProp] <<= pImpl->bSSLCertVerificatrionEnabled; + break; default: break; } commit c1743dc6f610db557de1a4fd31ce8c0f090f4c52 Author: Pedro Pinto Silva <pedro.si...@collabora.com> AuthorDate: Fri Jul 1 15:33:22 2022 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jul 4 16:55:52 2022 +0200 Rename UI Variant from Standard Toolbar to Compact To be more in-tune with COnline options Signed-off-by: Pedro Pinto Silva <pedro.si...@collabora.com> Change-Id: I38c4d1639dbf7d726fb8c3d784a298cd01a97201 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136743 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Andras Timar <andras.ti...@collabora.com> diff --git a/cui/uiconfig/ui/toolbarmodedialog.ui b/cui/uiconfig/ui/toolbarmodedialog.ui index d401f75edf73..58b399680760 100644 --- a/cui/uiconfig/ui/toolbarmodedialog.ui +++ b/cui/uiconfig/ui/toolbarmodedialog.ui @@ -108,7 +108,7 @@ <property name="spacing">3</property> <child> <object class="GtkRadioButton" id="rbButton1"> - <property name="label" translatable="yes" context="ToolbarmodeDialog|radiobutton1">Standard Toolbar</property> + <property name="label" translatable="yes" context="ToolbarmodeDialog|radiobutton1">Compact</property> <property name="visible">True</property> <property name="can-focus">True</property> <property name="receives-default">False</property> commit 5abd089d601fb745735ad784c1be48a30bdb0a40 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Jul 4 09:19:35 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jul 4 13:05:06 2022 +0200 sw content controls, checkbox: reduce left vs right amount of shading mismatch This was a visual problem with all content controls, but most visible with short ones, like checkbox. A content control's layout starts with a field portion (shaded), followed by a content control portion (also shaded). The shading around the checkbox character is not balanced, the left side has more shading. Half of the additional shading is caused by shading for the field portion: avoid this in case we know where will be a content control portion after the field portion. The result is not perfect, but the left/right mismatch for the amount of shading around the checkbox is much better this way. (cherry picked from commit 0203485a7f7dd85f8d3e04ce91579051aa89d26a) Conflicts: sw/source/core/text/porfld.hxx Change-Id: I147d23c43e679113c84c21fbfc0c8ac1ca9e51b6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136795 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx index 6ef492c1b9d5..413e8e4d4171 100644 --- a/sw/source/core/text/porfld.cxx +++ b/sw/source/core/text/porfld.cxx @@ -441,7 +441,7 @@ void SwFieldPortion::Paint( const SwTextPaintInfo &rInf ) const SwFontSave aSave( rInf, m_pFont.get() ); // OSL_ENSURE(GetLen() <= TextFrameIndex(1), "SwFieldPortion::Paint: rest-portion pollution?"); - if( Width() && ( !m_bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) ) + if( Width() && ( !m_bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) && !m_bContentControl ) { // A very liberal use of the background rInf.DrawViewOpt( *this, PortionType::Field ); diff --git a/sw/source/core/text/porfld.hxx b/sw/source/core/text/porfld.hxx index 519e56f8f58c..ec4757d56ea9 100644 --- a/sw/source/core/text/porfld.hxx +++ b/sw/source/core/text/porfld.hxx @@ -52,6 +52,7 @@ protected: bool m_bReplace : 1; // Used by SwGrfNumPortion const bool m_bPlaceHolder : 1; bool m_bNoLength : 1; // HACK for meta suffix (no CH_TXTATR) + bool m_bContentControl = false; void SetFont( std::unique_ptr<SwFont> pNew ) { m_pFont = std::move(pNew); } bool IsNoLength() const { return m_bNoLength; } @@ -107,6 +108,8 @@ public: // Accessibility: pass information about this portion to the PortionHandler virtual void HandlePortion( SwPortionHandler& rPH ) const override; + + void SetContentControl(bool bContentControl) { m_bContentControl = bContentControl; } }; /** diff --git a/sw/source/core/text/txtfld.cxx b/sw/source/core/text/txtfld.cxx index fc25dc4e9880..efb8d2926bc4 100644 --- a/sw/source/core/text/txtfld.cxx +++ b/sw/source/core/text/txtfld.cxx @@ -406,7 +406,12 @@ SwLinePortion *SwTextFormatter::NewExtraPortion( SwTextFormatInfo &rInf ) } if( !pRet ) { - pRet = new SwFieldPortion( "" ); + auto pFieldPortion = new SwFieldPortion( "" ); + if (pHint->Which() == RES_TXTATR_CONTENTCONTROL) + { + pFieldPortion->SetContentControl(true); + } + pRet = pFieldPortion; rInf.SetLen(TextFrameIndex(1)); } return pRet; commit d1d54800db7dc92c45f55661e81617b01638a492 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Jul 1 13:36:05 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jul 4 12:01:00 2022 +0200 sw content controls: link ODF proposal (cherry picked from commit 3f379f00b17268fbb63ba072d04336acb0c7e398) Change-Id: I18a62cce01eb8a5cc1764ee813a9265cb02c5fdf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136794 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index 959cc36e00b5..d78c60fbddd1 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -2795,7 +2795,7 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:element> </rng:define> - <!-- TODO(vmiklos) no proposal --> + <!-- https://issues.oasis-open.org/browse/OFFICE-4131 Inline content controls for text documents --> <rng:define name="paragraph-content" combine="choice"> <rng:element name="loext:content-control"> <rng:optional> commit 424fc806a0b96343bec8c74aef7dfc14eda2618d Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed Jun 29 08:55:17 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jul 4 08:10:26 2022 +0200 tdf#149748 sd theme: fix crash on selecting none from color bar Opening Impress, going to view -> color bar to enable it and then clicking on "none" resulted in a crash. This went wrong in commit f5db3b12ae1cd3bfe6ee5d260aec9532cc65f2dc (sd theme: add UI (sidebar) for shape fill color, 2022-04-06), where I assumed that in case the slot is a SID_ATTR_FILL_COLOR, then its item set also has a SID_ATTR_FILL_COLOR key. This is usually true, but not in case of "no color" (i.e. transparent). Fix the problem by just skipping theming metadata for such a color. It seems to me that the color set of a theme is not allowed to contain such "no color" colors, so this should be safe. (cherry picked from commit c09eb0f74c0a110e4a4cfc4783b59883aad30475) Conflicts: sd/qa/unit/uiimpress.cxx Change-Id: I3fb65548dca1d78631311de56c15fdb655b9645a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136751 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sd/qa/unit/uiimpress.cxx b/sd/qa/unit/uiimpress.cxx index 9b58251ffc93..23fabc297d86 100644 --- a/sd/qa/unit/uiimpress.cxx +++ b/sd/qa/unit/uiimpress.cxx @@ -960,6 +960,21 @@ CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testFillColorTheme) CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(6000), nFillColorLumOff); } +CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testFillColorNoColor) +{ + // Given an empty Impress document: + mxComponent = loadFromDesktop("private:factory/simpress", + "com.sun.star.presentation.PresentationDocument"); + auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get()); + sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell(); + SfxDispatcher* pDispatcher = pViewShell->GetViewFrame()->GetDispatcher(); + + // When dispatching a fill color that only has a fill style (no color), then make sure we don't + // crash: + XFillStyleItem aXFillStyleItem(drawing::FillStyle_NONE); + pDispatcher->ExecuteList(SID_ATTR_FILL_COLOR, SfxCallMode::RECORD, { &aXFillStyleItem }); +} + CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testThemeShapeInsert) { // Given a document with a theme, accent1 color is set to 0x000004: diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx index 02a3e3364c1c..5ca1f2d9c50a 100644 --- a/sd/source/ui/view/drviews2.cxx +++ b/sd/source/ui/view/drviews2.cxx @@ -598,24 +598,26 @@ public: { // Merge the color parameters to the color itself. const XFillColorItem* pColorItem = static_cast<const XFillColorItem*>(pArgs->GetItem(SID_ATTR_FILL_COLOR)); - assert(pColorItem); - XFillColorItem aColorItem(*pColorItem); - if (pArgs->GetItemState(SID_ATTR_COLOR_THEME_INDEX, false, &pItem) == SfxItemState::SET) + if (pColorItem) { - auto pIntItem = static_cast<const SfxInt16Item*>(pItem); - aColorItem.GetThemeColor().SetThemeIndex(pIntItem->GetValue()); - } - if (pArgs->GetItemState(SID_ATTR_COLOR_LUM_MOD, false, &pItem) == SfxItemState::SET) - { - auto pIntItem = static_cast<const SfxInt16Item*>(pItem); - aColorItem.GetThemeColor().SetLumMod(pIntItem->GetValue()); - } - if (pArgs->GetItemState(SID_ATTR_COLOR_LUM_OFF, false, &pItem) == SfxItemState::SET) - { - auto pIntItem = static_cast<const SfxInt16Item*>(pItem); - aColorItem.GetThemeColor().SetLumOff(pIntItem->GetValue()); + XFillColorItem aColorItem(*pColorItem); + if (pArgs->GetItemState(SID_ATTR_COLOR_THEME_INDEX, false, &pItem) == SfxItemState::SET) + { + auto pIntItem = static_cast<const SfxInt16Item*>(pItem); + aColorItem.GetThemeColor().SetThemeIndex(pIntItem->GetValue()); + } + if (pArgs->GetItemState(SID_ATTR_COLOR_LUM_MOD, false, &pItem) == SfxItemState::SET) + { + auto pIntItem = static_cast<const SfxInt16Item*>(pItem); + aColorItem.GetThemeColor().SetLumMod(pIntItem->GetValue()); + } + if (pArgs->GetItemState(SID_ATTR_COLOR_LUM_OFF, false, &pItem) == SfxItemState::SET) + { + auto pIntItem = static_cast<const SfxInt16Item*>(pItem); + aColorItem.GetThemeColor().SetLumOff(pIntItem->GetValue()); + } + pArgs->Put(aColorItem); } - pArgs->Put(aColorItem); } } } commit b16f2e3a39255dcb3e8cb064c81f6d2b33efb9cb Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Sun Apr 10 14:20:11 2022 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jul 4 08:10:08 2022 +0200 cid#1503836 silence Dereference null return value (cherry picked from commit 64046625553ecbfd9fe0661e5b6f48e283a909e0) Change-Id: I11dae0872d1f4add67b59ffd9696134c1dd2dbea Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136750 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx index 9918368dda65..02a3e3364c1c 100644 --- a/sd/source/ui/view/drviews2.cxx +++ b/sd/source/ui/view/drviews2.cxx @@ -597,8 +597,9 @@ public: if (nSlot == SID_ATTR_FILL_COLOR) { // Merge the color parameters to the color itself. - XFillColorItem aColorItem( - *static_cast<const XFillColorItem*>(pArgs->GetItem(SID_ATTR_FILL_COLOR))); + const XFillColorItem* pColorItem = static_cast<const XFillColorItem*>(pArgs->GetItem(SID_ATTR_FILL_COLOR)); + assert(pColorItem); + XFillColorItem aColorItem(*pColorItem); if (pArgs->GetItemState(SID_ATTR_COLOR_THEME_INDEX, false, &pItem) == SfxItemState::SET) { auto pIntItem = static_cast<const SfxInt16Item*>(pItem); commit fc4ab8cf4ad74fb8b84ca94800802c47d7efc2ff Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Jun 20 09:46:44 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jul 4 08:09:48 2022 +0200 sd theme: consider accent1 color when inserting shape with solid fill Once a theme is defined for the master page of the current slide, PowerPoint inserts a shapes with their fill color & line color set based on that theme (so this color is master-page-specific), while Impress sets the fill & line color based on the default shape style. The Impress behavior has the benefit of doing the usual style-based formatting, but now a document-level style overwrites a (master-)slide-specific theme, which is inconsistent. Fix the problem by extending sd::FuConstruct::SetStyleSheet(): if we construct a shape with fill, then not only apply the style sheet, but also set the fill & line color based on the theme (if there is any). Note that this works both in case the shape is instantly created on click (LOK case) or when the user first draws a top-left -> bottom-right point pair to define the position / size of the shape. At the same time line colors don't support themes yet, so that color is just a plain value for now. (cherry picked from commit 486810603fb3f84847bb549004ed0394a2e22d0b) Conflicts: sd/qa/unit/uiimpress.cxx Change-Id: Ic6ae8f91bd719bd80f2b56f12b001d29b0961e6e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136749 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/include/svx/ColorSets.hxx b/include/svx/ColorSets.hxx index ac9008cbeb32..6ad59a50c064 100644 --- a/include/svx/ColorSets.hxx +++ b/include/svx/ColorSets.hxx @@ -69,6 +69,23 @@ public: const ColorSet& getColorSet(std::u16string_view rName); }; +/// Offsets into the color list of a theme. +enum class ThemeColorType +{ + DK1 = 0, + LT1 = 1, + DK2 = 2, + LT2 = 3, + ACCENT1 = 4, + ACCENT2 = 5, + ACCENT3 = 6, + ACCENT4 = 7, + ACCENT5 = 8, + ACCENT6 = 9, + HLINK = 10, + FOLHLINK = 11, +}; + /// A named theme has a named color set. class SVXCORE_DLLPUBLIC Theme { @@ -94,6 +111,8 @@ public: void UpdateSdrPage(SdrPage* pPage); std::vector<Color> GetColors() const; + + Color GetColor(ThemeColorType eType) const; }; } // end of namespace svx diff --git a/sd/qa/unit/uiimpress.cxx b/sd/qa/unit/uiimpress.cxx index 283753f339c8..9b58251ffc93 100644 --- a/sd/qa/unit/uiimpress.cxx +++ b/sd/qa/unit/uiimpress.cxx @@ -16,6 +16,8 @@ #include <com/sun/star/uno/Reference.hxx> #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/drawing/XDrawView.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/drawing/XMasterPageTarget.hpp> #include <com/sun/star/frame/DispatchHelper.hpp> #include <com/sun/star/table/XMergeableCell.hpp> #include <com/sun/star/text/WritingMode2.hpp> @@ -44,6 +46,7 @@ #include <undo/undomanager.hxx> #include <vcl/scheduler.hxx> #include <comphelper/propertyvalue.hxx> +#include <comphelper/sequenceashashmap.hxx> #include <DrawDocShell.hxx> #include <ViewShell.hxx> @@ -957,6 +960,43 @@ CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testFillColorTheme) CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(6000), nFillColorLumOff); } +CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testThemeShapeInsert) +{ + // Given a document with a theme, accent1 color is set to 0x000004: + mxComponent = loadFromDesktop("private:factory/simpress", + "com.sun.star.presentation.PresentationDocument"); + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference<drawing::XMasterPageTarget> xMasterPageTarget(xDrawPage, uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xMasterPage(xMasterPageTarget->getMasterPage(), + uno::UNO_QUERY); + comphelper::SequenceAsHashMap aMap; + aMap["Name"] <<= OUString("mytheme"); + aMap["ColorSchemeName"] <<= OUString("mycolorscheme"); + uno::Sequence<util::Color> aColorScheme + = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb }; + aMap["ColorScheme"] <<= aColorScheme; + uno::Any aTheme(aMap.getAsConstPropertyValueList()); + xMasterPage->setPropertyValue("Theme", aTheme); + + // When inserting a shape: + uno::Sequence<beans::PropertyValue> aArgs = { + comphelper::makePropertyValue("CreateDirectly", true), + }; + dispatchCommand(mxComponent, ".uno:BasicShapes.round-rectangle", aArgs); + + // Then make sure the that fill color of the last shape is the accent1 color: + sal_Int32 nShapeIndex = xDrawPage->getCount() - 1; + uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(nShapeIndex), uno::UNO_QUERY); + sal_Int32 nFillColor{}; + xShape->getPropertyValue("FillColor") >>= nFillColor; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 0 / 0x000004 (~black) + // - Actual : 7512015 / 0x729fcf (~blue) + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x4), nFillColor); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/func/fuconstr.cxx b/sd/source/ui/func/fuconstr.cxx index ca248d808840..6a3ab78e7f4c 100644 --- a/sd/source/ui/func/fuconstr.cxx +++ b/sd/source/ui/func/fuconstr.cxx @@ -26,6 +26,9 @@ #include <sfx2/dispatch.hxx> #include <sfx2/viewfrm.hxx> #include <tools/debug.hxx> +#include <svx/xflclit.hxx> +#include <svx/xlineit0.hxx> +#include <svx/xlnclit.hxx> #include <app.hrc> #include <strings.hrc> @@ -367,6 +370,42 @@ void FuConstruct::SetStyleSheet( SfxItemSet& rAttr, SdrObject* pObj, pObj->SetMergedItemSet(aAttr); } } + else + { + // Creating an object with fill. + SdrPage* pThemePage = pPage; + if (pThemePage->TRG_HasMasterPage()) + { + pThemePage = &pThemePage->TRG_GetMasterPage(); + } + + svx::Theme* pTheme = pThemePage->getSdrPageProperties().GetTheme(); + if (pTheme) + { + // We construct an object on a page where the master page has a theme. Take the + // accent1 color from that theme, make sure it has priority over the shape's + // document-global style. + SfxItemSet aAttr(mpView->GetDefaultAttr()); + + aAttr.Put(XFillStyleItem(css::drawing::FillStyle_SOLID)); + + svx::ThemeColorType eColorType = svx::ThemeColorType::ACCENT1; + Color aColor = pTheme->GetColor(eColorType); + XFillColorItem aFillColorItem("", aColor); + aFillColorItem.GetThemeColor().SetThemeIndex(static_cast<sal_Int16>(eColorType)); + aAttr.Put(aFillColorItem); + + aAttr.Put(XLineStyleItem(css::drawing::LineStyle_SOLID)); + + // Line color is 50% darker than the fill color. + aColor.ApplyTintOrShade(-5000); + XLineColorItem aLineColorItem("", aColor); + // TODO no theme or theme effect for line colors yet. + aAttr.Put(aLineColorItem); + + pObj->SetMergedItemSet(aAttr); + } + } } } diff --git a/sd/source/ui/view/drviewse.cxx b/sd/source/ui/view/drviewse.cxx index 429ae789856f..b90d10ce25dd 100644 --- a/sd/source/ui/view/drviewse.cxx +++ b/sd/source/ui/view/drviewse.cxx @@ -525,6 +525,11 @@ void DrawViewShell::FuPermanent(SfxRequest& rReq) rReq.Done(); bCreateDirectly = comphelper::LibreOfficeKit::isActive(); + const SfxItemSet* pArgs = rReq.GetArgs(); + if (pArgs && pArgs->HasItem(FN_PARAM_1)) + { + bCreateDirectly = static_cast<const SfxBoolItem&>(pArgs->Get(FN_PARAM_1)).GetValue(); + } if ( nSId != SID_DRAW_CS_ID ) { diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi index f415e2522bd0..9ab00de7e881 100644 --- a/svx/sdi/svx.sdi +++ b/svx/sdi/svx.sdi @@ -10458,7 +10458,7 @@ SfxVoidItem SbaBrwInsert SID_SBA_BRW_INSERT SfxStringItem BasicShapes SID_DRAWTBX_CS_BASIC -(SfxStringItem BasicShapes SID_DRAWTBX_CS_BASIC) +(SfxStringItem BasicShapes SID_DRAWTBX_CS_BASIC, SfxBoolItem CreateDirectly FN_PARAM_1) [ AutoUpdate = TRUE, FastCall = FALSE, diff --git a/svx/source/styles/ColorSets.cxx b/svx/source/styles/ColorSets.cxx index 895ae91c8e47..88284249fc67 100644 --- a/svx/source/styles/ColorSets.cxx +++ b/svx/source/styles/ColorSets.cxx @@ -362,6 +362,16 @@ std::vector<Color> Theme::GetColors() const return aColors; } +Color Theme::GetColor(ThemeColorType eType) const +{ + if (!mpColorSet) + { + return {}; + } + + return mpColorSet->getColor(static_cast<size_t>(eType)); +} + } // end of namespace svx /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit cdb9706daccf3135e4789ecd93b57c9e32047315 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed May 25 20:06:36 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jul 4 08:07:15 2022 +0200 sd theme: add UI (sidebar) for shape fill color effects Which was perhaps the last missing piece of the "sd theme: shape fill color" story. (cherry picked from commit 645413a14a91a72bc06acf0fb4703ff7b9fffec9) Change-Id: Ice75d91412aa56afe0c9995086097d491ebf7299 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136748 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sd/qa/unit/uiimpress.cxx b/sd/qa/unit/uiimpress.cxx index fd4756388463..283753f339c8 100644 --- a/sd/qa/unit/uiimpress.cxx +++ b/sd/qa/unit/uiimpress.cxx @@ -925,10 +925,12 @@ CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testFillColorTheme) uno::UNO_QUERY); xController->select(uno::makeAny(xShape)); - // When setting the fill color of that shape, with theme metadata: + // When setting the fill color of that shape, with theme metadata & effects: uno::Sequence<beans::PropertyValue> aColorArgs = { comphelper::makePropertyValue("FillColor", static_cast<sal_Int32>(0xed7d31)), // orange comphelper::makePropertyValue("ColorThemeIndex", static_cast<sal_Int16>(4)), // accent 1 + comphelper::makePropertyValue("ColorLumMod", static_cast<sal_Int16>(4000)), + comphelper::makePropertyValue("ColorLumOff", static_cast<sal_Int16>(6000)), }; dispatchCommand(mxComponent, ".uno:FillColor", aColorArgs); Scheduler::ProcessEventsToIdle(); @@ -941,6 +943,18 @@ CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testFillColorTheme) // - Actual : -1 // i.e. the theme index was lost during the dispatch of the command. CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(4), nFillColorTheme); + + // Then also verify the effects: + sal_Int16 nFillColorLumMod = 10000; + xShape->getPropertyValue("FillColorLumMod") >>= nFillColorLumMod; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 4000 + // - Actual : 10000 + // i.e. the theme index was set, but not the effects. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(4000), nFillColorLumMod); + sal_Int16 nFillColorLumOff = 0; + xShape->getPropertyValue("FillColorLumOff") >>= nFillColorLumOff; + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(6000), nFillColorLumOff); } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx index b7f0638adb15..9918368dda65 100644 --- a/sd/source/ui/view/drviews2.cxx +++ b/sd/source/ui/view/drviews2.cxx @@ -604,6 +604,16 @@ public: auto pIntItem = static_cast<const SfxInt16Item*>(pItem); aColorItem.GetThemeColor().SetThemeIndex(pIntItem->GetValue()); } + if (pArgs->GetItemState(SID_ATTR_COLOR_LUM_MOD, false, &pItem) == SfxItemState::SET) + { + auto pIntItem = static_cast<const SfxInt16Item*>(pItem); + aColorItem.GetThemeColor().SetLumMod(pIntItem->GetValue()); + } + if (pArgs->GetItemState(SID_ATTR_COLOR_LUM_OFF, false, &pItem) == SfxItemState::SET) + { + auto pIntItem = static_cast<const SfxInt16Item*>(pItem); + aColorItem.GetThemeColor().SetLumOff(pIntItem->GetValue()); + } pArgs->Put(aColorItem); } } diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi index 4a258d860439..f415e2522bd0 100644 --- a/svx/sdi/svx.sdi +++ b/svx/sdi/svx.sdi @@ -2746,7 +2746,7 @@ XFillBitmapItem FillPageBitmap SID_ATTR_PAGE_BITMAP ] XFillColorItem FillColor SID_ATTR_FILL_COLOR -(SfxStringItem Color SID_ATTR_COLOR_STR, XFillColorItem FillColor SID_ATTR_FILL_COLOR, SfxInt16Item ColorThemeIndex SID_ATTR_COLOR_THEME_INDEX) +(SfxStringItem Color SID_ATTR_COLOR_STR, XFillColorItem FillColor SID_ATTR_FILL_COLOR, SfxInt16Item ColorThemeIndex SID_ATTR_COLOR_THEME_INDEX, SfxInt16Item ColorLumMod SID_ATTR_COLOR_LUM_MOD, SfxInt16Item ColorLumOff SID_ATTR_COLOR_LUM_OFF) [ AutoUpdate = TRUE, FastCall = FALSE, commit 3776c15fdf63262721126539bdaa6fd5d4474b1c Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue May 24 20:11:47 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jul 4 08:06:52 2022 +0200 tdf#149205 sd theme: fix PPTX export loosing dk1 and lt1 colors Document theme of Impress documents were exported to PPTX only partially: dk1 and lt1 was hardcoded to the SYS_COLOR_SCHEMES define, while the rest was written from master-slide-specific svx::Theme. The benefit of this is that our theme is just a set of colors (<a:srgbClr> markup in OOXML), while dk1 and lt1 is more dynamic by default in PowerPoint (<a:sysClr> in OOXML). The downside is that this way a custom dk1 and lt1 color was lost on export. Fix the problem by switching to <a:srgbClr> markup even for dk1 and lt1: not using the <a:sysClr> markup doesn't seem to be a problem in practice, or at least much less problematic than rendering with bad colors. If there is a need, dedicated <a:sysClr> markup support can be still added later by extending svx::ColorSet::maColors to not only store a list of colors, but also some additional properties of those colors. (cherry picked from commit 4a54a24c207f3040390e2fefec41cbbf0edd5eca) Change-Id: I26df3fd8c891c217df0d36382f6599805198f4bc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136747 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/include/oox/drawingml/clrscheme.hxx b/include/oox/drawingml/clrscheme.hxx index 01711fe8bfbd..a4f0b653441a 100644 --- a/include/oox/drawingml/clrscheme.hxx +++ b/include/oox/drawingml/clrscheme.hxx @@ -34,9 +34,9 @@ namespace oox::drawingml { enum PredefinedClrSchemeId { - //dk1, - //lt1, - dk2 = 0, + dk1 = 0, + lt1, + dk2, lt2, accent1, accent2, @@ -51,8 +51,8 @@ enum PredefinedClrSchemeId { static std::map<PredefinedClrSchemeId, OUString> PredefinedClrNames = { - //{ dk1, "dk1" }, - //{ lt1, "lt1" }, + { dk1, "dk1" }, + { lt1, "lt1" }, { dk2, "dk2" }, { lt2, "lt2" }, { accent1, "accent1" }, diff --git a/sd/CppunitTest_sd_filter_eppt.mk b/sd/CppunitTest_sd_filter_eppt.mk index 1a58e113643e..72b7b4d4dbb7 100644 --- a/sd/CppunitTest_sd_filter_eppt.mk +++ b/sd/CppunitTest_sd_filter_eppt.mk @@ -13,6 +13,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,sd_filter_eppt)) $(eval $(call gb_CppunitTest_use_externals,sd_filter_eppt,\ boost_headers \ + libxml2 \ )) $(eval $(call gb_CppunitTest_add_exception_objects,sd_filter_eppt, \ diff --git a/sd/qa/filter/eppt/eppt.cxx b/sd/qa/filter/eppt/eppt.cxx index d27713da20b0..1e8e2c7e1491 100644 --- a/sd/qa/filter/eppt/eppt.cxx +++ b/sd/qa/filter/eppt/eppt.cxx @@ -9,20 +9,25 @@ #include <test/bootstrapfixture.hxx> #include <unotest/macros_test.hxx> +#include <test/xmltesttools.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XMasterPageTarget.hpp> #include <com/sun/star/frame/Desktop.hpp> #include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/util/Color.hpp> #include <unotools/mediadescriptor.hxx> #include <unotools/tempfile.hxx> +#include <test/xmldocptr.hxx> using namespace ::com::sun::star; namespace { /// Covers sd/source/filter/eppt/ fixes. -class Test : public test::BootstrapFixture, public unotest::MacrosTest +class Test : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools { private: uno::Reference<lang::XComponent> mxComponent; @@ -30,6 +35,7 @@ private: public: void setUp() override; void tearDown() override; + void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override; uno::Reference<lang::XComponent>& getComponent() { return mxComponent; } }; @@ -48,6 +54,11 @@ void Test::tearDown() test::BootstrapFixture::tearDown(); } +void Test::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) +{ + XmlTestTools::registerOOXMLNamespaces(pXmlXpathCtx); +} + constexpr OUStringLiteral DATA_DIRECTORY = u"/sd/qa/filter/eppt/data/"; CPPUNIT_TEST_FIXTURE(Test, testOOXMLCustomShapeBitmapFill) @@ -76,6 +87,44 @@ CPPUNIT_TEST_FIXTURE(Test, testOOXMLCustomShapeBitmapFill) CPPUNIT_ASSERT_EQUAL(OUString("com.sun.star.drawing.GraphicObjectShape"), xShape->getShapeType()); } + +CPPUNIT_TEST_FIXTURE(Test, testThemeExport) +{ + // Given a document with a master slide and a theme, lt1 is set to 0x000002: + uno::Reference<lang::XComponent> xComponent = loadFromDesktop("private:factory/simpress"); + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(xComponent, uno::UNO_QUERY); + uno::Reference<drawing::XMasterPageTarget> xDrawPage( + xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xMasterPage(xDrawPage->getMasterPage(), uno::UNO_QUERY); + comphelper::SequenceAsHashMap aMap; + aMap["Name"] <<= OUString("mytheme"); + aMap["ColorSchemeName"] <<= OUString("mycolorscheme"); + uno::Sequence<util::Color> aColorScheme + = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc }; + aMap["ColorScheme"] <<= aColorScheme; + uno::Any aTheme(aMap.getAsConstPropertyValueList()); + xMasterPage->setPropertyValue("Theme", aTheme); + + // When exporting to PPTX: + utl::TempFile aTempFile; + uno::Reference<frame::XStorable> xStorable(xComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("Impress Office Open XML"); + aTempFile.EnableKillingFile(); + xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + validate(aTempFile.GetFileName(), test::OOXML); + + // Then verify that this color is not lost: + std::unique_ptr<SvStream> pStream = parseExportStream(aTempFile, "ppt/theme/theme1.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + assertXPath(pXmlDoc, "//a:clrScheme/a:lt1/a:srgbClr", "val", "000002"); + // Without the fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // - XPath '//a:clrScheme/a:lt1/a:srgbClr' number of nodes is incorrect + // i.e. the RGB color was lost on export. + xComponent->dispose(); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx index f6e78d357ead..cabd5c390078 100644 --- a/sd/source/filter/eppt/pptx-epptooxml.cxx +++ b/sd/source/filter/eppt/pptx-epptooxml.cxx @@ -2149,7 +2149,8 @@ bool PowerPointExport::WriteColorSets(const FSHelperPtr& pFS, svx::Theme* pTheme { static std::map<PredefinedClrSchemeId, sal_Int32> aPredefinedClrTokens = { - // dk1 and lt1 is intentionally missing. + { dk1, XML_dk1 }, + { lt1, XML_lt1 }, { dk2, XML_dk2 }, { lt2, XML_lt2 }, { accent1, XML_accent1 }, @@ -2173,14 +2174,11 @@ bool PowerPointExport::WriteColorSets(const FSHelperPtr& pFS, svx::Theme* pTheme return false; } - for (int nId = PredefinedClrSchemeId::dk2; nId < PredefinedClrSchemeId::Count; nId++) + for (int nId = PredefinedClrSchemeId::dk1; nId < PredefinedClrSchemeId::Count; nId++) { - // dk1 and lt1 are not written here. - int nIndex = nId + 2; - sal_Int32 nToken = aPredefinedClrTokens[static_cast<PredefinedClrSchemeId>(nId)]; pFS->startElementNS(XML_a, nToken); - pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(static_cast<sal_Int32>(pColorSet->getColor(nIndex)))); + pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(static_cast<sal_Int32>(pColorSet->getColor(nId)))); pFS->endElementNS(XML_a, nToken); } @@ -2272,15 +2270,17 @@ void PowerPointExport::WriteTheme(sal_Int32 nThemeNum, svx::Theme* pTheme) } pFS->startElementNS(XML_a, XML_clrScheme, XML_name, aColorSchemeName); - pFS->write(SYS_COLOR_SCHEMES); - - if (!WriteColorSets(pFS, pTheme) && !WriteColorSchemes(pFS, sThemePath)) + if (!WriteColorSets(pFS, pTheme)) { - // if style is not defined, try to use first one - if (!WriteColorSchemes(pFS, "ppt/theme/theme1.xml")) + pFS->write(SYS_COLOR_SCHEMES); + if (!WriteColorSchemes(pFS, sThemePath)) { - // color schemes are required - use default values - WriteDefaultColorSchemes(pFS); + // if style is not defined, try to use first one + if (!WriteColorSchemes(pFS, "ppt/theme/theme1.xml")) + { + // color schemes are required - use default values + WriteDefaultColorSchemes(pFS); + } } } commit c45b788517c9db9f8f3c0294ef3f8fdaae890815 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Jul 1 11:40:10 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jul 4 08:06:40 2022 +0200 sw content controls: fix picture placeholders This went wrong in commit c321498f915f4e8b3f4853232860ce040ab48e46 (sw content controls: reject typing inside checkbox or picture content controls, 2022-06-10), now a freshly inserted picture content control is not replaced with an image on click. The problem is that we want to forbid typing into a picture content control (it should only host a single as-char image), but changing the picture's bitmap is meant to be still possible. Fix the problem by allowing SID_CHANGE_PICTURE even if the cursor is protected: this allows changing the picture again, and a real read-only document still doesn't show the "change" menu item in its context menu. If we later find some other corner-case where this command should be still disabled, we can extend SwGrfShell::GetAttrState(), similar to how e.g. inserting images in input fields is disabled there. (cherry picked from commit c769c369c87a46ec877b7eefee27988044a2798f) Change-Id: I8b55e930330b9748ecda950dedae907b86c57e2f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136746 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/sdi/_grfsh.sdi b/sw/sdi/_grfsh.sdi index 8291745966bb..5475017d448e 100644 --- a/sw/sdi/_grfsh.sdi +++ b/sw/sdi/_grfsh.sdi @@ -63,7 +63,6 @@ interface BaseTextGraphic [ ExecMethod = Execute ; StateMethod = GetAttrState ; - DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; ] SID_EXTERNAL_EDIT commit 40a9a7e15c6131f903ea5ea9ed2fa44323098485 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Jul 1 09:02:27 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jul 4 08:06:19 2022 +0200 sw content controls, dropdown: use DecorationView for the button's arrow Instead of drawing manually, which was the way form field dropdowns did it. Also enable anti-aliasing. (cherry picked from commit 48010539f695bc269034f12cf72aa0665cca10de) Change-Id: Ia1ab5fe6168e0fb51dba3c760301764cfd1e0514 ... etc. - the rest is truncated