tdf#168559 PPTX imp: fix missing list style for outline shapes on master pages
Load oox/qa/unit/data/outliner-list-style.odp into Impress, save as PPTX, load it the PPTX, save the PPTX again (source is now PPTX), open it again, go to the end of the first bullet, enter, tab, indent grows to a large value. What happens is that the PPTX export could write the correct list style for the shape (based on the master page) when the source was ODP, but it can't do the same when the source was PPTX, so after all this a PPTX import problem. Fix this by improving the formatting of the outliner shape on master pages: if the outliner shape was empty, then we don't insert formatted text body, so instead try to format the existing content of the outliner shape, given that such shapes have pre-existing content on the master page. Notes: - Do this only for outliner shapes, CppunitTest_sd_import_tests2's testTdf103792 is a sample that shows doing this for all placeholders on the master page is not correct. - The first line offset is typically negative, but do guard for positive values, otherwise the exported ODP would be invalid, see CppunitTest_sd_export_tests's testTdf128550. - It's possible to have outliner shapes with custom prompt text, which is typically not bulleted, so leave those alone, otherwise we would lose that prompt text, as visible in CppunitTest_sd_export_tests-ooxml4's testCustomPromptTexts. Change-Id: I5b1768a4a4b9cb8494785a38e040dacdf4ab5289 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192270 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
This commit is contained in:
@@ -61,7 +61,7 @@ public:
|
||||
|
||||
/// 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);
|
||||
std::optional<size_t> nIgnoreLevel);
|
||||
|
||||
#ifdef DBG_UTIL
|
||||
void dump() const;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <com/sun/star/util/XTheme.hpp>
|
||||
#include <com/sun/star/drawing/HomogenMatrix3.hpp>
|
||||
#include <com/sun/star/drawing/PointSequenceSequence.hpp>
|
||||
#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
|
||||
|
||||
#include <docmodel/uno/UnoGradientTools.hxx>
|
||||
#include <docmodel/uno/UnoComplexColor.hxx>
|
||||
@@ -786,7 +787,7 @@ CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testDOCXVerticalLineRotation)
|
||||
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nRotateAngle);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testPPTXImportOutlinerListStyleDirectFormat)
|
||||
CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testPPTXImportOutlinerListStyle)
|
||||
{
|
||||
// Given a PPTX file with a slide with an outline shape:
|
||||
// When loading that document:
|
||||
@@ -818,6 +819,27 @@ CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testPPTXImportOutlinerListStyleDirectForm
|
||||
// - 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.
|
||||
|
||||
// Also check that the master slide's outliner has the correct numbering rules:
|
||||
uno::Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier(mxComponent, uno::UNO_QUERY);
|
||||
uno::Reference<drawing::XDrawPage> xMasterPage(
|
||||
xMasterPagesSupplier->getMasterPages()->getByIndex(0), uno::UNO_QUERY);
|
||||
// First would be the title shape.
|
||||
uno::Reference<text::XTextRange> xMasterShape(xMasterPage->getByIndex(1), uno::UNO_QUERY);
|
||||
xShapeText.set(xMasterShape->getText(), uno::UNO_QUERY);
|
||||
xParagraphs = xShapeText->createEnumeration();
|
||||
// As a sample, check the 2nd paragraph's level 3 left margin.
|
||||
xParagraphs->nextElement();
|
||||
xParagraph.set(xParagraphs->nextElement(), uno::UNO_QUERY);
|
||||
xParagraph->getPropertyValue(u"NumberingRules"_ustr) >>= xNumberingRules;
|
||||
aMap = comphelper::SequenceAsHashMap(xNumberingRules->getByIndex(2));
|
||||
nLeftMargin = 0;
|
||||
aMap["LeftMargin"] >>= nLeftMargin;
|
||||
// Without the accompanying fix in place, this test would have failed with:
|
||||
// - Expected: 2388
|
||||
// - Actual : 3600
|
||||
// i.e. the master was wrong, re-export to PPTX could not write the correct numbering rules.
|
||||
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2388), nLeftMargin);
|
||||
}
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
#include <com/sun/star/awt/FontWeight.hpp>
|
||||
#include <com/sun/star/graphic/XGraphic.hpp>
|
||||
#include <com/sun/star/container/XNamed.hpp>
|
||||
#include <com/sun/star/container/XEnumerationAccess.hpp>
|
||||
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
|
||||
#include <com/sun/star/xml/dom/XDocument.hpp>
|
||||
#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
|
||||
@@ -914,6 +915,45 @@ Degree100 lcl_MSORotateAngleToAPIAngle(const sal_Int32 nMSORotationAngle)
|
||||
// API RotateAngle has opposite direction than nMSORotationAngle, thus 'minus'.
|
||||
return NormAngle36000(-nAngle);
|
||||
}
|
||||
|
||||
void PushMasterTextListStyleToMasterShapeParagraphs(TextListStyle& rMasterTextListStyle, const uno::Reference<drawing::XShape>& xShape)
|
||||
{
|
||||
uno::Reference<text::XTextRange> xShapeText(xShape, UNO_QUERY);
|
||||
if (!xShapeText.is())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uno::Reference<container::XEnumerationAccess> xText(xShapeText->getText(), uno::UNO_QUERY);
|
||||
if (!xText.is())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uno::Reference<container::XEnumeration> xParagraphs = xText->createEnumeration();
|
||||
if (!xParagraphs.is())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (xParagraphs->hasMoreElements())
|
||||
{
|
||||
uno::Reference<beans::XPropertySet> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY);
|
||||
if (!xParagraph.is())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uno::Reference<container::XIndexReplace> xNumberingRules;
|
||||
if (!(xParagraph->getPropertyValue("NumberingRules") >>= xNumberingRules))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rMasterTextListStyle.pushToNumberingRules(xNumberingRules, std::nullopt);
|
||||
xParagraph->setPropertyValue("NumberingRules", uno::Any(xNumberingRules));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference< XShape > const & Shape::createAndInsert(
|
||||
@@ -1286,6 +1326,7 @@ Reference< XShape > const & Shape::createAndInsert(
|
||||
}
|
||||
|
||||
Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
|
||||
bool bPlaceholderWithCustomPrompt = pPlaceholder && pPlaceholder->getCustomPrompt();
|
||||
if (xSet.is())
|
||||
{
|
||||
if (bTopWriterLine && !maSize.Width)
|
||||
@@ -2209,6 +2250,13 @@ Reference< XShape > const & Shape::createAndInsert(
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mpTextBody && aServiceName == "com.sun.star.presentation.OutlinerShape"
|
||||
&& mpMasterTextListStyle && !bPlaceholderWithCustomPrompt)
|
||||
{
|
||||
// If mpTextBody is not empty, then the insertAt() above inserts formatted text. If it's
|
||||
// empty, then we format the existing text of the outliner shape here.
|
||||
PushMasterTextListStyleToMasterShapeParagraphs(*mpMasterTextListStyle, mxShape);
|
||||
}
|
||||
else if (mbTextBox)
|
||||
{
|
||||
// No drawingML text, but WPS text is expected: save the theme
|
||||
|
||||
@@ -70,7 +70,7 @@ void TextListStyle::apply( const TextListStyle& rTextListStyle )
|
||||
}
|
||||
|
||||
void TextListStyle::pushToNumberingRules(const uno::Reference<container::XIndexReplace>& xNumRules,
|
||||
size_t nIgnoreLevel)
|
||||
std::optional<size_t> oIgnoreLevel)
|
||||
{
|
||||
TextParagraphPropertiesArray& rListStyle = getListStyle();
|
||||
size_t nLevels = xNumRules->getCount();
|
||||
@@ -81,7 +81,7 @@ void TextListStyle::pushToNumberingRules(const uno::Reference<container::XIndexR
|
||||
|
||||
for (size_t nLevel = 0; nLevel < nLevels; ++nLevel)
|
||||
{
|
||||
if (nLevel == nIgnoreLevel)
|
||||
if (oIgnoreLevel && nLevel == *oIgnoreLevel)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -96,7 +96,14 @@ void TextListStyle::pushToNumberingRules(const uno::Reference<container::XIndexR
|
||||
}
|
||||
if (rLevel.getFirstLineIndentation())
|
||||
{
|
||||
aMap["FirstLineOffset"] <<= *rLevel.getFirstLineIndentation();
|
||||
sal_Int32 nFirstLineIndentation = *rLevel.getFirstLineIndentation();
|
||||
if (nFirstLineIndentation > 0)
|
||||
{
|
||||
// The opposite of this would be exported as <style:list-level-properties
|
||||
// text:min-label-width="..."> to ODF, where negative values are not allowed.
|
||||
nFirstLineIndentation = 0;
|
||||
}
|
||||
aMap["FirstLineOffset"] <<= nFirstLineIndentation;
|
||||
bChanged = true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user