include/xmloff/txtimp.hxx                            |    3 -
 sw/qa/filter/xml/data/format-char-style-change.odt   |binary
 sw/qa/filter/xml/xml.cxx                             |   32 ++++++++++++++
 sw/source/filter/xml/XMLRedlineImportHelper.cxx      |   43 ++++++++++++-------
 sw/source/filter/xml/XMLRedlineImportHelper.hxx      |    3 -
 sw/source/filter/xml/xmltexti.cxx                    |    5 +-
 sw/source/filter/xml/xmltexti.hxx                    |    3 -
 xmloff/source/text/XMLChangedRegionImportContext.cxx |   10 ++--
 xmloff/source/text/XMLChangedRegionImportContext.hxx |    2 
 xmloff/source/text/txtimp.cxx                        |    3 -
 10 files changed, 79 insertions(+), 25 deletions(-)

New commits:
commit 5d30325108f80fbb6ac913b42e74a64a7e13bd72
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Aug 21 08:42:03 2025 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Aug 21 19:26:06 2025 +0200

    tdf#167761 sw format redline, char style: implement ODF import
    
    Load the bugdoc, the format redline at the doc end has the Quote char
    style, reverting the redline should result in the Strong char style, but
    results in no character style.
    
    What happens is that XMLChangedRegionImportContext::SetChangeInfo()
    assumed that the style name of the format redline is always an automatic
    style, while it may be a named character style, too.
    
    Fix the problem by splitting the style name into two parts in
    XMLChangedRegionImportContext::SetChangeInfo() (named style, automatic
    style) and then work with that pair in
    XMLRedlineImportHelper::InsertIntoDocument(), similar to how
    XMLTextImportHelper::SetStyleAndAttrs() works for <text:span>'s style
    name.
    
    The ODF export worked already.
    
    Change-Id: I2fa1479a0d2463556e84be566967325584bc14f7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189984
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 0ba6dd9eb3f342345663b12527a29425675d2078)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189995
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/include/xmloff/txtimp.hxx b/include/xmloff/txtimp.hxx
index cb9b44145049..4d290f25327e 100644
--- a/include/xmloff/txtimp.hxx
+++ b/include/xmloff/txtimp.hxx
@@ -383,7 +383,8 @@ public:
             const OUString& rMoveId,
             /// merge last paras
             bool bMergeLastParagraph,
-            const OUString& rAutoStyleName);
+            const OUString& rStyleName,
+            const OUString& rAutoName);
 
     virtual css::uno::Reference< css::text::XTextCursor> RedlineCreateText(
             /// needed to get the document
diff --git a/sw/qa/filter/xml/data/format-char-style-change.odt 
b/sw/qa/filter/xml/data/format-char-style-change.odt
new file mode 100644
index 000000000000..03cddb9eea61
Binary files /dev/null and b/sw/qa/filter/xml/data/format-char-style-change.odt 
differ
diff --git a/sw/qa/filter/xml/xml.cxx b/sw/qa/filter/xml/xml.cxx
index de6d19aafd47..de92d086f482 100644
--- a/sw/qa/filter/xml/xml.cxx
+++ b/sw/qa/filter/xml/xml.cxx
@@ -15,6 +15,8 @@
 #include <docsh.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <redline.hxx>
+#include <wrtsh.hxx>
+#include <fchrfmt.hxx>
 
 namespace
 {
@@ -123,6 +125,36 @@ CPPUNIT_TEST_FIXTURE(Test, testDeleteThenFormatOdtImport)
     CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rInnerRedlineData.GetType());
     CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlines[2]->GetType());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testFormatCharStyleChangeOdtImport)
+{
+    // Given a document with a format redline, containing a char style change 
(strong -> quote):
+    // When importing that document:
+    createSwDoc("format-char-style-change.odt");
+
+    // Then make sure the model has the new style name, the redline has the 
old style name:
+    SwDocShell* pDocShell = getSwDocShell();
+    SwDoc* pDoc = pDocShell->GetDoc();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/false);
+    SfxItemSetFixed<RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT> 
aSet(pDoc->GetAttrPool());
+    pWrtShell->GetCurAttr(aSet);
+    const SwFormatCharFormat& rNewCharFormat = aSet.Get(RES_TXTATR_CHARFMT);
+    CPPUNIT_ASSERT_EQUAL(u"Quote Char"_ustr, 
rNewCharFormat.GetCharFormat()->GetName().toString());
+    const IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess();
+    const SwRedlineTable& rRedlineTable = rIDRA.GetRedlineTable();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlineTable.size());
+    const SwRangeRedline* pRedline = rRedlineTable[0];
+    auto pExtraData = dynamic_cast<const 
SwRedlineExtraData_FormatColl*>(pRedline->GetExtraData());
+    // Without the accompanying fix in place, this test would have failed, the 
format redline didn't
+    // contain the old style name.
+    CPPUNIT_ASSERT(pExtraData);
+    std::shared_ptr<SfxItemSet> pRedlineSet = pExtraData->GetItemSet();
+    CPPUNIT_ASSERT(pRedlineSet);
+    const SwFormatCharFormat& rOldCharFormat = 
pRedlineSet->Get(RES_TXTATR_CHARFMT);
+    CPPUNIT_ASSERT_EQUAL(u"Strong Emphasis"_ustr,
+                         rOldCharFormat.GetCharFormat()->GetName().toString());
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/xml/XMLRedlineImportHelper.cxx 
b/sw/source/filter/xml/XMLRedlineImportHelper.cxx
index faece01160a8..eed1fd273e91 100644
--- a/sw/source/filter/xml/XMLRedlineImportHelper.cxx
+++ b/sw/source/filter/xml/XMLRedlineImportHelper.cxx
@@ -44,6 +44,7 @@
 #include <xmloff/xmltoken.hxx>
 #include <vcl/svapp.hxx>
 #include <istyleaccess.hxx>
+#include <unocrsrhelper.hxx>
 
 using namespace ::com::sun::star;
 using namespace ::com::sun::star::uno;
@@ -191,7 +192,8 @@ public:
     util::DateTime aDateTime;       // change DateTime
     OUString sMovedID;              // change move id string
     bool bMergeLastParagraph;   // the SwRangeRedline::IsDelLastPara flag
-    OUString m_aAutoStyleName;
+    OUString m_aStyleName;
+    OUString m_aAutoName;
 
     // each position can may be either empty, an XTextRange, or an SwNodeIndex
 
@@ -374,7 +376,8 @@ void XMLRedlineImportHelper::Add(
     const util::DateTime& rDateTime,
     const OUString& rMovedID,
     bool bMergeLastPara,
-    const OUString& rAutoStyleName)
+    const OUString& rStyleName,
+    const OUString& rAutoName)
 {
     // we need to do the following:
     // 1) parse type string
@@ -413,7 +416,8 @@ void XMLRedlineImportHelper::Add(
     pInfo->aDateTime = rDateTime;
     pInfo->sMovedID = rMovedID;
     pInfo->bMergeLastParagraph = bMergeLastPara;
-    pInfo->m_aAutoStyleName = rAutoStyleName;
+    pInfo->m_aStyleName = rStyleName;
+    pInfo->m_aAutoName = rAutoName;
 
     //reserve MoveID so it won't be reused by others
     if (!rMovedID.isEmpty())
@@ -794,18 +798,29 @@ void 
XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo)
         }
 
         // Create the redline's extra data if we have a matching autostyle.
-        if (!pRedlineInfo->m_aAutoStyleName.isEmpty())
+        std::shared_ptr<SfxItemSet> pAutoStyle;
+        IStyleAccess& rStyleAccess = pDoc->GetIStyleAccess();
+        if (!pRedlineInfo->m_aStyleName.isEmpty())
         {
-            IStyleAccess& rStyleAccess = pDoc->GetIStyleAccess();
-            std::shared_ptr<SfxItemSet> pAutoStyle = rStyleAccess.getByName(
-                pRedlineInfo->m_aAutoStyleName, IStyleAccess::AUTO_STYLE_CHAR);
-            if (pAutoStyle)
-            {
-                sal_uInt16 nPoolFormatId = USHRT_MAX;
-                SwRedlineExtraData_FormatColl aExtraData(UIName(u""_ustr), 
nPoolFormatId, pAutoStyle);
-                // aExtraData is copied here.
-                pRedline->SetExtraData(&aExtraData);
-            }
+            // Named character style.
+            SfxItemSetFixed<RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT> 
aItemSet(pDoc->GetAttrPool());
+            uno::Any aStyleName;
+            aStyleName <<= pRedlineInfo->m_aStyleName;
+            SwUnoCursorHelper::SetCharStyle(*pDoc, aStyleName, aItemSet);
+            pAutoStyle = rStyleAccess.getAutomaticStyle(aItemSet, 
IStyleAccess::AUTO_STYLE_CHAR);
+        }
+        else if (!pRedlineInfo->m_aAutoName.isEmpty())
+        {
+            // Just a set of character properties with an automatic name.
+            pAutoStyle
+                = rStyleAccess.getByName(pRedlineInfo->m_aAutoName, 
IStyleAccess::AUTO_STYLE_CHAR);
+        }
+        if (pAutoStyle)
+        {
+            sal_uInt16 nPoolFormatId = USHRT_MAX;
+            SwRedlineExtraData_FormatColl aExtraData(UIName(u""_ustr), 
nPoolFormatId, pAutoStyle);
+            // aExtraData is copied here.
+            pRedline->SetExtraData(&aExtraData);
         }
 
         // set redline mode (without doing the associated book-keeping)
diff --git a/sw/source/filter/xml/XMLRedlineImportHelper.hxx 
b/sw/source/filter/xml/XMLRedlineImportHelper.hxx
index 17228eaed57b..c89e76a89fb2 100644
--- a/sw/source/filter/xml/XMLRedlineImportHelper.hxx
+++ b/sw/source/filter/xml/XMLRedlineImportHelper.hxx
@@ -82,7 +82,8 @@ public:
         const css::util::DateTime& rDateTime, // date+time
         const OUString& rMovedID,     // redline move id
         bool bMergeLastParagraph, // merge last paragraph?
-        const OUString& rAutoStyleName);
+        const OUString& rStyleName,
+        const OUString& rAutoName);
 
     // create a text section for the redline, and return an
     // XText/XTextCursor that may be used to write into it.
diff --git a/sw/source/filter/xml/xmltexti.cxx 
b/sw/source/filter/xml/xmltexti.cxx
index 1baa124fb6df..d4acb5fd6940 100644
--- a/sw/source/filter/xml/xmltexti.cxx
+++ b/sw/source/filter/xml/xmltexti.cxx
@@ -926,13 +926,14 @@ void SwXMLTextImportHelper::RedlineAdd(
     const util::DateTime& rDateTime,
     const OUString& rMovedID,
     bool bMergeLastPara,
-    const OUString& rAutoStyleName)
+    const OUString& rStyleName,
+    const OUString& rAutoName)
 {
     // create redline helper on demand
     OSL_ENSURE(nullptr != m_pRedlineHelper, "helper should have been created 
in constructor");
     if (nullptr != m_pRedlineHelper)
         m_pRedlineHelper->Add(rType, rId, rAuthor, rComment, rDateTime, 
rMovedID,
-                            bMergeLastPara, rAutoStyleName);
+                            bMergeLastPara, rStyleName, rAutoName);
 }
 
 uno::Reference<XTextCursor> SwXMLTextImportHelper::RedlineCreateText(
diff --git a/sw/source/filter/xml/xmltexti.hxx 
b/sw/source/filter/xml/xmltexti.hxx
index ccb06a53ac22..303b7131cf4a 100644
--- a/sw/source/filter/xml/xmltexti.hxx
+++ b/sw/source/filter/xml/xmltexti.hxx
@@ -92,7 +92,8 @@ public:
         const css::util::DateTime& rDateTime,  /// date+time
         const OUString& rMovedID,    /// redline move id, to find 
moveFrom/MoveTo parts
         bool bMergeLastPara,         /// merge last paragraph
-        const OUString& rAutoStyleName) override;
+        const OUString& rStyleName,
+        const OUString& rAutoName) override;
     virtual css::uno::Reference<css::text::XTextCursor> RedlineCreateText(
             css::uno::Reference<css::text::XTextCursor> & rOldCursor, /// 
needed to get the document
             const OUString& rId) override;    /// ID used to RedlineAdd() call
diff --git a/xmloff/source/text/XMLChangedRegionImportContext.cxx 
b/xmloff/source/text/XMLChangedRegionImportContext.cxx
index b29980528ff2..d3ee8e336168 100644
--- a/xmloff/source/text/XMLChangedRegionImportContext.cxx
+++ b/xmloff/source/text/XMLChangedRegionImportContext.cxx
@@ -103,7 +103,7 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > 
XMLChangedRegionImport
             switch (rAttribute.getToken())
             {
                 case XML_ELEMENT(LO_EXT, XML_STYLE_NAME):
-                    m_aAutoStyleName = rAttribute.toString();
+                    m_aStyleName = rAttribute.toString();
                     break;
                 default:
                     XMLOFF_WARN_UNKNOWN("xmloff", rAttribute);
@@ -157,15 +157,17 @@ void XMLChangedRegionImportContext::SetChangeInfo(
 {
     // If the format redline has an autostyle, look up the internal 'auto 
name'.
     OUString aAutoName;
-    if (!m_aAutoStyleName.isEmpty())
+    if (!m_aStyleName.isEmpty())
     {
         rtl::Reference<XMLTextImportHelper> xHelper = 
GetImport().GetTextImport();
         // Map the XML-level automatic style name (e.g. T1) to an 'auto name' 
that exists in the
         // char auto style pool (e.g. 3cb7b270).
-        XMLPropStyleContext* pStyle = 
xHelper->FindAutoCharStyle(m_aAutoStyleName);
+        XMLPropStyleContext* pStyle = xHelper->FindAutoCharStyle(m_aStyleName);
+        // Split m_aStyleName into a named character style and an autostyle.
         if (pStyle)
         {
             pStyle->GetAutoName() >>= aAutoName;
+            m_aStyleName = pStyle->GetParentName();
         }
     }
 
@@ -173,7 +175,7 @@ void XMLChangedRegionImportContext::SetChangeInfo(
     if (::sax::Converter::parseDateTime(aDateTime, rDate))
     {
         GetImport().GetTextImport()->RedlineAdd(
-            rType, sID, rAuthor, rComment, aDateTime, rMovedID, 
bMergeLastPara, aAutoName);
+            rType, sID, rAuthor, rComment, aDateTime, rMovedID, 
bMergeLastPara, m_aStyleName, aAutoName);
     }
 }
 
diff --git a/xmloff/source/text/XMLChangedRegionImportContext.hxx 
b/xmloff/source/text/XMLChangedRegionImportContext.hxx
index e12a9298597f..60362cbf3e1a 100644
--- a/xmloff/source/text/XMLChangedRegionImportContext.hxx
+++ b/xmloff/source/text/XMLChangedRegionImportContext.hxx
@@ -46,7 +46,7 @@ class XMLChangedRegionImportContext : public 
SvXMLImportContext
     /// merge-last-paragraph flag
     bool bMergeLastPara;
 
-    OUString m_aAutoStyleName;
+    OUString m_aStyleName;
 
 public:
 
diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx
index 4415fde16a25..339872247fd5 100644
--- a/xmloff/source/text/txtimp.cxx
+++ b/xmloff/source/text/txtimp.cxx
@@ -2329,7 +2329,8 @@ void XMLTextImportHelper::RedlineAdd( const OUString& 
/*rType*/,
                                       const util::DateTime& /*rDateTime*/,
                                       const OUString& /*rMovedID*/,
                                       bool /*bMergeLastPara*/,
-                                      const OUString& /*rAutoStyleName*/)
+                                      const OUString& /*rStyleName*/,
+                                      const OUString& /*rAutoName*/)
 {
     // dummy implementation: do nothing
 }

Reply via email to