diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2024-08-30 23:39:52 +0500 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-09-02 11:13:53 +0200 |
commit | e2bdae48f66d76d08552b6658d940f94f581a475 (patch) | |
tree | fbebc01be7e7fedbee6b5e14ac1360e3bc597eec | |
parent | d013199f5beb79ac047da83429b14d7bde6c3546 (diff) |
tdf#162715: do not import theme when pasting from clipboard
This change makes the two code paths consistent, that are used to paste
native ODF data into the Writer document: that uses own transferable in
usual copy/paste procedure; and that uses "foreign" clipboard data from
another Writer session. The path using own transferable already didn't
set document theme. This change passes the "IsInPaste" flag down to the
XML reader, to let the latter code path skip the theme when reading ODT.
Change-Id: I44d36e4583c58500febd647bb3def6421e585ed6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172688
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 3cf243ac31098de2d275c722a474a36b330df6e1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172681
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
-rw-r--r-- | sw/CppunitTest_sw_core_theme.mk | 1 | ||||
-rw-r--r-- | sw/inc/shellio.hxx | 7 | ||||
-rw-r--r-- | sw/qa/core/theme/ThemeTest.cxx | 189 | ||||
-rw-r--r-- | sw/qa/core/theme/data/theme_bar.odt | bin | 0 -> 9447 bytes | |||
-rw-r--r-- | sw/qa/core/theme/data/theme_foo.fodt | 39 | ||||
-rw-r--r-- | sw/source/filter/basflt/shellio.cxx | 2 | ||||
-rw-r--r-- | sw/source/filter/xml/swxml.cxx | 4 | ||||
-rw-r--r-- | sw/source/uibase/dochdl/swdtflvr.cxx | 1 | ||||
-rw-r--r-- | xmloff/source/style/xmlstyle.cxx | 23 |
9 files changed, 266 insertions, 0 deletions
diff --git a/sw/CppunitTest_sw_core_theme.mk b/sw/CppunitTest_sw_core_theme.mk index 03b42a32e666..5938916bd9df 100644 --- a/sw/CppunitTest_sw_core_theme.mk +++ b/sw/CppunitTest_sw_core_theme.mk @@ -24,6 +24,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_core_theme, \ docmodel \ sal \ sfx \ + sot \ subsequenttest \ sw \ swqahelper \ diff --git a/sw/inc/shellio.hxx b/sw/inc/shellio.hxx index 370f6f6daa68..1465db93be80 100644 --- a/sw/inc/shellio.hxx +++ b/sw/inc/shellio.hxx @@ -155,6 +155,7 @@ class SW_DLLPUBLIC SwReader: public SwDocFac OUString msBaseURL; bool mbSkipImages; bool mbSkipInvalidateNumRules = false; + bool mbIsInPaste = false; public: @@ -180,6 +181,8 @@ public: { mbSkipInvalidateNumRules = bSkipInvalidateNumRules; } + void SetInPaste(bool val) { mbIsInPaste = val; } + bool IsInPaste() const { return mbIsInPaste; } protected: void SetBaseURL( const OUString& rURL ) { msBaseURL = rURL; } @@ -232,6 +235,7 @@ protected: bool m_bHasAskTemplateName : 1; bool m_bIgnoreHTMLComments : 1; bool m_bSkipImages : 1; + bool m_bIsInPaste : 1 = false; virtual OUString GetTemplateName(SwDoc& rDoc) const; @@ -269,6 +273,9 @@ public: void SetIgnoreHTMLComments( bool bSet ) { m_bIgnoreHTMLComments = bSet; } + bool IsInPaste() const { return m_bIsInPaste; } + void SetInPaste(bool bSet) { m_bIsInPaste = bSet; } + virtual bool HasGlossaries() const; virtual bool ReadGlossaries( SwTextBlocks&, bool bSaveRelFiles ) const; diff --git a/sw/qa/core/theme/ThemeTest.cxx b/sw/qa/core/theme/ThemeTest.cxx index ce2be76edc65..9f33bafe33c1 100644 --- a/sw/qa/core/theme/ThemeTest.cxx +++ b/sw/qa/core/theme/ThemeTest.cxx @@ -9,17 +9,25 @@ #include <swmodeltestbase.hxx> +#include <com/sun/star/datatransfer/XTransferableSupplier.hpp> +#include <com/sun/star/ucb/SimpleFileAccess.hpp> + #include <memory> #include <docsh.hxx> #include <unotxdoc.hxx> #include <wrtsh.hxx> #include <drawdoc.hxx> #include <IDocumentDrawModelAccess.hxx> + +#include <comphelper/classids.hxx> +#include <comphelper/processfactory.hxx> #include <svx/svdpage.hxx> #include <docmodel/uno/UnoComplexColor.hxx> #include <docmodel/theme/Theme.hxx> #include <ThemeColorChanger.hxx> +#include <sot/exchange.hxx> #include <svx/ColorSets.hxx> +#include <vcl/transfer.hxx> using namespace css; @@ -479,6 +487,187 @@ CPPUNIT_TEST_FIXTURE(SwCoreThemeTest, testThemeChanging) } } +// A simple transferable, that provides only EMBED_SOURCE and OBJECTDESCRIPTOR flavors, taking +// data from an ODT file. This makes the transferable behave just like clipboard content created +// by Writer in a different instance, taking SwTransferable::PasteOLE path. +class TestSimpleFileTransferable : public cppu::WeakImplHelper<css::datatransfer::XTransferable> +{ +public: + TestSimpleFileTransferable(const OUString& fileURL); + css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& flavor) override; + css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override; + sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& flavor) override; + +private: + OUString m_fileURL; +}; + +TestSimpleFileTransferable::TestSimpleFileTransferable(const OUString& fileURL) + : m_fileURL(fileURL) +{ +} + +css::uno::Any +TestSimpleFileTransferable::getTransferData(const css::datatransfer::DataFlavor& flavor) +{ + if (flavor.MimeType == SotExchange::GetFormatMimeType(SotClipboardFormatId::EMBED_SOURCE)) + { + auto xSFA(ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext())); + auto xInputStream = xSFA->openFileRead(m_fileURL); + sal_Int32 bytes = xInputStream->available(); + css::uno::Sequence<sal_Int8> data; + CPPUNIT_ASSERT_EQUAL(bytes, xInputStream->readBytes(data, bytes)); + return css::uno::Any(data); + } + if (flavor.MimeType == SotExchange::GetFormatMimeType(SotClipboardFormatId::OBJECTDESCRIPTOR)) + { + TransferableObjectDescriptor aDesc; + aDesc.maClassName = SvGlobalName(SO3_SW_CLASSID); + SvMemoryStream aMemStm(1024, 1024); + WriteTransferableObjectDescriptor(aMemStm, aDesc); + css::uno::Sequence<sal_Int8> data(static_cast<const sal_Int8*>(aMemStm.GetData()), + aMemStm.GetSize()); + return css::uno::Any(data); + } + return {}; +} + +css::uno::Sequence<css::datatransfer::DataFlavor> +TestSimpleFileTransferable::getTransferDataFlavors() +{ + css::datatransfer::DataFlavor embed_source; + SotExchange::GetFormatDataFlavor(SotClipboardFormatId::EMBED_SOURCE, embed_source); + css::datatransfer::DataFlavor objectdescriptor; + SotExchange::GetFormatDataFlavor(SotClipboardFormatId::OBJECTDESCRIPTOR, objectdescriptor); + return { embed_source, objectdescriptor }; +} + +sal_Bool +TestSimpleFileTransferable::isDataFlavorSupported(const css::datatransfer::DataFlavor& flavor) +{ + if (flavor.MimeType == SotExchange::GetFormatMimeType(SotClipboardFormatId::EMBED_SOURCE)) + return true; + if (flavor.MimeType == SotExchange::GetFormatMimeType(SotClipboardFormatId::OBJECTDESCRIPTOR)) + return true; + return false; +} + +CPPUNIT_TEST_FIXTURE(SwCoreThemeTest, testTdf162715_customTransferable) +{ + // Given a document with a custom theme: + createSwDoc("theme_foo.fodt"); + + auto pDoc = getSwDoc(); + CPPUNIT_ASSERT(pDoc); + + auto pModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel(); + CPPUNIT_ASSERT(pModel); + auto pTheme = pModel->getTheme().get(); + CPPUNIT_ASSERT(pTheme); + CPPUNIT_ASSERT_EQUAL(u"foo"_ustr, pTheme->GetName()); + CPPUNIT_ASSERT_EQUAL(u"colors_foo"_ustr, pTheme->getColorSet()->getName()); + CPPUNIT_ASSERT_EQUAL(Color(0x000080), pTheme->GetColor(model::ThemeColorType::Dark1)); + CPPUNIT_ASSERT_EQUAL(Color(0x008000), pTheme->GetColor(model::ThemeColorType::Dark2)); + + // Select all and check the original text in the document: + auto pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->SelAll(); + CPPUNIT_ASSERT_EQUAL(u"Theme foo"_ustr, pWrtShell->GetSelText()); + + // Create a transferable from another document with another custom theme, + // and insert (paste) its content over the selection: + css::uno::Reference<css::datatransfer::XTransferable> xTransferable( + new TestSimpleFileTransferable(createFileURL(u"theme_bar.odt"))); + css::uno::Reference<css::frame::XModel> xModel(mxComponent, css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::datatransfer::XTransferableSupplier> xTS( + xModel->getCurrentController(), css::uno::UNO_QUERY_THROW); + xTS->insertTransferable(xTransferable); + + // Check that the paste is successful (the text has been replaced): + pWrtShell->SelAll(); + CPPUNIT_ASSERT_EQUAL(u"Theme bar"_ustr, pWrtShell->GetSelText()); + + // The original theme must not be replaced. + pTheme = pModel->getTheme().get(); + CPPUNIT_ASSERT(pTheme); + // Without the fix, this would fail, because the name was "bar": + CPPUNIT_ASSERT_EQUAL(u"foo"_ustr, pTheme->GetName()); + CPPUNIT_ASSERT_EQUAL(u"colors_foo"_ustr, pTheme->getColorSet()->getName()); + CPPUNIT_ASSERT_EQUAL(Color(0x000080), pTheme->GetColor(model::ThemeColorType::Dark1)); + CPPUNIT_ASSERT_EQUAL(Color(0x008000), pTheme->GetColor(model::ThemeColorType::Dark2)); +} + +CPPUNIT_TEST_FIXTURE(SwCoreThemeTest, testTdf162715_ownTransferable) +{ + css::uno::Reference<css::datatransfer::XTransferable> xTransferable; + { + // Given a document with a custom theme: + createSwDoc("theme_bar.odt"); + + auto pDoc = getSwDoc(); + CPPUNIT_ASSERT(pDoc); + + auto pModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel(); + CPPUNIT_ASSERT(pModel); + auto pTheme = pModel->getTheme().get(); + CPPUNIT_ASSERT(pTheme); + CPPUNIT_ASSERT_EQUAL(u"bar"_ustr, pTheme->GetName()); + CPPUNIT_ASSERT_EQUAL(u"colors_bar"_ustr, pTheme->getColorSet()->getName()); + CPPUNIT_ASSERT_EQUAL(Color(0x606000), pTheme->GetColor(model::ThemeColorType::Dark1)); + CPPUNIT_ASSERT_EQUAL(Color(0x800000), pTheme->GetColor(model::ThemeColorType::Dark2)); + + // Select all and check the original text in the document: + auto pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->SelAll(); + CPPUNIT_ASSERT_EQUAL(u"Theme bar"_ustr, pWrtShell->GetSelText()); + + // Create a normal Writer's transferable out of the selection: + css::uno::Reference<css::frame::XModel> xModel(mxComponent, css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::datatransfer::XTransferableSupplier> xTS( + xModel->getCurrentController(), css::uno::UNO_QUERY_THROW); + xTransferable = xTS->getTransferable(); + } + { + // Open another document with another custom theme: + createSwDoc("theme_foo.fodt"); + + auto pDoc = getSwDoc(); + CPPUNIT_ASSERT(pDoc); + + auto pModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel(); + CPPUNIT_ASSERT(pModel); + auto pTheme = pModel->getTheme().get(); + CPPUNIT_ASSERT(pTheme); + CPPUNIT_ASSERT_EQUAL(u"foo"_ustr, pTheme->GetName()); + CPPUNIT_ASSERT_EQUAL(u"colors_foo"_ustr, pTheme->getColorSet()->getName()); + CPPUNIT_ASSERT_EQUAL(Color(0x000080), pTheme->GetColor(model::ThemeColorType::Dark1)); + CPPUNIT_ASSERT_EQUAL(Color(0x008000), pTheme->GetColor(model::ThemeColorType::Dark2)); + + // Select all and check the original text in the second document: + auto pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->SelAll(); + CPPUNIT_ASSERT_EQUAL(u"Theme foo"_ustr, pWrtShell->GetSelText()); + + // Insert (paste) the previously created transferable's content over the selection: + css::uno::Reference<css::frame::XModel> xModel(mxComponent, css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::datatransfer::XTransferableSupplier> xTS( + xModel->getCurrentController(), css::uno::UNO_QUERY_THROW); + xTS->insertTransferable(xTransferable); + + // Check that the paste is successful (the text has been replaced): + pWrtShell->SelAll(); + CPPUNIT_ASSERT_EQUAL(u"Theme bar"_ustr, pWrtShell->GetSelText()); + + // The original theme must not be replaced. + pTheme = pModel->getTheme().get(); + CPPUNIT_ASSERT(pTheme); + CPPUNIT_ASSERT_EQUAL(u"foo"_ustr, pTheme->GetName()); + CPPUNIT_ASSERT_EQUAL(u"colors_foo"_ustr, pTheme->getColorSet()->getName()); + CPPUNIT_ASSERT_EQUAL(Color(0x000080), pTheme->GetColor(model::ThemeColorType::Dark1)); + CPPUNIT_ASSERT_EQUAL(Color(0x008000), pTheme->GetColor(model::ThemeColorType::Dark2)); + } +} + } // end anonymous namnespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/qa/core/theme/data/theme_bar.odt b/sw/qa/core/theme/data/theme_bar.odt Binary files differnew file mode 100644 index 000000000000..30892fcd03aa --- /dev/null +++ b/sw/qa/core/theme/data/theme_bar.odt diff --git a/sw/qa/core/theme/data/theme_foo.fodt b/sw/qa/core/theme/data/theme_foo.fodt new file mode 100644 index 000000000000..29837a34d54c --- /dev/null +++ b/sw/qa/core/theme/data/theme_foo.fodt @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <loext:theme loext:name="foo"> + <loext:theme-colors loext:name="colors_foo"> + <loext:color loext:name="dark1" loext:color="#000080"/> + <loext:color loext:name="light1" loext:color="#ffffff"/> + <loext:color loext:name="dark2" loext:color="#008000"/> + <loext:color loext:name="light2" loext:color="#ffffff"/> + <loext:color loext:name="accent1" loext:color="#18a303"/> + <loext:color loext:name="accent2" loext:color="#0369a3"/> + <loext:color loext:name="accent3" loext:color="#a33e03"/> + <loext:color loext:name="accent4" loext:color="#8e03a3"/> + <loext:color loext:name="accent5" loext:color="#c99c00"/> + <loext:color loext:name="accent6" loext:color="#c9211e"/> + <loext:color loext:name="hyperlink" loext:color="#0000ee"/> + <loext:color loext:name="followed-hyperlink" loext:color="#551a8b"/> + </loext:theme-colors> + </loext:theme> + </office:styles> + <office:automatic-styles> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:color="#000080"> + <loext:char-complex-color loext:theme-type="dark1" loext:color-type="theme"/> + </style:text-properties> + </style:style> + <style:style style:name="T2" style:family="text"> + <style:text-properties fo:color="#008000"> + <loext:char-complex-color loext:theme-type="dark2" loext:color-type="theme"/> + </style:text-properties> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p><text:span text:style-name="T1">Theme</text:span> <text:span text:style-name="T2">foo</text:span></text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/source/filter/basflt/shellio.cxx b/sw/source/filter/basflt/shellio.cxx index 875d67d4321a..26fc61ab6b69 100644 --- a/sw/source/filter/basflt/shellio.cxx +++ b/sw/source/filter/basflt/shellio.cxx @@ -96,6 +96,7 @@ ErrCodeMsg SwReader::Read( const Reader& rOptions ) po->m_xStorage = mxStg; po->m_bInsertMode = nullptr != mpCursor; po->m_bSkipImages = mbSkipImages; + po->SetInPaste(IsInPaste()); // if a Medium is selected, get its Stream if( nullptr != (po->m_pMedium = mpMedium ) && @@ -394,6 +395,7 @@ ErrCodeMsg SwReader::Read( const Reader& rOptions ) po->SetBlockMode( false ); po->SetOrganizerMode( false ); po->SetIgnoreHTMLComments( false ); + po->SetInPaste(false); return nError; } diff --git a/sw/source/filter/xml/swxml.cxx b/sw/source/filter/xml/swxml.cxx index 36b8c91eac94..47a423ea340e 100644 --- a/sw/source/filter/xml/swxml.cxx +++ b/sw/source/filter/xml/swxml.cxx @@ -591,6 +591,8 @@ ErrCodeMsg XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, beans::PropertyAttribute::MAYBEVOID, 0 }, { u"SourceStorage"_ustr, 0, cppu::UnoType<embed::XStorage>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 }, + { u"IsInPaste"_ustr, 0, cppu::UnoType<bool>::get(), + beans::PropertyAttribute::MAYBEVOID, 0 }, }; uno::Reference< beans::XPropertySet > xInfoSet( comphelper::GenericPropertySet_CreateInstance( @@ -640,6 +642,8 @@ ErrCodeMsg XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, xInfoSet->setPropertyValue( u"SourceStorage"_ustr, Any( xStorage ) ); + xInfoSet->setPropertyValue(u"IsInPaste"_ustr, Any(IsInPaste())); + // prepare filter arguments, WARNING: the order is important! Sequence<Any> aFilterArgs{ Any(xInfoSet), Any(xStatusIndicator), diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx index b5cd76930891..0ec3b35e86b9 100644 --- a/sw/source/uibase/dochdl/swdtflvr.cxx +++ b/sw/source/uibase/dochdl/swdtflvr.cxx @@ -2358,6 +2358,7 @@ bool SwTransferable::PasteOLE( const TransferableDataHelper& rData, SwWrtShell& { SwPaM &rPAM = *rSh.GetCursor(); SwReader aReader(xStore, OUString(), rPAM); + aReader.SetInPaste(true); if( ! aReader.Read( *pRead ).IsError() ) bRet = true; else if( bMsg ) diff --git a/xmloff/source/style/xmlstyle.cxx b/xmloff/source/style/xmlstyle.cxx index efc4da3e6842..e09ef37bfa12 100644 --- a/xmloff/source/style/xmlstyle.cxx +++ b/xmloff/source/style/xmlstyle.cxx @@ -21,6 +21,7 @@ #include <sal/config.h> +#include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/frame/XModel.hpp> #include <com/sun/star/container/XNameContainer.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> @@ -28,6 +29,8 @@ #include <com/sun/star/style/XAutoStyleFamily.hpp> #include <com/sun/star/drawing/XDrawPageSupplier.hpp> #include <PageMasterPropMapper.hxx> + +#include <comphelper/diagnose_ex.hxx> #include <sal/log.hxx> #include <svl/style.hxx> #include <utility> @@ -683,6 +686,26 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLStylesContext::cr { if (nElement == XML_ELEMENT(LO_EXT, XML_THEME)) { + if (auto xImportInfo = GetImport().getImportInfo()) + { + try + { + if (auto xPropertySetInfo = xImportInfo->getPropertySetInfo()) + { + if (xPropertySetInfo->hasPropertyByName(u"IsInPaste"_ustr)) + { + css::uno::Any value = xImportInfo->getPropertyValue(u"IsInPaste"_ustr); + if (bool b; (value >>= b) && b) + return nullptr; // do not import themes in paste mode + } + } + } + catch (const css::uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff"); + } + } + uno::Reference<uno::XInterface> xObject(GetImport().GetModel(), uno::UNO_QUERY); uno::Reference<drawing::XDrawPageSupplier> const xDrawPageSupplier(GetImport().GetModel(), uno::UNO_QUERY); if (xDrawPageSupplier.is()) |