include/vcl/weld.hxx | 11 ++++ sw/source/uibase/inc/QuickFindPanel.hxx | 6 ++ sw/source/uibase/sidebar/QuickFindPanel.cxx | 75 ++++++++++++++++++++++++++++ sw/uiconfig/swriter/ui/sidebarquickfind.ui | 71 +++++++++++++++++++++++++- vcl/inc/jsdialog/jsdialogbuilder.hxx | 1 vcl/jsdialog/jsdialogbuilder.cxx | 11 ++++ 6 files changed, 173 insertions(+), 2 deletions(-)
New commits: commit 989cf8f65342835c61c49026ca0595cc997946e0 Author: NickWingate <[email protected]> AuthorDate: Fri Sep 12 18:50:16 2025 +0100 Commit: Szymon Kłos <[email protected]> CommitDate: Wed Sep 24 13:39:10 2025 +0200 JSTreeView: send select actions to online Previously we just defaulted to `SalInstanceTreeView::select` which doesn't notify online of entries being selected. Signed-off-by: NickWingate <[email protected]> Change-Id: Ia7644b2dc1619cbd97f2e154658dabeb0ae966f3 (cherry picked from commit 047c05ee1d43bba80e24612bf759e5b520146d2d) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191430 Tested-by: Szymon Kłos <[email protected]> Reviewed-by: Szymon Kłos <[email protected]> diff --git a/vcl/inc/jsdialog/jsdialogbuilder.hxx b/vcl/inc/jsdialog/jsdialogbuilder.hxx index 962b806f6bae..37b1f45f442c 100644 --- a/vcl/inc/jsdialog/jsdialogbuilder.hxx +++ b/vcl/inc/jsdialog/jsdialogbuilder.hxx @@ -724,6 +724,7 @@ public: using SalInstanceTreeView::select; /// pos is used differently here, it defines how many steps of iterator we need to perform to take entry virtual void select(int pos) override; + virtual void select(const weld::TreeIter& rIter) override; virtual weld::TreeView* get_drag_source() const override; diff --git a/vcl/jsdialog/jsdialogbuilder.cxx b/vcl/jsdialog/jsdialogbuilder.cxx index 29c5bff12161..9138f9faca65 100644 --- a/vcl/jsdialog/jsdialogbuilder.cxx +++ b/vcl/jsdialog/jsdialogbuilder.cxx @@ -1745,6 +1745,17 @@ void JSTreeView::select(int pos) sendAction(std::move(pMap)); } +void JSTreeView::select(const weld::TreeIter& rIter) +{ + SalInstanceTreeView::select(rIter); + + std::unique_ptr<jsdialog::ActionDataMap> pMap = std::make_unique<jsdialog::ActionDataMap>(); + const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter); + (*pMap)[ACTION_TYPE ""_ostr] = "select"; + (*pMap)["position"_ostr] = OUString::number(m_xTreeView->GetEntryPos(rVclIter.iter)); + sendAction(std::move(pMap)); +} + weld::TreeView* JSTreeView::get_drag_source() const { return g_DragSource; } void JSTreeView::drag_start() { g_DragSource = this; } commit b61e0e7463a0dc24d2c53d2cc8f416e6dd80a598 Author: NickWingate <[email protected]> AuthorDate: Wed Sep 10 12:59:28 2025 +0100 Commit: Szymon Kłos <[email protected]> CommitDate: Wed Sep 24 13:39:00 2025 +0200 QuickFindPanel: Add navigation (up, down) buttons We add `iter_nth_from_start` to `weld::TreeView` to access the last entry in the treeview. Signed-off-by: NickWingate <[email protected]> Change-Id: Ib2f71719a84ab6f1a73fb1c844e68c3907d69c0c (cherry picked from commit 8fa5f638dbc65c30020b851b3d59bec748922c00) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191428 Reviewed-by: Szymon Kłos <[email protected]> Tested-by: Szymon Kłos <[email protected]> diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index fdda5b5168bb..277686c5061f 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -1175,6 +1175,17 @@ public: return false; return iter_nth_sibling(rIter, nChild); } + bool iter_nth_from_start(TreeIter& rIter, int nIndex) const + { + if (!get_iter_first(rIter)) + return false; + for (int i = 0; i < nIndex; ++i) + { + if (!iter_next(rIter)) + return false; + } + return true; + } virtual bool iter_parent(TreeIter& rIter) const = 0; virtual int get_iter_depth(const TreeIter& rIter) const = 0; virtual int get_iter_index_in_parent(const TreeIter& rIter) const = 0; diff --git a/sw/source/uibase/inc/QuickFindPanel.hxx b/sw/source/uibase/inc/QuickFindPanel.hxx index 90b591959216..0085b31164a3 100644 --- a/sw/source/uibase/inc/QuickFindPanel.hxx +++ b/sw/source/uibase/inc/QuickFindPanel.hxx @@ -60,8 +60,11 @@ private: std::unique_ptr<weld::Toolbar> m_xFindAndReplaceToolbar; std::unique_ptr<ToolbarUnoDispatcher> m_xFindAndReplaceToolbarDispatch; std::unique_ptr<weld::Box> m_xTopbar; + std::unique_ptr<weld::Box> m_xQuickFindControls; std::unique_ptr<weld::TreeView> m_xSearchFindsList; std::unique_ptr<weld::Label> m_xSearchFindFoundTimesLabel; + std::unique_ptr<weld::Button> m_xFindNextButton; + std::unique_ptr<weld::Button> m_xFindPreviousButton; SwWrtShell* m_pWrtShell; @@ -84,7 +87,10 @@ private: DECL_LINK(SearchFindsListMousePressHandler, const MouseEvent&, bool); DECL_LINK(SearchOptionsToolbarClickedHandler, const OUString&, void); DECL_LINK(FindAndReplaceToolbarClickedHandler, const OUString&, void); + DECL_LINK(FindNextClickedHandler, weld::Button&, void); + DECL_LINK(FindPreviousClickedHandler, weld::Button&, void); + void NavigateSearchFinds(bool bNext); void FillSearchFindsList(); }; diff --git a/sw/source/uibase/sidebar/QuickFindPanel.cxx b/sw/source/uibase/sidebar/QuickFindPanel.cxx index b6e5b2c72625..d43b6bfac663 100644 --- a/sw/source/uibase/sidebar/QuickFindPanel.cxx +++ b/sw/source/uibase/sidebar/QuickFindPanel.cxx @@ -143,8 +143,11 @@ QuickFindPanel::QuickFindPanel(weld::Widget* pParent, const uno::Reference<frame , m_xFindAndReplaceToolbarDispatch( new ToolbarUnoDispatcher(*m_xFindAndReplaceToolbar, *m_xBuilder, rxFrame)) , m_xTopbar(m_xBuilder->weld_box(u"topbar"_ustr)) + , m_xQuickFindControls(m_xBuilder->weld_box(u"quickfindcontrols"_ustr)) , m_xSearchFindsList(m_xBuilder->weld_tree_view(u"searchfinds"_ustr)) , m_xSearchFindFoundTimesLabel(m_xBuilder->weld_label("numberofsearchfinds")) + , m_xFindNextButton(m_xBuilder->weld_button(u"findnext"_ustr)) + , m_xFindPreviousButton(m_xBuilder->weld_button(u"findprevious"_ustr)) , m_pWrtShell(::GetActiveWrtShell()) { if (comphelper::LibreOfficeKit::isActive()) @@ -184,6 +187,11 @@ QuickFindPanel::QuickFindPanel(weld::Widget* pParent, const uno::Reference<frame LINK(this, QuickFindPanel, SearchFindsListRowActivatedHandler)); m_xSearchFindsList->connect_mouse_press( LINK(this, QuickFindPanel, SearchFindsListMousePressHandler)); + + m_xQuickFindControls->set_visible(false); + + m_xFindNextButton->connect_clicked(LINK(this, QuickFindPanel, FindNextClickedHandler)); + m_xFindPreviousButton->connect_clicked(LINK(this, QuickFindPanel, FindPreviousClickedHandler)); } IMPL_LINK_NOARG(QuickFindPanel, SearchOptionsToolbarClickedHandler, const OUString&, void) @@ -247,6 +255,7 @@ IMPL_LINK_NOARG(QuickFindPanel, SearchFindEntryChangedHandler, weld::Entry&, voi m_xSearchFindEntry->set_message_type(weld::EntryMessageType::Normal); m_xSearchFindsList->clear(); m_xSearchFindFoundTimesLabel->set_label(OUString()); + m_xQuickFindControls->set_visible(false); } IMPL_LINK_NOARG(QuickFindPanel, SearchFindEntryActivateHandler, weld::Entry&, bool) @@ -427,6 +436,8 @@ IMPL_LINK_NOARG(QuickFindPanel, SearchFindsListSelectionChangedHandler, weld::Tr sText = sText.replaceFirst("%1", OUString::number(sId.toUInt32() + 1)); sText = sText.replaceFirst("%2", OUString::number(nSearchFindFoundTimes)); m_xSearchFindFoundTimesLabel->set_label(sText); + if (nSearchFindFoundTimes > 1) + m_xQuickFindControls->set_visible(true); SwShellCursor* pShellCursor = m_pWrtShell->GetCursor_(); std::vector<basegfx::B2DRange> vRanges; @@ -452,11 +463,73 @@ IMPL_LINK_NOARG(QuickFindPanel, SearchFindsListRowActivatedHandler, weld::TreeVi return true; } +IMPL_LINK_NOARG(QuickFindPanel, FindNextClickedHandler, weld::Button&, void) +{ + NavigateSearchFinds(true); // true = next/down +} + +IMPL_LINK_NOARG(QuickFindPanel, FindPreviousClickedHandler, weld::Button&, void) +{ + NavigateSearchFinds(false); // false = previous/up +} + +void QuickFindPanel::NavigateSearchFinds(bool bNext) +{ + if (!m_xSearchFindsList || m_xSearchFindsList->n_children() == 0) + return; + + std::unique_ptr<weld::TreeIter> xEntry(m_xSearchFindsList->make_iterator()); + + bool bMoved = false; + + // no current selection, select first/last entry + if (!m_xSearchFindsList->get_cursor(xEntry.get())) + { + bMoved = m_xSearchFindsList->iter_nth_from_start( + *xEntry, bNext ? 0 : m_xSearchFindsList->n_children() - 1); + } + else + { + if (bNext) + bMoved = m_xSearchFindsList->iter_next(*xEntry); + else + bMoved = m_xSearchFindsList->iter_previous(*xEntry); + } + + if (!bMoved) + { + bMoved = m_xSearchFindsList->iter_nth_from_start( + *xEntry, bNext ? 0 : m_xSearchFindsList->n_children() - 1); + } + + // Keep going until we find a non-page entry + while (IsPageEntry(*xEntry)) + { + // skip page entry + if (bNext) + bMoved = m_xSearchFindsList->iter_next(*xEntry); + else + bMoved = m_xSearchFindsList->iter_previous(*xEntry); + + if (!bMoved) + { + bMoved = m_xSearchFindsList->iter_nth_from_start( + *xEntry, bNext ? 0 : m_xSearchFindsList->n_children() - 1); + } + } + m_xSearchFindsList->set_cursor(*xEntry); + + // todo: ideally we dont need to manually call this handler, but select disables event propagation see SalInstanceTreeView::select(const weld::TreeIter& rIter) + m_xSearchFindsList->select(*xEntry); + SearchFindsListSelectionChangedHandler(*m_xSearchFindsList); +} + void QuickFindPanel::FillSearchFindsList() { m_vPaMs.clear(); m_xSearchFindsList->clear(); m_xSearchFindFoundTimesLabel->set_label(OUString()); + m_xQuickFindControls->set_visible(false); const OUString sFindEntry = m_xSearchFindEntry->get_text(); if (sFindEntry.isEmpty()) @@ -654,6 +727,8 @@ void QuickFindPanel::FillSearchFindsList() OUString sText(SwResId(STR_SEARCH_KEY_FOUND_TIMES, nSearchFindFoundTimes)); sText = sText.replaceFirst("%1", OUString::number(nSearchFindFoundTimes)); m_xSearchFindFoundTimesLabel->set_label(sText); + if (nSearchFindFoundTimes > 1) + m_xQuickFindControls->set_visible(true); } } // end of namespace ::sw::sidebar diff --git a/sw/uiconfig/swriter/ui/sidebarquickfind.ui b/sw/uiconfig/swriter/ui/sidebarquickfind.ui index 7701a42005cf..9345733622dd 100644 --- a/sw/uiconfig/swriter/ui/sidebarquickfind.ui +++ b/sw/uiconfig/swriter/ui/sidebarquickfind.ui @@ -10,6 +10,18 @@ <column type="gchararray"/> </columns> </object> + <object class="GtkImage" id="prevImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">pan-up-symbolic</property> + <property name="icon_size">2</property> + </object> + <object class="GtkImage" id="nextImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">pan-down-symbolic</property> + <property name="icon_size">2</property> + </object> <!-- n-columns=1 n-rows=1 --> <object class="GtkGrid" id="QuickFindPanel"> <property name="visible">True</property> @@ -156,16 +168,71 @@ </packing> </child> <child> - <object class="GtkLabel" id="numberofsearchfinds"> + <object class="GtkBox" id="searchresultscontainer"> <property name="visible">True</property> <property name="can-focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="numberofsearchfinds"> + <property name="visible">True</property> + <property name="can-focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="quickfindcontrols"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="spacing">3</property> + <child> + <object class="GtkButton" id="findprevious"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="tooltip-text">Previous Result</property> <!-- TODO: add translatable --> + <property name="image">prevImage</property> + <property name="always-show-image">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="findnext"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="tooltip-text">Next Result</property> <!-- TODO: add translatable --> + <property name="image">nextImage</property> + <property name="always-show-image">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">3</property> + <property name="position">2</property> </packing> </child> + </object> <packing> <property name="left-attach">0</property>
