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 473c6a9..fe63d4c 100644
--- a/sw/source/ui/misc/bookmark.cxx
+++ b/sw/source/ui/misc/bookmark.cxx
@@ -88,6 +88,7 @@
// 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 @@
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 @@
{
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 @@
{
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 @@
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 @@
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 @@
{
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 @@
, 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 @@
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 @@
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 6441a5f..36f83f3 100644
--- a/sw/source/uibase/inc/bookmark.hxx
+++ b/sw/source/uibase/inc/bookmark.hxx
@@ -32,7 +32,7 @@
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 @@
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 @@
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 @@
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 @@
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 0cd5225..0a183c4 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>
@@ -364,6 +366,20 @@
</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>
<property name="visible">True</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>