oox/inc/drawingml/textliststyle.hxx | 6 +++ oox/inc/drawingml/textparagraphproperties.hxx | 3 + oox/qa/unit/data/outliner-list-style.pptx |binary oox/qa/unit/drawingml.cxx | 34 +++++++++++++++++++ oox/source/drawingml/textliststyle.cxx | 41 +++++++++++++++++++++++ oox/source/drawingml/textparagraph.cxx | 2 - oox/source/drawingml/textparagraphproperties.cxx | 10 +++++ 7 files changed, 93 insertions(+), 3 deletions(-)
New commits: commit 92f97778b87348b0b82c0497c4daee077005cbd1 Author: Miklos Vajna <[email protected]> AuthorDate: Fri Oct 10 08:50:25 2025 +0200 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Oct 10 16:30:47 2025 +0200 tdf#168559 PPTX imp: fix missing custom level list style for outline shapes Export the bugdoc to PPTX, reopen it in Impress, go to the end of the first bullet, enter, tab, indent grows to a large value, while it should only grow to match the existing other already indented bullet. This happens because the shape text's paragraphs have a numbering rule defined for the current list level, but the other list levels are left untouched by the PPTX import. Fix the problem by optionally giving the shape's list style to TextParagraphProperties::pushToPropSet(), and if that's given, then use the list style to initialize the numbering rules of the paragraph for all non-current levels. (Current level was initialized already.) Not all possible properties are set, but left/first margin is done, which is the primary use-case of the bug. This fixes, the bug, but a full PPTX export+import+export+import cycle is still bad, probably because something is not imported on the masterpage, that's still to be done. (PPTX export+import+export then edit in PowerPoint works.) Change-Id: I3575b986faaacb4103e6dde083b13b10b7d957c1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192168 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins diff --git a/oox/inc/drawingml/textliststyle.hxx b/oox/inc/drawingml/textliststyle.hxx index 464e48756165..88de4621de13 100644 --- a/oox/inc/drawingml/textliststyle.hxx +++ b/oox/inc/drawingml/textliststyle.hxx @@ -20,6 +20,8 @@ #ifndef INCLUDED_OOX_DRAWINGML_TEXTLISTSTYLE_HXX #define INCLUDED_OOX_DRAWINGML_TEXTLISTSTYLE_HXX +#include <com/sun/star/container/XIndexReplace.hpp> + #include <drawingml/textparagraphproperties.hxx> #include <array> @@ -57,6 +59,10 @@ public: */ bool hasListStyleOnImport() const { return mbHasListStyleOnImport; } + /// Set properties on xNumRules based on maListStyle, for all levels except nIgnoreLevel. + void pushToNumberingRules(const css::uno::Reference<css::container::XIndexReplace>& xNumRules, + size_t nIgnoreLevel); + #ifdef DBG_UTIL void dump() const; #endif diff --git a/oox/inc/drawingml/textparagraphproperties.hxx b/oox/inc/drawingml/textparagraphproperties.hxx index e362119ed6f9..9903c502cba4 100644 --- a/oox/inc/drawingml/textparagraphproperties.hxx +++ b/oox/inc/drawingml/textparagraphproperties.hxx @@ -104,7 +104,8 @@ public: const BulletList* pMasterBuList, bool bApplyBulletList, float fFontSize, - bool bPushDefaultValues = false ) const; + bool bPushDefaultValues = false, + TextListStyle* pTextListStyle = nullptr ) const; /** Returns the largest character size of this paragraph. If possible the masterstyle should have been applied before, otherwise the character diff --git a/oox/qa/unit/data/outliner-list-style.pptx b/oox/qa/unit/data/outliner-list-style.pptx new file mode 100644 index 000000000000..d1d37432e2a6 Binary files /dev/null and b/oox/qa/unit/data/outliner-list-style.pptx differ diff --git a/oox/qa/unit/drawingml.cxx b/oox/qa/unit/drawingml.cxx index 49a037c2cc0f..8b443970f691 100644 --- a/oox/qa/unit/drawingml.cxx +++ b/oox/qa/unit/drawingml.cxx @@ -786,6 +786,40 @@ CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testDOCXVerticalLineRotation) CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nRotateAngle); } +CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testPPTXImportOutlinerListStyleDirectFormat) +{ + // Given a PPTX file with a slide with an outline shape: + // When loading that document: + loadFromFile(u"outliner-list-style.pptx"); + + // Then make sure that the resulting shape has enough numbering rules, so adding a new paragraph + // and increasing indent results in correct behavior of 1499 mm100 / 1.5cm indent: + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xShapeText(xShape->getText(), uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParagraphs = xShapeText->createEnumeration(); + xParagraphs->nextElement(); + uno::Reference<beans::XPropertySet> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xNumberingRules; + xParagraph->getPropertyValue(u"NumberingRules"_ustr) >>= xNumberingRules; + comphelper::SequenceAsHashMap aMap(xNumberingRules->getByIndex(2)); + sal_Int32 nLeftMargin{}; + aMap["LeftMargin"] >>= nLeftMargin; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2388 + // - Actual : 3600 + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2388), nLeftMargin); + sal_Int32 nFirstLineOffset{}; + aMap["FirstLineOffset"] >>= nFirstLineOffset; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: -889 + // - Actual : -800 + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-889), nFirstLineOffset); + // i.e. the sum of these two were 2800, not 1499, the indent was larger than expected. +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/drawingml/textliststyle.cxx b/oox/source/drawingml/textliststyle.cxx index 42679ad4451c..ee695908d48a 100644 --- a/oox/source/drawingml/textliststyle.cxx +++ b/oox/source/drawingml/textliststyle.cxx @@ -19,6 +19,9 @@ #include <drawingml/textliststyle.hxx> #include <sal/log.hxx> +#include <comphelper/sequenceashashmap.hxx> + +using namespace css; namespace oox::drawingml { @@ -66,6 +69,44 @@ void TextListStyle::apply( const TextListStyle& rTextListStyle ) applyStyleList( rTextListStyle.getListStyle(), getListStyle() ); } +void TextListStyle::pushToNumberingRules(const uno::Reference<container::XIndexReplace>& xNumRules, + size_t nIgnoreLevel) +{ + TextParagraphPropertiesArray& rListStyle = getListStyle(); + size_t nLevels = xNumRules->getCount(); + if (rListStyle.size() < nLevels) + { + nLevels = rListStyle.size(); + } + + for (size_t nLevel = 0; nLevel < nLevels; ++nLevel) + { + if (nLevel == nIgnoreLevel) + { + continue; + } + + comphelper::SequenceAsHashMap aMap(xNumRules->getByIndex(nLevel)); + TextParagraphProperties& rLevel = rListStyle[nLevel]; + bool bChanged = false; + if (rLevel.getParaLeftMargin()) + { + aMap["LeftMargin"] <<= *rLevel.getParaLeftMargin(); + bChanged = true; + } + if (rLevel.getFirstLineIndentation()) + { + aMap["FirstLineOffset"] <<= *rLevel.getFirstLineIndentation(); + bChanged = true; + } + + if (bChanged) + { + xNumRules->replaceByIndex(nLevel, aMap.getAsConstAny(true)); + } + } +} + #ifdef DBG_UTIL void TextListStyle::dump() const { diff --git a/oox/source/drawingml/textparagraph.cxx b/oox/source/drawingml/textparagraph.cxx index 60615e6563e0..d256f9d8af64 100644 --- a/oox/source/drawingml/textparagraph.cxx +++ b/oox/source/drawingml/textparagraph.cxx @@ -187,7 +187,7 @@ void TextParagraph::insertAt( } float fCharacterSize = nCharHeight > 0 ? GetFontHeight ( nCharHeight ) : pTextParagraphStyle->getCharHeightPoints( 12 ); - aParaProp.pushToPropSet( &rFilterBase, xProps, aioBulletList, &pTextParagraphStyle->getBulletList(), true, fCharacterSize, true ); + aParaProp.pushToPropSet( &rFilterBase, xProps, aioBulletList, &pTextParagraphStyle->getBulletList(), true, fCharacterSize, true, &aCombinedTextStyle ); } // empty paragraphs do not have bullets in ppt diff --git a/oox/source/drawingml/textparagraphproperties.cxx b/oox/source/drawingml/textparagraphproperties.cxx index 54c1d23c7b1a..44b1e10702da 100644 --- a/oox/source/drawingml/textparagraphproperties.cxx +++ b/oox/source/drawingml/textparagraphproperties.cxx @@ -18,6 +18,7 @@ */ #include <drawingml/textparagraphproperties.hxx> +#include <drawingml/textliststyle.hxx> #include <com/sun/star/text/XNumberingRulesSupplier.hpp> #include <com/sun/star/container/XIndexReplace.hpp> @@ -410,7 +411,7 @@ void TextParagraphProperties::apply( const TextParagraphProperties& rSourceProps void TextParagraphProperties::pushToPropSet( const ::oox::core::XmlFilterBase* pFilterBase, const Reference < XPropertySet >& xPropSet, PropertyMap& rioBulletMap, const BulletList* pMasterBuList, bool bApplyBulletMap, float fCharacterSize, - bool bPushDefaultValues ) const + bool bPushDefaultValues, TextListStyle* pTextListStyle ) const { PropertySet aPropSet( xPropSet ); aPropSet.setProperties( maTextParagraphPropertyMap ); @@ -474,6 +475,13 @@ void TextParagraphProperties::pushToPropSet( const ::oox::core::XmlFilterBase* p rioBulletMap.setProperty<sal_Int16>( PROP_BulletRelSize, 100); Sequence< PropertyValue > aBulletPropSeq = rioBulletMap.makePropertyValueSequence(); xNumRule->replaceByIndex( getLevel(), Any( aBulletPropSeq ) ); + + if (pTextListStyle) + { + // We got the list style of this shape, then set the other levels of the + // numbering rules, too. + pTextListStyle->pushToNumberingRules(xNumRule, getLevel()); + } } aPropSet.setProperty( PROP_NumberingRules, xNumRule );
