sw/inc/IDocumentMarkAccess.hxx | 2 + sw/qa/uibase/uno/uno.cxx | 33 +++++++++++++++++++++++++++ sw/source/core/doc/docbm.cxx | 23 +++++++++++++++++++ sw/source/core/inc/MarkManager.hxx | 1 sw/source/uibase/uno/loktxdoc.cxx | 44 +++++++++++++++++++++++++++++++++++-- 5 files changed, 101 insertions(+), 2 deletions(-)
New commits: commit 4bcb66ec7b417fbe113267f2615e78fe47eb55ca Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed Jan 11 10:38:05 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Jan 11 13:13:48 2023 +0000 sw lok: expose name of bookmark under cursor It was possible to get the names of all bookmarks, but you could not get the name of the (innermost) bookmark under the current cursor. Getting the name of the current bookmark is useful for Zotero: if we already have a citation and want to insert one more, then we should turn the current citation into a citation cluster. Fix the problem by adding an API similar to what commit bb20dee2ef1b0804065e1cda2c834d257fdd90ed (sw lok: expose field type & command of fieldmark under cursor, 2023-01-05) did, but here we deal with bookmarks, not fieldmarks. Handle the actual bookmark lookup in MarkManager, such functionality looks useful outside LOK as well. Change-Id: Ic5b9b36fda243c5d7d360fa03745b3e121b67b06 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145323 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx index 93690fb2b305..20f876d16495 100644 --- a/sw/inc/IDocumentMarkAccess.hxx +++ b/sw/inc/IDocumentMarkAccess.hxx @@ -313,6 +313,8 @@ class IDocumentMarkAccess */ virtual const_iterator_t findFirstBookmarkStartsAfter(const SwPosition& rPos) const =0; + /// Get the innermost bookmark that contains rPos. + virtual sw::mark::IMark* getBookmarkFor(const SwPosition& rPos) const = 0; // Fieldmarks /** returns a STL-like random access iterator to the begin of the sequence of fieldmarks. diff --git a/sw/qa/uibase/uno/uno.cxx b/sw/qa/uibase/uno/uno.cxx index 4b21bca0bb0c..d2be66457b81 100644 --- a/sw/qa/uibase/uno/uno.cxx +++ b/sw/qa/uibase/uno/uno.cxx @@ -442,6 +442,39 @@ CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetSections) CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aTree.get_child("sections").count("")); } +CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetBookmark) +{ + // Given a document with a bookmark: + createSwDoc(); + uno::Sequence<css::beans::PropertyValue> aArgs = { + comphelper::makePropertyValue("Bookmark", uno::Any(OUString("ZOTERO_BREF_1"))), + comphelper::makePropertyValue("BookmarkText", uno::Any(OUString("<p>aaa</p><p>bbb</p>"))), + }; + dispatchCommand(mxComponent, ".uno:InsertBookmark", aArgs); + + // When stepping into the bookmark with the cursor and getting the command value for + // .uno:Bookmark: + SwDoc* pDoc = getSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->SttEndDoc(/*bStt=*/false); + pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false); + tools::JsonWriter aJsonWriter; + std::string_view aCommand(".uno:Bookmark?namePrefix=ZOTERO_BREF_"); + auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + pXTextDocument->getCommandValues(aJsonWriter, aCommand); + + // Then make sure we find the inserted bookmark: + std::unique_ptr<char[], o3tl::free_delete> pJSON(aJsonWriter.extractData()); + std::stringstream aStream(pJSON.get()); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + boost::property_tree::ptree aBookmark = aTree.get_child("bookmark"); + // Without the accompanying fix in place, this test would have failed with: + // - No such node (bookmark) + // i.e. the returned JSON was an empty object. + CPPUNIT_ASSERT_EQUAL(std::string("ZOTERO_BREF_1"), aBookmark.get<std::string>("name")); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx index 8e4d2ef72e95..7152c2a2314a 100644 --- a/sw/source/core/doc/docbm.cxx +++ b/sw/source/core/doc/docbm.cxx @@ -1437,6 +1437,29 @@ namespace sw::mark return dynamic_cast<IFieldmark*>(pFieldmark); } + IMark* MarkManager::getBookmarkFor(const SwPosition& rPos) const + { + auto it = std::find_if(m_vBookmarks.begin(), m_vBookmarks.end(), + [&rPos](const sw::mark::MarkBase* pMark) + { return pMark->IsCoveringPosition(rPos); }); + if (it == m_vBookmarks.end()) + { + return nullptr; + } + sw::mark::IMark* pBookmark = *it; + for (; it != m_vBookmarks.end() && (*it)->GetMarkStart() <= rPos; ++it) + { + // Find the innermost bookmark. + if (rPos < (*it)->GetMarkEnd() + && (pBookmark->GetMarkStart() < (*it)->GetMarkStart() + || (*it)->GetMarkEnd() < pBookmark->GetMarkEnd())) + { + pBookmark = *it; + } + } + return pBookmark; + } + void MarkManager::deleteFieldmarkAt(const SwPosition& rPos) { auto const pFieldmark = dynamic_cast<Fieldmark*>(getFieldmarkAt(rPos)); diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx index d362036b5464..1599996ae055 100644 --- a/sw/source/core/inc/MarkManager.hxx +++ b/sw/source/core/inc/MarkManager.hxx @@ -88,6 +88,7 @@ namespace sw::mark { virtual sal_Int32 getBookmarksCount() const override; virtual const_iterator_t findBookmark(const OUString& rName) const override; virtual const_iterator_t findFirstBookmarkStartsAfter(const SwPosition& rPos) const override; + virtual ::sw::mark::IMark* getBookmarkFor(const SwPosition& rPos) const override; // Fieldmarks virtual const_iterator_t getFieldmarksBegin() const override; diff --git a/sw/source/uibase/uno/loktxdoc.cxx b/sw/source/uibase/uno/loktxdoc.cxx index a2f5b3cdd131..44b72d4f1eae 100644 --- a/sw/source/uibase/uno/loktxdoc.cxx +++ b/sw/source/uibase/uno/loktxdoc.cxx @@ -230,6 +230,41 @@ void GetBookmarks(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell, } } +/// Implements getCommandValues(".uno:Bookmark"). +/// +/// Parameters: +/// +/// - namePrefix: bookmark name prefix to not return all bookmarks +void GetBookmark(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell, + const std::map<OUString, OUString>& rArguments) +{ + OUString aNamePrefix; + { + auto it = rArguments.find("namePrefix"); + if (it != rArguments.end()) + { + aNamePrefix = it->second; + } + } + + IDocumentMarkAccess& rIDMA = *pDocShell->GetDoc()->getIDocumentMarkAccess(); + SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); + SwPosition& rCursor = *pWrtShell->GetCursor()->GetPoint(); + sw::mark::IMark* pBookmark = rIDMA.getBookmarkFor(rCursor); + tools::ScopedJsonWriterNode aBookmark = rJsonWriter.startNode("bookmark"); + if (!pBookmark) + { + return; + } + + if (!pBookmark->GetName().startsWith(aNamePrefix)) + { + return; + } + + rJsonWriter.put("name", pBookmark->GetName()); +} + /// Implements getCommandValues(".uno:Fields"). /// /// Parameters: @@ -326,8 +361,8 @@ void GetSections(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell, bool SwXTextDocument::supportsCommand(std::u16string_view rCommand) { static const std::initializer_list<std::u16string_view> vForward - = { u"TextFormFields", u"TextFormField", u"SetDocumentProperties", - u"Bookmarks", u"Fields", u"Sections" }; + = { u"TextFormFields", u"TextFormField", u"SetDocumentProperties", u"Bookmarks", u"Fields", + u"Sections", u"Bookmark" }; return std::find(vForward.begin(), vForward.end(), rCommand) != vForward.end(); } @@ -342,6 +377,7 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& rJsonWriter, std::stri static constexpr OStringLiteral aBookmarks(".uno:Bookmarks"); static constexpr OStringLiteral aFields(".uno:Fields"); static constexpr OStringLiteral aSections(".uno:Sections"); + static constexpr OStringLiteral aBookmark(".uno:Bookmark"); INetURLObject aParser(OUString::fromUtf8(rCommand)); OUString aArguments = aParser.GetParam(); @@ -389,6 +425,10 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& rJsonWriter, std::stri { GetSections(rJsonWriter, m_pDocShell, aMap); } + else if (o3tl::starts_with(rCommand, aBookmark)) + { + GetBookmark(rJsonWriter, m_pDocShell, aMap); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */