tdf#99438: sc: support for .xltx export

Added support for content types for template and template
with macros (.xltm, but no user interface for this yet).

Fixed preferred extension for template: by default it is .xltx
and not .xltm (macro-enabled), because MS Excel is very strict
about matching of content-type and extension here.

Fixed wrong namespace in FilterService for ExcelFilter.

Change-Id: Ie717d31d72203601324860f069918d75082add4a
Reviewed-on: https://gerrit.libreoffice.org/65111
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
diff --git a/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML_Template.xcu b/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML_Template.xcu
index f42c60d..db5cb9a 100644
--- a/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML_Template.xcu
+++ b/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML_Template.xcu
@@ -16,7 +16,7 @@
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
-->
<node oor:name="Calc MS Excel 2007 XML Template" oor:op="replace">
    <prop oor:name="Flags"><value>IMPORT ALIEN 3RDPARTYFILTER TEMPLATE TEMPLATEPATH</value></prop>
    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER TEMPLATE TEMPLATEPATH</value></prop>
    <prop oor:name="UIComponent"/>
    <prop oor:name="FilterService"><value>com.sun.star.comp.oox.xls.ExcelFilter</value></prop>
    <prop oor:name="UserData"/>
diff --git a/filter/source/config/fragments/filters/calc_OOXML_Template.xcu b/filter/source/config/fragments/filters/calc_OOXML_Template.xcu
index 848e7ee..b65a756 100644
--- a/filter/source/config/fragments/filters/calc_OOXML_Template.xcu
+++ b/filter/source/config/fragments/filters/calc_OOXML_Template.xcu
@@ -18,7 +18,7 @@
<node oor:name="Calc Office Open XML Template" oor:op="replace">
    <prop oor:name="Flags"><value>IMPORT ALIEN 3RDPARTYFILTER TEMPLATE TEMPLATEPATH</value></prop>
    <prop oor:name="UIComponent"/>
    <prop oor:name="FilterService"><value>com.sun.star.comp.oox.ExcelFilter</value></prop>
    <prop oor:name="FilterService"><value>com.sun.star.comp.oox.xls.ExcelFilter</value></prop>
    <prop oor:name="UserData"><value>OOXML</value></prop>
    <prop oor:name="FileFormatVersion"><value>1</value></prop>
    <prop oor:name="Type"><value>Office Open XML Spreadsheet Template</value></prop>
diff --git a/filter/source/config/fragments/types/MS_Excel_2007_XML_Template.xcu b/filter/source/config/fragments/types/MS_Excel_2007_XML_Template.xcu
index c55f639..35c18e4 100644
--- a/filter/source/config/fragments/types/MS_Excel_2007_XML_Template.xcu
+++ b/filter/source/config/fragments/types/MS_Excel_2007_XML_Template.xcu
@@ -18,7 +18,7 @@
<node oor:name="MS Excel 2007 XML Template" oor:op="replace" >
    <prop oor:name="DetectService"><value>com.sun.star.comp.oox.FormatDetector</value></prop>
    <prop oor:name="URLPattern"/>
    <prop oor:name="Extensions"><value>xltm xltx</value></prop>
    <prop oor:name="Extensions"><value>xltx xltm</value></prop>
    <prop oor:name="MediaType"><value>application/vnd.openxmlformats-officedocument.spreadsheetml.template</value></prop>
    <prop oor:name="Preferred"><value>false</value></prop>
    <prop oor:name="PreferredFilter"><value>Calc MS Excel 2007 XML Template</value></prop>
diff --git a/sc/qa/unit/helper/qahelper.cxx b/sc/qa/unit/helper/qahelper.cxx
index e3b2db0..81c4431 100644
--- a/sc/qa/unit/helper/qahelper.cxx
+++ b/sc/qa/unit/helper/qahelper.cxx
@@ -87,7 +87,8 @@
    { "xml", "MS Excel 2003 XML Orcus", "calc_MS_Excel_2003_XML", XLS_XML_FORMAT_TYPE },
    { "xlsb", "Calc MS Excel 2007 Binary", "MS Excel 2007 Binary", XLSB_XML_FORMAT_TYPE },
    { "fods", "OpenDocument Spreadsheet Flat XML", "calc_ODS_FlatXML", FODS_FORMAT_TYPE },
    { "gnumeric", "Gnumeric Spreadsheet", "Gnumeric XML", GNUMERIC_FORMAT_TYPE }
    { "gnumeric", "Gnumeric Spreadsheet", "Gnumeric XML", GNUMERIC_FORMAT_TYPE },
    { "xltx", "Calc Office Open XML Template", "Office Open XML Spreadsheet Template", XLTX_FORMAT_TYPE }
};

bool testEqualsWithTolerance( long nVal1, long nVal2, long nTol )
diff --git a/sc/qa/unit/helper/qahelper.hxx b/sc/qa/unit/helper/qahelper.hxx
index 2482248..96268db 100644
--- a/sc/qa/unit/helper/qahelper.hxx
+++ b/sc/qa/unit/helper/qahelper.hxx
@@ -47,6 +47,7 @@
#define XLSB_XML_FORMAT_TYPE (SfxFilterFlags::IMPORT |                          SfxFilterFlags::ALIEN | SfxFilterFlags::STARONEFILTER | SfxFilterFlags::PREFERED)
#define FODS_FORMAT_TYPE     (SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::OWN | SfxFilterFlags::STARONEFILTER )
#define GNUMERIC_FORMAT_TYPE (SfxFilterFlags::IMPORT | SfxFilterFlags::ALIEN | SfxFilterFlags::PREFERED )
#define XLTX_FORMAT_TYPE     (SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::TEMPLATE |SfxFilterFlags::ALIEN | SfxFilterFlags::STARONEFILTER | SfxFilterFlags::PREFERED)

#define FORMAT_ODS      0
#define FORMAT_XLS      1
@@ -60,6 +61,7 @@
#define FORMAT_XLSB     9
#define FORMAT_FODS     10
#define FORMAT_GNUMERIC 11
#define FORMAT_XLTX     12

enum class StringType { PureString, StringValue };

diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index fcfb60f..5b1ff5f 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -209,6 +209,8 @@
    void testTdf118990();
    void testTdf121612();

    void testXltxExport();

    CPPUNIT_TEST_SUITE(ScExportTest);
    CPPUNIT_TEST(test);
    CPPUNIT_TEST(testTdf111876);
@@ -323,6 +325,8 @@
    CPPUNIT_TEST(testTdf118990);
    CPPUNIT_TEST(testTdf121612);

    CPPUNIT_TEST(testXltxExport);

    CPPUNIT_TEST_SUITE_END();

private:
@@ -356,6 +360,7 @@
        { 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("ContentType"), BAD_CAST("http://schemas.openxmlformats.org/package/2006/content-types") },
    };
    for(size_t i = 0; i < SAL_N_ELEMENTS(aNamespaces); ++i)
    {
@@ -4189,6 +4194,22 @@
    CPPUNIT_ASSERT_EQUAL(size_t(1), pDPColl->GetCount());
}

void ScExportTest::testXltxExport()
{
    // Create new document
    ScDocShell* pShell = new ScDocShell(
        SfxModelFlags::EMBEDDED_OBJECT |
        SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS |
        SfxModelFlags::DISABLE_DOCUMENT_RECOVERY);
    pShell->DoInitNew();

    // Export as template and check content type
    xmlDocPtr pDoc = XPathHelper::parseExport2(*this, *pShell, m_xSFactory, "[Content_Types].xml", FORMAT_XLTX);
    CPPUNIT_ASSERT(pDoc);
    assertXPath(pDoc, "/ContentType:Types/ContentType:Override[@PartName='/xl/workbook.xml']",
        "ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml");
}

CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest);

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx
index 45178df..3455b74 100644
--- a/sc/source/filter/excel/xestream.cxx
+++ b/sc/source/filter/excel/xestream.cxx
@@ -911,10 +911,11 @@
    return pStream;
}

XclExpXmlStream::XclExpXmlStream( const uno::Reference< XComponentContext >& rCC, bool bExportVBA )
XclExpXmlStream::XclExpXmlStream( const uno::Reference< XComponentContext >& rCC, bool bExportVBA, bool bExportTemplate )
    : XmlFilterBase( rCC ),
      mpRoot( nullptr ),
      mbExportVBA(bExportVBA)
      mbExportVBA(bExportVBA),
      mbExportTemplate(bExportTemplate)
{
}

@@ -1076,11 +1077,29 @@
        ScDocShell::GetViewData()->WriteExtOptions( mpRoot->GetExtDocOptions() );

    OUString const workbook = "xl/workbook.xml";
    const char* pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";


    const char* pWorkbookContentType = nullptr;
    if (mbExportVBA)
        pWorkbookContentType = "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
    {
        if (mbExportTemplate)
        {
            pWorkbookContentType = "application/vnd.ms-excel.template.macroEnabled.main+xml";
        }
        else
        {
            pWorkbookContentType = "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
        }
    }
    else
    {
        if (mbExportTemplate)
        {
            pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml";
        }
        else
        {
            pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
        }
    }

    PushStream( CreateOutputStream( workbook, workbook,
                                    uno::Reference <XOutputStream>(),
diff --git a/sc/source/filter/inc/xestream.hxx b/sc/source/filter/inc/xestream.hxx
index 5b10d6a..20cd690 100644
--- a/sc/source/filter/inc/xestream.hxx
+++ b/sc/source/filter/inc/xestream.hxx
@@ -275,7 +275,7 @@
class XclExpXmlStream : public oox::core::XmlFilterBase
{
public:
    XclExpXmlStream( const css::uno::Reference< css::uno::XComponentContext >& rCC, bool bExportVBA );
    XclExpXmlStream( const css::uno::Reference< css::uno::XComponentContext >& rCC, bool bExportVBA, bool bExportTemplate );
    virtual ~XclExpXmlStream() override;

    /** Returns the filter root data. */
@@ -355,6 +355,7 @@
    XclExpXmlPathToStateMap                     maOpenedStreamMap;

    bool const mbExportVBA;
    bool const mbExportTemplate;
};

#endif
diff --git a/sc/source/filter/oox/excelfilter.cxx b/sc/source/filter/oox/excelfilter.cxx
index e638d0d..c5fda17 100644
--- a/sc/source/filter/oox/excelfilter.cxx
+++ b/sc/source/filter/oox/excelfilter.cxx
@@ -227,7 +227,7 @@
    {
        bool bExportVBA = exportVBA();
        Reference< XExporter > xExporter(
            new XclExpXmlStream( getComponentContext(), bExportVBA ) );
            new XclExpXmlStream( getComponentContext(), bExportVBA, isExportTemplate() ) );

        Reference< XComponent > xDocument( getModel(), UNO_QUERY );
        Reference< XFilter > xFilter( xExporter, UNO_QUERY );