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);