diff options
author | Michael Stahl <Michael.Stahl@cib.de> | 2020-01-22 15:18:19 +0100 |
---|---|---|
committer | Michael Stahl <Michael.Stahl@cib.de> | 2020-06-04 17:50:10 +0200 |
commit | b93b2b974e003a2e6b8cf9852b7e7e4fb126fff0 (patch) | |
tree | 73084e3d531d6b46d0ae517fe1980ea450153ef0 /sw | |
parent | a0e1983427439031b3228187f61fe60f92520ae8 (diff) |
tdf#45589 sw: add bookmarks to SwScriptInfo
Add a list of bookmark positions in the text frame to SwScriptInfo.
Initialising this turned out to be more complicated than expected.
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/87202
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@cib.de>
(cherry picked from commit 46e04a712e97f9095ef4da7f0e52f50cf2bfbb32)
Change-Id: I1738186b057b0eece80177097a03826365107589
Diffstat (limited to 'sw')
-rw-r--r-- | sw/source/core/inc/scriptinfo.hxx | 11 | ||||
-rw-r--r-- | sw/source/core/text/porlay.cxx | 233 | ||||
-rw-r--r-- | sw/source/core/txtnode/modeltoviewhelper.cxx | 2 |
3 files changed, 236 insertions, 10 deletions
diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx index e3d64b1627f3..e1022370c76b 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -34,6 +34,7 @@ class MultiSelection; typedef std::vector< sal_Int32 > PositionList; enum class SwFontScript; namespace sw { struct MergedPara; } +namespace sw::mark { class IBookmark; } #define SPACING_PRECISION_FACTOR 100 @@ -42,6 +43,7 @@ class SwScriptInfo { public: enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE, SPECIAL_MIDDLE}; + enum class MarkKind { Start, End, Point }; private: //! Records a single change in script type. @@ -68,6 +70,7 @@ private: std::deque<TextFrameIndex> m_NoKashidaLine; std::deque<TextFrameIndex> m_NoKashidaLineEnd; std::deque<TextFrameIndex> m_HiddenChg; + std::vector<std::pair<TextFrameIndex, MarkKind>> m_Bookmarks; //! Records a single change in compression. struct CompressionChangeInfo { @@ -178,8 +181,12 @@ public: assert(nCnt < m_HiddenChg.size()); return m_HiddenChg[ nCnt ]; } - static void CalcHiddenRanges(const SwTextNode& rNode, MultiSelection& rHiddenMulti); - static void selectHiddenTextProperty(const SwTextNode& rNode, MultiSelection &rHiddenMulti); + static void CalcHiddenRanges(const SwTextNode& rNode, + MultiSelection& rHiddenMulti, + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> * pBookmarks); + static void selectHiddenTextProperty(const SwTextNode& rNode, + MultiSelection &rHiddenMulti, + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> * pBookmarks); static void selectRedLineDeleted(const SwTextNode& rNode, MultiSelection &rHiddenMulti, bool bSelect=true); // "high" level operations, nPos refers to string position diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index 11e78a915433..630ff74a0176 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -35,6 +35,9 @@ #include <com/sun/star/i18n/WordType.hpp> #include <com/sun/star/i18n/XBreakIterator.hpp> #include <paratr.hxx> +#include <sal/log.hxx> +#include <boost/optional.hpp> +#include <IMark.hxx> #include <editeng/adjustitem.hxx> #include <editeng/scripttypeitem.hxx> #include <editeng/charhiddenitem.hxx> @@ -706,6 +709,173 @@ SwFontScript SwScriptInfo::WhichFont(sal_Int32 nIdx, OUString const& rText) return lcl_ScriptToFont(nScript); } +static void InitBookmarks( + boost::optional<std::vector<sw::Extent>::const_iterator> oPrevIter, + std::vector<sw::Extent>::const_iterator iter, + std::vector<sw::Extent>::const_iterator const end, + TextFrameIndex nOffset, + std::vector<std::pair<sw::mark::IBookmark const*, SwScriptInfo::MarkKind>> & rBookmarks, + std::vector<std::pair<TextFrameIndex, SwScriptInfo::MarkKind>> & o_rBookmarks) +{ + SwTextNode const*const pNode(iter->pNode); + for (auto const& it : rBookmarks) + { + assert(iter->pNode == pNode || pNode->GetIndex() < iter->pNode->GetIndex()); + assert(!oPrevIter || (*oPrevIter)->pNode->GetIndex() <= pNode->GetIndex()); + switch (it.second) + { + case SwScriptInfo::MarkKind::Start: + { + // SwUndoSaveContent::DelContentIndex() is rather messy but + // apparently bookmarks "on the edge" are deleted if + // * point: equals start-of-selection (not end-of-selection) + // * expanded: one position equals edge of selection + // and other does not (is inside) + // interesting case: if end[/start] of the mark is on the + // start of first[/end of last] extent, and the other one + // is outside this merged paragraph, is it deleted or not? + // assume "no" because the line break it contains isn't deleted. + SwPosition const& rStart(it.first->GetMarkStart()); + SwPosition const& rEnd(it.first->GetMarkEnd()); + assert(&rStart.nNode.GetNode() == pNode); + while (iter != end) + { + if (&rStart.nNode.GetNode() != iter->pNode // iter moved to next node + || rStart.nContent.GetIndex() < iter->nStart) + { + if (rEnd.nNode.GetIndex() < iter->pNode->GetIndex() + || (&rEnd.nNode.GetNode() == iter->pNode && rEnd.nContent.GetIndex() <= iter->nStart)) + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back(nOffset, it.second); + break; + } + } + else if (rStart.nContent.GetIndex() <= iter->nEnd) + { + auto const iterNext(iter + 1); + if (rStart.nContent.GetIndex() == iter->nEnd + && (iterNext == end + ? &rEnd.nNode.GetNode() == iter->pNode + : (rEnd.nNode.GetIndex() < iterNext->pNode->GetIndex() + || (&rEnd.nNode.GetNode() == iterNext->pNode && rEnd.nContent.GetIndex() < iterNext->nStart)))) + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back( + nOffset + TextFrameIndex(rStart.nContent.GetIndex() - iter->nStart), + it.second); + break; + } + } + else + { + nOffset += TextFrameIndex(iter->nEnd - iter->nStart); + oPrevIter = iter; + ++iter; // bookmarks are sorted... + } + } + if (iter == end) + { + if (pNode->GetIndex() < rEnd.nNode.GetIndex()) // pNode is last node of merged + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back(nOffset, it.second); + } + } + break; + } + case SwScriptInfo::MarkKind::End: + { + SwPosition const& rEnd(it.first->GetMarkEnd()); + assert(&rEnd.nNode.GetNode() == pNode); + while (true) + { + if (iter == end + || &rEnd.nNode.GetNode() != iter->pNode // iter moved to next node + || rEnd.nContent.GetIndex() <= iter->nStart) + { + SwPosition const& rStart(it.first->GetMarkStart()); + // oPrevIter may point to pNode or a preceding node + if (oPrevIter + ? ((*oPrevIter)->pNode->GetIndex() < rStart.nNode.GetIndex() + || ((*oPrevIter)->pNode == &rStart.nNode.GetNode() + && ((iter != end && &rEnd.nNode.GetNode() == iter->pNode && rEnd.nContent.GetIndex() == iter->nStart) + ? (*oPrevIter)->nEnd < rStart.nContent.GetIndex() + : (*oPrevIter)->nEnd <= rStart.nContent.GetIndex()))) + : rStart.nNode == rEnd.nNode) + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back(nOffset, it.second); + break; + } + } + else if (rEnd.nContent.GetIndex() <= iter->nEnd) + { + o_rBookmarks.emplace_back( + nOffset + TextFrameIndex(rEnd.nContent.GetIndex() - iter->nStart), + it.second); + break; + } + else + { + nOffset += TextFrameIndex(iter->nEnd - iter->nStart); + oPrevIter = iter; + ++iter; + } + } + break; + } + case SwScriptInfo::MarkKind::Point: + { + SwPosition const& rPos(it.first->GetMarkPos()); + assert(&rPos.nNode.GetNode() == pNode); + while (iter != end) + { + if (&rPos.nNode.GetNode() != iter->pNode // iter moved to next node + || rPos.nContent.GetIndex() < iter->nStart) + { + break; // deleted - skip it + } + else if (rPos.nContent.GetIndex() <= iter->nEnd) + { + if (rPos.nContent.GetIndex() == iter->nEnd + && rPos.nContent.GetIndex() != iter->pNode->Len()) + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back( + nOffset + TextFrameIndex(rPos.nContent.GetIndex() - iter->nStart), + it.second); + } + break; + } + else + { + nOffset += TextFrameIndex(iter->nEnd - iter->nStart); + oPrevIter = iter; + ++iter; + } + } + break; + } + } + } +} + // searches for script changes in rText and stores them void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, sw::MergedPara const*const pMerged) @@ -722,12 +892,15 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, // HIDDEN TEXT INFORMATION + m_Bookmarks.clear(); m_HiddenChg.clear(); if (pMerged) { SwTextNode const* pNode(nullptr); TextFrameIndex nOffset(0); - for (auto iter = pMerged->extents.begin(); iter != pMerged->extents.end(); ++iter) + boost::optional<std::vector<sw::Extent>::const_iterator> oPrevIter; + for (auto iter = pMerged->extents.begin(); iter != pMerged->extents.end(); + oPrevIter = iter, ++iter) { if (iter->pNode == pNode) { @@ -737,7 +910,10 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, pNode = iter->pNode; Range aRange( 0, pNode->Len() > 0 ? pNode->Len() - 1 : 0 ); MultiSelection aHiddenMulti( aRange ); - CalcHiddenRanges( *pNode, aHiddenMulti ); + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> bookmarks; + CalcHiddenRanges(*pNode, aHiddenMulti, &bookmarks); + + InitBookmarks(oPrevIter, iter, pMerged->extents.end(), nOffset, bookmarks, m_Bookmarks); for (sal_Int32 i = 0; i < aHiddenMulti.GetRangeCount(); ++i) { @@ -782,7 +958,24 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, { Range aRange( 0, !rText.isEmpty() ? rText.getLength() - 1 : 0 ); MultiSelection aHiddenMulti( aRange ); - CalcHiddenRanges( rNode, aHiddenMulti ); + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> bookmarks; + CalcHiddenRanges(rNode, aHiddenMulti, &bookmarks); + + for (auto const& it : bookmarks) + { + switch (it.second) + { + case MarkKind::Start: + m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkStart().nContent.GetIndex()), it.second); + break; + case MarkKind::End: + m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkEnd().nContent.GetIndex()), it.second); + break; + case MarkKind::Point: + m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkPos().nContent.GetIndex()), it.second); + break; + } + } for (sal_Int32 i = 0; i < aHiddenMulti.GetRangeCount(); ++i) { @@ -1559,7 +1752,7 @@ bool SwScriptInfo::GetBoundsOfHiddenRange( const SwTextNode& rNode, sal_Int32 nP ? rNode.GetText().getLength() - 1 : 0); MultiSelection aHiddenMulti( aRange ); - SwScriptInfo::CalcHiddenRanges( rNode, aHiddenMulti ); + SwScriptInfo::CalcHiddenRanges(rNode, aHiddenMulti, nullptr); for( sal_Int32 i = 0; i < aHiddenMulti.GetRangeCount(); ++i ) { const Range& rRange = aHiddenMulti.GetRange( i ); @@ -2219,7 +2412,9 @@ SwTwips SwTextFrame::HangingMargin() const return nRet; } -void SwScriptInfo::selectHiddenTextProperty(const SwTextNode& rNode, MultiSelection &rHiddenMulti) +void SwScriptInfo::selectHiddenTextProperty(const SwTextNode& rNode, + MultiSelection & rHiddenMulti, + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> *const pBookmarks) { assert((rNode.GetText().isEmpty() && rHiddenMulti.GetTotalRange().Len() == 1) || (rNode.GetText().getLength() == rHiddenMulti.GetTotalRange().Len())); @@ -2251,6 +2446,28 @@ void SwScriptInfo::selectHiddenTextProperty(const SwTextNode& rNode, MultiSelect } } } + + for (const SwIndex* pIndex = rNode.GetFirstIndex(); pIndex; pIndex = pIndex->GetNext()) + { + const sw::mark::IMark* pMark = pIndex->GetMark(); + const sw::mark::IBookmark* pBookmark = dynamic_cast<const sw::mark::IBookmark*>(pMark); + if (pBookmarks && pBookmark) + { + if (!pBookmark->IsExpanded()) + { + pBookmarks->emplace_back(pBookmark, MarkKind::Point); + } + else if (pIndex == &pBookmark->GetMarkStart().nContent) + { + pBookmarks->emplace_back(pBookmark, MarkKind::Start); + } + else + { + assert(pIndex == &pBookmark->GetMarkEnd().nContent); + pBookmarks->emplace_back(pBookmark, MarkKind::End); + } + } + } } void SwScriptInfo::selectRedLineDeleted(const SwTextNode& rNode, MultiSelection &rHiddenMulti, bool bSelect) @@ -2288,9 +2505,11 @@ void SwScriptInfo::selectRedLineDeleted(const SwTextNode& rNode, MultiSelection } // Returns a MultiSection indicating the hidden ranges. -void SwScriptInfo::CalcHiddenRanges( const SwTextNode& rNode, MultiSelection& rHiddenMulti ) +void SwScriptInfo::CalcHiddenRanges( const SwTextNode& rNode, + MultiSelection & rHiddenMulti, + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> *const pBookmarks) { - selectHiddenTextProperty(rNode, rHiddenMulti); + selectHiddenTextProperty(rNode, rHiddenMulti, pBookmarks); // If there are any hidden ranges in the current text node, we have // to unhide the redlining ranges: diff --git a/sw/source/core/txtnode/modeltoviewhelper.cxx b/sw/source/core/txtnode/modeltoviewhelper.cxx index e6f5b1885f56..91c70599754e 100644 --- a/sw/source/core/txtnode/modeltoviewhelper.cxx +++ b/sw/source/core/txtnode/modeltoviewhelper.cxx @@ -92,7 +92,7 @@ ModelToViewHelper::ModelToViewHelper(const SwTextNode &rNode, ExpandMode eMode) MultiSelection aHiddenMulti(aRange); if (eMode & ExpandMode::HideInvisible) - SwScriptInfo::selectHiddenTextProperty(rNode, aHiddenMulti); + SwScriptInfo::selectHiddenTextProperty(rNode, aHiddenMulti, nullptr); if (eMode & ExpandMode::HideDeletions) SwScriptInfo::selectRedLineDeleted(rNode, aHiddenMulti); |