sw/qa/filter/xml/data/delete-then-format.odt |binary sw/qa/filter/xml/xml.cxx | 24 ++++++++++++++++++++ sw/source/filter/xml/XMLRedlineImportHelper.cxx | 28 ++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 2 deletions(-)
New commits: commit 277ec361442413cfc50e73ab134e31f067d9cfb3 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed May 21 09:16:38 2025 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Wed May 21 09:57:00 2025 +0200 tdf#166319 sw interdependent redlines: handle ODF import of delete under format The bugdoc has <del>AA<format>BB</format>CC</del> in it, ODT import created a model that contains <del>AACC</del> instead, i.e. the format-on-delete part was lost. The first problem was that XMLRedlineImportHelper::ConvertRedline() rejected the format-on-delete, fixing the used CanCombineTypesForImport() resulted in a format-on-delete redline that was in the document, but the order was wrong: BBAACC (matching the order in the file, since deletions are listed separately, before the body text). The second problem was that XMLRedlineImportHelper::InsertIntoDocument() didn't consider format-on-delete when it looked for deletions: fixing that results in the wanted AABBCC string in the document model. With this, the ODF import/export for ins-then-del, ins-then-fmt & del-then-fmt should work. Change-Id: I7bcdd4d7452d9bca0ff31ce99cbc29795eb63fa5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185588 Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/sw/qa/filter/xml/data/delete-then-format.odt b/sw/qa/filter/xml/data/delete-then-format.odt new file mode 100644 index 000000000000..70d531912b58 Binary files /dev/null and b/sw/qa/filter/xml/data/delete-then-format.odt differ diff --git a/sw/qa/filter/xml/xml.cxx b/sw/qa/filter/xml/xml.cxx index 472f01bbc410..de6d19aafd47 100644 --- a/sw/qa/filter/xml/xml.cxx +++ b/sw/qa/filter/xml/xml.cxx @@ -99,6 +99,30 @@ CPPUNIT_TEST_FIXTURE(Test, testInsertThenFormatOdtImport) CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rInnerRedlineData.GetType()); CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rRedlines[2]->GetType()); } + +CPPUNIT_TEST_FIXTURE(Test, testDeleteThenFormatOdtImport) +{ + // Given a document with <del>A<format>B</format>C</del> style redlines: + // When importing that document: + createSwDoc("delete-then-format.odt"); + + // Then make sure that both the delete and the format on top of it is in the model: + SwDoc* pDoc = getSwDocShell()->GetDoc(); + IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess(); + SwRedlineTable& rRedlines = rIDRA.GetRedlineTable(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 3 + // - Actual : 2 + // i.e. there was an empty format redline at doc start and a delete redline for "AC". + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), rRedlines.size()); + CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlines[0]->GetType()); + const SwRedlineData& rRedlineData1 = rRedlines[1]->GetRedlineData(0); + CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedlineData1.GetType()); + CPPUNIT_ASSERT(rRedlineData1.Next()); + const SwRedlineData& rInnerRedlineData = *rRedlineData1.Next(); + CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rInnerRedlineData.GetType()); + CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlines[2]->GetType()); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/xml/XMLRedlineImportHelper.cxx b/sw/source/filter/xml/XMLRedlineImportHelper.cxx index 7850e61ce881..5eac6501fe25 100644 --- a/sw/source/filter/xml/XMLRedlineImportHelper.cxx +++ b/sw/source/filter/xml/XMLRedlineImportHelper.cxx @@ -640,6 +640,23 @@ static auto RecursiveContains(SwStartNode const& rRedlineSection, SwNode const& return false; } +namespace +{ +/// Similar to GetRedlineTypeIgnoringAdditonalFormat(), but for import purposes. +RedlineType GetRedlineTypeIgnoringAdditonalFormatForImport(RedlineInfo& rRedlineInfo) +{ + RedlineType eType = rRedlineInfo.eType; + + if (eType == RedlineType::Format && rRedlineInfo.pNextRedline + && rRedlineInfo.pNextRedline->eType == RedlineType::Delete) + { + eType = RedlineType::Delete; + } + + return eType; +} +} + void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo) { assert(pRedlineInfo && "need redline info"); @@ -741,7 +758,8 @@ void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo) // the already inserted redlines temporarily and inserting them back in reverse // order after inserting pRedline std::vector<const SwRangeRedline*> aSwapRedlines; - if ( RedlineType::Delete == pRedlineInfo->eType ) + // Move both delete and format-on-delete redlines to aSwapRedlines. + if (GetRedlineTypeIgnoringAdditonalFormatForImport(*pRedlineInfo) == RedlineType::Delete) { SwRedlineTable::size_type n = 0; while ( const SwRangeRedline* pRedline2 = @@ -793,13 +811,19 @@ bool CanCombineTypesForImport(RedlineInfo* pRedlineInfo) return false; } + RedlineType eOuterType = pRedlineInfo->eType; RedlineType eInnerType = pRedlineInfo->pNextRedline->eType; + if (eInnerType == RedlineType::Delete) + { + // Delete can only have format on it. + return eOuterType == RedlineType::Format; + } + if (eInnerType != RedlineType::Insert) { return false; } - RedlineType eOuterType = pRedlineInfo->eType; switch (eOuterType) { case RedlineType::Delete: