xref: /core/formula/source/ui/dlg/funcpage.cxx (revision 12215925)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/event.hxx>
21 #include <vcl/svapp.hxx>
22 #include <formula/IFunctionDescription.hxx>
23 
24 #include "funcpage.hxx"
25 #include <unotools/syslocale.hxx>
26 #include <unotools/charclass.hxx>
27 
28 namespace formula
29 {
IMPL_LINK(FuncPage,KeyInputHdl,const KeyEvent &,rKEvt,bool)30 IMPL_LINK(FuncPage, KeyInputHdl, const KeyEvent&, rKEvt, bool)
31 {
32     if (rKEvt.GetCharCode() == ' ')
33     {
34         aDoubleClickLink.Call(*this);
35         return true;
36     }
37     return false;
38 }
39 
40 // tdf#104487 - remember last used function category - set default to All category
41 sal_Int32 FuncPage::m_nRememberedFunctionCategory = 1;
42 
FuncPage(weld::Container * pParent,const IFunctionManager * _pFunctionManager)43 FuncPage::FuncPage(weld::Container* pParent, const IFunctionManager* _pFunctionManager)
44     : m_xBuilder(Application::CreateBuilder(pParent, u"formula/ui/functionpage.ui"_ustr))
45     , m_xContainer(m_xBuilder->weld_container(u"FunctionPage"_ustr))
46     , m_xLbCategory(m_xBuilder->weld_combo_box(u"category"_ustr))
47     , m_xLbFunction(m_xBuilder->weld_tree_view(u"function"_ustr))
48     , m_xLbFunctionSearchString(m_xBuilder->weld_entry(u"search"_ustr))
49     , m_pFunctionManager(_pFunctionManager)
50 {
51     m_xLbFunction->make_sorted();
52     m_aHelpId = m_xLbFunction->get_help_id();
53 
54     m_pFunctionManager->fillLastRecentlyUsedFunctions(aLRUList);
55 
56     const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
57     for (sal_uInt32 j = 0; j < nCategoryCount; ++j)
58     {
59         const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j);
60         OUString sId(weld::toId(pCategory));
61         m_xLbCategory->append(sId, pCategory->getName());
62     }
63 
64     // tdf#104487 - remember last used function category
65     m_xLbCategory->set_active(m_nRememberedFunctionCategory);
66     OUString searchStr = m_xLbFunctionSearchString->get_text();
67     UpdateFunctionList(searchStr);
68     // lock to its initial size
69     m_xLbFunction->set_size_request(m_xLbFunction->get_preferred_size().Width(),
70                                     m_xLbFunction->get_height_rows(15));
71     m_xLbCategory->connect_changed(LINK(this, FuncPage, SelComboBoxHdl));
72     m_xLbFunction->connect_changed(LINK(this, FuncPage, SelTreeViewHdl));
73     m_xLbFunction->connect_row_activated(LINK(this, FuncPage, DblClkHdl));
74     m_xLbFunction->connect_key_press(LINK(this, FuncPage, KeyInputHdl));
75     m_xLbFunctionSearchString->connect_changed(LINK(this, FuncPage, ModifyHdl));
76 
77     m_xLbFunctionSearchString->grab_focus();
78 }
79 
~FuncPage()80 FuncPage::~FuncPage() {}
81 
impl_addFunctions(const IFunctionCategory * _pCategory)82 void FuncPage::impl_addFunctions(const IFunctionCategory* _pCategory)
83 {
84     const sal_uInt32 nCount = _pCategory->getCount();
85     for (sal_uInt32 i = 0; i < nCount; ++i)
86     {
87         TFunctionDesc pDesc(_pCategory->getFunction(i));
88         if (!pDesc->isHidden())
89         {
90             OUString sId(weld::toId(pDesc));
91             m_xLbFunction->append(sId, pDesc->getFunctionName());
92         }
93     }
94 }
95 
96 //aStr is non-empty when user types in the search box to search some function
UpdateFunctionList(const OUString & aStr)97 void FuncPage::UpdateFunctionList(const OUString& aStr)
98 {
99     m_xLbFunction->clear();
100     m_xLbFunction->freeze();
101 
102     const sal_Int32 nSelPos = m_xLbCategory->get_active();
103     // tdf#104487 - remember last used function category
104     m_nRememberedFunctionCategory = nSelPos;
105 
106     if (aStr.isEmpty() || nSelPos == 0)
107     {
108         const IFunctionCategory* pCategory
109             = weld::fromId<const IFunctionCategory*>(m_xLbCategory->get_id(nSelPos));
110 
111         if (nSelPos > 0)
112         {
113             if (pCategory == nullptr)
114             {
115                 const sal_uInt32 nCount = m_pFunctionManager->getCount();
116                 for (sal_uInt32 i = 0; i < nCount; ++i)
117                 {
118                     impl_addFunctions(m_pFunctionManager->getCategory(i));
119                 }
120             }
121             else
122             {
123                 impl_addFunctions(pCategory);
124             }
125         }
126         else // LRU-List
127         {
128             for (auto const& elem : aLRUList)
129             {
130                 if (elem) // may be null if a function is no longer available
131                 {
132                     OUString sId(weld::toId(elem));
133                     m_xLbFunction->append(sId, elem->getFunctionName());
134                 }
135             }
136         }
137     }
138     else
139     {
140         SvtSysLocale aSysLocale;
141         const CharClass& rCharClass = aSysLocale.GetCharClass();
142         const OUString aSearchStr(rCharClass.uppercase(aStr));
143 
144         const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
145         // Category listbox holds additional entries for Last Used and All, so
146         // the offset should be two but hard coded numbers are ugly...
147         const sal_Int32 nCategoryOffset = m_xLbCategory->get_count() - nCategoryCount;
148         // If a real category (not Last Used or All) is selected, list only
149         // functions of that category. Else list all, LRU is handled above.
150         sal_Int32 nCatBeg = (nSelPos == -1 ? -1 : nSelPos - nCategoryOffset);
151         sal_uInt32 nCatEnd;
152         if (nCatBeg < 0)
153         {
154             nCatBeg = 0;
155             nCatEnd = nCategoryCount;
156         }
157         else
158         {
159             nCatEnd = nCatBeg + 1;
160         }
161         for (sal_uInt32 i = nCatBeg; i < nCatEnd; ++i)
162         {
163             const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(i);
164             const sal_uInt32 nFunctionCount = pCategory->getCount();
165             for (sal_uInt32 j = 0; j < nFunctionCount; ++j)
166             {
167                 TFunctionDesc pDesc(pCategory->getFunction(j));
168                 // tdf#146781 - search for the desired function also in the description
169                 if (rCharClass.uppercase(pDesc->getFunctionName()).indexOf(aSearchStr) >= 0
170                     || rCharClass.uppercase(pDesc->getDescription()).indexOf(aSearchStr) >= 0)
171                 {
172                     if (!pDesc->isHidden())
173                     {
174                         OUString sId(weld::toId(pDesc));
175                         m_xLbFunction->append(sId, pDesc->getFunctionName());
176                     }
177                 }
178             }
179         }
180     }
181 
182     m_xLbFunction->thaw();
183     // Ensure no function is selected so the Next button doesn't overwrite a
184     // function that is not in the list with an arbitrary selected one.
185     m_xLbFunction->unselect_all();
186 
187     if (IsVisible())
188         SelTreeViewHdl(*m_xLbFunction);
189 }
190 
IMPL_LINK_NOARG(FuncPage,SelComboBoxHdl,weld::ComboBox &,void)191 IMPL_LINK_NOARG(FuncPage, SelComboBoxHdl, weld::ComboBox&, void)
192 {
193     OUString searchStr = m_xLbFunctionSearchString->get_text();
194     m_xLbFunction->set_help_id(m_aHelpId);
195     UpdateFunctionList(searchStr);
196 }
197 
IMPL_LINK_NOARG(FuncPage,SelTreeViewHdl,weld::TreeView &,void)198 IMPL_LINK_NOARG(FuncPage, SelTreeViewHdl, weld::TreeView&, void)
199 {
200     const IFunctionDescription* pDesc = GetFuncDesc(GetFunction());
201     if (pDesc)
202     {
203         const OUString sHelpId = pDesc->getHelpId();
204         if (!sHelpId.isEmpty())
205             m_xLbFunction->set_help_id(sHelpId);
206     }
207     aSelectionLink.Call(*this);
208 }
209 
IMPL_LINK_NOARG(FuncPage,DblClkHdl,weld::TreeView &,bool)210 IMPL_LINK_NOARG(FuncPage, DblClkHdl, weld::TreeView&, bool)
211 {
212     aDoubleClickLink.Call(*this);
213     return true;
214 }
215 
IMPL_LINK_NOARG(FuncPage,ModifyHdl,weld::Entry &,void)216 IMPL_LINK_NOARG(FuncPage, ModifyHdl, weld::Entry&, void)
217 {
218     // While typing select All category.
219     m_xLbCategory->set_active(1);
220     OUString searchStr = m_xLbFunctionSearchString->get_text();
221     UpdateFunctionList(searchStr);
222 }
223 
SetCategory(sal_Int32 nCat)224 void FuncPage::SetCategory(sal_Int32 nCat)
225 {
226     // tdf#104487 - remember last used function category
227     m_nRememberedFunctionCategory = nCat;
228     m_xLbCategory->set_active(nCat);
229     UpdateFunctionList(OUString());
230 }
231 
GetFuncPos(const IFunctionDescription * _pDesc)232 sal_Int32 FuncPage::GetFuncPos(const IFunctionDescription* _pDesc)
233 {
234     return m_xLbFunction->find_id(weld::toId(_pDesc));
235 }
236 
SetFunction(sal_Int32 nFunc)237 void FuncPage::SetFunction(sal_Int32 nFunc)
238 {
239     if (nFunc == -1)
240         m_xLbFunction->unselect_all();
241     else
242         m_xLbFunction->select(nFunc);
243 }
244 
SetFocus()245 void FuncPage::SetFocus() { m_xLbFunction->grab_focus(); }
246 
GetCategory() const247 sal_Int32 FuncPage::GetCategory() const { return m_xLbCategory->get_active(); }
248 
GetCategoryEntryCount() const249 sal_Int32 FuncPage::GetCategoryEntryCount() const { return m_xLbCategory->get_count(); }
250 
GetFunction() const251 sal_Int32 FuncPage::GetFunction() const { return m_xLbFunction->get_selected_index(); }
252 
GetFunctionEntryCount() const253 sal_Int32 FuncPage::GetFunctionEntryCount() const { return m_xLbFunction->n_children(); }
254 
GetSelFunctionName() const255 OUString FuncPage::GetSelFunctionName() const { return m_xLbFunction->get_selected_text(); }
256 
GetFuncDesc(sal_Int32 nPos) const257 const IFunctionDescription* FuncPage::GetFuncDesc(sal_Int32 nPos) const
258 {
259     if (nPos == -1)
260         return nullptr;
261     // not pretty, but hopefully rare
262     return weld::fromId<const IFunctionDescription*>(m_xLbFunction->get_id(nPos));
263 }
264 
265 } // formula
266 
267 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
268