include/xmloff/txtimp.hxx | 3 + sw/source/filter/xml/XMLRedlineImportHelper.cxx | 21 +++++++++++- sw/source/filter/xml/XMLRedlineImportHelper.hxx | 3 + sw/source/filter/xml/xmltexti.cxx | 5 +- sw/source/filter/xml/xmltexti.hxx | 3 + xmloff/qa/unit/data/redline-format-char-props.odt |binary xmloff/qa/unit/text.cxx | 29 ++++++++++++++++- xmloff/source/text/XMLChangedRegionImportContext.cxx | 32 +++++++++++++++++-- xmloff/source/text/XMLChangedRegionImportContext.hxx | 2 + xmloff/source/text/txtimp.cxx | 3 + 10 files changed, 91 insertions(+), 10 deletions(-)
New commits: commit 0e21f3b36cbd12787021c3b8ef439aab9a09efdd Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Aug 18 08:38:09 2025 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Aug 18 13:27:04 2025 +0200 tdf#167761 sw format redline, char props: implement ODF import Load the bugdoc, save as ODF, open the ODF, revert the format redline, the font size should go from 36pt (new direct format) to 24pt (old direct format), but it goes to 12pt (doc default). What happens is that the format redline specifies the old direct format via <text:format-change loext:style-name="..."> (referring to an automatic character style), but this was not handled on import. Fix the problem by: 1) Handling the new attribute in XMLChangedRegionImportContext::createFastChildContext() 2) Looking up the already imported autostyle for the style name in XMLChangedRegionImportContext::SetChangeInfo() 3) Creating a matching SwRedlineExtraData_FormatColl in XMLRedlineImportHelper::InsertIntoDocument() when the format redline is created in sw/ core. Note that this means we have two autostyle names at play, the first is T<number> and the second is effectively a pointer address as a string, like 3cb7b270; FindAutoCharStyle() mapping from the first to the second. Unfortunately both are just string references to the already imported autostyle. Change-Id: Ib0f18bad223f4320afe5aaa11ea713e610f6c029 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189845 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/include/xmloff/txtimp.hxx b/include/xmloff/txtimp.hxx index e97d0dfac7b3..cb9b44145049 100644 --- a/include/xmloff/txtimp.hxx +++ b/include/xmloff/txtimp.hxx @@ -382,7 +382,8 @@ public: /// move id, to find other parts (moveFrom/MoveTo) const OUString& rMoveId, /// merge last paras - bool bMergeLastParagraph); + bool bMergeLastParagraph, + const OUString& rAutoStyleName); virtual css::uno::Reference< css::text::XTextCursor> RedlineCreateText( /// needed to get the document diff --git a/sw/source/filter/xml/XMLRedlineImportHelper.cxx b/sw/source/filter/xml/XMLRedlineImportHelper.cxx index 5eac6501fe25..faece01160a8 100644 --- a/sw/source/filter/xml/XMLRedlineImportHelper.cxx +++ b/sw/source/filter/xml/XMLRedlineImportHelper.cxx @@ -43,6 +43,7 @@ #include <o3tl/any.hxx> #include <xmloff/xmltoken.hxx> #include <vcl/svapp.hxx> +#include <istyleaccess.hxx> using namespace ::com::sun::star; using namespace ::com::sun::star::uno; @@ -190,6 +191,7 @@ public: util::DateTime aDateTime; // change DateTime OUString sMovedID; // change move id string bool bMergeLastParagraph; // the SwRangeRedline::IsDelLastPara flag + OUString m_aAutoStyleName; // each position can may be either empty, an XTextRange, or an SwNodeIndex @@ -371,7 +373,8 @@ void XMLRedlineImportHelper::Add( const OUString& rComment, const util::DateTime& rDateTime, const OUString& rMovedID, - bool bMergeLastPara) + bool bMergeLastPara, + const OUString& rAutoStyleName) { // we need to do the following: // 1) parse type string @@ -410,6 +413,7 @@ void XMLRedlineImportHelper::Add( pInfo->aDateTime = rDateTime; pInfo->sMovedID = rMovedID; pInfo->bMergeLastParagraph = bMergeLastPara; + pInfo->m_aAutoStyleName = rAutoStyleName; //reserve MoveID so it won't be reused by others if (!rMovedID.isEmpty()) @@ -789,6 +793,21 @@ void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo) SAL_WARN("sw", "Recursive change tracking"); } + // Create the redline's extra data if we have a matching autostyle. + if (!pRedlineInfo->m_aAutoStyleName.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); + } + } + // set redline mode (without doing the associated book-keeping) pDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern(RedlineFlags::On); pDoc->getIDocumentRedlineAccess().AppendRedline(pRedline, false); diff --git a/sw/source/filter/xml/XMLRedlineImportHelper.hxx b/sw/source/filter/xml/XMLRedlineImportHelper.hxx index 63d34d405f62..17228eaed57b 100644 --- a/sw/source/filter/xml/XMLRedlineImportHelper.hxx +++ b/sw/source/filter/xml/XMLRedlineImportHelper.hxx @@ -81,7 +81,8 @@ public: const OUString& rComment, // redline comment const css::util::DateTime& rDateTime, // date+time const OUString& rMovedID, // redline move id - bool bMergeLastParagraph); // merge last paragraph? + bool bMergeLastParagraph, // merge last paragraph? + const OUString& rAutoStyleName); // 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 0005c2f0712c..1baa124fb6df 100644 --- a/sw/source/filter/xml/xmltexti.cxx +++ b/sw/source/filter/xml/xmltexti.cxx @@ -925,13 +925,14 @@ void SwXMLTextImportHelper::RedlineAdd( const OUString& rComment, const util::DateTime& rDateTime, const OUString& rMovedID, - bool bMergeLastPara) + bool bMergeLastPara, + const OUString& rAutoStyleName) { // 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); + bMergeLastPara, rAutoStyleName); } uno::Reference<XTextCursor> SwXMLTextImportHelper::RedlineCreateText( diff --git a/sw/source/filter/xml/xmltexti.hxx b/sw/source/filter/xml/xmltexti.hxx index 886ce4c7ac1c..ccb06a53ac22 100644 --- a/sw/source/filter/xml/xmltexti.hxx +++ b/sw/source/filter/xml/xmltexti.hxx @@ -91,7 +91,8 @@ public: const OUString& rComment, /// redline comment const css::util::DateTime& rDateTime, /// date+time const OUString& rMovedID, /// redline move id, to find moveFrom/MoveTo parts - bool bMergeLastPara) override; /// merge last paragraph + bool bMergeLastPara, /// merge last paragraph + const OUString& rAutoStyleName) 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/qa/unit/data/redline-format-char-props.odt b/xmloff/qa/unit/data/redline-format-char-props.odt new file mode 100644 index 000000000000..3d6a63c9f622 Binary files /dev/null and b/xmloff/qa/unit/data/redline-format-char-props.odt differ diff --git a/xmloff/qa/unit/text.cxx b/xmloff/qa/unit/text.cxx index 798e311be507..a6a90f0587c9 100644 --- a/xmloff/qa/unit/text.cxx +++ b/xmloff/qa/unit/text.cxx @@ -21,6 +21,7 @@ #include <com/sun/star/drawing/XDrawPageSupplier.hpp> #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> #include <com/sun/star/text/XTextFramesSupplier.hpp> +#include <com/sun/star/text/XTextViewCursorSupplier.hpp> #include <comphelper/propertysequence.hxx> #include <comphelper/propertyvalue.hxx> @@ -1307,7 +1308,7 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDeleteThenFormatOdtExport) assertXPath(pXmlDoc, "//text:tracked-changes/text:changed-region[2]/text:deletion/text:p"); } -CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testRedlineFormatCharProps) +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testRedlineFormatCharPropsExport) { // Given a document with a format redline, the redline contains the old char props: loadFromFile(u"redline-format-char-props.docx"); @@ -1326,6 +1327,32 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testRedlineFormatCharProps) CPPUNIT_ASSERT(!aStyleName.isEmpty()); } +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testRedlineFormatCharPropsImport) +{ + // Given a document with a format redline, the redline contains the old char props: + loadFromFile(u"redline-format-char-props.odt"); + + // When rejecting the format redline: + dispatchCommand(mxComponent, u".uno:NextTrackedChange"_ustr, {}); + dispatchCommand(mxComponent, u".uno:RejectTrackedChange"_ustr, {}); + + // Then make sure the old direct format is restored, not the doc default: + uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY); + CPPUNIT_ASSERT(xModel.is()); + uno::Reference<text::XTextViewCursorSupplier> xController(xModel->getCurrentController(), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xController.is()); + uno::Reference<beans::XPropertySet> xViewCursor(xController->getViewCursor(), uno::UNO_QUERY); + CPPUNIT_ASSERT(xViewCursor.is()); + float fCharheight{}; + xViewCursor->getPropertyValue(u"CharHeight"_ustr) >>= fCharheight; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 24 + // - Actual : 12 + // i.e. the font size was the doc default, not the old direct format. + CPPUNIT_ASSERT_EQUAL(24.f, fCharheight); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangedRegionImportContext.cxx b/xmloff/source/text/XMLChangedRegionImportContext.cxx index 9b0ecbc4b866..b29980528ff2 100644 --- a/xmloff/source/text/XMLChangedRegionImportContext.cxx +++ b/xmloff/source/text/XMLChangedRegionImportContext.cxx @@ -29,6 +29,7 @@ #include <xmloff/xmlimp.hxx> #include <xmloff/xmlnamespace.hxx> #include <xmloff/xmltoken.hxx> +#include <xmloff/prstylei.hxx> using namespace ::xmloff::token; @@ -85,7 +86,7 @@ void XMLChangedRegionImportContext::startFastElement( } css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChangedRegionImportContext::createFastChildContext( - sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) { SvXMLImportContextRef xContext; @@ -96,6 +97,19 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChangedRegionImport nElement == XML_ELEMENT(TEXT, XML_DELETION) || nElement == XML_ELEMENT(TEXT, XML_FORMAT_CHANGE) ) { + // Parse attributes, e.g. <text:format-change loext:style-name="...">. + for (const auto& rAttribute : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (rAttribute.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_STYLE_NAME): + m_aAutoStyleName = rAttribute.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", rAttribute); + } + } + // create XMLChangeElementImportContext for all kinds of changes xContext = new XMLChangeElementImportContext( GetImport(), @@ -141,11 +155,25 @@ void XMLChangedRegionImportContext::SetChangeInfo( std::u16string_view rDate, const OUString& rMovedID) { + // If the format redline has an autostyle, look up the internal 'auto name'. + OUString aAutoName; + if (!m_aAutoStyleName.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); + if (pStyle) + { + pStyle->GetAutoName() >>= aAutoName; + } + } + util::DateTime aDateTime; if (::sax::Converter::parseDateTime(aDateTime, rDate)) { GetImport().GetTextImport()->RedlineAdd( - rType, sID, rAuthor, rComment, aDateTime, rMovedID, bMergeLastPara); + rType, sID, rAuthor, rComment, aDateTime, rMovedID, bMergeLastPara, aAutoName); } } diff --git a/xmloff/source/text/XMLChangedRegionImportContext.hxx b/xmloff/source/text/XMLChangedRegionImportContext.hxx index 6a4c924c095f..e12a9298597f 100644 --- a/xmloff/source/text/XMLChangedRegionImportContext.hxx +++ b/xmloff/source/text/XMLChangedRegionImportContext.hxx @@ -46,6 +46,8 @@ class XMLChangedRegionImportContext : public SvXMLImportContext /// merge-last-paragraph flag bool bMergeLastPara; + OUString m_aAutoStyleName; + public: diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx index d79d3fc1c4d6..5eff96a8ad0d 100644 --- a/xmloff/source/text/txtimp.cxx +++ b/xmloff/source/text/txtimp.cxx @@ -2327,7 +2327,8 @@ void XMLTextImportHelper::RedlineAdd( const OUString& /*rType*/, const OUString& /*rComment*/, const util::DateTime& /*rDateTime*/, const OUString& /*rMovedID*/, - bool /*bMergeLastPara*/) + bool /*bMergeLastPara*/, + const OUString& /*rAutoStyleName*/) { // dummy implementation: do nothing }