sc/CppunitTest_sc_macros_test.mk | 3 sc/qa/extras/macros-test.cxx | 76 +++++++++++++- sc/qa/extras/testdocuments/macro-button-form-control.xlsm |binary sc/source/filter/excel/xeescher.cxx | 32 ++++- sc/source/filter/inc/xeescher.hxx | 2 5 files changed, 102 insertions(+), 11 deletions(-)
New commits: commit 9ef217144d6452fead389ec031eb6f78ba5067e7 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Jul 6 14:31:07 2021 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Jul 9 11:26:45 2021 +0200 XLSX export: handle macros on button form controls This builds on top of commit 1e3263a677b61c718d0fd1be15c066b933f7de18 (XLSX export: handle button form controls, 2021-07-01). The binary XLS export already had code to turn Calc macro names into Excel ones, reuse that for XLSX purposes. Also fix the unwanted named range on export, oox::xls::FormulaParser::importMacroName() mentions how XLSX doesn't have matching named ranges for vba macros (while XLS has), mirror this on the export side as well. (cherry picked from commit 7e7a871bcd4f923b015a7e040969335696b434c6) Conflicts: sc/source/filter/excel/xeescher.cxx Change-Id: I877b6ba2c2e834a2327482da5cadcddf1b4672bb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118563 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/CppunitTest_sc_macros_test.mk b/sc/CppunitTest_sc_macros_test.mk index e0852b653598..b4f62624e693 100644 --- a/sc/CppunitTest_sc_macros_test.mk +++ b/sc/CppunitTest_sc_macros_test.mk @@ -12,6 +12,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,sc_macros_test)) $(eval $(call gb_CppunitTest_use_externals,sc_macros_test, \ boost_headers \ mdds_headers \ + libxml2 \ )) $(eval $(call gb_CppunitTest_use_common_precompiled_header,sc_macros_test)) @@ -37,6 +38,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_macros_test, \ sax \ sb \ sc \ + scqahelper \ sfx \ sot \ subsequenttest \ @@ -58,6 +60,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_macros_test, \ $(eval $(call gb_CppunitTest_set_include,sc_macros_test,\ -I$(SRCDIR)/sc/source/ui/inc \ -I$(SRCDIR)/sc/inc \ + -I$(SRCDIR)/sc/qa/unit \ $$(INCLUDE) \ )) diff --git a/sc/qa/extras/macros-test.cxx b/sc/qa/extras/macros-test.cxx index 9322a3eab7cd..adc451127108 100644 --- a/sc/qa/extras/macros-test.cxx +++ b/sc/qa/extras/macros-test.cxx @@ -14,6 +14,7 @@ #include <unotools/tempfile.hxx> #include <vcl/svapp.hxx> #include <editeng/borderline.hxx> +#include <unotools/mediadescriptor.hxx> #include <docsh.hxx> #include <document.hxx> @@ -25,13 +26,17 @@ #include <com/sun/star/script/XLibraryContainerPassword.hpp> #include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <helper/xpath.hxx> + using namespace ::com::sun::star; using namespace ::com::sun::star::uno; /* Implementation of Macros test */ -class ScMacrosTest : public UnoApiTest +class ScMacrosTest : public UnoApiTest, public XmlTestTools { +protected: + void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override; public: ScMacrosTest(); void saveAndReload(css::uno::Reference<css::lang::XComponent>& xComponent, @@ -55,6 +60,7 @@ public: void testTdf43003(); void testTdf138646(); void testTdf90278(); + void testMacroButtonFormControlXlsxExport(); CPPUNIT_TEST_SUITE(ScMacrosTest); CPPUNIT_TEST(testStarBasic); @@ -75,10 +81,47 @@ public: CPPUNIT_TEST(testTdf43003); CPPUNIT_TEST(testTdf138646); CPPUNIT_TEST(testTdf90278); + CPPUNIT_TEST(testMacroButtonFormControlXlsxExport); CPPUNIT_TEST_SUITE_END(); }; +void ScMacrosTest::registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) +{ + static const struct { xmlChar* pPrefix; xmlChar* pURI; } aNamespaces[] = + { + { BAD_CAST("w"), BAD_CAST("http://schemas.openxmlformats.org/wordprocessingml/2006/main") }, + { BAD_CAST("x"), BAD_CAST("http://schemas.openxmlformats.org/spreadsheetml/2006/main") }, + { BAD_CAST("v"), BAD_CAST("urn:schemas-microsoft-com:vml") }, + { BAD_CAST("c"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/chart") }, + { BAD_CAST("a"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/main") }, + { BAD_CAST("mc"), BAD_CAST("http://schemas.openxmlformats.org/markup-compatibility/2006") }, + { BAD_CAST("wps"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingShape") }, + { BAD_CAST("wpg"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingGroup") }, + { BAD_CAST("wp"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing") }, + { BAD_CAST("office"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:office:1.0") }, + { BAD_CAST("table"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:table:1.0") }, + { BAD_CAST("text"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:text:1.0") }, + { BAD_CAST("style"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:style:1.0") }, + { BAD_CAST("draw"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0") }, + { BAD_CAST("xlink"), BAD_CAST("http://www.w3c.org/1999/xlink") }, + { BAD_CAST("xdr"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing") }, + { BAD_CAST("xx"), BAD_CAST("urn:schemas-microsoft-com:office:excel") }, + { BAD_CAST("r"), BAD_CAST("http://schemas.openxmlformats.org/package/2006/relationships") }, + { BAD_CAST("number"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0") }, + { BAD_CAST("loext"), BAD_CAST("urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0") }, + { BAD_CAST("tableooo"), BAD_CAST("http://openoffice.org/2009/table") }, + { BAD_CAST("ContentType"), BAD_CAST("http://schemas.openxmlformats.org/package/2006/content-types") }, + { BAD_CAST("x14"), BAD_CAST("http://schemas.microsoft.com/office/spreadsheetml/2009/9/main") }, + { BAD_CAST("xm"), BAD_CAST("http://schemas.microsoft.com/office/excel/2006/main") }, + { BAD_CAST("x12ac"), BAD_CAST("http://schemas.microsoft.com/office/spreadsheetml/2011/1/ac") }, + }; + for(size_t i = 0; i < SAL_N_ELEMENTS(aNamespaces); ++i) + { + xmlXPathRegisterNs(pXmlXPathCtx, aNamespaces[i].pPrefix, aNamespaces[i].pURI ); + } +} + void ScMacrosTest::saveAndReload(css::uno::Reference<css::lang::XComponent>& xComponent, const OUString& rFilter) { @@ -473,6 +516,37 @@ void ScMacrosTest::testRowColumn() pDocSh->DoClose(); } +void ScMacrosTest::testMacroButtonFormControlXlsxExport() +{ + // Given a button form control with an associated macro: + OUString aFileName; + createFileURL(u"macro-button-form-control.xlsm", aFileName); + uno::Reference<lang::XComponent> xComponent = loadFromDesktop(aFileName, "com.sun.star.sheet.SpreadsheetDocument"); + + // When exporting to XLSM: + uno::Reference<frame::XStorable> xStorable(xComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("Calc MS Excel 2007 VBA XML"); + auto pTempFile = std::make_shared<utl::TempFile>(); + pTempFile->EnableKillingFile(); + xStorable->storeToURL(pTempFile->GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + xComponent->dispose(); + + // Then make sure that the macro is associated with the control: + xmlDocUniquePtr pSheetDoc = XPathHelper::parseExport(pTempFile, m_xSFactory, "xl/worksheets/sheet1.xml"); + CPPUNIT_ASSERT(pSheetDoc); + // Without the fix in place, this test would have failed with: + // - XPath '//x:controlPr' no attribute 'macro' exist + // i.e. the macro was lost on export. + assertXPath(pSheetDoc, "//x:controlPr", "macro", "Module1.Button1_Click"); + + // Then also make sure that there is no defined name for the macro, which is only needed for + // XLS: + xmlDocUniquePtr pWorkbookDoc = XPathHelper::parseExport(pTempFile, m_xSFactory, "xl/workbook.xml"); + CPPUNIT_ASSERT(pWorkbookDoc); + assertXPath(pWorkbookDoc, "//x:workbook/definedNames", 0); +} + void ScMacrosTest::testTdf131562() { OUString aFileName; diff --git a/sc/qa/extras/testdocuments/macro-button-form-control.xlsm b/sc/qa/extras/testdocuments/macro-button-form-control.xlsm new file mode 100644 index 000000000000..e4e76b13ff5a Binary files /dev/null and b/sc/qa/extras/testdocuments/macro-button-form-control.xlsm differ diff --git a/sc/source/filter/excel/xeescher.cxx b/sc/source/filter/excel/xeescher.cxx index 67b1e7807322..dc137c5e3481 100644 --- a/sc/source/filter/excel/xeescher.cxx +++ b/sc/source/filter/excel/xeescher.cxx @@ -1104,11 +1104,12 @@ class VmlFormControlExporter : public oox::vml::VMLExport tools::Rectangle m_aAreaFrom; tools::Rectangle m_aAreaTo; OUString m_aLabel; + OUString m_aMacroName; public: VmlFormControlExporter(const sax_fastparser::FSHelperPtr& p, sal_uInt16 nObjType, const tools::Rectangle& rAreaFrom, const tools::Rectangle& rAreaTo, - const OUString& rLabel); + const OUString& rLabel, const OUString& rMacroName); protected: using VMLExport::StartShape; @@ -1121,12 +1122,13 @@ VmlFormControlExporter::VmlFormControlExporter(const sax_fastparser::FSHelperPtr sal_uInt16 nObjType, const tools::Rectangle& rAreaFrom, const tools::Rectangle& rAreaTo, - const OUString& rLabel) + const OUString& rLabel, const OUString& rMacroName) : VMLExport(p) , m_nObjType(nObjType) , m_aAreaFrom(rAreaFrom) , m_aAreaTo(rAreaTo) , m_aLabel(rLabel) + , m_aMacroName(rMacroName) { } @@ -1168,6 +1170,11 @@ void VmlFormControlExporter::EndShape(sal_Int32 nShapeElement) aAnchor += ", " + OString::number(m_aAreaTo.Bottom()); XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_Anchor), aAnchor); + if (!m_aMacroName.isEmpty()) + { + XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_FmlaMacro), m_aMacroName); + } + // XclExpOcxControlObj::WriteSubRecs() has the same fixed values. if (m_nObjType == EXC_OBJTYPE_BUTTON) { @@ -1190,7 +1197,7 @@ void XclExpTbxControlObj::SaveVml(XclExpXmlStream& rStrm) // Unlike XclExpTbxControlObj::SaveXml(), this is not calculated in EMUs. lcl_GetFromTo(mrRoot, pObj->GetLogicRect(), GetTab(), aAreaFrom, aAreaTo); VmlFormControlExporter aFormControlExporter(rStrm.GetCurrentStream(), GetObjType(), aAreaFrom, - aAreaTo, msLabel); + aAreaTo, msLabel, GetMacroName()); aFormControlExporter.AddSdrObject(*pObj, /*eHOri=*/-1, /*eVOri=*/-1, /*eHRel=*/-1, /*eVRel=*/-1, /*pWrapAttrList=*/nullptr, /*bOOxmlExport=*/true); @@ -1481,11 +1488,11 @@ void XclExpTbxControlObj::SaveSheetXml(XclExpXmlStream& rStrm, const OUString& a rWorksheet->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "x14"); rWorksheet->startElement(XML_control, XML_shapeId, OString::number(mnShapeId).getStr(), - FSNS(XML_r, XML_id), aIdFormControlPr, XML_name, msLabel); + FSNS(XML_r, XML_id), aIdFormControlPr, XML_name, msCtrlName); rWorksheet->startElement(XML_controlPr, XML_defaultSize, "0", XML_print, mbPrint ? "true" : "false", XML_autoFill, "0", XML_autoPict, - "0"); + "0", XML_macro, GetMacroName()); rWorksheet->startElement(XML_anchor, XML_moveWithCells, "true", XML_sizeWithCells, "false"); @@ -1809,13 +1816,15 @@ void XclMacroHelper::WriteMacroSubRec( XclExpStream& rStrm ) WriteFormulaSubRec( rStrm, EXC_ID_OBJMACRO, *mxMacroLink ); } +OUString XclMacroHelper::GetMacroName() const { return maMacroName; } + bool XclMacroHelper::SetMacroLink( const ScriptEventDescriptor& rEvent, const XclTbxEventType& nEventType ) { - OUString aMacroName = XclControlHelper::ExtractFromMacroDescriptor( rEvent, nEventType ); - if( !aMacroName.isEmpty() ) + maMacroName = XclControlHelper::ExtractFromMacroDescriptor(rEvent, nEventType); + if (!maMacroName.isEmpty()) { - return SetMacroLink( aMacroName ); + return SetMacroLink(maMacroName); } return false; } @@ -1823,10 +1832,13 @@ XclMacroHelper::SetMacroLink( const ScriptEventDescriptor& rEvent, const XclTbxE bool XclMacroHelper::SetMacroLink( const OUString& rMacroName ) { - if( !rMacroName.isEmpty() ) + // OOXML documents do not store any defined name for VBA macros (while BIFF documents do). + bool bOOXML = GetOutput() == EXC_OUTPUT_XML_2007; + if (!rMacroName.isEmpty() && !bOOXML) { sal_uInt16 nExtSheet = GetLocalLinkManager().FindExtSheet( EXC_EXTSH_OWNDOC ); - sal_uInt16 nNameIdx = GetNameManager().InsertMacroCall( rMacroName, true, false ); + sal_uInt16 nNameIdx + = GetNameManager().InsertMacroCall(rMacroName, /*bVBasic=*/true, /*bFunc=*/false); mxMacroLink = GetFormulaCompiler().CreateNameXFormula( nExtSheet, nNameIdx ); return true; } diff --git a/sc/source/filter/inc/xeescher.hxx b/sc/source/filter/inc/xeescher.hxx index b37117521093..da0c929a9714 100644 --- a/sc/source/filter/inc/xeescher.hxx +++ b/sc/source/filter/inc/xeescher.hxx @@ -195,6 +195,7 @@ protected: class XclMacroHelper : public XclExpControlHelper { XclTokenArrayRef mxMacroLink; /// Token array containing a link to an attached macro. + OUString maMacroName; public: explicit XclMacroHelper( const XclExpRoot& rRoot ); @@ -208,6 +209,7 @@ public: /** Sets the name of a macro @return true = The passed macro name has been found. */ bool SetMacroLink( const OUString& rMacro ); + OUString GetMacroName() const; }; class XclExpShapeObj : public XclObjAny, public XclMacroHelper _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits