sc/qa/unit/data/xlsx/pivot-table/two-data-fields.xlsx |binary sc/qa/unit/subsequent_export-test.cxx | 122 ++++++++++++++++++ sc/source/filter/excel/xepivotxml.cxx | 83 ++++++++++-- sc/source/ui/unoobj/dapiuno.cxx | 13 + 4 files changed, 201 insertions(+), 17 deletions(-)
New commits: commit 151d7a62230c98bb06628667170165f875788637 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Fri Aug 29 18:07:29 2014 -0400 Write test for importing and exporting of pivot table with 2 data fields. This is for xlsx format. Change-Id: I8ef2ae41cc88eeeab610e1a89726c62acb9e2fcb diff --git a/sc/qa/unit/data/xlsx/pivot-table/two-data-fields.xlsx b/sc/qa/unit/data/xlsx/pivot-table/two-data-fields.xlsx new file mode 100644 index 0000000..793af59 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot-table/two-data-fields.xlsx differ diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx index d20bf73..432bc75 100644 --- a/sc/qa/unit/subsequent_export-test.cxx +++ b/sc/qa/unit/subsequent_export-test.cxx @@ -39,6 +39,7 @@ #include <dpcache.hxx> #include <dpobject.hxx> #include <dpsave.hxx> +#include <dputil.hxx> #include <svx/svdoole2.hxx> #include "tabprotection.hxx" @@ -122,6 +123,7 @@ public: void testSheetProtection(); void testPivotTableXLSX(); + void testPivotTableTwoDataFieldsXLSX(); CPPUNIT_TEST_SUITE(ScExportTest); CPPUNIT_TEST(test); @@ -160,6 +162,7 @@ public: #endif CPPUNIT_TEST(testSheetProtection); CPPUNIT_TEST(testPivotTableXLSX); + CPPUNIT_TEST(testPivotTableTwoDataFieldsXLSX); CPPUNIT_TEST(testFunctionsExcel2010ODS); CPPUNIT_TEST_SUITE_END(); @@ -2121,6 +2124,125 @@ void ScExportTest::testPivotTableXLSX() xDocSh2->DoClose(); } +void ScExportTest::testPivotTableTwoDataFieldsXLSX() +{ + struct + { + bool check( const ScDocument& rDoc ) + { + if (!rDoc.HasPivotTable()) + { + cerr << "The document should have pivot table." << endl; + return false; + } + + const ScDPCollection* pDPs = rDoc.GetDPCollection(); + if (!pDPs) + { + cerr << "Pivot table container should exist." << endl; + return false; + } + + ScRange aSrcRange(1,1,1,2,8,1); // B2:C9 on the 2nd sheet. + const ScDPCache* pCache = pDPs->GetSheetCaches().getExistingCache(aSrcRange); + if (!pCache) + { + cerr << "The document should have a pivot cache for B2:C9 on 'Src'." << endl; + return false; + } + + const char* pNames[] = { "Name", "Value" }; + + size_t nCount = pCache->GetFieldCount(); + if (nCount != SAL_N_ELEMENTS(pNames)) + { + cout << "Incorrect number of fields in pivot cache." << endl; + return false; + } + + const ScDPObject* pDPObj = rDoc.GetDPAtCursor(0,2,0); // A3 + if (!pDPObj) + { + cerr << "A pivot table should exist over A3." << endl; + return false; + } + + // Output range should be A3:C12. + ScRange aOutRange = pDPObj->GetOutRange(); + if (ScRange(0,2,0,2,11,0) != aOutRange) + { + cerr << "Incorrect output range." << endl; + return false; + } + + const ScDPSaveData* pSaveData = pDPObj->GetSaveData(); + if (!pSaveData) + { + cerr << "Save data should exist in each pivot table object." << endl; + return false; + } + + std::vector<const ScDPSaveDimension*> aDims; + pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_ROW, aDims); + if (aDims.size() != 1 || aDims[0]->GetName() != "Name") + { + cerr << "Pivot table should have one row field labeld 'Name'" << endl; + return false; + } + + pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDims); + if (aDims.size() != 2 || + ScDPUtil::getSourceDimensionName(aDims[0]->GetName()) != "Value" || + ScDPUtil::getSourceDimensionName(aDims[1]->GetName()) != "Value") + { + cerr << "Pivot table should have two duplicated data fields both of which are named 'Value'." << endl; + return false; + } + + if (aDims[0]->GetFunction() != sheet::GeneralFunction_SUM) + { + cerr << "First data field should be SUM." << endl; + return false; + } + + if (aDims[1]->GetFunction() != sheet::GeneralFunction_COUNT) + { + cerr << "First data field should be COUNT." << endl; + return false; + } + + pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_COLUMN, aDims); + if (aDims.size() != 1 || !aDims[0]->IsDataLayout()) + { + cerr << "Pivot table should have one column field which is a data layout field." << endl; + return false; + } + + return true; + } + + } aTest; + + ScDocShellRef xDocSh = loadDoc("pivot-table/two-data-fields.", XLSX); + CPPUNIT_ASSERT(xDocSh.Is()); + ScDocument* pDoc = &xDocSh->GetDocument(); + + // Initial check. + bool bCheck = aTest.check(*pDoc); + CPPUNIT_ASSERT_MESSAGE("Initial check failed.", bCheck); + + ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLSX); + xDocSh->DoClose(); + CPPUNIT_ASSERT(xDocSh2.Is()); + pDoc = &xDocSh2->GetDocument(); + + // Reload check. + bCheck = aTest.check(*pDoc); + CPPUNIT_ASSERT_MESSAGE("Reload check failed.", bCheck); + + xDocSh2->DoClose(); +} + void ScExportTest::testFunctionsExcel2010ODS() { //testFunctionsExcel2010(ODS); commit f37c6e0d111c2237d422be07acbb67b7d0dcbbeb Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Fri Aug 29 17:43:00 2014 -0400 Correctly export subtotal functions of data fields. Take note that data field may be duplicated. Change-Id: I8f787075869f38d0101da2787bac315c71d8a6e8 diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx index 5ff871a..3f7d320 100644 --- a/sc/source/filter/excel/xepivotxml.cxx +++ b/sc/source/filter/excel/xepivotxml.cxx @@ -18,6 +18,7 @@ #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> #include <com/sun/star/sheet/DataPilotOutputRangeType.hpp> +#include <com/sun/star/sheet/GeneralFunction.hpp> #include <vector> @@ -74,6 +75,40 @@ const char* toOOXMLAxisType( sheet::DataPilotFieldOrientation eOrient ) return ""; } +const char* toOOXMLSubtotalType( sheet::GeneralFunction eFunc ) +{ + switch (eFunc) + { + case sheet::GeneralFunction_SUM: + return "sum"; + case sheet::GeneralFunction_COUNT: + return "count"; + case sheet::GeneralFunction_AVERAGE: + return "average"; + case sheet::GeneralFunction_MAX: + return "max"; + case sheet::GeneralFunction_MIN: + return "min"; + case sheet::GeneralFunction_PRODUCT: + return "product"; + case sheet::GeneralFunction_COUNTNUMS: + return "countNums"; + case sheet::GeneralFunction_STDEV: + return "stdDev"; + case sheet::GeneralFunction_STDEVP: + return "stdDevp"; + case sheet::GeneralFunction_VAR: + return "var"; + case sheet::GeneralFunction_VARP: + return "varp"; + case sheet::GeneralFunction_NONE: + case sheet::GeneralFunction_AUTO: + default: + ; + } + return NULL; +} + } XclExpXmlPivotCaches::XclExpXmlPivotCaches( const XclExpRoot& rRoot ) : @@ -354,6 +389,18 @@ void XclExpXmlPivotTables::SaveXml( XclExpXmlStream& rStrm ) } } +namespace { + +struct DataField +{ + long mnPos; // field index in pivot cache. + const ScDPSaveDimension* mpDim; + + DataField( long nPos, const ScDPSaveDimension* pDim ) : mnPos(nPos), mpDim(pDim) {} +}; + +} + void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDPObject& rDPObj, sal_Int32 nCacheId ) { typedef boost::unordered_map<OUString, long, OUStringHash> NameToIdMapType; @@ -383,7 +430,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP std::vector<long> aRowFields; std::vector<long> aColFields; std::vector<long> aPageFields; - std::vector<long> aDataFields; + std::vector<DataField> aDataFields; // Use dimensions in the save data to get their correct ordering. // Dimension order here is significant as they specify the order of @@ -426,7 +473,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP aPageFields.push_back(nPos); break; case sheet::DataPilotFieldOrientation_DATA: - aDataFields.push_back(nPos); + aDataFields.push_back(DataField(nPos, &rDim)); break; case sheet::DataPilotFieldOrientation_HIDDEN: default: @@ -607,12 +654,12 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP XML_count, OString::number(static_cast<long>(aDataFields.size())), FSEND); - std::vector<long>::iterator it = aDataFields.begin(), itEnd = aDataFields.end(); + std::vector<DataField>::iterator it = aDataFields.begin(), itEnd = aDataFields.end(); for (; it != itEnd; ++it) { - long nDimIdx = *it; + long nDimIdx = it->mnPos; assert(aCachedDims[nDimIdx]); // the loop above should have screened for NULL's. - const ScDPSaveDimension& rDim = *aCachedDims[nDimIdx]; + const ScDPSaveDimension& rDim = *it->mpDim; const OUString* pName = rDim.GetLayoutName(); pPivotStrm->write("<")->writeId(XML_dataField); if (pName) @@ -620,6 +667,11 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP rStrm.WriteAttributes(XML_fld, OString::number(nDimIdx).getStr(), FSEND); + sheet::GeneralFunction eFunc = static_cast<sheet::GeneralFunction>(rDim.GetFunction()); + const char* pSubtotal = toOOXMLSubtotalType(eFunc); + if (pSubtotal) + rStrm.WriteAttributes(XML_subtotal, pSubtotal, FSEND); + pPivotStrm->write("/>"); } commit 3b856f028735d292c9b02168704d4a07e2f43cd5 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Fri Aug 29 17:18:09 2014 -0400 Use the source dimension name when searching for a dimension. Otherwise we might miss the right dimension object. This fixes the bug where the subtotal function of the second data field was not set correctly when importing from xlsx. Change-Id: Id6ecb07b86cf6803a3f6f7604267ce2f5f9a4067 diff --git a/sc/source/ui/unoobj/dapiuno.cxx b/sc/source/ui/unoobj/dapiuno.cxx index 5cc6f06..cd4e0a2 100644 --- a/sc/source/ui/unoobj/dapiuno.cxx +++ b/sc/source/ui/unoobj/dapiuno.cxx @@ -38,6 +38,7 @@ #include "dpgroup.hxx" #include "dpdimsave.hxx" #include "hints.hxx" +#include <dputil.hxx> #include <com/sun/star/sheet/XHierarchiesSupplier.hpp> #include <com/sun/star/sheet/XLevelsSupplier.hpp> @@ -1481,13 +1482,17 @@ ScDPSaveDimension* ScDataPilotChildObjBase::GetDPDimension( ScDPObject** ppDPObj return pSaveData->GetDimensionByName( maFieldId.maFieldName ); // find dimension with specified index (search in duplicated dimensions) - const boost::ptr_vector<ScDPSaveDimension>& rDimensions = pSaveData->GetDimensions(); + const ScDPSaveData::DimsType& rDims = pSaveData->GetDimensions(); sal_Int32 nFoundIdx = 0; - boost::ptr_vector<ScDPSaveDimension>::const_iterator it; - for(it = rDimensions.begin(); it != rDimensions.end(); ++it) + ScDPSaveData::DimsType::const_iterator it; + for (it = rDims.begin(); it != rDims.end(); ++it) { - if( !it->IsDataLayout() && (it->GetName() == maFieldId.maFieldName) ) + if (it->IsDataLayout()) + continue; + + OUString aSrcName = ScDPUtil::getSourceDimensionName(it->GetName()); + if (aSrcName == maFieldId.maFieldName) { if( nFoundIdx == maFieldId.mnFieldIdx ) return const_cast<ScDPSaveDimension*>(&(*it)); commit bfaf4401b440b56d6e226a4dca32a18e84949d52 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Fri Aug 29 16:23:57 2014 -0400 Export data layout field to xlsx correctly. Excel uses a field index of -2 to indicate a data layout field. Change-Id: I6b18c0bcff439eb4425ef0b0d0b841633dc81dd7 diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx index cef5a85..5ff871a 100644 --- a/sc/source/filter/excel/xepivotxml.cxx +++ b/sc/source/filter/excel/xepivotxml.cxx @@ -395,16 +395,21 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP const ScDPSaveDimension& rDim = rDims[i]; long nPos = -1; // position in cache - OUString aSrcName = ScDPUtil::getSourceDimensionName(rDim.GetName()); - NameToIdMapType::iterator it = aNameToIdMap.find(aSrcName); - if (it != aNameToIdMap.end()) - nPos = it->second; + if (rDim.IsDataLayout()) + nPos = -2; // Excel uses an index of -2 to indicate a data layout field. + else + { + OUString aSrcName = ScDPUtil::getSourceDimensionName(rDim.GetName()); + NameToIdMapType::iterator it = aNameToIdMap.find(aSrcName); + if (it != aNameToIdMap.end()) + nPos = it->second; - if (nPos == -1) - continue; + if (nPos == -1) + continue; - if (!aCachedDims[nPos]) - continue; + if (!aCachedDims[nPos]) + continue; + } sheet::DataPilotFieldOrientation eOrient = static_cast<sheet::DataPilotFieldOrientation>(rDim.GetOrientation()); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits