sc/source/ui/formdlg/dwfunctr.cxx | 137 +++++++++++++++++++++++++++++++--- sc/source/ui/inc/dwfunctr.hxx | 8 + sc/source/ui/view/tabvwsh3.cxx | 3 sc/uiconfig/scalc/ui/functionpanel.ui | 36 ++++++++ 4 files changed, 166 insertions(+), 18 deletions(-)
New commits: commit b5a8cdbd71a61c76f2b1a6ad33b0757911603184 Author: Rafael Lima <rafael.palma.l...@gmail.com> AuthorDate: Tue Jul 25 22:42:49 2023 +0200 Commit: Rafael Lima <rafael.palma.l...@gmail.com> CommitDate: Fri Sep 15 13:25:49 2023 +0200 tdf#122718 Add search functionality to the Functions sidebar With this patch it is possible to search the list of functions in the Functions sidebar. To use this feature: 1) In Calc, go to View - Function List 2) The Functions sidebar will open with the "Search" entry focused 3) You can now type your search 4) With the "Search" entry focused, it is possible to use the arrow keys (up/down) to select the function to insert 5) Press "Enter" to insert the function The Escape key will clear the search box and F1 will open the help page of the selected function. Change-Id: I1af6c1c2489ff736c44e1b3750bea21c05786602 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154917 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins Reviewed-by: Rafael Lima <rafael.palma.l...@gmail.com> diff --git a/sc/source/ui/formdlg/dwfunctr.cxx b/sc/source/ui/formdlg/dwfunctr.cxx index 8fde50549be1..d158a4aada69 100644 --- a/sc/source/ui/formdlg/dwfunctr.cxx +++ b/sc/source/ui/formdlg/dwfunctr.cxx @@ -21,6 +21,7 @@ #include <editeng/editview.hxx> #include <sfx2/viewsh.hxx> #include <formula/funcvarargs.h> +#include <unotools/charclass.hxx> #include <global.hxx> #include <scmod.hxx> @@ -29,6 +30,8 @@ #include <funcdesc.hxx> #include <dwfunctr.hxx> +#include <scresid.hxx> +#include <strings.hrc> /************************************************************************* #* Member: ScFunctionWin @@ -50,6 +53,7 @@ ScFunctionWin::ScFunctionWin(weld::Widget* pParent) , xFuncList(m_xBuilder->weld_tree_view("funclist")) , xInsertButton(m_xBuilder->weld_button("insert")) , xFiFuncDesc(m_xBuilder->weld_text_view("funcdesc")) + , m_xSearchString(m_xBuilder->weld_entry("search")) , xConfigListener(new comphelper::ConfigurationListener("/org.openoffice.Office.Calc/Formula/Syntax")) , xConfigChange(std::make_unique<EnglishFunctionNameChange>(xConfigListener, this)) , pFuncDesc(nullptr) @@ -57,11 +61,15 @@ ScFunctionWin::ScFunctionWin(weld::Widget* pParent) InitLRUList(); nArgs=0; - m_aHelpId = xFuncList->get_help_id(); + m_aListHelpId = xFuncList->get_help_id(); + m_aSearchHelpId = m_xSearchString->get_help_id(); // Description box has a height of 8 lines of text xFiFuncDesc->set_size_request(-1, 8 * xFiFuncDesc->get_text_height()); + m_xSearchString->connect_changed(LINK(this, ScFunctionWin, ModifyHdl)); + m_xSearchString->connect_key_press(LINK(this, ScFunctionWin, KeyInputHdl)); + xCatBox->connect_changed(LINK( this, ScFunctionWin, SelComboHdl)); xFuncList->connect_changed(LINK( this, ScFunctionWin, SelTreeHdl)); @@ -100,7 +108,7 @@ ScFunctionWin::~ScFunctionWin() } /************************************************************************* -#* Member: UpdateFunctionList +#* Member: InitLRUList #*------------------------------------------------------------------------ #* #* Class: ScFunctionWin @@ -121,11 +129,11 @@ void ScFunctionWin::InitLRUList() sal_Int32 nSelPos = xCatBox->get_active(); if (nSelPos == 0) - UpdateFunctionList(); + UpdateFunctionList(""); } /************************************************************************* -#* Member: UpdateFunctionList +#* Member: UpdateLRUList #*------------------------------------------------------------------------ #* #* Class: ScFunctionWin @@ -183,7 +191,7 @@ void ScFunctionWin::SetDescription() if (!sHelpId.isEmpty()) xFuncList->set_help_id(pDesc->getHelpId()); else - xFuncList->set_help_id(m_aHelpId); + xFuncList->set_help_id(m_aListHelpId); } } @@ -195,13 +203,13 @@ void ScFunctionWin::SetDescription() #* #* Function: Updates the list of functions depending on the set category #* -#* Input: --- +#* Input: Search string used to filter the list of functions #* #* Output: --- #* #************************************************************************/ -void ScFunctionWin::UpdateFunctionList() +void ScFunctionWin::UpdateFunctionList(const OUString& rSearchString) { sal_Int32 nSelPos = xCatBox->get_active(); sal_Int32 nCategory = ( -1 != nSelPos ) @@ -214,12 +222,32 @@ void ScFunctionWin::UpdateFunctionList() { ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr(); + SvtSysLocale aSysLocale; + const CharClass& rCharClass = aSysLocale.GetCharClass(); + const OUString aSearchStr(rCharClass.uppercase(rSearchString)); + + // First add the functions that start with the search string const ScFuncDesc* pDesc = pFuncMgr->First( nCategory ); while ( pDesc ) { - xFuncList->append(weld::toId(pDesc), *(pDesc->mxFuncName)); + if (rSearchString.isEmpty() + || (rCharClass.uppercase(pDesc->getFunctionName()).startsWith(aSearchStr))) + xFuncList->append(weld::toId(pDesc), *(pDesc->mxFuncName)); pDesc = pFuncMgr->Next(); } + + // Now add the functions that have the search string in the middle of the function name + // Note that this will only be necessary if the search string is not empty + if (!rSearchString.isEmpty()) + { + pDesc = pFuncMgr->First( nCategory ); + while ( pDesc ) + { + if (rCharClass.uppercase(pDesc->getFunctionName()).indexOf(aSearchStr) > 0) + xFuncList->append(weld::toId(pDesc), *(pDesc->mxFuncName)); + pDesc = pFuncMgr->Next(); + } + } } else // LRU list { @@ -359,7 +387,90 @@ void ScFunctionWin::DoEnter() } /************************************************************************* -#* Handle: SelHdl +#* Handle: ModifyHdl +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: Handles changes in the search text +#* +#************************************************************************/ + +IMPL_LINK_NOARG(ScFunctionWin, ModifyHdl, weld::Entry&, void) +{ + // Switch to the "All" category when searching a function + xCatBox->set_active(1); + OUString searchStr = m_xSearchString->get_text(); + UpdateFunctionList(searchStr); + SetDescription(); +} + +/************************************************************************* +#* Handle: KeyInputHdl +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: Processes key inputs when the serch entry has focus +#* +#************************************************************************/ + +IMPL_LINK(ScFunctionWin, KeyInputHdl, const KeyEvent&, rEvent, bool) +{ + bool bHandled = false; + + switch (rEvent.GetKeyCode().GetCode()) + { + case KEY_RETURN: + { + DoEnter(); + bHandled = true; + } + break; + case KEY_DOWN: + { + int nNewIndex = std::min(xFuncList->get_selected_index() + 1, xFuncList->n_children() - 1); + xFuncList->select(nNewIndex); + SetDescription(); + bHandled = true; + } + break; + case KEY_UP: + { + int nNewIndex = std::max(xFuncList->get_selected_index() - 1, 0); + xFuncList->select(nNewIndex); + SetDescription(); + bHandled = true; + } + break; + case KEY_ESCAPE: + { + m_xSearchString->set_text(""); + UpdateFunctionList(""); + bHandled = true; + } + break; + case KEY_F1: + { + const ScFuncDesc* pDesc = weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id()); + OUString sHelpId; + if (pDesc) + sHelpId = pDesc->getHelpId(); + + if (!sHelpId.isEmpty()) + m_xSearchString->set_help_id(sHelpId); + else + m_xSearchString->set_help_id(m_aSearchHelpId); + bHandled = false; + } + break; + } + + return bHandled; +} + +/************************************************************************* +#* Handle: SelComboHdl #*------------------------------------------------------------------------ #* #* Class: ScFunctionWin @@ -374,8 +485,10 @@ void ScFunctionWin::DoEnter() IMPL_LINK_NOARG(ScFunctionWin, SelComboHdl, weld::ComboBox&, void) { - UpdateFunctionList(); + UpdateFunctionList(""); SetDescription(); + m_xSearchString->set_text(""); + m_xSearchString->grab_focus(); } IMPL_LINK_NOARG(ScFunctionWin, SelTreeHdl, weld::TreeView&, void) @@ -384,7 +497,7 @@ IMPL_LINK_NOARG(ScFunctionWin, SelTreeHdl, weld::TreeView&, void) } /************************************************************************* -#* Handle: SelHdl +#* Handle: SetSelectionClickHdl #*------------------------------------------------------------------------ #* #* Class: ScFunctionWin @@ -412,7 +525,7 @@ void EnglishFunctionNameChange::setProperty(const css::uno::Any &rProperty) { ConfigurationListenerProperty::setProperty(rProperty); m_pFunctionWin->InitLRUList(); - m_pFunctionWin->UpdateFunctionList(); + m_pFunctionWin->UpdateFunctionList(""); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/inc/dwfunctr.hxx b/sc/source/ui/inc/dwfunctr.hxx index b6d0d032a857..faf68ecd4198 100644 --- a/sc/source/ui/inc/dwfunctr.hxx +++ b/sc/source/ui/inc/dwfunctr.hxx @@ -47,12 +47,14 @@ private: std::unique_ptr<weld::TreeView> xFuncList; std::unique_ptr<weld::Button> xInsertButton; std::unique_ptr<weld::TextView> xFiFuncDesc; + std::unique_ptr<weld::Entry> m_xSearchString; rtl::Reference<comphelper::ConfigurationListener> xConfigListener; std::unique_ptr<EnglishFunctionNameChange> xConfigChange; const ScFuncDesc* pFuncDesc; sal_uInt16 nArgs; - OUString m_aHelpId; + OUString m_aListHelpId; + OUString m_aSearchHelpId; ::std::vector< const formula::IFunctionDescription*> aLRUList; @@ -64,6 +66,8 @@ private: DECL_LINK( SetSelectionClickHdl, weld::Button&, void ); DECL_LINK( SelComboHdl, weld::ComboBox&, void ); DECL_LINK( SelTreeHdl, weld::TreeView&, void ); + DECL_LINK( ModifyHdl, weld::Entry&, void ); + DECL_LINK( KeyInputHdl, const KeyEvent&, bool); public: ScFunctionWin(weld::Widget* pParent); @@ -71,7 +75,7 @@ public: virtual ~ScFunctionWin() override; void InitLRUList(); - void UpdateFunctionList(); + void UpdateFunctionList(const OUString&); }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/view/tabvwsh3.cxx b/sc/source/ui/view/tabvwsh3.cxx index ce0453040461..60754c58baff 100644 --- a/sc/source/ui/view/tabvwsh3.cxx +++ b/sc/source/ui/view/tabvwsh3.cxx @@ -677,7 +677,8 @@ void ScTabViewShell::Execute( SfxRequest& rReq ) rThisFrame.ShowChildWindow(SID_SIDEBAR); ::sfx2::sidebar::Sidebar::ShowPanel(u"ScFunctionsPanel", - rThisFrame.GetFrame().GetFrameInterface()); + rThisFrame.GetFrame().GetFrameInterface(), + true); rReq.Done (); } break; diff --git a/sc/uiconfig/scalc/ui/functionpanel.ui b/sc/uiconfig/scalc/ui/functionpanel.ui index 380bf7b6b651..c0682699776b 100644 --- a/sc/uiconfig/scalc/ui/functionpanel.ui +++ b/sc/uiconfig/scalc/ui/functionpanel.ui @@ -31,7 +31,7 @@ <property name="border-width">6</property> <property name="row-spacing">6</property> <child> - <!-- n-columns=1 n-rows=2 --> + <!-- n-columns=1 n-rows=3 --> <object class="GtkGrid"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -94,7 +94,7 @@ </object> <packing> <property name="left-attach">0</property> - <property name="top-attach">0</property> + <property name="top-attach">1</property> </packing> </child> <child> @@ -138,7 +138,37 @@ </object> <packing> <property name="left-attach">0</property> - <property name="top-attach">1</property> + <property name="top-attach">2</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkEntry" id="search"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="hexpand">True</property> + <property name="placeholder-text" translatable="yes" context="functionpanel|search">Search all functions</property> + <child internal-child="accessible"> + <object class="AtkObject" id="search-atkobject"> + <property name="AtkObject::accessible-name" translatable="yes" context="functionpanel|accessiblename|search">Search all functions</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">0</property> </packing> </child> </object>