diff options
Diffstat (limited to 'sw/source/core/text/redlnitr.cxx')
-rw-r--r-- | sw/source/core/text/redlnitr.cxx | 205 |
1 files changed, 144 insertions, 61 deletions
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx index b6cbb86bbeb3..afa87aba0963 100644 --- a/sw/source/core/text/redlnitr.cxx +++ b/sw/source/core/text/redlnitr.cxx @@ -37,7 +37,7 @@ #include <IDocumentLayoutAccess.hxx> #include <IDocumentMarkAccess.hxx> #include <IMark.hxx> -#include <bookmrk.hxx> +#include <bookmark.hxx> #include <rootfrm.hxx> #include <breakit.hxx> #include <vcl/commandevent.hxx> @@ -47,6 +47,12 @@ #include <vcl/svapp.hxx> #include "redlnitr.hxx" #include <extinput.hxx> +#include <fmtpdsc.hxx> +#include <editeng/charhiddenitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/formatbreakitem.hxx> +#include <editeng/udlnitem.hxx> using namespace ::com::sun::star; @@ -59,12 +65,15 @@ private: IDocumentMarkAccess const& m_rIDMA; bool const m_isHideRedlines; sw::FieldmarkMode const m_eFieldmarkMode; + bool const m_isHideParagraphBreaks; SwPosition const m_Start; /// next redline SwRedlineTable::size_type m_RedlineIndex; /// next fieldmark - std::pair<sw::mark::IFieldmark const*, std::unique_ptr<SwPosition>> m_Fieldmark; + std::pair<sw::mark::IFieldmark const*, std::optional<SwPosition>> m_Fieldmark; std::optional<SwPosition> m_oNextFieldmarkHide; + /// previous paragraph break - because m_pStartPos/EndPos are non-owning + std::optional<std::pair<SwPosition, SwPosition>> m_oParagraphBreak; /// current start/end pair SwPosition const* m_pStartPos; SwPosition const* m_pEndPos; @@ -74,13 +83,15 @@ public: SwPosition const* GetEndPos() const { return m_pEndPos; } HideIterator(SwTextNode & rTextNode, - bool const isHideRedlines, sw::FieldmarkMode const eMode) + bool const isHideRedlines, sw::FieldmarkMode const eMode, + sw::ParagraphBreakMode const ePBMode) : m_rIDRA(rTextNode.getIDocumentRedlineAccess()) , m_rIDMA(*rTextNode.getIDocumentMarkAccess()) , m_isHideRedlines(isHideRedlines) , m_eFieldmarkMode(eMode) + , m_isHideParagraphBreaks(ePBMode == sw::ParagraphBreakMode::Hidden) , m_Start(rTextNode, 0) - , m_RedlineIndex(m_rIDRA.GetRedlinePos(rTextNode, RedlineType::Any)) + , m_RedlineIndex(isHideRedlines ? m_rIDRA.GetRedlinePos(rTextNode, RedlineType::Any) : SwRedlineTable::npos) , m_pStartPos(nullptr) , m_pEndPos(&m_Start) { @@ -101,22 +112,21 @@ public: { SwRangeRedline const*const pRed = m_rIDRA.GetRedlineTable()[m_RedlineIndex]; - if (m_pEndPos->nNode.GetIndex() < pRed->Start()->nNode.GetIndex()) + if (m_pEndPos->GetNodeIndex() < pRed->Start()->GetNodeIndex()) break; if (pRed->GetType() != RedlineType::Delete) continue; - SwPosition const*const pStart(pRed->Start()); - SwPosition const*const pEnd(pRed->End()); + auto [pStart, pEnd] = pRed->StartEnd(); // SwPosition* if (*pStart == *pEnd) { // only allowed while moving (either way?) // assert(IDocumentRedlineAccess::IsHideChanges(rIDRA.GetRedlineFlags())); continue; } - if (pStart->nNode.GetNode().IsTableNode()) + if (pStart->GetNode().IsTableNode()) { - assert(pEnd->nNode == m_Start.nNode && pEnd->nContent.GetIndex() == 0); + assert(pEnd->GetNode() == m_Start.GetNode() && pEnd->GetContentIndex() == 0); continue; // known pathology, ignore it } if (*m_pEndPos <= *pStart) @@ -134,16 +144,16 @@ public: sal_Unicode const magic(m_eFieldmarkMode == sw::FieldmarkMode::ShowResult ? CH_TXT_ATR_FIELDSTART : CH_TXT_ATR_FIELDSEP); - SwTextNode* pTextNode = m_pEndPos->nNode.GetNode().GetTextNode(); + SwTextNode* pTextNode = m_pEndPos->GetNode().GetTextNode(); sal_Int32 const nPos = pTextNode ? pTextNode->GetText().indexOf( - magic, m_pEndPos->nContent.GetIndex()) : -1; + magic, m_pEndPos->GetContentIndex()) : -1; if (nPos != -1) { m_oNextFieldmarkHide.emplace(*pTextNode, nPos); sw::mark::IFieldmark const*const pFieldmark( m_eFieldmarkMode == sw::FieldmarkMode::ShowResult ? m_rIDMA.getFieldmarkAt(*m_oNextFieldmarkHide) - : m_rIDMA.getFieldmarkFor(*m_oNextFieldmarkHide)); + : m_rIDMA.getInnerFieldmarkFor(*m_oNextFieldmarkHide)); assert(pFieldmark); m_Fieldmark.first = pFieldmark; // for cursor travelling, there should be 2 visible chars; @@ -152,16 +162,15 @@ public: // always hide the CH_TXT_ATR_FIELDSEP for now if (m_eFieldmarkMode == sw::FieldmarkMode::ShowResult) { - m_Fieldmark.second.reset( - new SwPosition(sw::mark::FindFieldSep(*m_Fieldmark.first))); - ++m_Fieldmark.second->nContent; - ++m_oNextFieldmarkHide->nContent; // skip start + m_Fieldmark.second.emplace( + sw::mark::FindFieldSep(*m_Fieldmark.first)); + m_Fieldmark.second->AdjustContent(+1); + m_oNextFieldmarkHide->AdjustContent(+1); // skip start } else { - m_Fieldmark.second.reset( - new SwPosition(pFieldmark->GetMarkEnd())); - --m_Fieldmark.second->nContent; + m_Fieldmark.second.emplace(pFieldmark->GetMarkEnd()); + m_Fieldmark.second->AdjustContent(-1); } } } @@ -184,15 +193,69 @@ public: { assert(!pNextRedlineHide || *m_oNextFieldmarkHide <= *pNextRedlineHide); m_pStartPos = &*m_oNextFieldmarkHide; - m_pEndPos = m_Fieldmark.second.get(); + m_pEndPos = &*m_Fieldmark.second; return true; } - else // nothing + else { assert(!pNextRedlineHide && !m_oNextFieldmarkHide); - m_pStartPos = nullptr; - m_pEndPos = nullptr; - return false; + auto const hasHiddenItem = [](auto const& rNode) { + auto const& rpSet(rNode.GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle()); + return rpSet ? rpSet->Get(RES_CHRATR_HIDDEN).GetValue() : false; + }; + auto const hasBreakBefore = [](SwTextNode const& rNode) { + if (rNode.GetAttr(RES_PAGEDESC).GetPageDesc()) + { + return true; + } + switch (rNode.GetAttr(RES_BREAK).GetBreak()) + { + case SvxBreak::ColumnBefore: + case SvxBreak::ColumnBoth: + case SvxBreak::PageBefore: + case SvxBreak::PageBoth: + return true; + default: + break; + } + return false; + }; + auto const hasBreakAfter = [](SwTextNode const& rNode) { + switch (rNode.GetAttr(RES_BREAK).GetBreak()) + { + case SvxBreak::ColumnAfter: + case SvxBreak::ColumnBoth: + case SvxBreak::PageAfter: + case SvxBreak::PageBoth: + return true; + default: + break; + } + return false; + }; + if (m_isHideParagraphBreaks + && m_pEndPos->GetNode().IsTextNode() // ooo27109-1.sxw + // only merge if next node is also text node + && m_pEndPos->GetNodes()[m_pEndPos->GetNodeIndex()+1]->IsTextNode() + && hasHiddenItem(*m_pEndPos->GetNode().GetTextNode()) + // no merge if there's a page break on any node + && !hasBreakBefore(*m_pEndPos->GetNodes()[m_pEndPos->GetNodeIndex()+1]->GetTextNode()) + // first node, see SwTextFrame::GetBreak() + && !hasBreakAfter(*m_Start.GetNode().GetTextNode())) + { + m_oParagraphBreak.emplace( + SwPosition(*m_pEndPos->GetNode().GetTextNode(), m_pEndPos->GetNode().GetTextNode()->Len()), + SwPosition(*m_pEndPos->GetNodes()[m_pEndPos->GetNodeIndex()+1]->GetTextNode(), 0)); + m_pStartPos = &m_oParagraphBreak->first; + m_pEndPos = &m_oParagraphBreak->second; + return true; + } + else // nothing + { + m_pStartPos = nullptr; + m_pEndPos = nullptr; + return false; + } } } }; @@ -220,25 +283,27 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, sal_Int32 nLastEnd(0); for (auto iter = HideIterator(rTextNode, rFrame.getRootFrame()->IsHideRedlines(), - rFrame.getRootFrame()->GetFieldmarkMode()); iter.Next(); ) + rFrame.getRootFrame()->GetFieldmarkMode(), + rFrame.getRootFrame()->GetParagraphBreakMode()); + iter.Next(); ) { SwPosition const*const pStart(iter.GetStartPos()); SwPosition const*const pEnd(iter.GetEndPos()); bHaveRedlines = true; - assert(pNode != &rTextNode || &pStart->nNode.GetNode() == &rTextNode); // detect calls with wrong start node - if (pStart->nContent != nLastEnd) // not 0 so we eliminate adjacent deletes + assert(pNode != &rTextNode || &pStart->GetNode() == &rTextNode); // detect calls with wrong start node + if (pStart->GetContentIndex() != nLastEnd) // not 0 so we eliminate adjacent deletes { - extents.emplace_back(pNode, nLastEnd, pStart->nContent.GetIndex()); - mergedText.append(std::u16string_view(pNode->GetText()).substr(nLastEnd, pStart->nContent.GetIndex() - nLastEnd)); + extents.emplace_back(pNode, nLastEnd, pStart->GetContentIndex()); + mergedText.append(pNode->GetText().subView(nLastEnd, pStart->GetContentIndex() - nLastEnd)); } - if (&pEnd->nNode.GetNode() != pNode) + if (&pEnd->GetNode() != pNode) { if (pNode == &rTextNode) { pNode->SetRedlineMergeFlag(SwNode::Merge::First); } // else: was already set before int nLevel(0); - for (sal_uLong j = pNode->GetIndex() + 1; j < pEnd->nNode.GetIndex(); ++j) + for (SwNodeOffset j = pNode->GetIndex() + 1; j < pEnd->GetNodeIndex(); ++j) { SwNode *const pTmp(pNode->GetNodes()[j]); if (nLevel == 0) @@ -268,12 +333,12 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, } // note: in DelLastPara() case, the end node is not actually merged // and is likely a SwTableNode! - if (!pEnd->nNode.GetNode().IsTextNode()) + if (!pEnd->GetNode().IsTextNode()) { - assert(pEnd->nNode != pStart->nNode); + assert(pEnd->GetNode() != pStart->GetNode()); // must set pNode too because it will mark the last node pNode = nodes.back(); - assert(pNode == pNode->GetNodes()[pEnd->nNode.GetIndex() - 1]); + assert(pNode == pNode->GetNodes()[pEnd->GetNodeIndex() - 1]); if (pNode != &rTextNode) { // something might depend on last merged one being NonFirst? pNode->SetRedlineMergeFlag(SwNode::Merge::NonFirst); @@ -282,15 +347,15 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, } else { - pNode = pEnd->nNode.GetNode().GetTextNode(); + pNode = pEnd->GetNode().GetTextNode(); nodes.push_back(pNode); pNode->SetRedlineMergeFlag(SwNode::Merge::NonFirst); - nLastEnd = pEnd->nContent.GetIndex(); + nLastEnd = pEnd->GetContentIndex(); } } else { - nLastEnd = pEnd->nContent.GetIndex(); + nLastEnd = pEnd->GetContentIndex(); } } if (pNode == &rTextNode) @@ -308,7 +373,7 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, // * the first SwTextNode inside each start node of the previous point // Other (non-first) SwTextNodes in nested sections shouldn't be reset! int nLevel(0); - for (sal_uLong j = pNode->GetIndex() + 1; j < pNode->GetNodes().Count(); ++j) + for (SwNodeOffset j = pNode->GetIndex() + 1; j < pNode->GetNodes().Count(); ++j) { SwNode *const pTmp(pNode->GetNodes()[j]); if (!pTmp->IsCreateFrameWhenHidingRedlines()) @@ -350,7 +415,7 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, if (nLastEnd != pNode->Len()) { extents.emplace_back(pNode, nLastEnd, pNode->Len()); - mergedText.append(std::u16string_view(pNode->GetText()).substr(nLastEnd, pNode->Len() - nLastEnd)); + mergedText.append(pNode->GetText().subView(nLastEnd, pNode->Len() - nLastEnd)); } if (extents.empty()) // there was no text anywhere { @@ -422,7 +487,7 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, } for (auto const pSectionNode : sections) { - pSectionNode->DelFrames(rFrame.getRootFrame()); + pSectionNode->GetSection().GetFormat()->DelFrames(/*rFrame.getRootFrame()*/); } } auto pRet(std::make_unique<sw::MergedPara>(rFrame, std::move(extents), @@ -441,7 +506,7 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, void SwAttrIter::InitFontAndAttrHandler( SwTextNode const& rPropsNode, SwTextNode const& rTextNode, - OUString const& rText, + std::u16string_view aText, bool const*const pbVertLayout, bool const*const pbVertLayoutLRBT) { @@ -511,7 +576,7 @@ void SwAttrIter::InitFontAndAttrHandler( m_pFont->GetFontCacheId( m_aFontCacheIds[ nTmp ], m_aFontIdx[ nTmp ], nTmp ); } } - while (nChg < TextFrameIndex(rText.getLength())); + while (nChg < TextFrameIndex(aText.size())); } void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode, @@ -646,14 +711,16 @@ SwRedlineItr::SwRedlineItr( const SwTextNode& rTextNd, SwFont& rFnt, , m_nNdIdx( rTextNd.GetIndex() ) , m_nFirst( nRed ) , m_nAct( SwRedlineTable::npos ) + , m_nStart( COMPLETE_STRING ) + , m_nEnd( COMPLETE_STRING ) , m_bOn( false ) , m_eMode( mode ) { if( pArr ) { assert(pExtInputStart); - m_pExt.reset( new SwExtend(*pArr, pExtInputStart->nNode.GetIndex(), - pExtInputStart->nContent.GetIndex()) ); + m_pExt.reset( new SwExtend(*pArr, pExtInputStart->GetNodeIndex(), + pExtInputStart->GetContentIndex()) ); } else m_pExt = nullptr; @@ -670,7 +737,7 @@ SwRedlineItr::~SwRedlineItr() COVERITY_NOEXCEPT_FALSE // The return value of SwRedlineItr::Seek tells you if the current font // has been manipulated by leaving (-1) or accessing (+1) of a section short SwRedlineItr::Seek(SwFont& rFnt, - sal_uLong const nNode, sal_Int32 const nNew, sal_Int32 const nOld) + SwNodeOffset const nNode, sal_Int32 const nNew, sal_Int32 const nOld) { short nRet = 0; if( ExtOn() ) @@ -703,17 +770,18 @@ short SwRedlineItr::Seek(SwFont& rFnt, m_nStart = COMPLETE_STRING; m_nEnd = COMPLETE_STRING; + const SwRedlineTable& rTable = m_rDoc.getIDocumentRedlineAccess().GetRedlineTable(); - for ( ; m_nAct < m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size() ; ++m_nAct) + for ( ; m_nAct < rTable.size() ; ++m_nAct) { - m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ m_nAct ]->CalcStartEnd(nNode, m_nStart, m_nEnd); + rTable[ m_nAct ]->CalcStartEnd(nNode, m_nStart, m_nEnd); if (nNew < m_nEnd) { if (nNew >= m_nStart) // only possible candidate { m_bOn = true; - const SwRangeRedline *pRed = m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ m_nAct ]; + const SwRangeRedline *pRed = rTable[ m_nAct ]; if (m_pSet) m_pSet->ClearItem(); @@ -721,7 +789,7 @@ short SwRedlineItr::Seek(SwFont& rFnt, { SwAttrPool& rPool = const_cast<SwDoc&>(m_rDoc).GetAttrPool(); - m_pSet = std::make_unique<SfxItemSet>(rPool, svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END-1>{}); + m_pSet = std::make_unique<SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END-1>>(rPool); } if( 1 < pRed->GetStackCount() ) @@ -729,12 +797,23 @@ short SwRedlineItr::Seek(SwFont& rFnt, FillHints( pRed->GetAuthor(), pRed->GetType() ); SfxWhichIter aIter( *m_pSet ); + + // moved text: dark green with double underline or strikethrough + if ( pRed->IsMoved() ) + { + m_pSet->Put(SvxColorItem( COL_GREEN, RES_CHRATR_COLOR )); + if (SfxItemState::SET == m_pSet->GetItemState(RES_CHRATR_CROSSEDOUT, true)) + m_pSet->Put(SvxCrossedOutItem( STRIKEOUT_DOUBLE, RES_CHRATR_CROSSEDOUT )); + else + m_pSet->Put(SvxUnderlineItem( LINESTYLE_DOUBLE, RES_CHRATR_UNDERLINE )); + } + sal_uInt16 nWhich = aIter.FirstWhich(); while( nWhich ) { const SfxPoolItem* pItem; if( ( nWhich < RES_CHRATR_END ) && - ( SfxItemState::SET == m_pSet->GetItemState( nWhich, true, &pItem ) ) ) + ( SfxItemState::SET == aIter.GetItemState( true, &pItem ) ) ) { SwTextAttr* pAttr = MakeRedlineTextAttr( const_cast<SwDoc&>(m_rDoc), @@ -773,9 +852,9 @@ short SwRedlineItr::Seek(SwFont& rFnt, m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[m_nAct]); SwPosition const*const pStart(pRedline->Start()); if (pRedline->GetType() == RedlineType::Delete - && (nNode < pStart->nNode.GetIndex() - || (nNode == pStart->nNode.GetIndex() - && nNew <= pStart->nContent.GetIndex()))) + && (nNode < pStart->GetNodeIndex() + || (nNode == pStart->GetNodeIndex() + && nNew <= pStart->GetContentIndex()))) { pRedline->CalcStartEnd(nNode, m_nStart, m_nEnd); break; @@ -837,7 +916,7 @@ void SwRedlineItr::Clear_( SwFont* pFnt ) m_rAttrHandler.PopAndChg( *hint, *pFnt ); else m_rAttrHandler.Pop( *hint ); - SwTextAttr::Destroy(hint, const_cast<SwDoc&>(m_rDoc).GetAttrPool() ); + SwTextAttr::Destroy(hint); } m_Hints.clear(); } @@ -939,15 +1018,15 @@ bool SwRedlineItr::ChkSpecialUnderline_() const } bool SwRedlineItr::CheckLine( - sal_uLong const nStartNode, sal_Int32 const nChkStart, - sal_uLong const nEndNode, sal_Int32 nChkEnd, OUString& rRedlineText, - bool& bRedlineEnd, RedlineType& eRedlineEnd) + SwNodeOffset const nStartNode, sal_Int32 const nChkStart, + SwNodeOffset const nEndNode, sal_Int32 nChkEnd, OUString& rRedlineText, + bool& bRedlineEnd, RedlineType& eRedlineEnd, size_t* pAuthorAtPos) { // note: previously this would return true in the (!m_bShow && m_pExt) // case, but surely that was a bug? if (m_nFirst == SwRedlineTable::npos || m_eMode != Mode::Show) return false; - if( nChkEnd == nChkStart ) // empty lines look one char further + if( nChkEnd == nChkStart && pAuthorAtPos == nullptr ) // empty lines look one char further ++nChkEnd; sal_Int32 nOldStart = m_nStart; sal_Int32 nOldEnd = m_nEnd; @@ -978,6 +1057,8 @@ bool SwRedlineItr::CheckLine( eRedlineEnd = pRedline->GetType(); bRedlineEnd = true; isBreak = true; + if (pAuthorAtPos) + *pAuthorAtPos = pRedline->GetAuthor(); [[fallthrough]]; case SwComparePosition::OverlapBefore: case SwComparePosition::CollideEnd: @@ -1032,6 +1113,8 @@ void SwExtend::ActualizeFont( SwFont &rFnt, ExtTextInputAttr nAttr ) { if ( nAttr & ExtTextInputAttr::Underline ) rFnt.SetUnderline( LINESTYLE_SINGLE ); + else if ( nAttr & ExtTextInputAttr::DoubleUnderline ) + rFnt.SetUnderline( LINESTYLE_DOUBLE ); else if ( nAttr & ExtTextInputAttr::BoldUnderline ) rFnt.SetUnderline( LINESTYLE_BOLD ); else if ( nAttr & ExtTextInputAttr::DottedUnderline ) @@ -1052,7 +1135,7 @@ void SwExtend::ActualizeFont( SwFont &rFnt, ExtTextInputAttr nAttr ) rFnt.SetGreyWave( true ); } -short SwExtend::Enter(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew) +short SwExtend::Enter(SwFont& rFnt, SwNodeOffset const nNode, sal_Int32 const nNew) { OSL_ENSURE( !m_pFont, "SwExtend: Enter with Font" ); if (nNode != m_nNode) @@ -1068,7 +1151,7 @@ short SwExtend::Enter(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew) return 0; } -bool SwExtend::Leave_(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew) +bool SwExtend::Leave_(SwFont& rFnt, SwNodeOffset const nNode, sal_Int32 const nNew) { OSL_ENSURE(nNode == m_nNode && Inside(), "SwExtend: Leave without Enter"); if (nNode != m_nNode) @@ -1093,7 +1176,7 @@ bool SwExtend::Leave_(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew) return false; } -sal_Int32 SwExtend::Next(sal_uLong const nNode, sal_Int32 nNext) +sal_Int32 SwExtend::Next(SwNodeOffset const nNode, sal_Int32 nNext) { if (nNode != m_nNode) return nNext; |