Kaydet (Commit) 33eb6ba0 authored tarafından Mike Kaganski's avatar Mike Kaganski

tdf#124810: Roundtrip pivot table style info from XLSX.

Also provide a default pivot table style for those tables that don't
have a style info. Let's use the style settings that Excel uses.

Change-Id: I8006a33a0aa0e92629f7db0a9c24a6ff52d17945
Reviewed-on: https://gerrit.libreoffice.org/70933
Tested-by: Jenkins
Reviewed-by: 's avatarMike Kaganski <mike.kaganski@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/71006Tested-by: 's avatarMike Kaganski <mike.kaganski@collabora.com>
üst a8e019f0
...@@ -94,6 +94,11 @@ private: ...@@ -94,6 +94,11 @@ private:
// cached data // cached data
css::uno::Reference<css::sheet::XDimensionsSupplier> xSource; css::uno::Reference<css::sheet::XDimensionsSupplier> xSource;
ScDPOutput* pOutput; ScDPOutput* pOutput;
// name -> sequence of sequences of css::xml::FastAttribute or css::xml::Attribute
// see PivotTable::putToInteropGrabBag in sc/source/filter/oox/pivottablebuffer.cxx for details
std::map<OUString, css::uno::Any> maInteropGrabBag;
long nHeaderRows; // page fields plus filter button long nHeaderRows; // page fields plus filter button
bool mbHeaderLayout:1; // true : grid, false : standard bool mbHeaderLayout:1; // true : grid, false : standard
bool bAllowMove:1; bool bAllowMove:1;
...@@ -252,6 +257,19 @@ public: ...@@ -252,6 +257,19 @@ public:
static bool IsOrientationAllowed( css::sheet::DataPilotFieldOrientation nOrient, sal_Int32 nDimFlags ); static bool IsOrientationAllowed( css::sheet::DataPilotFieldOrientation nOrient, sal_Int32 nDimFlags );
void PutInteropGrabBag(std::map<OUString, css::uno::Any>&& val)
{
maInteropGrabBag = std::move(val);
}
std::pair<bool, css::uno::Any> GetInteropGrabBagValue(const OUString& sName) const
{
const auto it = maInteropGrabBag.find(sName);
if (it != maInteropGrabBag.end())
return { true, it->second };
return { false, css::uno::Any() };
}
#if DUMP_PIVOT_TABLE #if DUMP_PIVOT_TABLE
void Dump() const; void Dump() const;
void DumpCache() const; void DumpCache() const;
......
...@@ -92,6 +92,7 @@ public: ...@@ -92,6 +92,7 @@ public:
void testTdf124651(); void testTdf124651();
void testTdf124736(); void testTdf124736();
void tesTtdf124772NumFmt(); void tesTtdf124772NumFmt();
void testTdf124810();
CPPUNIT_TEST_SUITE(ScPivotTableFiltersTest); CPPUNIT_TEST_SUITE(ScPivotTableFiltersTest);
...@@ -138,6 +139,7 @@ public: ...@@ -138,6 +139,7 @@ public:
CPPUNIT_TEST(testTdf124651); CPPUNIT_TEST(testTdf124651);
CPPUNIT_TEST(testTdf124736); CPPUNIT_TEST(testTdf124736);
CPPUNIT_TEST(tesTtdf124772NumFmt); CPPUNIT_TEST(tesTtdf124772NumFmt);
CPPUNIT_TEST(testTdf124810);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
...@@ -2560,6 +2562,57 @@ void ScPivotTableFiltersTest::tesTtdf124772NumFmt() ...@@ -2560,6 +2562,57 @@ void ScPivotTableFiltersTest::tesTtdf124772NumFmt()
"formatCode", "\\$#,##0"); "formatCode", "\\$#,##0");
} }
void ScPivotTableFiltersTest::testTdf124810()
{
{
// First, test that we roundtrip existing pivot table style information from XLSX.
ScDocShellRef xDocSh = loadDoc("pivot_dark1.", FORMAT_XLSX);
CPPUNIT_ASSERT(xDocSh.is());
std::shared_ptr<utl::TempFile> pXPathFile
= ScBootstrapFixture::exportTo(xDocSh.get(), FORMAT_XLSX);
xDocSh->DoClose();
xmlDocPtr pTable
= XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/pivotTables/pivotTable1.xml");
CPPUNIT_ASSERT(pTable);
// All attributes must have been roundtripped correctly (testdoc uses some non-default values)
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "name",
"PivotStyleDark1");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showRowHeaders", "1");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showColHeaders", "1");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showRowStripes", "1");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showColStripes", "0");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showLastColumn", "0");
}
{
// Now check that we export default style information when there's no such information in
// original document. Just use some ODS as source. This might be changed when we start
// exporting better pivot table style information.
ScDocShellRef xDocSh = loadDoc("tdf124651_simplePivotTable.", FORMAT_ODS);
CPPUNIT_ASSERT(xDocSh.is());
std::shared_ptr<utl::TempFile> pXPathFile
= ScBootstrapFixture::exportTo(xDocSh.get(), FORMAT_XLSX);
xDocSh->DoClose();
xmlDocPtr pTable
= XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/pivotTables/pivotTable1.xml");
CPPUNIT_ASSERT(pTable);
// The default style for pivot tables in Excel 2007 through 2016 is PivotStyleLight16
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "name",
"PivotStyleLight16");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showRowHeaders", "1");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showColHeaders", "1");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showRowStripes", "0");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showColStripes", "0");
assertXPath(pTable, "/x:pivotTableDefinition/x:pivotTableStyleInfo", "showLastColumn", "1");
}
}
CPPUNIT_TEST_SUITE_REGISTRATION(ScPivotTableFiltersTest); CPPUNIT_TEST_SUITE_REGISTRATION(ScPivotTableFiltersTest);
CPPUNIT_PLUGIN_IMPLEMENT(); CPPUNIT_PLUGIN_IMPLEMENT();
......
...@@ -333,6 +333,7 @@ ScDPObject::ScDPObject(const ScDPObject& r) : ...@@ -333,6 +333,7 @@ ScDPObject::ScDPObject(const ScDPObject& r) :
pServDesc( nullptr ), pServDesc( nullptr ),
mpTableData(static_cast<ScDPTableData*>(nullptr)), mpTableData(static_cast<ScDPTableData*>(nullptr)),
pOutput( nullptr ), pOutput( nullptr ),
maInteropGrabBag(r.maInteropGrabBag),
nHeaderRows( r.nHeaderRows ), nHeaderRows( r.nHeaderRows ),
mbHeaderLayout( r.mbHeaderLayout ), mbHeaderLayout( r.mbHeaderLayout ),
bAllowMove(false), bAllowMove(false),
...@@ -364,6 +365,7 @@ ScDPObject& ScDPObject::operator= (const ScDPObject& r) ...@@ -364,6 +365,7 @@ ScDPObject& ScDPObject::operator= (const ScDPObject& r)
aTableTag = r.aTableTag; aTableTag = r.aTableTag;
aOutRange = r.aOutRange; aOutRange = r.aOutRange;
nHeaderRows = r.nHeaderRows; nHeaderRows = r.nHeaderRows;
maInteropGrabBag = r.maInteropGrabBag;
mbHeaderLayout = r.mbHeaderLayout; mbHeaderLayout = r.mbHeaderLayout;
bAllowMove = false; bAllowMove = false;
bSettingsChanged = false; bSettingsChanged = false;
...@@ -812,6 +814,7 @@ void ScDPObject::Clear() ...@@ -812,6 +814,7 @@ void ScDPObject::Clear()
pImpDesc = nullptr; pImpDesc = nullptr;
pServDesc = nullptr; pServDesc = nullptr;
ClearTableData(); ClearTableData();
maInteropGrabBag.clear();
} }
void ScDPObject::ClearTableData() void ScDPObject::ClearTableData()
......
...@@ -711,6 +711,38 @@ sal_Int32 GetSubtotalAttrToken(ScGeneralFunction eFunc) ...@@ -711,6 +711,38 @@ sal_Int32 GetSubtotalAttrToken(ScGeneralFunction eFunc)
return XML_defaultSubtotal; return XML_defaultSubtotal;
} }
// An item is expected to contain sequences of css::xml::FastAttribute and css::xml::Attribute
void WriteGrabBagItemToStream(XclExpXmlStream& rStrm, sal_Int32 tokenId, const css::uno::Any& rItem)
{
css::uno::Sequence<css::uno::Any> aSeqs;
if (rItem >>= aSeqs)
{
auto& pStrm = rStrm.GetCurrentStream();
pStrm->write("<")->writeId(tokenId);
css::uno::Sequence<css::xml::FastAttribute> aFastSeq;
css::uno::Sequence<css::xml::Attribute> aUnkSeq;
for (const auto& a : aSeqs)
{
if (a >>= aFastSeq)
{
for (const auto& rAttr : aFastSeq)
rStrm.WriteAttributes(rAttr.Token, rAttr.Value.toUtf8(), FSEND);
}
else if (a >>= aUnkSeq)
{
for (const auto& rAttr : aUnkSeq)
pStrm->write(" ")
->write(rAttr.Name)
->write("=\"")
->writeEscaped(rAttr.Value)
->write("\"");
}
}
pStrm->write("/>");
}
}
} }
void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDPObject& rDPObj, sal_Int32 nCacheId ) void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDPObject& rDPObj, sal_Int32 nCacheId )
...@@ -1137,6 +1169,16 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP ...@@ -1137,6 +1169,16 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
pPivotStrm->endElement(XML_dataFields); pPivotStrm->endElement(XML_dataFields);
} }
// Now add style info (use grab bag, or just a set which is default on Excel 2007 through 2016)
const auto aValPair = rDPObj.GetInteropGrabBagValue("pivotTableStyleInfo");
if (aValPair.first)
WriteGrabBagItemToStream(rStrm, XML_pivotTableStyleInfo, aValPair.second);
else
pPivotStrm->singleElement(XML_pivotTableStyleInfo, XML_name, "PivotStyleLight16",
XML_showRowHeaders, "1", XML_showColHeaders, "1",
XML_showRowStripes, "0", XML_showColStripes, "0",
XML_showLastColumn, "1", FSEND);
OUStringBuffer aBuf("../pivotCache/pivotCacheDefinition"); OUStringBuffer aBuf("../pivotCache/pivotCacheDefinition");
aBuf.append(nCacheId); aBuf.append(nCacheId);
aBuf.append(".xml"); aBuf.append(".xml");
......
...@@ -297,6 +297,8 @@ public: ...@@ -297,6 +297,8 @@ public:
void importPageField( const AttributeList& rAttribs ); void importPageField( const AttributeList& rAttribs );
/** Reads the settings of a field located in the data dimension from the dataField element. */ /** Reads the settings of a field located in the data dimension from the dataField element. */
void importDataField( const AttributeList& rAttribs ); void importDataField( const AttributeList& rAttribs );
/** Puts the attributes to the named grab bag value. */
void putToInteropGrabBag(const OUString& sName, const AttributeList& rAttribs);
/** Reads global pivot table settings from the PTDEFINITION record. */ /** Reads global pivot table settings from the PTDEFINITION record. */
void importPTDefinition( SequenceInputStream& rStrm ); void importPTDefinition( SequenceInputStream& rStrm );
...@@ -379,6 +381,7 @@ private: ...@@ -379,6 +381,7 @@ private:
PivotCache* mpPivotCache; /// The pivot cache this table is based on. PivotCache* mpPivotCache; /// The pivot cache this table is based on.
css::uno::Reference< css::sheet::XDataPilotDescriptor > css::uno::Reference< css::sheet::XDataPilotDescriptor >
mxDPDescriptor; /// Descriptor of the DataPilot object. mxDPDescriptor; /// Descriptor of the DataPilot object.
std::map<OUString, css::uno::Any> maInteropGrabBag;
}; };
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <com/sun/star/sheet/XDataPilotField.hpp> #include <com/sun/star/sheet/XDataPilotField.hpp>
#include <com/sun/star/sheet/XDataPilotTablesSupplier.hpp> #include <com/sun/star/sheet/XDataPilotTablesSupplier.hpp>
#include <com/sun/star/sheet/XSheetOperation.hpp> #include <com/sun/star/sheet/XSheetOperation.hpp>
#include <com/sun/star/xml/sax/XFastAttributeList.hpp>
#include <oox/helper/binaryinputstream.hxx> #include <oox/helper/binaryinputstream.hxx>
#include <oox/helper/attributelist.hxx> #include <oox/helper/attributelist.hxx>
#include <oox/helper/containerhelper.hxx> #include <oox/helper/containerhelper.hxx>
...@@ -1033,6 +1034,18 @@ void PivotTable::importDataField( const AttributeList& rAttribs ) ...@@ -1033,6 +1034,18 @@ void PivotTable::importDataField( const AttributeList& rAttribs )
maDataFields.push_back( aModel ); maDataFields.push_back( aModel );
} }
void PivotTable::putToInteropGrabBag(const OUString& sName, const AttributeList& rAttribs)
{
if (auto xFastAttributeList = rAttribs.getFastAttributeList())
{
// Store both known and unknown attribute sequences to the grab bag as is
css::uno::Sequence<css::xml::FastAttribute> aFast = xFastAttributeList->getFastAttributes();
css::uno::Sequence<css::xml::Attribute> aUnk = xFastAttributeList->getUnknownAttributes();
css::uno::Sequence<css::uno::Any> aVal{ css::uno::Any(aFast), css::uno::Any(aUnk) };
maInteropGrabBag[sName] <<= aVal;
}
}
void PivotTable::importPTDefinition( SequenceInputStream& rStrm ) void PivotTable::importPTDefinition( SequenceInputStream& rStrm )
{ {
sal_uInt32 nFlags1, nFlags2, nFlags3; sal_uInt32 nFlags1, nFlags2, nFlags3;
...@@ -1274,6 +1287,9 @@ void PivotTable::finalizeImport() ...@@ -1274,6 +1287,9 @@ void PivotTable::finalizeImport()
if( !maPageFields.empty() ) if( !maPageFields.empty() )
aPos.Row = ::std::max< sal_Int32 >( static_cast< sal_Int32 >( aPos.Row - maPageFields.size() - 1 ), 0 ); aPos.Row = ::std::max< sal_Int32 >( static_cast< sal_Int32 >( aPos.Row - maPageFields.size() - 1 ), 0 );
// save interop grab bag
mpDPObject->PutInteropGrabBag(std::move(maInteropGrabBag));
// insert the DataPilot table into the sheet // insert the DataPilot table into the sheet
xDPTables->insertNewByName( maDefModel.maName, aPos, mxDPDescriptor ); xDPTables->insertNewByName( maDefModel.maName, aPos, mxDPDescriptor );
} }
......
...@@ -181,6 +181,9 @@ ContextHandlerRef PivotTableFragment::onCreateContext( sal_Int32 nElement, const ...@@ -181,6 +181,9 @@ ContextHandlerRef PivotTableFragment::onCreateContext( sal_Int32 nElement, const
case XLS_TOKEN( pageFields ): return this; case XLS_TOKEN( pageFields ): return this;
case XLS_TOKEN( dataFields ): return this; case XLS_TOKEN( dataFields ): return this;
case XLS_TOKEN( filters ): return this; case XLS_TOKEN( filters ): return this;
case XLS_TOKEN(pivotTableStyleInfo):
mrPivotTable.putToInteropGrabBag("pivotTableStyleInfo", rAttribs);
break;
} }
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment