sw/inc/redline.hxx | 3 - sw/qa/extras/layout/data/CT-formatted-deletion.docx |binary sw/qa/extras/layout/layout2.cxx | 19 ++++++++ sw/source/core/crsr/crstrvl.cxx | 32 +++++++++++++ sw/source/core/doc/docredln.cxx | 5 +- sw/source/core/text/redlnitr.cxx | 46 +++++++++++++++----- vcl/source/gdi/mtfxmldump.cxx | 1 7 files changed, 93 insertions(+), 13 deletions(-)
New commits: commit 9bd50bdd21145199fd4be48e24d1a7b270175fcd Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Thu Feb 20 18:08:33 2025 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Feb 25 17:45:53 2025 +0100 tdf#165322 sw: apply formatting for multiple redlines in SwRedlineItr SwRedlineItr::Seek() assumes that redlines don't overlap, but sometimes they do, at least a ParagraphFormat and a Delete redline can overlap (unsure if that is a good idea) when imported from DOCX. Change-Id: Ic13080bfe8c9910ffef44f3e48d11c7f852427ba Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181961 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit b3567d7e1f08df7c050d3cec86cbb200af558172) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182163 Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> diff --git a/sw/inc/redline.hxx b/sw/inc/redline.hxx index ef7c8129ce6a..2078a57ffa7f 100644 --- a/sw/inc/redline.hxx +++ b/sw/inc/redline.hxx @@ -250,7 +250,8 @@ public: void ShowOriginal(sal_uInt16 nLoop, size_t nMyPos, bool bForced = false); /// Calculates the intersection with text node number nNdIdx. - void CalcStartEnd(SwNodeOffset nNdIdx, sal_Int32& rStart, sal_Int32& rEnd) const; + /// @return true if the entire redline precedes nNdIdx + bool CalcStartEnd(SwNodeOffset nNdIdx, sal_Int32& rStart, sal_Int32& rEnd) const; enum class Invalidation { Add, Remove }; /// Initiate the layout. diff --git a/sw/qa/extras/layout/data/CT-formatted-deletion.docx b/sw/qa/extras/layout/data/CT-formatted-deletion.docx new file mode 100644 index 000000000000..585d7ba27cab Binary files /dev/null and b/sw/qa/extras/layout/data/CT-formatted-deletion.docx differ diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx index f968b10bf698..8c069e76374a 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -677,6 +677,25 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf129357) u"-"_ustr); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf165322) +{ + createSwDoc("CT-formatted-deletion.docx"); + SwDocShell* pShell = getSwDocShell(); + + // Dump the rendering of the first page as an XML file. + std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile(); + MetafileXmlDump dumper; + + xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile); + CPPUNIT_ASSERT(pXmlDoc); + + // paragraph with 2 redlines was not marked as deleted + assertXPath(pXmlDoc, + "//text[text() = 'Nunc viverra imperdiet enim. Fusce est. Vivamus a " + "tellus.']/parent::textarray/preceding-sibling::font[1]", + "strikeout", u"1"_ustr); +} + CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testRedlineNumberInNumbering) { createSwDoc("tdf42748.fodt"); diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx index b16dcb3b1490..f49c74dae574 100644 --- a/sw/source/core/doc/docredln.cxx +++ b/sw/source/core/doc/docredln.cxx @@ -1748,7 +1748,8 @@ void SwRangeRedline::InvalidateRange(Invalidation const eWhy) /** Calculates the start and end position of the intersection rTmp and text node nNdIdx */ -void SwRangeRedline::CalcStartEnd( SwNodeOffset nNdIdx, sal_Int32& rStart, sal_Int32& rEnd ) const +bool SwRangeRedline::CalcStartEnd(SwNodeOffset const nNdIdx, + sal_Int32 & rStart, sal_Int32 & rEnd) const { auto [pRStt, pREnd] = StartEnd(); // SwPosition* if( pRStt->GetNodeIndex() < nNdIdx ) @@ -1767,6 +1768,7 @@ void SwRangeRedline::CalcStartEnd( SwNodeOffset nNdIdx, sal_Int32& rStart, sal_I { rStart = COMPLETE_STRING; rEnd = COMPLETE_STRING; + return true; } } else if( pRStt->GetNodeIndex() == nNdIdx ) @@ -1782,6 +1784,7 @@ void SwRangeRedline::CalcStartEnd( SwNodeOffset nNdIdx, sal_Int32& rStart, sal_I rStart = COMPLETE_STRING; rEnd = COMPLETE_STRING; } + return false; } static void lcl_storeAnnotationMarks(SwDoc& rDoc, const SwPosition* pStt, const SwPosition* pEnd) diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx index a49f6d03dc50..53b9b9641699 100644 --- a/sw/source/core/text/redlnitr.cxx +++ b/sw/source/core/text/redlnitr.cxx @@ -789,7 +789,7 @@ short SwRedlineItr::Seek(SwFont& rFnt, { --nRet; Clear_( &rFnt ); // We go behind the current section - ++m_nAct; // and check the next one +// ++m_nAct; // don't increment, could be in next range too if overlap } else if (nNew < m_nStart) { @@ -809,16 +809,35 @@ short SwRedlineItr::Seek(SwFont& rFnt, m_nStart = COMPLETE_STRING; m_nEnd = COMPLETE_STRING; const SwRedlineTable& rTable = m_rDoc.getIDocumentRedlineAccess().GetRedlineTable(); + ::std::optional<decltype(m_nAct)> oFirstMatch; for ( ; m_nAct < rTable.size() ; ++m_nAct) { - rTable[ m_nAct ]->CalcStartEnd(nNode, m_nStart, m_nEnd); + decltype(m_nStart) nStart; + decltype(m_nEnd) nEnd; + if (rTable[m_nAct]->CalcStartEnd(nNode, nStart, nEnd)) + { // previous redline intersected nNode but this one precedes it + continue; + } - if (nNew < m_nEnd) + // redline table is sorted, but here it's not the complete redlines + assert(m_nStart == COMPLETE_STRING || m_nStart <= nStart); + assert(m_nStart == COMPLETE_STRING || m_nStart <= nEnd); + if (oFirstMatch && nNew < nStart) { - if (nNew >= m_nStart) // only possible candidate + m_nEnd = std::min(m_nEnd, nStart); + break; + } + if (nNew < nEnd) + { + m_nStart = nStart; + m_nEnd = std::min(m_nEnd, nEnd); + if (nStart <= nNew) // there can be a format and another redline... { - m_bOn = true; + if (!oFirstMatch) + { + oFirstMatch.emplace(m_nAct); + } const SwRangeRedline *pRed = rTable[ m_nAct ]; if (m_pSet) @@ -862,13 +881,19 @@ short SwRedlineItr::Seek(SwFont& rFnt, } nWhich = aIter.NextWhich(); } - - ++nRet; } - break; + else + { + break; + } } - m_nStart = COMPLETE_STRING; - m_nEnd = COMPLETE_STRING; + } + + if (oFirstMatch) + { + m_bOn = true; + m_nAct = *oFirstMatch; // rewind + ++nRet; // increment only once per m_nStart/m_nEnd range } } else if (m_eMode == Mode::Hide) @@ -916,6 +941,7 @@ void SwRedlineItr::FillHints( std::size_t nAuthor, RedlineType eType ) break; case RedlineType::Format: case RedlineType::FmtColl: + case RedlineType::ParagraphFormat: SW_MOD()->GetFormatAuthorAttr(nAuthor, *m_pSet); break; default: diff --git a/vcl/source/gdi/mtfxmldump.cxx b/vcl/source/gdi/mtfxmldump.cxx index fda2db24ecb9..7311d8431cf2 100644 --- a/vcl/source/gdi/mtfxmldump.cxx +++ b/vcl/source/gdi/mtfxmldump.cxx @@ -1333,6 +1333,7 @@ void MetafileXmlDump::writeXml(const GDIMetaFile& rMetaFile, tools::XmlWriter& r rWriter.attribute("orientation", aFont.GetOrientation().get()); rWriter.attribute("weight", convertFontWeightToString(aFont.GetWeight())); rWriter.attribute("vertical", aFont.IsVertical() ? "true" : "false"); + rWriter.attribute("strikeout", aFont.GetStrikeout()); rWriter.endElement(); } commit b016c132eed47439fe96a1d9f933f3d6368a9718 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Thu Feb 20 19:00:04 2025 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Feb 25 17:45:40 2025 +0100 tdf#165322 sw: prefer insert/delete redline in mouse-over tooltip Unfortunately SwCursorShell::GetContentAtPos() can only report 1 redline for a given position; in case there is a format and a insert/delete redline at the same position, the latter is more important. This is then used in SwEditWin::RequestHelp() to display a tooltip if the user moves the mouse cursor over a redline. Change-Id: I32af7a154873e3fa5775a711980bb3dab3e307ad Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181960 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit f439448d21ef2feb03a9920d95d30f23795db6ac) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182153 Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx index effc825987c7..ca4538974864 100644 --- a/sw/source/core/crsr/crstrvl.cxx +++ b/sw/source/core/crsr/crstrvl.cxx @@ -1859,10 +1859,40 @@ bool SwCursorShell::GetContentAtPos( const Point& rPt, if( !bRet && IsAttrAtPos::Redline & rContentAtPos.eContentAtPos ) { - const SwRangeRedline* pRedl = GetDoc()->getIDocumentRedlineAccess().GetRedline(aPos, nullptr); + SwRedlineTable::size_type index; + IDocumentRedlineAccess const& rIDRA{GetDoc()->getIDocumentRedlineAccess()}; + const SwRangeRedline* pRedl{rIDRA.GetRedline(aPos, &index)}; if( pRedl ) { + // treat insert/delete as more important than formatting + for (; index < rIDRA.GetRedlineTable().size(); ++index) + { + SwRangeRedline const*const pTmp{rIDRA.GetRedlineTable()[index]}; + if (aPos < *pTmp->Start()) + { + break; + } + switch (pRedl->GetType()) + { + case RedlineType::Format: + case RedlineType::FmtColl: + case RedlineType::ParagraphFormat: + switch (pTmp->GetType()) + { + case RedlineType::Insert: + case RedlineType::Delete: + pRedl = pTmp; + break; + default: + break; + } + break; + default: + break; + } + }; + rContentAtPos.aFnd.pRedl = pRedl; rContentAtPos.eContentAtPos = IsAttrAtPos::Redline; rContentAtPos.pFndTextAttr = nullptr;