[Libreoffice-commits] core.git: sw/inc sw/source

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Mon Feb 3 11:06:29 UTC 2020


 sw/inc/IDocumentMarkAccess.hxx     |    3 
 sw/source/core/crsr/pam.cxx        |   41 ++++++++++
 sw/source/core/doc/docbm.cxx       |  148 +++++++++++++++++++++++--------------
 sw/source/core/inc/MarkManager.hxx |    1 
 4 files changed, 140 insertions(+), 53 deletions(-)

New commits:
commit 9e7b5c74b484fcfd3317db56745b26b10897047d
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Jan 31 12:05:43 2020 +0100
Commit:     Michael Stahl <michael.stahl at cib.de>
CommitDate: Mon Feb 3 12:05:56 2020 +0100

    sw: implement protection of bookmarks and fields
    
    SwPaM::HasReadonlySel() checks PROTECT_BOOKMARKS / PROTECT_FIELDS
    setting and checks if bookmarks or fields are selected for deletion.
    
    This should already be called by the UI code in all the right places,
    for the other content protection features, and cause a dialog to pop
    up.
    
    What's not ideal about this is that it's impossible to delete a
    character immediately before or after a point bookmark because that
    would delete the point bookmark too.
    
    The bookmark check is done by extracting a function out of
    MarkManager::deleteMarks() so both will use the same logic.
    
    The problem of DelContentIndex() duplicating that logic remains...
    
    Apparently the status bar at the bottom already displays "read-only"
    for such a selection.
    
    Change-Id: Id87999198a03ba847ef0eff5651fef3bd2517fae
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/87778
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>

diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx
index a076a6dada66..736f12e98c8f 100644
--- a/sw/inc/IDocumentMarkAccess.hxx
+++ b/sw/inc/IDocumentMarkAccess.hxx
@@ -278,6 +278,9 @@ class IDocumentMarkAccess
 
         // interface IBookmarks (BOOKMARK, CROSSREF_NUMITEM_BOOKMARK, CROSSREF_HEADING_BOOKMARK )
 
+        /** check if the selection would delete a BOOKMARK */
+        virtual bool isBookmarkDeleted(SwPaM const& rPaM) const =0;
+
         /** returns a STL-like random access iterator to the begin of the sequence the IBookmarks.
         */
         virtual const_iterator_t getBookmarksBegin() const =0;
diff --git a/sw/source/core/crsr/pam.cxx b/sw/source/core/crsr/pam.cxx
index 9b742776cae9..f50b87b02bf3 100644
--- a/sw/source/core/crsr/pam.cxx
+++ b/sw/source/core/crsr/pam.cxx
@@ -43,6 +43,7 @@
 #include <IMark.hxx>
 #include <DocumentSettingManager.hxx>
 #include <hints.hxx>
+#include <txatbase.hxx>
 #include <xmloff/odffields.hxx>
 
 #include <editsh.hxx>
@@ -758,6 +759,46 @@ bool SwPaM::HasReadonlySel( bool bFormView ) const
             bRet = pDoc->GetEditShell()->IsCursorInParagraphMetadataField();
     }
 
+    if (!bRet &&
+        pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
+    {
+        if (pDoc->getIDocumentMarkAccess()->isBookmarkDeleted(*this))
+        {
+            return true;
+        }
+    }
+    if (!bRet &&
+        pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FIELDS))
+    {
+        SwPosition const& rStart(*Start());
+        SwPosition const& rEnd(*End());
+        for (SwNodeIndex n = rStart.nNode; n <= rEnd.nNode; ++n)
+        {
+            if (SwTextNode const*const pNode = n.GetNode().GetTextNode())
+            {
+                if (SwpHints const*const pHints = pNode->GetpSwpHints())
+                {
+                    for (size_t i = 0; i < pHints->Count(); ++i)
+                    {
+                        SwTextAttr const*const pHint(pHints->Get(i));
+                        if (n == rStart.nNode && pHint->GetStart() < rStart.nContent.GetIndex())
+                        {
+                            continue; // before selection
+                        }
+                        if (n == rEnd.nNode && rEnd.nContent.GetIndex() <= pHint->GetStart())
+                        {
+                            break; // after selection
+                        }
+                        if (pHint->Which() == RES_TXTATR_FIELD)
+                        {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     return bRet;
 }
 
diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx
index bff33b553eb9..273cc6d23de1 100644
--- a/sw/source/core/doc/docbm.cxx
+++ b/sw/source/core/doc/docbm.cxx
@@ -959,6 +959,98 @@ namespace sw::mark
         lcl_DebugMarks(m_vAllMarks);
     }
 
+    static bool isDeleteMark(
+            ::sw::mark::MarkBase const*const pMark,
+            SwNodeIndex const& rStt,
+            SwNodeIndex const& rEnd,
+            SwIndex const*const pSttIdx,
+            SwIndex const*const pEndIdx,
+            bool & rbIsPosInRange,
+            bool & rbIsOtherPosInRange)
+    {
+        assert(pMark);
+        // navigator marks should not be moved
+        // TODO: Check if this might make them invalid
+        if (IDocumentMarkAccess::GetType(*pMark) == IDocumentMarkAccess::MarkType::NAVIGATOR_REMINDER)
+        {
+            return false;
+        }
+
+        // on position ??
+        rbIsPosInRange = lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx)
+                            && lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx);
+        rbIsOtherPosInRange = pMark->IsExpanded()
+                            && lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx)
+                            && lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx);
+        // special case: completely in range, touching the end?
+        if ( pEndIdx != nullptr
+             && ( ( rbIsOtherPosInRange
+                    && pMark->GetMarkPos().nNode == rEnd
+                    && pMark->GetMarkPos().nContent == *pEndIdx )
+                  || ( rbIsPosInRange
+                       && pMark->IsExpanded()
+                       && pMark->GetOtherMarkPos().nNode == rEnd
+                       && pMark->GetOtherMarkPos().nContent == *pEndIdx ) ) )
+        {
+            rbIsPosInRange = true;
+            rbIsOtherPosInRange = true;
+        }
+
+        if (rbIsPosInRange
+             && (rbIsOtherPosInRange
+                  || !pMark->IsExpanded()))
+        {
+            // completely in range
+
+            bool bDeleteMark = true;
+            {
+                switch ( IDocumentMarkAccess::GetType( *pMark ) )
+                {
+                case IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK:
+                case IDocumentMarkAccess::MarkType::CROSSREF_NUMITEM_BOOKMARK:
+                    // no delete of cross-reference bookmarks, if range is inside one paragraph
+                    bDeleteMark = rStt != rEnd;
+                    break;
+                case IDocumentMarkAccess::MarkType::UNO_BOOKMARK:
+                    // no delete of UNO mark, if it is not expanded and only touches the start of the range
+                    bDeleteMark = rbIsOtherPosInRange
+                                  || pMark->IsExpanded()
+                                  || pSttIdx == nullptr
+                                  || !( pMark->GetMarkPos().nNode == rStt
+                                        && pMark->GetMarkPos().nContent == *pSttIdx );
+                    break;
+                default:
+                    bDeleteMark = true;
+                    break;
+                }
+            }
+            return bDeleteMark;
+        }
+        return false;
+    }
+
+    bool MarkManager::isBookmarkDeleted(SwPaM const& rPaM) const
+    {
+        SwPosition const& rStart(*rPaM.Start());
+        SwPosition const& rEnd(*rPaM.End());
+        for (auto ppMark = m_vBookmarks.begin();
+            ppMark != m_vBookmarks.end();
+            ++ppMark)
+        {
+            bool bIsPosInRange(false);
+            bool bIsOtherPosInRange(false);
+            bool const bDeleteMark = isDeleteMark(*ppMark,
+                rStart.nNode, rEnd.nNode, &rStart.nContent, &rEnd.nContent,
+                bIsPosInRange, bIsOtherPosInRange);
+            if (bDeleteMark
+                && IDocumentMarkAccess::GetType(**ppMark) == MarkType::BOOKMARK)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void MarkManager::deleteMarks(
             const SwNodeIndex& rStt,
             const SwNodeIndex& rEnd,
@@ -980,65 +1072,15 @@ namespace sw::mark
             ppMark != m_vAllMarks.end();
             ++ppMark)
         {
-            // navigator marks should not be moved
-            // TODO: Check if this might make them invalid
-            if(IDocumentMarkAccess::GetType(**ppMark) == MarkType::NAVIGATOR_REMINDER)
-                continue;
-
             ::sw::mark::MarkBase *const pMark = *ppMark;
-
-            if (!pMark)
-                continue;
-
-            // on position ??
-            bool bIsPosInRange = lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx)
-                                 && lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx);
-            bool bIsOtherPosInRange = pMark->IsExpanded()
-                                      && lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx)
-                                      && lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx);
-            // special case: completely in range, touching the end?
-            if ( pEndIdx != nullptr
-                 && ( ( bIsOtherPosInRange
-                        && pMark->GetMarkPos().nNode == rEnd
-                        && pMark->GetMarkPos().nContent == *pEndIdx )
-                      || ( bIsPosInRange
-                           && pMark->IsExpanded()
-                           && pMark->GetOtherMarkPos().nNode == rEnd
-                           && pMark->GetOtherMarkPos().nContent == *pEndIdx ) ) )
-            {
-                bIsPosInRange = true;
-                bIsOtherPosInRange = true;
-            }
+            bool bIsPosInRange(false);
+            bool bIsOtherPosInRange(false);
+            bool const bDeleteMark = isDeleteMark(pMark, rStt, rEnd, pSttIdx, pEndIdx, bIsPosInRange, bIsOtherPosInRange);
 
             if ( bIsPosInRange
                  && ( bIsOtherPosInRange
                       || !pMark->IsExpanded() ) )
             {
-                // completely in range
-
-                bool bDeleteMark = true;
-                {
-                    switch ( IDocumentMarkAccess::GetType( *pMark ) )
-                    {
-                    case IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK:
-                    case IDocumentMarkAccess::MarkType::CROSSREF_NUMITEM_BOOKMARK:
-                        // no delete of cross-reference bookmarks, if range is inside one paragraph
-                        bDeleteMark = rStt != rEnd;
-                        break;
-                    case IDocumentMarkAccess::MarkType::UNO_BOOKMARK:
-                        // no delete of UNO mark, if it is not expanded and only touches the start of the range
-                        bDeleteMark = bIsOtherPosInRange
-                                      || pMark->IsExpanded()
-                                      || pSttIdx == nullptr
-                                      || !( pMark->GetMarkPos().nNode == rStt
-                                            && pMark->GetMarkPos().nContent == *pSttIdx );
-                        break;
-                    default:
-                        bDeleteMark = true;
-                        break;
-                    }
-                }
-
                 if ( bDeleteMark )
                 {
                     if ( pSaveBkmk )
diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx
index edf8121836b6..a9457f916763 100644
--- a/sw/source/core/inc/MarkManager.hxx
+++ b/sw/source/core/inc/MarkManager.hxx
@@ -78,6 +78,7 @@ namespace sw {
             virtual const_iterator_t findMark(const OUString& rName) const override;
 
             // bookmarks
+            virtual bool isBookmarkDeleted(SwPaM const& rPaM) const override;
             virtual const_iterator_t getBookmarksBegin() const override;
             virtual const_iterator_t getBookmarksEnd() const override;
             virtual sal_Int32 getBookmarksCount() const override;


More information about the Libreoffice-commits mailing list