sw/inc/cmdid.h                      |    1 
 sw/qa/uibase/shells/shells.cxx      |   36 ++++++++++++++++++++++++
 sw/sdi/_textsh.sdi                  |    6 ++++
 sw/sdi/swriter.sdi                  |   14 +++++++++
 sw/source/uibase/shells/textsh1.cxx |   54 ++++++++++++++++++++++++++++++++++++
 5 files changed, 111 insertions(+)

New commits:
commit eb60a0f5fb7e8ae3e838433d875fc637ac7bf538
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Jan 13 11:05:52 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Jan 16 08:48:06 2023 +0000

    sw: add a new .uno:DeleteBookmarks UNO command
    
    This is similar to commit c68d06dfa1498f862923eaddf3e5d247650a53d5 (sw:
    add a new .uno:DeleteTextFormFields UNO command, 2023-01-10), but that
    was for fieldmarks and this is for bookmarks.
    
    The primary use-case is to specify a prefix for the name, so e.g. all
    Zotero-related bookmarks can be removed, but it can be also used to
    remove all bookmarks when no prefix is specified.
    
    (cherry picked from commit 40753de837b9776dd8b33e830be0cceef83f024a)
    
    Change-Id: Ifc1f666f66d9fc3f6cd055f9263f0e4f949c191d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145470
    Reviewed-by: Justin Luth <jl...@mail.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h
index 4238f1893d62..62c0e057a23a 100644
--- a/sw/inc/cmdid.h
+++ b/sw/inc/cmdid.h
@@ -316,6 +316,7 @@
 #define FN_DELETE_TEXT_FORMFIELDS (FN_INSERT2 + 36)
 #define FN_UPDATE_BOOKMARK (FN_INSERT2 + 37)
 #define FN_UPDATE_FIELD (FN_INSERT2 + 38)
+#define FN_DELETE_BOOKMARKS (FN_INSERT2 + 39)
 
 // Region: Format
 #define FN_AUTOFORMAT_APPLY     (FN_FORMAT + 1 ) /* apply autoformat options */
diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index 640443538241..300912595660 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -793,6 +793,42 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmark)
     CPPUNIT_ASSERT_EQUAL(OUString("new content"), pTextNode->GetText());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDeleteBookmarks)
+{
+    // Given a document with 2 bookmarks, first covering "B" and second 
covering "D":
+    SwDoc* pDoc = createSwDoc();
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    pWrtShell->Insert("ABCDE");
+    pWrtShell->SttEndDoc(/*bStt=*/true);
+    pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+    pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, 
/*bBasicCall=*/false);
+    pWrtShell->SetBookmark(vcl::KeyCode(), "ZOTERO_BREF_GiQ7DAWQYWLy");
+    pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+    pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, 
/*bBasicCall=*/false);
+    pWrtShell->SetBookmark(vcl::KeyCode(), "other");
+
+    // When deleting 1 matching bookmark:
+    pWrtShell->SttEndDoc(/*bStt=*/true);
+    std::vector<beans::PropertyValue> aArgsVec = 
comphelper::JsonToPropertyValues(R"json(
+{
+    "BookmarkNamePrefix": {
+        "type": "string",
+        "value": "ZOTERO_BREF_"
+    }
+}
+)json");
+    uno::Sequence<beans::PropertyValue> aArgs = 
comphelper::containerToSequence(aArgsVec);
+    dispatchCommand(mxComponent, ".uno:DeleteBookmarks", aArgs);
+
+    // Then make sure that only the other bookmark is kept:
+    auto it = 
pDoc->getIDocumentMarkAccess()->findMark("ZOTERO_BREF_GiQ7DAWQYWLy");
+    // Without the accompanying fix in place, this test would have failed, the 
matching bookmark was
+    // not removed.
+    CPPUNIT_ASSERT(bool(it == 
pDoc->getIDocumentMarkAccess()->getAllMarksEnd()));
+    it = pDoc->getIDocumentMarkAccess()->findMark("other");
+    CPPUNIT_ASSERT(it != pDoc->getIDocumentMarkAccess()->getAllMarksEnd());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/sdi/_textsh.sdi b/sw/sdi/_textsh.sdi
index 0bb4189ababa..6cb500b8b4bf 100644
--- a/sw/sdi/_textsh.sdi
+++ b/sw/sdi/_textsh.sdi
@@ -1825,6 +1825,12 @@ interface BaseText
         StateMethod = GetState ;
     ]
 
+    FN_DELETE_BOOKMARKS
+    [
+        ExecMethod = Execute ;
+        DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+    ]
+
     SID_FM_CTL_PROPERTIES
     [
         ExecMethod = Execute ;
diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi
index d569a10437f1..80a424279e6c 100644
--- a/sw/sdi/swriter.sdi
+++ b/sw/sdi/swriter.sdi
@@ -2568,6 +2568,20 @@ SfxVoidItem UpdateBookmarks FN_UPDATE_BOOKMARKS
     GroupId = SfxGroupId::Insert;
 ]
 
+SfxVoidItem DeleteBookmarks FN_DELETE_BOOKMARKS
+(SfxStringItem BookmarkNamePrefix FN_PARAM_1)
+[
+    AutoUpdate = TRUE,
+    FastCall = FALSE,
+    ReadOnlyDoc = FALSE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+
+    GroupId = SfxGroupId::Controls;
+]
+
 SfxVoidItem UpdateBookmark FN_UPDATE_BOOKMARK
 (SfxStringItem BookmarkNamePrefix FN_PARAM_1, SfxUnoAnyItem Bookmark 
FN_PARAM_2)
 [
diff --git a/sw/source/uibase/shells/textsh1.cxx 
b/sw/source/uibase/shells/textsh1.cxx
index ed1d61b5f514..469a47e206c0 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -613,6 +613,53 @@ void UpdateBookmark(SfxRequest& rReq, SwWrtShell& rWrtSh)
     rIDCO.DeleteAndJoin(aEndMarker);
     rIDMA.assureSortedMarkContainers();
 }
+
+void DeleteBookmarks(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+    if 
(rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
+    {
+        return;
+    }
+
+    OUString aBookmarkNamePrefix;
+    const SfxStringItem* pBookmarkNamePrefix = 
rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+    if (pBookmarkNamePrefix)
+    {
+        aBookmarkNamePrefix = pBookmarkNamePrefix->GetValue();
+    }
+
+    rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELBOOKMARK, 
nullptr);
+    rWrtSh.StartAction();
+    comphelper::ScopeGuard g(
+        [&rWrtSh]
+        {
+            rWrtSh.EndAction();
+            
rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELBOOKMARK, nullptr);
+        });
+
+    IDocumentMarkAccess* pMarkAccess = 
rWrtSh.GetDoc()->getIDocumentMarkAccess();
+    std::vector<sw::mark::IMark*> aRemovals;
+    for (auto it = pMarkAccess->getBookmarksBegin(); it != 
pMarkAccess->getBookmarksEnd(); ++it)
+    {
+        auto pBookmark = dynamic_cast<sw::mark::Bookmark*>(*it);
+        assert(pBookmark);
+
+        if (!aBookmarkNamePrefix.isEmpty())
+        {
+            if (!pBookmark->GetName().startsWith(aBookmarkNamePrefix))
+            {
+                continue;
+            }
+        }
+
+        aRemovals.push_back(pBookmark);
+    }
+
+    for (const auto& pMark : aRemovals)
+    {
+        pMarkAccess->deleteMark(pMark);
+    }
+}
 }
 
 void SwTextShell::Execute(SfxRequest &rReq)
@@ -1001,6 +1048,7 @@ void SwTextShell::Execute(SfxRequest &rReq)
         }
         case FN_DELETE_BOOKMARK:
         {
+            // This deletes a bookmark with the specified name.
             if (pItem && 
!rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
             {
                 IDocumentMarkAccess* const pMarkAccess = 
rWrtSh.getIDocumentMarkAccess();
@@ -1008,6 +1056,12 @@ void SwTextShell::Execute(SfxRequest &rReq)
             }
             break;
         }
+        case FN_DELETE_BOOKMARKS:
+        {
+            // This deletes all bookmarks in the document matching a specified 
prefix.
+            DeleteBookmarks(rReq, rWrtSh);
+            break;
+        }
         case FN_UPDATE_SECTIONS:
         {
             UpdateSections(rReq, rWrtSh);

Reply via email to