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 ++
 7 files changed, 86 insertions(+), 12 deletions(-)

New commits:
commit e48bf9b364c520eb68f9a3f962dc640eaa9e6661
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Dec 19 08:47:18 2022 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Jan 3 12:36:53 2023 +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
    (cherry picked from commit 6249858a8972aef077e0249bd93cfe8f01bce4d6)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144491
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144675
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144960
    Tested-by: Miklos Vajna <vmik...@collabora.com>

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 e26e227b059b..58723f829439 100644
--- a/sw/qa/core/unocore/unocore.cxx
+++ b/sw/qa/core/unocore/unocore.cxx
@@ -762,6 +762,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:
+    load(DATA_DIRECTORY, "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, "//Special[@nType='PortionType::Number']/SwFont", 
"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 7e4cce4ce6de..a14b0473ae08 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx
@@ -854,7 +854,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 936bc01e0521..4c0098be8681 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 2a29eb452cb8..94b168768ba9 100644
--- a/sw/source/core/unocore/unoobj.cxx
+++ b/sw/source/core/unocore/unoobj.cxx
@@ -548,10 +548,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 dd44538edbd1..12459c3cf29c 100644
--- a/sw/source/core/unocore/unoport.cxx
+++ b/sw/source/core/unocore/unoport.cxx
@@ -70,9 +70,14 @@ SwXTextPortion::SwXTextPortion(
             :  PROPERTY_MAP_TEXTPORTION_EXTENSIONS))
     , m_xParentText(rParent)
     , 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);
 }
 
@@ -86,6 +91,7 @@ SwXTextPortion::SwXTextPortion(
     , m_pFrameFormat(&rFormat)
     , m_ePortionType(PORTION_FRAME)
     , m_bIsCollapsed(false)
+    , m_bIsListAutoFormat(false)
 {
     StartListening(rFormat.GetNotifier());
     init( pPortionCursor);
@@ -107,6 +113,7 @@ SwXTextPortion::SwXTextPortion(
     , m_pFrameFormat(nullptr)
     , m_ePortionType( bIsEnd ? PORTION_RUBY_END : PORTION_RUBY_START )
     , m_bIsCollapsed(false)
+    , m_bIsListAutoFormat(false)
 {
     init( pPortionCursor);
 
@@ -362,8 +369,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->GetNode().GetTextNode();
+                std::shared_ptr<SfxItemSet> pListSet
+                    = static_cast<const 
SwFormatAutoFormat&>(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)
@@ -598,11 +620,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.GetNode().GetTextNode();
+            std::shared_ptr<SfxItemSet> pListSet
+                = static_cast<const 
SwFormatAutoFormat&>(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 23d5655eb499..40b318a0c6fc 100644
--- a/sw/source/core/unocore/unoportenum.cxx
+++ b/sw/source/core/unocore/unoportenum.cxx
@@ -1504,6 +1504,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

Reply via email to