Rebased ref, commits from common ancestor: commit 45b74b4b7e61751b350fcbc2526d482a2ad1b18b Author: Mert Tumer <mert.tu...@collabora.com> AuthorDate: Tue Jul 5 12:03:27 2022 +0300 Commit: Mert Tumer <mert.tu...@collabora.com> CommitDate: Thu Jul 14 18:45:31 2022 +0300
wip translate Signed-off-by: Mert Tumer <mert.tu...@collabora.com> diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk index d455a64ab266..c4c0a52b2ef4 100644 --- a/cui/Library_cui.mk +++ b/cui/Library_cui.mk @@ -181,6 +181,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\ cui/source/options/optgenrl \ cui/source/options/opthtml \ cui/source/options/optlanguagetool \ + cui/source/options/optdeepl \ cui/source/options/optinet2 \ cui/source/options/optjava \ cui/source/options/optjsearch \ diff --git a/cui/UIConfig_cui.mk b/cui/UIConfig_cui.mk index 806779daaa9d..0ed879e2b228 100644 --- a/cui/UIConfig_cui.mk +++ b/cui/UIConfig_cui.mk @@ -139,6 +139,7 @@ $(eval $(call gb_UIConfig_add_uifiles,cui,\ cui/uiconfig/ui/optgeneralpage \ cui/uiconfig/ui/opthtmlpage \ cui/uiconfig/ui/langtoolconfigpage \ + cui/uiconfig/ui/deepltabpage \ cui/uiconfig/ui/optionsdialog \ cui/uiconfig/ui/optjsearchpage \ cui/uiconfig/ui/optlanguagespage \ diff --git a/cui/inc/treeopt.hrc b/cui/inc/treeopt.hrc index 952b79ea92d4..6d5bc4004a53 100644 --- a/cui/inc/treeopt.hrc +++ b/cui/inc/treeopt.hrc @@ -55,7 +55,8 @@ const std::pair<TranslateId, sal_uInt16> SID_LANGUAGE_OPTIONS_RES[] = { NC_("SID_LANGUAGE_OPTIONS_RES", "Searching in Japanese"), RID_SVXPAGE_JSEARCH_OPTIONS }, { NC_("SID_LANGUAGE_OPTIONS_RES", "Asian Layout"), RID_SVXPAGE_ASIAN_LAYOUT }, { NC_("SID_LANGUAGE_OPTIONS_RES", "Complex Text Layout"), RID_SVXPAGE_OPTIONS_CTL }, - { NC_("SID_LANGUAGE_OPTIONS_RES", "LanguageTool Server Settings"), RID_SVXPAGE_LANGTOOL_OPTIONS } + { NC_("SID_LANGUAGE_OPTIONS_RES", "LanguageTool Server Settings"), RID_SVXPAGE_LANGTOOL_OPTIONS }, + { NC_("SID_LANGUAGE_OPTIONS_RES", "DeepL Server Settings"), RID_SVXPAGE_DEEPL_OPTIONS } }; const std::pair<TranslateId, sal_uInt16> SID_INET_DLG_RES[] = diff --git a/cui/source/options/optdeepl.cxx b/cui/source/options/optdeepl.cxx new file mode 100644 index 000000000000..94b48ccc2f43 --- /dev/null +++ b/cui/source/options/optdeepl.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 "optdeepl.hxx" +#include <svtools/deeplcfg.hxx> + +OptDeeplTabPage::OptDeeplTabPage(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "cui/ui/deepltabpage.ui", "OptDeeplPage", &rSet) + , m_xAPIUrl(m_xBuilder->weld_entry("apiurl")) + , m_xAuthKey(m_xBuilder->weld_entry("authkey")) +{ + +} + +OptDeeplTabPage::~OptDeeplTabPage() {} + +void OptDeeplTabPage::Reset(const SfxItemSet*) +{ + SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get(); + m_xAPIUrl->set_text(rDeeplOptions.getAPIUrl()); + m_xAuthKey->set_text(rDeeplOptions.getAuthKey()); +} + +bool OptDeeplTabPage::FillItemSet(SfxItemSet*) +{ + SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get(); + rDeeplOptions.setAPIUrl(m_xAPIUrl->get_text()); + rDeeplOptions.setAuthKey(m_xAuthKey->get_text()); + 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 000000000000..124f9494c4aa --- /dev/null +++ b/cui/source/options/optdeepl.hxx @@ -0,0 +1,37 @@ +/* -*- 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 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/treeopt.cxx b/cui/source/options/treeopt.cxx index e3029ca45eaf..1ab88a7e5381 100644 --- a/cui/source/options/treeopt.cxx +++ b/cui/source/options/treeopt.cxx @@ -64,6 +64,7 @@ #include <treeopt.hxx> #include "optbasic.hxx" #include "optlanguagetool.hxx" +#include "optdeepl.hxx" #include <com/sun/star/awt/XContainerWindowEventHandler.hpp> #include <com/sun/star/awt/ContainerWindowProvider.hpp> @@ -299,6 +300,7 @@ static std::unique_ptr<SfxTabPage> CreateGeneralTabPage(sal_uInt16 nId, weld::Co 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; diff --git a/cui/uiconfig/ui/deepltabpage.ui b/cui/uiconfig/ui/deepltabpage.ui new file mode 100644 index 000000000000..f17ff52a787e --- /dev/null +++ b/cui/uiconfig/ui/deepltabpage.ui @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.2 --> +<interface domain="cui"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkBox" id="OptDeeplPage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</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="halign">start</property> + <property name="xpad">5</property> + <property name="ypad">5</property> + <property name="label" translatable="yes" context="deepltabpage|label1">DeepL API Options</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">grid1</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLinkButton" id="privacy"> + <property name="label" translatable="yes" context="deepltabpage|privacy">Please read the privacy policy</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="halign">start</property> + <property name="relief">none</property> + <property name="uri">https://www.deepl.com/privacy/</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_left">5</property> + <property name="margin_right">5</property> + <property name="margin_top">5</property> + <property name="margin_bottom">5</property> + <property name="row_spacing">6</property> + <property name="column_spacing">5</property> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="margin_left">5</property> + <property name="label" translatable="yes" context="deepltabpage|privacy">API URL:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">apiurl</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="margin_right">5</property> + <property name="label" translatable="yes" context="deepltabpage|label3">Auth Key:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">authkey</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="apiurl"> + <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="GtkEntry" id="authkey"> + <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">1</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> +</interface> diff --git a/include/sfx2/pageids.hxx b/include/sfx2/pageids.hxx index 9371848b784a..1464ec40c55a 100644 --- a/include/sfx2/pageids.hxx +++ b/include/sfx2/pageids.hxx @@ -57,6 +57,7 @@ #define RID_SVXPAGE_COLORCONFIG (RID_SVX_START + 249) #define RID_SVXPAGE_BASICIDE_OPTIONS (RID_SVX_START + 209) #define RID_SVXPAGE_LANGTOOL_OPTIONS (RID_SVX_START + 210) +#define RID_SVXPAGE_DEEPL_OPTIONS (RID_SVX_START + 211) // Resource-Id's ------------------------------------------------------------ diff --git a/include/sfx2/sfxsids.hrc b/include/sfx2/sfxsids.hrc index 39a3ec5bf9d6..1937368ba2b9 100644 --- a/include/sfx2/sfxsids.hrc +++ b/include/sfx2/sfxsids.hrc @@ -208,6 +208,7 @@ class SvxSearchItem; #define SID_VIEW_DATA_SOURCE_BROWSER (SID_SFX_START + 1660) #define SID_UNPACK (SID_SFX_START + 1662) // (SID_SFX_START + 1663) used further down +#define SID_ATTR_TARGETLANG_STR (SID_SFX_START + 1664) // FREE #define SID_OUTPUTSTREAM (SID_SFX_START + 1666) #define SID_IMAGE_ORIENTATION (SID_SFX_START + 1667) diff --git a/include/svtools/deeplcfg.hxx b/include/svtools/deeplcfg.hxx new file mode 100644 index 000000000000..b8e8ca4d7cd4 --- /dev/null +++ b/include/svtools/deeplcfg.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 <unotools/configitem.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <svtools/svtdllapi.h> + +using namespace utl; +using namespace com::sun::star::uno; + +struct DeeplOptions_Impl; + +class SVT_DLLPUBLIC SvxDeeplOptions final : public utl::ConfigItem +{ +public: + SvxDeeplOptions(); + virtual ~SvxDeeplOptions() override; + + virtual void Notify(const css::uno::Sequence<OUString>& _rPropertyNames) override; + static SvxDeeplOptions& Get(); + + const OUString getAPIUrl() const; + void setAPIUrl(const OUString& rVal); + + const OUString& getAuthKey() const; + void setAuthKey(const OUString& rVal); + +private: + std::unique_ptr<DeeplOptions_Impl> pImpl; + void Load(const css::uno::Sequence<OUString>& rPropertyNames); + virtual void ImplCommit() override; + static const Sequence<OUString>& GetPropertyNames(); +}; 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..59c46c8472b4 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...</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/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs b/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs index a3fc5f1296c8..c80db6c6aa09 100644 --- a/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs @@ -444,6 +444,28 @@ </prop> </group> </group> + <group oor:name="Translation"> + <info> + <desc>Contains translation relevant settings.</desc> + </info> + <group oor:name="Deepl"> + <info> + <desc>Contains DeepL API relevant settings.</desc> + </info> + <prop oor:name="ApiURL" oor:type="xs:string"> + <info> + <desc>Deepl Translator API URL</desc> + <label>URL for the Deepl translator api</label> + </info> + </prop> + <prop oor:name="AuthKey" oor:type="xs:string"> + <info> + <desc>Deepl Translator API URL Authkey</desc> + <label>Auth key for the Deepl translator api</label> + </info> + </prop> + </group> + </group> <group oor:name="Hyphenation"> <info> <desc>Contains hyphenation relevant settings.</desc> diff --git a/svtools/Library_svt.mk b/svtools/Library_svt.mk index 94b4f8848ba5..895c34780443 100644 --- a/svtools/Library_svt.mk +++ b/svtools/Library_svt.mk @@ -83,6 +83,7 @@ $(eval $(call gb_Library_add_exception_objects,svt,\ svtools/source/config/fontsubstconfig \ svtools/source/config/htmlcfg \ svtools/source/config/languagetoolcfg \ + svtools/source/config/deeplcfg \ svtools/source/config/itemholder2 \ svtools/source/config/miscopt \ svtools/source/config/slidesorterbaropt \ diff --git a/svtools/source/config/deeplcfg.cxx b/svtools/source/config/deeplcfg.cxx new file mode 100644 index 000000000000..edace497a482 --- /dev/null +++ b/svtools/source/config/deeplcfg.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/. + * + * 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 <sal/config.h> +#include <svtools/deeplcfg.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <tools/debug.hxx> + +using namespace utl; +using namespace com::sun::star::uno; + +struct DeeplOptions_Impl +{ + OUString sAPIUrl; + OUString sAuthKey; +}; + +const Sequence<OUString>& SvxDeeplOptions::GetPropertyNames() +{ + static Sequence<OUString> const aNames{ + "Deepl/ApiURL", + "Deepl/AuthKey", + }; + return aNames; +} + +const OUString SvxDeeplOptions::getAPIUrl() const { return pImpl->sAPIUrl; } + +void SvxDeeplOptions::setAPIUrl(const OUString& rVal) +{ + pImpl->sAPIUrl = rVal; + SetModified(); +} + +const OUString& SvxDeeplOptions::getAuthKey() const { return pImpl->sAuthKey; } + +void SvxDeeplOptions::setAuthKey(const OUString& rVal) +{ + pImpl->sAuthKey = rVal; + SetModified(); +} + +namespace +{ +class theSvxDeeplOptions + : public rtl::Static<SvxDeeplOptions, theSvxDeeplOptions> +{ +}; +} + +SvxDeeplOptions& SvxDeeplOptions::Get() { return theSvxDeeplOptions::get(); } + +SvxDeeplOptions::SvxDeeplOptions() + : ConfigItem("Office.Linguistic/Translation") + , pImpl(new DeeplOptions_Impl) +{ + Load(GetPropertyNames()); +} + +SvxDeeplOptions::~SvxDeeplOptions() {} +void SvxDeeplOptions::Notify(const css::uno::Sequence<OUString>&) +{ + Load(GetPropertyNames()); +} + +void SvxDeeplOptions::Load(const css::uno::Sequence<OUString>& aNames) +{ + Sequence<Any> aValues = GetProperties(aNames); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed"); + if (aValues.getLength() != aNames.getLength()) + return; + for (int nProp = 0; nProp < aNames.getLength(); nProp++) + { + if (!pValues[nProp].hasValue()) + continue; + switch (nProp) + { + case 0: + pValues[nProp] >>= pImpl->sAPIUrl; + break; + case 1: + pValues[nProp] >>= pImpl->sAuthKey; + break; + default: + break; + } + } +} + +void SvxDeeplOptions::ImplCommit() +{ + const Sequence<OUString>& aNames = GetPropertyNames(); + Sequence<Any> aValues(aNames.getLength()); + Any* pValues = aValues.getArray(); + for (int nProp = 0; nProp < aNames.getLength(); nProp++) + { + switch (nProp) + { + case 0: + pValues[nProp] <<= pImpl->sAPIUrl; + break; + case 1: + pValues[nProp] <<= pImpl->sAuthKey; + break; + default: + break; + } + } + PutProperties(aNames, aValues); +} \ No newline at end of file diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi index 9ab00de7e881..ac886aaa0cd4 100644 --- a/svx/sdi/svx.sdi +++ b/svx/sdi/svx.sdi @@ -1596,6 +1596,23 @@ SfxBoolItem NavigationBar SID_FM_NAVIGATIONBAR GroupId = SfxGroupId::Controls; ] +SfxBoolItem Translate SID_FM_TRANSLATE +(SfxStringItem TargetLang SID_ATTR_TARGETLANG_STR) +[ + 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..e221e7dadaaa 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,15 @@ #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> +#include <swwait.hxx> +#include <svtools/deeplcfg.hxx> using namespace ::com::sun::star; using namespace com::sun::star::beans; @@ -1503,6 +1515,169 @@ void SwTextShell::Execute(SfxRequest &rReq) } } break; + case SID_FM_TRANSLATE: + { + // TODO + // collabora online + // move htmltransferable to sw/ + // progressbar + SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get(); + if (rDeeplOptions.getAPIUrl().isEmpty() || rDeeplOptions.getAuthKey().isEmpty()) + { + SAL_WARN("deepl", "API options are not set"); + break; + } + OString aAPIUrl = OUStringToOString(OUString(rDeeplOptions.getAPIUrl() + "?tag_handling=html"), RTL_TEXTENCODING_UTF8).trim(); + OString aAuthKey = OUStringToOString(rDeeplOptions.getAuthKey(), RTL_TEXTENCODING_UTF8).trim(); + SwPaM *pPaM = nullptr; + if (rWrtSh.HasSelection()) + { + pPaM = rWrtSh.GetCursor(); + } + auto replacePara = [&rWrtSh, aAuthKey, aAPIUrl](const OString& res, const OString& targetLang, SwPaM *pCursor, bool isSelection = false) { + // 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, aAPIUrl.getStr()); + 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=" + aAuthKey + "&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 perform 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", "API did not return any 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 ) ) + { + if (isSelection != true) + { + rWrtSh.SetSelection(*pCursor); + } + SwTransferable::Paste(rWrtSh, aDataHelper); + rWrtSh.KillSelection(nullptr, false); + } + } + }; + auto exportAndReplace = [&rWrtSh, replacePara] (const OString& targetLang, SwPaM *pCursor) + { + // freeze everything + SwWait aWait( *rWrtSh.GetView().GetDocShell(), true ); + OString aResult; + auto const& pNodes = rWrtSh.GetNodes(); + WriterRef xWrt; + GetHTMLWriter( OUString("NoLineLimit,SkipHeaderFooter"), OUString(), xWrt ); + SwNode* pNode = nullptr; + if (pCursor != nullptr) + { + SvMemoryStream aMemoryStream; + SwWriter aWriter(aMemoryStream, *pCursor); + ErrCode nError = aWriter.Write(xWrt); + if (nError.IsError()) + { + SAL_WARN("deepl", "failed to export selection to HTML"); + return; + } + aResult = OString(static_cast<const char*>(aMemoryStream.GetData()), aMemoryStream.GetSize()); + replacePara(aResult, targetLang, pCursor, true); + return; + } + 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); + if (nError.IsError()) + { + SAL_WARN("deepl", "failed to export the paragraph to HTML"); + continue; + } + 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, targetLang, cursor.get()); + } + } + }; + + const SfxPoolItem* pTargetLangStringItem = nullptr; + if (pArgs && SfxItemState::SET == pArgs->GetItemState(SID_ATTR_TARGETLANG_STR, false, &pTargetLangStringItem)) + { + OString targetLang = OUStringToOString(static_cast<const SfxStringItem*>(pTargetLangStringItem)->GetValue(), RTL_TEXTENCODING_UTF8); + exportAndReplace(targetLang, pPaM); + } + else + { + 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, [exportAndReplace, pAbstractDialog, pPaM] (sal_Int32 nResult) + { + if (nResult != RET_OK) + { + return; + } + auto languageItem = pAbstractDialog->GetSelectedLanguage(); + if (!languageItem.has_value()) + { + return; + } + const OString targetLang = languageItem->getLanguage(); + exportAndReplace(targetLang, pPaM); + }); + } + + } + 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..fb2a01b0187e --- /dev/null +++ b/sw/uiconfig/swriter/ui/translationdialog.ui @@ -0,0 +1,107 @@ +<?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="resizable">False</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="margin_left">5</property> + <property name="margin_right">5</property> + <property name="margin_top">5</property> + <property name="margin_bottom">25</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="halign">start</property> + <property name="margin_top">5</property> + <property name="margin_bottom">5</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> + <property name="margin_left">5</property> + <property name="margin_right">5</property> + <property name="margin_top">5</property> + <property name="margin_bottom">5</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