oox/source/ppt/slidepersist.cxx | 12 +++-- sd/qa/unit/data/pptx/tdf152434.pptx |binary sd/qa/unit/import-tests.cxx | 13 +++++ sw/qa/core/unocore/data/paragraph-marker.docx |binary sw/qa/core/unocore/unocore.cxx | 19 ++++++++ sw/qa/extras/ooxmlexport/ooxmlexport2.cxx | 3 - sw/source/core/inc/unoport.hxx | 7 ++- sw/source/core/unocore/unoobj.cxx | 7 ++- sw/source/core/unocore/unoport.cxx | 57 ++++++++++++++++++++++---- sw/source/core/unocore/unoportenum.cxx | 5 ++ 10 files changed, 107 insertions(+), 16 deletions(-)
New commits: commit 6249858a8972aef077e0249bd93cfe8f01bce4d6 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Dec 19 08:47:18 2022 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Dec 19 11:32:56 2022 +0000 sw: ODT import/export of DOCX's paragraph marker formatting The bugdoc had a numbering, where the paragraph marker was explicitly formatted to a custom sans font, and this font is also used for the numbering portion's font. This was imported from DOCX correctly, but once you save to ODT and reload, the font used in the numbering portion changed from sans to serif, which is incorrect. The reason for this seems to be that earlier 5ba30f588d6e41a13d68b1461345fca7a7ca61ac (tdf#64222 sw: better DOCX import/export of paragraph marker formatting, 2019-09-06) introduced support for storing this paragraph marker formatting in RES_PARATR_LIST_AUTOFMT, but this was lost on ODT export / import. Fix the problem by 1) adding the autostyle to the autostyle pool, so the font gets written when writing automatic char styles 2) extending SwXTextPortion to have a mode where it exposes the RES_PARATR_LIST_AUTOFMT of the current text node and 3) improving lcl_CreatePortions() to expose a trailing empty text portion that works with these properties. This also required adjusting CppunitTest_sw_ooxmlexport2's testFdo64238_b, which explicitly asserted that the format of the paragraph marker is not exposed in the UNO API text portion enumeration. An additional improvement would be to go with a more explicit markup in the ODT output for RES_PARATR_LIST_AUTOFMT, but we would need to decide what name to use there, since currently we call this paragraph marker formatting RES_PARATR_LIST_AUTOFMT / ListAutoFormat, and somewhat confusingly this is primarily about paragraph marker formatting, not lists / numberings (that is just a consequence). Change-Id: I19c7eed19c6fc85c251ef87a5181c0719a0a382c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144447 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/core/unocore/data/paragraph-marker.docx b/sw/qa/core/unocore/data/paragraph-marker.docx new file mode 100644 index 000000000000..8dac2d96c76d Binary files /dev/null and b/sw/qa/core/unocore/data/paragraph-marker.docx differ diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx index d7bccacde173..2b0ed9e21f92 100644 --- a/sw/qa/core/unocore/unocore.cxx +++ b/sw/qa/core/unocore/unocore.cxx @@ -864,6 +864,25 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControls) CPPUNIT_ASSERT_EQUAL(OUString("tag2"), aTag); } +CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testParagraphMarkerODFExport) +{ + // Given a document with a red numbering portion, from the paragraph marker's format: + createSwDoc("paragraph-marker.docx"); + + // When saving that as ODT + reload: + reload("writer8", nullptr); + + // Then make sure that it still has the correct color: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 00ff0000 (COL_LIGHTRED) + // - Actual : ffffffff (COL_AUTO) + // i.e. the custom "red" color was lost as RES_PARATR_LIST_AUTOFMT was not serialized to ODT. + CPPUNIT_ASSERT_EQUAL( + OUString("00ff0000"), + getXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwFieldPortion", "font-color")); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx index 550246983796..5b47a78aa7e6 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx @@ -841,7 +841,8 @@ DECLARE_OOXMLEXPORT_TEST(testFdo64238_b, "fdo64238_b.docx") xRunEnum->nextElement(); numOfRuns++; } - CPPUNIT_ASSERT_EQUAL(sal_Int32(5), numOfRuns); + // "This is the ", "ODD", " [", "LEFT", "] header" and the colored paragraph marker + CPPUNIT_ASSERT_EQUAL(sal_Int32(6), numOfRuns); } DECLARE_OOXMLEXPORT_TEST(testFdo56679, "fdo56679.docx") diff --git a/sw/source/core/inc/unoport.hxx b/sw/source/core/inc/unoport.hxx index 5bdade8eda6e..ff7cb5caaabd 100644 --- a/sw/source/core/inc/unoport.hxx +++ b/sw/source/core/inc/unoport.hxx @@ -76,7 +76,8 @@ enum SwTextPortionType PORTION_ANNOTATION, PORTION_ANNOTATION_END, PORTION_LINEBREAK, - PORTION_CONTENT_CONTROL + PORTION_CONTENT_CONTROL, + PORTION_LIST_AUTOFMT }; class SwXTextPortion : public cppu::WeakImplHelper @@ -123,6 +124,10 @@ private: bool m_bIsCollapsed; + /// Expose the paragraph's RES_PARATR_LIST_AUTOFMT, not the char props of the underlying (empty) + /// text. + bool m_bIsListAutoFormat; + void init(const SwUnoCursor* pPortionCursor); protected: diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx index 4ff691cee980..5edb3e4bbd6f 100644 --- a/sw/source/core/unocore/unoobj.cxx +++ b/sw/source/core/unocore/unoobj.cxx @@ -545,10 +545,13 @@ SwUnoCursorHelper::SetCursorPropertyValue( rPropSet.setPropertyValue(*pEntry, prop.Value, items); } + IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess(); + // Add it to the autostyle pool, needed by the ODT export. + const std::shared_ptr<SfxItemSet> pAutoStyle + = rStyleAccess.getAutomaticStyle(items, IStyleAccess::AUTO_STYLE_CHAR); SwFormatAutoFormat item(RES_PARATR_LIST_AUTOFMT); - // TODO: for ODF export we'd need to add it to the autostyle pool // note: paragraph auto styles have ParaStyleName property for the parent style; character auto styles currently do not because there's a separate hint, but for this it would be a good way to add it in order to export it as style:parent-style-name, see XMLTextParagraphExport::Add() - item.SetStyleHandle(std::make_shared<SfxItemSet>(items)); + item.SetStyleHandle(pAutoStyle); pTextNd->SetAttr(item); } } diff --git a/sw/source/core/unocore/unoport.cxx b/sw/source/core/unocore/unoport.cxx index d0bc33645e4d..2d5e3b17c7a6 100644 --- a/sw/source/core/unocore/unoport.cxx +++ b/sw/source/core/unocore/unoport.cxx @@ -71,9 +71,14 @@ SwXTextPortion::SwXTextPortion( : PROPERTY_MAP_TEXTPORTION_EXTENSIONS)) , m_xParentText(std::move(xParent)) , m_pFrameFormat(nullptr) - , m_ePortionType(eType) + , m_ePortionType(eType != PORTION_LIST_AUTOFMT ? eType : PORTION_TEXT) , m_bIsCollapsed(false) + , m_bIsListAutoFormat(false) { + if (eType == PORTION_LIST_AUTOFMT) + { + m_bIsListAutoFormat = true; + } init( pPortionCursor); } @@ -87,6 +92,7 @@ SwXTextPortion::SwXTextPortion( , m_pFrameFormat(&rFormat) , m_ePortionType(PORTION_FRAME) , m_bIsCollapsed(false) + , m_bIsListAutoFormat(false) { StartListening(rFormat.GetNotifier()); init( pPortionCursor); @@ -103,6 +109,7 @@ SwXTextPortion::SwXTextPortion( , m_pFrameFormat(nullptr) , m_ePortionType( bIsEnd ? PORTION_RUBY_END : PORTION_RUBY_START ) , m_bIsCollapsed(false) + , m_bIsListAutoFormat(false) { if (!bIsEnd) { @@ -370,8 +377,23 @@ void SwXTextPortion::GetPropertyValue( break; default: beans::PropertyState eTemp; - bool bDone = SwUnoCursorHelper::getCursorPropertyValue( - rEntry, *pUnoCursor, &rVal, eTemp ); + bool bDone = false; + if (m_bIsListAutoFormat) + { + SwTextNode* pTextNode = pUnoCursor->GetPointNode().GetTextNode(); + std::shared_ptr<SfxItemSet> pListSet + = pTextNode->GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle(); + if (pListSet) + { + m_pPropSet->getPropertyValue(rEntry, *pListSet, rVal); + bDone = true; + } + } + if (!bDone) + { + bDone = SwUnoCursorHelper::getCursorPropertyValue( + rEntry, *pUnoCursor, &rVal, eTemp ); + } if(!bDone) { if(!pSet) @@ -610,11 +632,30 @@ uno::Sequence< beans::GetDirectPropertyTolerantResult > SwXTextPortion::GetPrope const SfxItemPropertyMap& rPropMap = m_pPropSet->getPropertyMap(); - uno::Sequence< beans::PropertyState > aPropertyStates = - SwUnoCursorHelper::GetPropertyStates( - rUnoCursor, *m_pPropSet, - rPropertyNames, - SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT ); + uno::Sequence< beans::PropertyState > aPropertyStates; + if (m_bIsListAutoFormat) + { + SwTextNode* pTextNode = rUnoCursor.GetPointNode().GetTextNode(); + std::shared_ptr<SfxItemSet> pListSet + = pTextNode->GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle(); + if (pListSet) + { + std::vector<beans::PropertyState> aStates; + for (const auto& rPropertyName : rPropertyNames) + { + aStates.push_back(m_pPropSet->getPropertyState(rPropertyName, *pListSet)); + } + aPropertyStates = comphelper::containerToSequence(aStates); + } + } + if (!aPropertyStates.hasElements()) + { + aPropertyStates = + SwUnoCursorHelper::GetPropertyStates( + rUnoCursor, *m_pPropSet, + rPropertyNames, + SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT ); + } const beans::PropertyState* pPropertyStates = aPropertyStates.getConstArray(); for (sal_Int32 i = 0; i < nProps; ++i) diff --git a/sw/source/core/unocore/unoportenum.cxx b/sw/source/core/unocore/unoportenum.cxx index 3b439d454336..fc0239370eaa 100644 --- a/sw/source/core/unocore/unoportenum.cxx +++ b/sw/source/core/unocore/unoportenum.cxx @@ -1513,6 +1513,11 @@ static void lcl_CreatePortions( // text portion because there may be a hyperlink attribute xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT); } + else if (bAtEnd && !xRef.is() && pTextNode->GetSwAttrSet().HasItem(RES_PARATR_LIST_AUTOFMT)) + { + // We have explicit paragraph marker formatting, export it. + xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_LIST_AUTOFMT); + } else if (bAtEnd && !xRef.is() && pHints) { // See if there is an empty autofmt at the paragraph end. If so, export it, since that commit c3f1ec60569727d8aba50b2f59882e13a8443880 Author: Tibor Nagy <nagy.tib...@nisz.hu> AuthorDate: Mon Dec 12 16:44:07 2022 +0100 Commit: László Németh <nem...@numbertext.org> CommitDate: Mon Dec 19 11:32:48 2022 +0000 tdf#152434 PPTX import: fix lost shapes with connectors Regression from commit eec48130271188cab63665acedbabf1ff5e850a2 "tdf#148926 tdf#151678 PPTX import: position of standard connector - part1". Change-Id: Ib9381403f7c0edf9a06e3d98965067a51b4797d8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144000 Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> diff --git a/oox/source/ppt/slidepersist.cxx b/oox/source/ppt/slidepersist.cxx index 9d2ad58b5be2..c875239aac46 100644 --- a/oox/source/ppt/slidepersist.cxx +++ b/oox/source/ppt/slidepersist.cxx @@ -504,10 +504,14 @@ void SlidePersist::createConnectorShapeConnection() } } } - ConnectorType aConnectorType; - xPropertySet->getPropertyValue("EdgeKind") >>= aConnectorType; - if (aConnectorType == ConnectorType_STANDARD) - lcl_SetEdgeLineValue(xConnector, pIt->second); + uno::Reference<beans::XPropertySetInfo> xPropInfo = xPropertySet->getPropertySetInfo(); + if (xPropInfo->hasPropertyByName("EdgeKind")) + { + ConnectorType aConnectorType; + xPropertySet->getPropertyValue("EdgeKind") >>= aConnectorType; + if (aConnectorType == ConnectorType_STANDARD) + lcl_SetEdgeLineValue(xConnector, pIt->second); + } } } maConnectorShapeId.clear(); diff --git a/sd/qa/unit/data/pptx/tdf152434.pptx b/sd/qa/unit/data/pptx/tdf152434.pptx new file mode 100644 index 000000000000..f0716a92fe1b Binary files /dev/null and b/sd/qa/unit/data/pptx/tdf152434.pptx differ diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx index eb125a46834f..abd21782bf68 100644 --- a/sd/qa/unit/import-tests.cxx +++ b/sd/qa/unit/import-tests.cxx @@ -83,6 +83,7 @@ public: } void testDocumentLayout(); + void testTdf152434(); void testConnectors(); void testTdf150719(); void testTdf149314(); @@ -157,6 +158,7 @@ public: CPPUNIT_TEST_SUITE(SdImportTest); CPPUNIT_TEST(testDocumentLayout); + CPPUNIT_TEST(testTdf152434); CPPUNIT_TEST(testConnectors); CPPUNIT_TEST(testTdf150719); CPPUNIT_TEST(testTdf149314); @@ -338,6 +340,17 @@ void SdImportTest::testDocumentLayout() } } +void SdImportTest::testTdf152434() +{ + createSdImpressDoc("pptx/tdf152434.pptx"); + + SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get()); + CPPUNIT_ASSERT(pXImpressDocument); + SdDrawDocument* pDoc = pXImpressDocument->GetDoc(); + const SdrPage* pPage = pDoc->GetPage(1); + CPPUNIT_ASSERT_EQUAL(size_t(1), pPage->GetObjCount()); +} + void SdImportTest::testConnectors() { createSdImpressDoc("pptx/connectors.pptx");