diff --git a/sc/qa/unit/PivotTableFormatsImportExport.cxx b/sc/qa/unit/PivotTableFormatsImportExport.cxx index e107d6344db8..1438fde71b23 100644 --- a/sc/qa/unit/PivotTableFormatsImportExport.cxx +++ b/sc/qa/unit/PivotTableFormatsImportExport.cxx @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -408,6 +409,34 @@ CPPUNIT_TEST_FIXTURE(ScPivotTableFormatsImportExport, testPivotTableFormatsSubTo checkFormats(); } +CPPUNIT_TEST_FIXTURE(ScPivotTableFormatsImportExport, testTdf122473_PivotTableLabelRotation) +{ + // Contains a pivotTable with differential formatting (dxf) and direct formatting + // with only an child (textRotation) applied to two row-label cells + // ("Sum of C" rotated 90° and "Sum of D" set to stacked/vertical text). + createScDoc("xlsx/pivot-table/tdf122473_PivotTableLabelRotation.xlsx"); + auto checkFormats = [this]() { + ScDocument& rDocument = *getScDoc(); + + // Without the fix in place, this test would have failed with + // - Expected: 9000 + // - Actual : 0 + // "Sum of C" row label at F9 -> dxf 0: textRotation="90" + CPPUNIT_ASSERT_EQUAL(Degree100(9000).get(), + rDocument.GetAttr(5, 8, 0, ATTR_ROTATE_VALUE).GetValue().get()); + + // Without the fix in place, this test would have failed with + // - Expected: 1 + // - Actual : 0 + // "Sum of D" row label at F10 -> dxf 1: textRotation="255" (stacked/vertical) + CPPUNIT_ASSERT_EQUAL(true, rDocument.GetAttr(5, 9, 0, ATTR_STACKED).GetValue()); + }; + + checkFormats(); + saveAndReload(TestFilter::XLSX); + checkFormats(); +} + } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sc/qa/unit/data/xlsx/pivot-table/tdf122473_PivotTableLabelRotation.xlsx b/sc/qa/unit/data/xlsx/pivot-table/tdf122473_PivotTableLabelRotation.xlsx new file mode 100644 index 000000000000..292f7cb05a5d Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot-table/tdf122473_PivotTableLabelRotation.xlsx differ diff --git a/sc/source/filter/inc/PivotTableFormat.hxx b/sc/source/filter/inc/PivotTableFormat.hxx index 544ee06cc2d0..189d0049a33f 100644 --- a/sc/source/filter/inc/PivotTableFormat.hxx +++ b/sc/source/filter/inc/PivotTableFormat.hxx @@ -51,7 +51,8 @@ private: bool mbOutline = true; std::optional moOffset = std::nullopt; bool mbCollapsedLevelsAreSubtotals = false; - // TODO Axis + // tdf#122473 - import alignment and axis-based pivot area formats + std::optional moAxis = std::nullopt; std::optional moFieldPosition = std::nullopt; std::vector> maReferences; diff --git a/sc/source/filter/inc/stylesbuffer.hxx b/sc/source/filter/inc/stylesbuffer.hxx index 3ad9eea63b95..0e003fedfe6c 100644 --- a/sc/source/filter/inc/stylesbuffer.hxx +++ b/sc/source/filter/inc/stylesbuffer.hxx @@ -339,6 +339,9 @@ private: ApiAlignmentData maApiData; /// Alignment data converted to API constants. }; +// tdf#122473 - import alignment and axis-based pivot area formats +typedef std::shared_ptr AlignmentRef; + /** Contains all XML cell protection attributes, e.g. from a protection element. */ struct ProtectionModel { @@ -705,6 +708,8 @@ public: BorderRef const & createBorder( bool bAlwaysNew = true ); /** Creates a new empty fill object. */ FillRef const & createFill( bool bAlwaysNew = true ); + /** Creates a new empty alignment object. */ + AlignmentRef const& createAlignment(bool bAlwaysNew = true); /** Creates a new empty protection object. */ ProtectionRef const & createProtection( bool bAlwaysNew = true ); diff --git a/sc/source/filter/oox/PivotTableFormat.cxx b/sc/source/filter/oox/PivotTableFormat.cxx index be27ca1e2aad..ee44ccc1f497 100644 --- a/sc/source/filter/oox/PivotTableFormat.cxx +++ b/sc/source/filter/oox/PivotTableFormat.cxx @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,8 @@ void PivotTableFormat::importPivotArea(const oox::AttributeList& rAttribs) moOffset = rAttribs.getXString(XML_offset); mbCollapsedLevelsAreSubtotals = rAttribs.getBool(XML_collapsedLevelsAreSubtotals, false); moFieldPosition = rAttribs.getUnsigned(XML_fieldPosition); + // tdf#122473 - import alignment and axis-based pivot area formats + moAxis = rAttribs.getToken(XML_axis); } void PivotTableFormat::finalizeImport() @@ -146,6 +149,18 @@ void PivotTableFormat::finalizeImport() .bHasSubtotal = bHasSubtotal }); } } + + // tdf#122473 - import alignment and axis-based pivot area formats + // There is no field or reference given. However, there exists an axis value. + // The format uses it to identify the label of the field data. Treat it as an + // explicit reference to the values field. + if (maReferences.empty() && mbLabelOnly && moAxis && *moAxis == XML_axisValues) + { + aFormat.aSelections.push_back(sc::Selection{ .bSelected = true, + .nField = sal_Int32(sc::constDataDimension), + .nIndices = {}, + .bHasSubtotal = false }); + } aFormats.add(aFormat); pSaveData->setFormats(aFormats); diff --git a/sc/source/filter/oox/stylesbuffer.cxx b/sc/source/filter/oox/stylesbuffer.cxx index 7f9ef58c358f..70e835211cf2 100644 --- a/sc/source/filter/oox/stylesbuffer.cxx +++ b/sc/source/filter/oox/stylesbuffer.cxx @@ -2453,6 +2453,14 @@ FillRef const & Dxf::createFill( bool bAlwaysNew ) return mxFill; } +// tdf#122473 - import alignment and axis-based pivot area formats +AlignmentRef const& Dxf::createAlignment(bool bAlwaysNew) +{ + if (bAlwaysNew || !mxAlignment) + mxAlignment = std::make_shared(*this); + return mxAlignment; +} + ProtectionRef const & Dxf::createProtection( bool bAlwaysNew ) { if ( bAlwaysNew || !mxProtection ) diff --git a/sc/source/filter/oox/stylesfragment.cxx b/sc/source/filter/oox/stylesfragment.cxx index c738016029c3..e4f04c7beedf 100644 --- a/sc/source/filter/oox/stylesfragment.cxx +++ b/sc/source/filter/oox/stylesfragment.cxx @@ -149,9 +149,8 @@ ContextHandlerRef DxfContext::onCreateContext( sal_Int32 nElement, const Attribu case XLS_TOKEN( fill ): return new FillContext( *this, mxDxf->createFill() ); case XLS_TOKEN( numFmt ): mxDxf->importNumFmt( rAttribs ); break; -#if 0 - case XLS_TOKEN( alignment ): mxDxf->importAlignment( rAttribs ); break; -#endif + // tdf#122473 - import alignment and axis-based pivot area formats + case XLS_TOKEN(alignment): mxDxf->createAlignment()->importAlignment(rAttribs); break; case XLS_TOKEN( protection ): mxDxf->createProtection()->importProtection( rAttribs ); break; } break; @@ -163,6 +162,8 @@ ContextHandlerRef DxfContext::onCreateContext( sal_Int32 nElement, const Attribu case XLS_TOKEN( border ): return new BorderContext( *this, mxDxf->createBorder() ); case XLS_TOKEN( fill ): return new FillContext( *this, mxDxf->createFill() ); case XLS_TOKEN( numFmt ): mxDxf->importNumFmt( rAttribs ); break; + // tdf#122473 - import alignment and axis-based pivot area formats + case XLS_TOKEN(alignment): mxDxf->createAlignment()->importAlignment(rAttribs); break; case XLS_TOKEN( protection ): mxDxf->createProtection()->importProtection( rAttribs ); break; } break;