sw/source/ui/misc/bookmark.cxx | 99 +++++++++++++++++++++++-------- sw/source/uibase/inc/bookmark.hxx | 11 +++ sw/uiconfig/swriter/ui/insertbookmark.ui | 20 +++++- 3 files changed, 102 insertions(+), 28 deletions(-)
New commits: commit aa6ec3f79607478213272283b7eb17ec2116173c Author: Michael Stahl <[email protected]> AuthorDate: Thu Jul 21 19:31:45 2022 +0200 Commit: Michael Stahl <[email protected]> CommitDate: Tue Jul 26 20:15:37 2022 +0200 tdf#150017 sw: allow editing bookmark text in Insert->Bookmarks dialog Enable editing the text of the bookmark if it's "short" enough and doesn't span multiple paragraphs; Replace the text when finished. This will delete any footnotes or text fields in the bookmark text, which isn't ideal but there's Undo. Double-clicking the column via property "editable" only seems to work with native GTK widgets, so provide an additional "Edit Text" button to start the editing. The button requires commit fe38553aef2121f358fb58e450ec69314aad851e to edit the correct column with VCL widgets, and it doesn't work yet with GTK widgets (but with GTK double-clicking works). Change-Id: If9e8a148b039889924e4870b2e9bbe977c977ce9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137355 Tested-by: Jenkins Reviewed-by: Michael Stahl <[email protected]> diff --git a/sw/source/ui/misc/bookmark.cxx b/sw/source/ui/misc/bookmark.cxx index 473c6a99b49f..fe63d4c133ca 100644 --- a/sw/source/ui/misc/bookmark.cxx +++ b/sw/source/ui/misc/bookmark.cxx @@ -88,6 +88,7 @@ IMPL_LINK_NOARG(SwInsertBookmarkDlg, ModifyHdl, weld::Entry&, void) // allow to delete only if all bookmarks are recognized m_xDeleteBtn->set_sensitive(nEntries > 0 && nSelectedEntries == nEntries && !m_bAreProtected); m_xGotoBtn->set_sensitive(nEntries == 1 && nSelectedEntries == 1); + m_xEditTextBtn->set_sensitive(nEntries == 1 && nSelectedEntries == 1); m_xRenameBtn->set_sensitive(nEntries == 1 && nSelectedEntries == 1 && !m_bAreProtected); } @@ -128,6 +129,7 @@ IMPL_LINK_NOARG(SwInsertBookmarkDlg, DeleteHdl, weld::Button&, void) m_xDeleteBtn->set_sensitive(false); m_xGotoBtn->set_sensitive(false); + m_xEditTextBtn->set_sensitive(false); m_xRenameBtn->set_sensitive(false); m_xInsertBtn->set_sensitive(false); } @@ -166,6 +168,7 @@ IMPL_LINK_NOARG(SwInsertBookmarkDlg, SelectionChangedHdl, weld::TreeView&, void) { m_xInsertBtn->set_sensitive(false); m_xGotoBtn->set_sensitive(nSelectedRows == 1); + m_xEditTextBtn->set_sensitive(nSelectedRows == 1); m_xRenameBtn->set_sensitive(nSelectedRows == 1 && !m_bAreProtected); m_xDeleteBtn->set_sensitive(!m_bAreProtected); m_xEditBox->set_text(sEditBoxText.makeStringAndClear()); @@ -174,11 +177,23 @@ IMPL_LINK_NOARG(SwInsertBookmarkDlg, SelectionChangedHdl, weld::TreeView&, void) { m_xInsertBtn->set_sensitive(!m_bAreProtected); m_xGotoBtn->set_sensitive(false); + m_xEditTextBtn->set_sensitive(false); m_xRenameBtn->set_sensitive(false); m_xDeleteBtn->set_sensitive(false); } } +IMPL_LINK_NOARG(SwInsertBookmarkDlg, EditTextHdl, weld::Button&, void) +{ + if (!ValidateBookmarks()) + return; + auto pSelected = m_xBookmarksBox->get_selected(); + if (!pSelected) + return; + + m_xBookmarksBox->start_editing(*pSelected); +} + IMPL_LINK_NOARG(SwInsertBookmarkDlg, RenameHdl, weld::Button&, void) { if (!ValidateBookmarks()) @@ -207,6 +222,7 @@ IMPL_LINK_NOARG(SwInsertBookmarkDlg, RenameHdl, weld::Button&, void) ValidateBookmarks(); m_xDeleteBtn->set_sensitive(false); m_xGotoBtn->set_sensitive(false); + m_xEditTextBtn->set_sensitive(false); m_xRenameBtn->set_sensitive(false); m_xInsertBtn->set_sensitive(false); } @@ -229,6 +245,45 @@ IMPL_LINK(SwInsertBookmarkDlg, ChangeHideHdl, weld::Toggleable&, rBox, void) m_xConditionFT->set_sensitive(bHide); } +IMPL_LINK(SwInsertBookmarkDlg, EditingHdl, weld::TreeIter const&, rIter, bool) +{ + sw::mark::IMark const* const pBookmark( + weld::fromId<sw::mark::IMark*>(m_xBookmarksBox->get_id(rIter))); + assert(pBookmark); + return pBookmark->IsExpanded() + && pBookmark->GetMarkPos().nNode == pBookmark->GetOtherMarkPos().nNode + && !m_xBookmarksBox->get_text(rIter).endsWith(u"…"); +} + +IMPL_LINK(SwInsertBookmarkDlg, EditedHdl, weld::TreeView::iter_string const&, rIterString, bool) +{ + sw::mark::IMark const* const pBookmark( + weld::fromId<sw::mark::IMark*>(m_xBookmarksBox->get_id(rIterString.first))); + assert(pBookmark); + bool bRet(false); + if (pBookmark->GetMarkPos() != pBookmark->GetOtherMarkPos()) + { + if (pBookmark->GetMarkPos().nNode != pBookmark->GetOtherMarkPos().nNode) + { + return false; // don't allow editing if it spans multiple nodes + } + rSh.Push(); + rSh.GotoMark(pBookmark); + // GetSelText only works for 1 paragraph, but it's checked above + if (rSh.GetSelText() != rIterString.second) + { + bRet = rSh.Replace(rIterString.second, false); + } + rSh.Pop(SwEditShell::PopMode::DeleteCurrent); + } + else if (pBookmark->IsExpanded() && !rIterString.second.isEmpty()) + { // SwEditShell::Replace does nothing for empty selection + rSh.Insert(rIterString.second); + bRet = true; + } + return bRet; +} + void SwInsertBookmarkDlg::GotoSelectedBookmark() { if (!ValidateBookmarks()) @@ -293,7 +348,7 @@ void SwInsertBookmarkDlg::PopulateTable() { if (IDocumentMarkAccess::MarkType::BOOKMARK == IDocumentMarkAccess::GetType(**ppBookmark)) { - m_xBookmarksBox->InsertBookmark(*ppBookmark); + m_xBookmarksBox->InsertBookmark(rSh, *ppBookmark); aTableBookmarks.emplace_back(*ppBookmark, (*ppBookmark)->GetName()); } } @@ -309,6 +364,7 @@ SwInsertBookmarkDlg::SwInsertBookmarkDlg(weld::Window* pParent, SwWrtShell& rS) , m_xInsertBtn(m_xBuilder->weld_button("insert")) , m_xDeleteBtn(m_xBuilder->weld_button("delete")) , m_xGotoBtn(m_xBuilder->weld_button("goto")) + , m_xEditTextBtn(m_xBuilder->weld_button("edittext")) , m_xRenameBtn(m_xBuilder->weld_button("rename")) , m_xHideCB(m_xBuilder->weld_check_button("hide")) , m_xConditionFT(m_xBuilder->weld_label("condlabel")) @@ -319,17 +375,24 @@ SwInsertBookmarkDlg::SwInsertBookmarkDlg(weld::Window* pParent, SwWrtShell& rS) m_xBookmarksBox->connect_changed(LINK(this, SwInsertBookmarkDlg, SelectionChangedHdl)); m_xBookmarksBox->connect_row_activated(LINK(this, SwInsertBookmarkDlg, DoubleClickHdl)); m_xBookmarksBox->connect_column_clicked(LINK(this, SwInsertBookmarkDlg, HeaderBarClick)); + m_xBookmarksBox->connect_editing(LINK(this, SwInsertBookmarkDlg, EditingHdl), + LINK(this, SwInsertBookmarkDlg, EditedHdl)); m_xEditBox->connect_changed(LINK(this, SwInsertBookmarkDlg, ModifyHdl)); m_xInsertBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, InsertHdl)); m_xDeleteBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, DeleteHdl)); m_xGotoBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, GotoHdl)); + m_xEditTextBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, EditTextHdl)); m_xRenameBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, RenameHdl)); m_xHideCB->connect_toggled(LINK(this, SwInsertBookmarkDlg, ChangeHideHdl)); m_xDeleteBtn->set_sensitive(false); m_xGotoBtn->set_sensitive(false); + m_xEditTextBtn->set_sensitive(false); m_xRenameBtn->set_sensitive(false); + // select 3rd colum, otherwise it'll pick 1st one FIXME doesn't work with gtk? + m_xBookmarksBox->set_column_editables({ false, false, true, false, false }); + PopulateTable(); m_xEditBox->set_text(m_xBookmarksBox->GetNameProposal()); @@ -413,41 +476,27 @@ std::unique_ptr<weld::TreeIter> BookmarkTable::get_selected() const return xIter; } -void BookmarkTable::InsertBookmark(sw::mark::IMark* pMark) +void BookmarkTable::InsertBookmark(SwWrtShell& rSh, sw::mark::IMark* const pMark) { sw::mark::IBookmark* pBookmark = dynamic_cast<sw::mark::IBookmark*>(pMark); assert(pBookmark); - OUString sBookmarkNodeText = pBookmark->GetMarkStart().nNode.GetNode().GetTextNode()->GetText(); - sal_Int32 nBookmarkNodeTextPos = pBookmark->GetMarkStart().nContent.GetIndex(); - sal_Int32 nBookmarkTextLen = 0; - bool bPulledAll = false; - bool bPulling = false; + OUString sBookmarkNodeText; static const sal_Int32 nMaxTextLen = 50; if (pBookmark->IsExpanded()) { - nBookmarkTextLen = pBookmark->GetMarkEnd().nContent.GetIndex() - nBookmarkNodeTextPos; + rSh.Push(); + rSh.GotoMark(pBookmark); + rSh.GetSelectedText(sBookmarkNodeText, ParaBreakType::ToBlank); + rSh.Pop(SwEditShell::PopMode::DeleteCurrent); } - else + if (nMaxTextLen < sBookmarkNodeText.getLength()) { - if (nBookmarkNodeTextPos == sBookmarkNodeText.getLength()) // no text after bookmark - { - nBookmarkNodeTextPos = std::max<sal_Int32>(0, nBookmarkNodeTextPos - nMaxTextLen); - bPulling = true; - if (nBookmarkNodeTextPos == 0) - bPulledAll = true; - } - nBookmarkTextLen = sBookmarkNodeText.getLength() - nBookmarkNodeTextPos; + sBookmarkNodeText = sBookmarkNodeText.subView(0, nMaxTextLen); + ; + sBookmarkNodeText += u"…"; } - bool bExceedsLength = nBookmarkTextLen > nMaxTextLen; - nBookmarkTextLen = std::min<sal_Int32>(nMaxTextLen, nBookmarkTextLen); - sBookmarkNodeText - = o3tl::trim(sBookmarkNodeText.subView(nBookmarkNodeTextPos, nBookmarkTextLen)); - if (bExceedsLength) - sBookmarkNodeText += "..."; - else if (bPulling && !bPulledAll) - sBookmarkNodeText = "..." + sBookmarkNodeText; const OUString& sHideCondition = pBookmark->GetHideCondition(); OUString sHidden = SwResId(STR_BOOKMARK_NO); diff --git a/sw/source/uibase/inc/bookmark.hxx b/sw/source/uibase/inc/bookmark.hxx index 6441a5f16f63..36f83f3a86e9 100644 --- a/sw/source/uibase/inc/bookmark.hxx +++ b/sw/source/uibase/inc/bookmark.hxx @@ -32,7 +32,7 @@ class BookmarkTable std::unique_ptr<weld::TreeIter> GetRowByBookmarkName(const OUString& sName); public: BookmarkTable(std::unique_ptr<weld::TreeView> xControl); - void InsertBookmark(sw::mark::IMark* pMark); + void InsertBookmark(SwWrtShell & rSh, sw::mark::IMark* pMark); void SelectByName(const OUString& sName); sw::mark::IMark* GetBookmarkByName(const OUString& sName); OUString GetNameProposal() const; @@ -43,6 +43,7 @@ public: void clear() { m_xControl->clear(); } void select(const weld::TreeIter& rIter) { m_xControl->select(rIter); } void remove_selection() { m_xControl->remove_selection(); } + OUString get_text(const weld::TreeIter& rIter) const { return m_xControl->get_text(rIter, 2); } OUString get_id(const weld::TreeIter& rIter) const { return m_xControl->get_id(rIter); } void set_sort_indicator(TriState eState, int nColumn = -1) { m_xControl->set_sort_indicator(eState, nColumn); } void selected_foreach(const std::function<bool(weld::TreeIter&)>& func) { m_xControl->selected_foreach(func); } @@ -50,6 +51,10 @@ public: void connect_changed(const Link<weld::TreeView&, void>& rLink) { m_xControl->connect_changed(rLink); } void connect_row_activated(const Link<weld::TreeView&, bool>& rLink) { m_xControl->connect_row_activated(rLink); } void connect_column_clicked(const Link<int, void>& rLink) { m_xControl->connect_column_clicked(rLink); } + void connect_editing(const Link<const weld::TreeIter&, bool>& rStartLink, + const Link<const weld::TreeView::iter_string&, bool>& rEndLink) { m_xControl->connect_editing(rStartLink, rEndLink); } + void set_column_editables(::std::vector<bool> const& rEditables) { m_xControl->set_column_editables(rEditables); } + void start_editing(weld::TreeIter const& rIter) { m_xControl->start_editing(rIter); } void make_sorted() { m_xControl->make_sorted(); } bool get_sort_order() const { return m_xControl->get_sort_order(); } void set_sort_order(bool bAscending) { m_xControl->set_sort_order(bAscending); } @@ -72,6 +77,7 @@ class SwInsertBookmarkDlg final : public SfxDialogController std::unique_ptr<weld::Button> m_xInsertBtn; std::unique_ptr<weld::Button> m_xDeleteBtn; std::unique_ptr<weld::Button> m_xGotoBtn; + std::unique_ptr<weld::Button> m_xEditTextBtn; std::unique_ptr<weld::Button> m_xRenameBtn; std::unique_ptr<weld::CheckButton> m_xHideCB; std::unique_ptr<weld::Label> m_xConditionFT; @@ -82,12 +88,15 @@ class SwInsertBookmarkDlg final : public SfxDialogController DECL_LINK(ModifyHdl, weld::Entry&, void); DECL_LINK(InsertHdl, weld::Button&, void); DECL_LINK(DeleteHdl, weld::Button&, void); + DECL_LINK(EditTextHdl, weld::Button&, void); DECL_LINK(RenameHdl, weld::Button&, void); DECL_LINK(GotoHdl, weld::Button&, void); DECL_LINK(SelectionChangedHdl, weld::TreeView&, void); DECL_LINK(DoubleClickHdl, weld::TreeView&, bool); DECL_LINK(HeaderBarClick, int, void); DECL_LINK(ChangeHideHdl, weld::Toggleable&, void); + DECL_LINK(EditingHdl, weld::TreeIter const&, bool); + DECL_LINK(EditedHdl, weld::TreeView::iter_string const&, bool); // Fill table with bookmarks void PopulateTable(); diff --git a/sw/uiconfig/swriter/ui/insertbookmark.ui b/sw/uiconfig/swriter/ui/insertbookmark.ui index 0cd5225733f0..0a183c4e1f51 100644 --- a/sw/uiconfig/swriter/ui/insertbookmark.ui +++ b/sw/uiconfig/swriter/ui/insertbookmark.ui @@ -267,7 +267,9 @@ <property name="title" translatable="yes" context="insertbookmark|text">Text</property> <property name="clickable">True</property> <child> - <object class="GtkCellRendererText" id="cellrenderer2"/> + <object class="GtkCellRendererText" id="cellrenderer2"> + <property name="editable">True</property> + </object> <attributes> <attribute name="text">2</attribute> </attributes> @@ -363,6 +365,20 @@ <property name="position">1</property> </packing> </child> + <child> + <object class="GtkButton" id="edittext"> + <property name="label" translatable="yes" context="insertbookmark|edittext">Edit Text</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack-type">end</property> + <property name="position">2</property> + </packing> + </child> <child> <object class="GtkButton" id="rename"> <property name="label" translatable="yes" context="insertbookmark|rename">Rename</property> @@ -374,7 +390,7 @@ <property name="expand">False</property> <property name="fill">False</property> <property name="pack-type">end</property> - <property name="position">2</property> + <property name="position">3</property> </packing> </child> </object>
