tdf#123421 : xlsx export : Don't write data field entry...

under colFields tag if there is only one data-field.

<colFields count=[*]>
    <field x="-2"/>  <--- -2 indicates data field.
</colFields>

Excel 2013/2016 seems to crash at the presence of '<field x="-2"/>'
in colFields when there is only one data-field.

Additionally, call GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE)
on all ScDPObject's in non-const mode, so that the internal
pOuput member of ScDPObject is populated. Otherwise the
const GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE)
call always return an invalid range.

This also adds 2 unit tests :-
1. To check the presence of <field x="-2"/> in colFields tag
   if there are more than one data-fields.
2. To ensure the absence of <field x="-2"/> in colFields tag
   if there is only one data-field.

Change-Id: I8f470bd1ab883f73586f04a3fcc30e3fbf948c4a
Reviewed-on: https://gerrit.libreoffice.org/70316
Tested-by: Jenkins
Reviewed-by: Andras Timar <andras.timar@collabora.com>
(cherry picked from commit 97af58093978d8e6b9d90eedcc59141304e7200e)
Reviewed-on: https://gerrit.libreoffice.org/70704
Reviewed-by: Dennis Francis <dennis.francis@collabora.com>
diff --git a/sc/inc/dpsave.hxx b/sc/inc/dpsave.hxx
index 7558a6b..49cb240 100644
--- a/sc/inc/dpsave.hxx
+++ b/sc/inc/dpsave.hxx
@@ -315,7 +315,7 @@ public:

    ScDPSaveDimension* GetInnermostDimension(css::sheet::DataPilotFieldOrientation nOrientation);
    ScDPSaveDimension* GetFirstDimension(css::sheet::DataPilotFieldOrientation eOrientation);
    long GetDataDimensionCount() const;
    SC_DLLPUBLIC long GetDataDimensionCount() const;

    void SetPosition( ScDPSaveDimension* pDim, long nNew );
    SC_DLLPUBLIC void SetColumnGrand( bool bSet );
diff --git a/sc/qa/unit/data/ods/tdf123421_1datafield.ods b/sc/qa/unit/data/ods/tdf123421_1datafield.ods
new file mode 100644
index 0000000..985d6c0
--- /dev/null
+++ b/sc/qa/unit/data/ods/tdf123421_1datafield.ods
Binary files differ
diff --git a/sc/qa/unit/data/ods/tdf123421_2datafields.ods b/sc/qa/unit/data/ods/tdf123421_2datafields.ods
new file mode 100644
index 0000000..c5d8a09
--- /dev/null
+++ b/sc/qa/unit/data/ods/tdf123421_2datafields.ods
Binary files differ
diff --git a/sc/qa/unit/pivottable_filters_test.cxx b/sc/qa/unit/pivottable_filters_test.cxx
index e68e349..7550746 100644
--- a/sc/qa/unit/pivottable_filters_test.cxx
+++ b/sc/qa/unit/pivottable_filters_test.cxx
@@ -61,6 +61,8 @@ public:

    // Export
    void testPivotTableExportXLSX();
    void testPivotTableExportXLSXSingleDataField();
    void testPivotTableExportXLSXMultipleDataFields();
    void testPivotCacheExportXLSX();
    void testPivotTableXLSX();
    void testPivotTableTwoDataFieldsXLSX();
@@ -100,6 +102,8 @@ public:
    CPPUNIT_TEST(testTdf112501);

    CPPUNIT_TEST(testPivotTableExportXLSX);
    CPPUNIT_TEST(testPivotTableExportXLSXSingleDataField);
    CPPUNIT_TEST(testPivotTableExportXLSXMultipleDataFields);
    CPPUNIT_TEST(testPivotCacheExportXLSX);
    CPPUNIT_TEST(testPivotTableXLSX);
    CPPUNIT_TEST(testPivotTableTwoDataFieldsXLSX);
@@ -755,6 +759,58 @@ void ScPivotTableFiltersTest::testPivotTableExportXLSX()
                "h", "1");
}

void ScPivotTableFiltersTest::testPivotTableExportXLSXSingleDataField()
{
    ScDocShellRef xShell = loadDoc("tdf123421_1datafield.", FORMAT_ODS);
    CPPUNIT_ASSERT(xShell.is());

    std::shared_ptr<utl::TempFile> pXPathFile
        = ScBootstrapFixture::exportTo(&(*xShell), FORMAT_XLSX);
    xmlDocPtr pTable
        = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/pivotTables/pivotTable1.xml");
    CPPUNIT_ASSERT(pTable);

    assertXPath(pTable, "/x:pivotTableDefinition/x:location", "ref", "A3:B6");
    assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstHeaderRow", "1");
    assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstDataRow", "1");
    assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstDataCol", "1");
    assertXPath(pTable, "/x:pivotTableDefinition/x:dataFields", "count", "1");

    // There should not be any colFields tag, before the fix there used to be a singleton with
    // <field x="-2"/> as child node.
    assertXPath(pTable, "/x:pivotTableDefinition/x:colFields", 0);

    xShell->DoClose();
}

void ScPivotTableFiltersTest::testPivotTableExportXLSXMultipleDataFields()
{
    ScDocShellRef xShell = loadDoc("tdf123421_2datafields.", FORMAT_ODS);
    CPPUNIT_ASSERT(xShell.is());

    std::shared_ptr<utl::TempFile> pXPathFile
        = ScBootstrapFixture::exportTo(&(*xShell), FORMAT_XLSX);
    xmlDocPtr pTable
        = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/pivotTables/pivotTable1.xml");
    CPPUNIT_ASSERT(pTable);

    assertXPath(pTable, "/x:pivotTableDefinition/x:location", "ref", "A1:C6");
    assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstHeaderRow", "1");
    assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstDataRow", "2");
    assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstDataCol", "1");

    assertXPath(pTable, "/x:pivotTableDefinition/x:dataFields", "count", "2");

    // There should be a single colFields tag with sole child node
    // <field x="-2"/>.
    assertXPath(pTable, "/x:pivotTableDefinition/x:colFields", 1);
    assertXPath(pTable, "/x:pivotTableDefinition/x:colFields", "count", "1");
    assertXPath(pTable, "/x:pivotTableDefinition/x:colFields/x:field", 1);
    assertXPath(pTable, "/x:pivotTableDefinition/x:colFields/x:field", "x", "-2");

    xShell->DoClose();
}

void ScPivotTableFiltersTest::testPivotCacheExportXLSX()
{
    // tdf#89139 FILESAVE xlsx pivot table corrupted after save with LO and re-open with MS Office
diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx
index 271b4cb..611078f 100644
--- a/sc/source/filter/excel/xepivotxml.cxx
+++ b/sc/source/filter/excel/xepivotxml.cxx
@@ -432,6 +432,7 @@ void XclExpXmlPivotTableManager::Initialize()
    {
        ScDPObject& rDPObj = (*pDPColl)[i];
        rDPObj.SyncAllDimensionMembers();
        (void)rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE);
    }

    // Go through the caches first.
@@ -615,6 +616,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
    std::vector<long> aPageFields;
    std::vector<DataField> aDataFields;

    long nDataDimCount = rSaveData.GetDataDimensionCount();
    // Use dimensions in the save data to get their correct ordering.
    // Dimension order here is significant as they specify the order of
    // appearance in each axis.
@@ -646,6 +648,8 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
        switch (eOrient)
        {
            case sheet::DataPilotFieldOrientation_COLUMN:
                if (nPos == -2 && nDataDimCount <= 1)
                    break;
                aColFields.push_back(nPos);
            break;
            case sheet::DataPilotFieldOrientation_ROW:
@@ -693,15 +697,16 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
    sal_Int32 nFirstDataRow = 2;
    sal_Int32 nFirstDataCol = 1;
    ScRange aResRange = rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::RESULT);

    if (!aOutRange.IsValid())
        aOutRange = rDPObj.GetOutRange();

    if (aOutRange.IsValid() && aResRange.IsValid())
    {
        nFirstDataRow = aResRange.aStart.Row() - aOutRange.aStart.Row();
        nFirstDataCol = aResRange.aStart.Col() - aOutRange.aStart.Col();
    }

    if (!aOutRange.IsValid())
        aOutRange = rDPObj.GetOutRange();

    pPivotStrm->write("<")->writeId(XML_location);
    rStrm.WriteAttributes(XML_ref,
        XclXmlUtils::ToOString(aOutRange),