Update git submodules
[LibreOffice.git] / sc / source / ui / formdlg / dwfunctr.cxx
blob3345e1f83f954ecb139ff7e6fe7cc47d2694ba52
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <comphelper/string.hxx>
21 #include <editeng/editview.hxx>
22 #include <sfx2/viewsh.hxx>
23 #include <formula/funcvarargs.h>
24 #include <unotools/charclass.hxx>
25 #include <unotools/textsearch.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/help.hxx>
29 #include <global.hxx>
30 #include <scmod.hxx>
31 #include <inputhdl.hxx>
32 #include <tabvwsh.hxx>
33 #include <funcdesc.hxx>
34 #include <compiler.hxx>
36 #include <dwfunctr.hxx>
38 /*************************************************************************
39 #* Member: ScFunctionWin
40 #*------------------------------------------------------------------------
42 #* Class: ScFunctionWin
44 #* Function: Constructor of ScFunctionWin Class
46 #* Input: Sfx - links, window, resource
48 #* Output: ---
50 #************************************************************************/
52 ScFunctionWin::ScFunctionWin(weld::Widget* pParent)
53 : PanelLayout(pParent, u"FunctionPanel"_ustr, u"modules/scalc/ui/functionpanel.ui"_ustr)
54 , xCatBox(m_xBuilder->weld_combo_box(u"category"_ustr))
55 , xFuncList(m_xBuilder->weld_tree_view(u"funclist"_ustr))
56 , xScratchIter(xFuncList->make_iterator())
57 , xInsertButton(m_xBuilder->weld_button(u"insert"_ustr))
58 , xHelpButton(m_xBuilder->weld_button(u"help"_ustr))
59 , xSimilaritySearch(m_xBuilder->weld_check_button(u"similaritysearch"_ustr))
60 , xFiFuncDesc(m_xBuilder->weld_text_view(u"funcdesc"_ustr))
61 , m_xSearchString(m_xBuilder->weld_entry(u"search"_ustr))
62 , xConfigListener(new comphelper::ConfigurationListener(u"/org.openoffice.Office.Calc/Formula/Syntax"_ustr))
63 , xConfigChange(std::make_unique<EnglishFunctionNameChange>(xConfigListener, this))
64 , pFuncDesc(nullptr)
66 InitLRUList();
68 nArgs=0;
69 m_aListHelpId = xFuncList->get_help_id();
70 m_aSearchHelpId = m_xSearchString->get_help_id();
72 // Description box has a height of 8 lines of text
73 xFiFuncDesc->set_size_request(-1, 8 * xFiFuncDesc->get_text_height());
75 m_xSearchString->connect_changed(LINK(this, ScFunctionWin, ModifyHdl));
76 m_xSearchString->connect_key_press(LINK(this, ScFunctionWin, KeyInputHdl));
78 xCatBox->connect_changed(LINK( this, ScFunctionWin, SelComboHdl));
79 xFuncList->connect_selection_changed(LINK(this, ScFunctionWin, SelTreeHdl));
81 xFuncList->connect_row_activated(LINK( this, ScFunctionWin, SetRowActivatedHdl));
82 xInsertButton->connect_clicked(LINK( this, ScFunctionWin, SetSelectionClickHdl));
83 xHelpButton->connect_clicked(LINK( this, ScFunctionWin, SetHelpClickHdl));
84 xSimilaritySearch->connect_toggled(LINK(this, ScFunctionWin, SetSimilarityToggleHdl));
86 xCatBox->set_active(0);
88 SelComboHdl(*xCatBox);
91 /*************************************************************************
92 #* Member: ScFunctionWin
93 #*------------------------------------------------------------------------
95 #* Class: ScFunctionWin
97 #* Function: Destructor of ScFunctionWin Class
99 #* Input: ---
101 #* Output: ---
103 #************************************************************************/
105 ScFunctionWin::~ScFunctionWin()
107 xConfigChange.reset();
108 xConfigListener->dispose();
109 xConfigListener.clear();
111 xCatBox.reset();
112 xFuncList.reset();
113 xInsertButton.reset();
114 xHelpButton.reset();
115 xSimilaritySearch.reset();
116 xFiFuncDesc.reset();
119 /*************************************************************************
120 #* Member: InitLRUList
121 #*------------------------------------------------------------------------
123 #* Class: ScFunctionWin
125 #* Function: Updates the list of functions depending on the set category
127 #* Input: ---
129 #* Output: ---
131 #************************************************************************/
133 void ScFunctionWin::InitLRUList()
135 ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr();
136 pFuncMgr->fillLastRecentlyUsedFunctions(aLRUList);
138 sal_Int32 nSelPos = xCatBox->get_active();
140 if (nSelPos == 0)
141 UpdateFunctionList(u""_ustr);
145 /*************************************************************************
146 #* Member: FillCategoriesMap
147 #*------------------------------------------------------------------------
149 #* Class: ScFunctionWin
151 #* Function: Fills the categories map.
153 #* Input: ---
155 #* Output: ---
157 #************************************************************************/
159 weld::TreeIter* ScFunctionWin::FillCategoriesMap(const OUString& aCategory, bool bFill)
161 if (!bFill)
162 return nullptr;
164 if (mCategories.find(aCategory) == mCategories.end())
166 mCategories[aCategory] = xFuncList->make_iterator();
167 xFuncList->insert(nullptr, -1, &aCategory, nullptr, nullptr, nullptr, false,
168 mCategories[aCategory].get());
170 return mCategories[aCategory].get();
173 /*************************************************************************
174 #* Member: UpdateLRUList
175 #*------------------------------------------------------------------------
177 #* Class: ScFunctionWin
179 #* Function: Updates the list of last used functions.
181 #* Input: ---
183 #* Output: ---
185 #************************************************************************/
187 void ScFunctionWin::UpdateLRUList()
189 if (pFuncDesc && pFuncDesc->nFIndex!=0)
191 ScModule::get()->InsertEntryToLRUList(pFuncDesc->nFIndex);
195 void ScFunctionWin::SearchFunction(const OUString& rFuncName, const OUString& rSearchString,
196 const ScFuncDesc* pDesc, const bool bSimilaritySearch)
198 std::pair<sal_Int32, sal_Int32> score = std::make_pair(0, 0);
199 if (bSimilaritySearch && !utl::TextSearch::SimilaritySearch(rFuncName, rSearchString, score))
200 return;
201 if (!bSimilaritySearch && rFuncName.indexOf(rSearchString) < 0
202 && rSearchString.indexOf(rFuncName) < 0)
203 return;
205 sFuncScores.insert(std::make_pair(score, std::make_pair(rFuncName, pDesc)));
208 /*************************************************************************
209 #* Member: SetDescription
210 #*------------------------------------------------------------------------
212 #* Class: ScFunctionWin
214 #* Function:
216 #* Input: ---
218 #* Output: ---
220 #************************************************************************/
222 void ScFunctionWin::SetDescription()
224 xFiFuncDesc->set_text(OUString());
225 const ScFuncDesc* pDesc =
226 weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id());
227 if (pDesc)
229 pDesc->initArgumentInfo(); // full argument info is needed
231 OUString aBuf = xFuncList->get_selected_text() +
232 ":\n\n" +
233 pDesc->GetParamList() +
234 "\n\n" +
235 *pDesc->mxFuncDesc;
237 xFiFuncDesc->set_text(aBuf);
239 // Update help ID for the selected entry
240 const OUString sHelpId = pDesc->getHelpId();
241 if (!sHelpId.isEmpty())
242 xFuncList->set_help_id(pDesc->getHelpId());
243 else
244 xFuncList->set_help_id(m_aListHelpId);
248 /*************************************************************************
249 #* Member: UpdateFunctionList
250 #*------------------------------------------------------------------------
252 #* Class: ScFunctionWin
254 #* Function: Updates the list of functions depending on the set category
256 #* Input: Search string used to filter the list of functions
258 #* Output: ---
260 #************************************************************************/
262 void ScFunctionWin::UpdateFunctionList(const OUString& rSearchString)
264 sal_Int32 nSelPos = xCatBox->get_active();
265 sal_Int32 nCategory = ( -1 != nSelPos )
266 ? (nSelPos-1) : 0;
268 xFuncList->clear();
269 xFuncList->freeze();
270 mCategories.clear();
271 sFuncScores.clear();
273 bool bCollapse = nCategory == 0;
274 bool bFilter = !rSearchString.isEmpty();
275 if ( nSelPos > 0 )
277 ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr();
279 // Use the corresponding CharClass for uppercase() depending on whether
280 // English function names are used, or localized names.
281 const CharClass* pCharClass = (ScGlobal::GetStarCalcFunctionList()->IsEnglishFunctionNames()
282 ? ScCompiler::GetCharClassEnglish()
283 : ScCompiler::GetCharClassLocalized());
285 const OUString aSearchStr(pCharClass->uppercase(rSearchString));
287 const ScFuncDesc* pDesc = pFuncMgr->First(nCategory);
288 while (pDesc)
290 const OUString aCategory(pDesc->getCategory()->getName());
291 const OUString aFunction(pCharClass->uppercase(pDesc->getFunctionName()));
292 const OUString aFuncDescId(weld::toId(pDesc));
294 if (bFilter)
295 SearchFunction(aFunction, aSearchStr, pDesc, xSimilaritySearch->get_active());
296 else
298 weld::TreeIter* pCategory = FillCategoriesMap(aCategory, bCollapse);
299 xFuncList->insert(pCategory, -1, &aFunction, &aFuncDescId, nullptr, nullptr,
300 false, xScratchIter.get());
302 pDesc = pFuncMgr->Next();
305 for (const auto& func : sFuncScores)
307 pDesc = func.second.second;
308 const OUString aCategory(pDesc->getCategory()->getName());
309 const OUString aFunction(func.second.first);
310 const OUString aFuncDescId(weld::toId(pDesc));
311 weld::TreeIter* pCategory = FillCategoriesMap(aCategory, bCollapse);
313 xFuncList->insert(pCategory, -1, &aFunction, &aFuncDescId, nullptr, nullptr, false,
314 xScratchIter.get());
317 else // LRU list
319 for (const formula::IFunctionDescription* pDesc : aLRUList)
321 if (pDesc)
323 OUString aFunction = pDesc->getFunctionName();
324 OUString aFuncDescId = weld::toId(pDesc);
326 xFuncList->insert(nullptr, -1, &aFunction, &aFuncDescId, nullptr, nullptr,
327 false, xScratchIter.get());
332 xFuncList->thaw();
334 if (bCollapse && bFilter)
336 for (const auto& category : mCategories)
337 xFuncList->expand_row(*category.second);
340 if (xFuncList->n_children() > 0)
342 xFuncList->set_sensitive(true);
343 xFuncList->select(0);
345 else
347 xFuncList->set_sensitive(false);
351 /*************************************************************************
352 #* Member: DoEnter
353 #*------------------------------------------------------------------------
355 #* Class: ScFunctionWin
357 #* Function: Save input into document. Is called after clicking the
358 #* Apply button or a double-click on the function list.
360 #* Input: Boolean to know if I double-clicked/press-enter or not
362 #* Output: ---
364 #************************************************************************/
366 void ScFunctionWin::DoEnter(bool bDoubleOrEnter)
368 OUString aString=xFuncList->get_selected_text();
369 const bool isCategory = mCategories.find(aString) != mCategories.end();
370 if (isCategory && !bDoubleOrEnter)
371 return;
373 if (isCategory)
375 const auto& categoryRow = *(mCategories[aString]);
376 if (xFuncList->get_row_expanded(categoryRow))
377 xFuncList->collapse_row(categoryRow);
378 else
379 xFuncList->expand_row(categoryRow);
380 return;
383 OUStringBuffer aArgStr;
384 SfxViewShell* pCurSh = SfxViewShell::Current();
385 nArgs=0;
387 if(!aString.isEmpty())
389 OUString aFirstArgStr;
390 ScModule* pScMod = ScModule::get();
391 ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pCurSh );
392 ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
393 if(!pScMod->IsEditMode())
395 rtl::Reference<comphelper::ConfigurationListener> xDetectDisposed(xConfigListener);
396 pScMod->SetInputMode(SC_INPUT_TABLE);
397 // the above call can result in us being disposed
398 if (xDetectDisposed->isDisposed())
399 return;
400 aString = "=" + xFuncList->get_selected_text();
401 if (pHdl)
402 pHdl->ClearText();
404 const ScFuncDesc* pDesc =
405 weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id());
406 if (pDesc)
408 pFuncDesc=pDesc;
409 UpdateLRUList();
410 nArgs = pDesc->nArgCount;
411 if(nArgs>0)
413 // NOTE: Theoretically the first parameter could have the
414 // suppress flag as well, but practically it doesn't.
415 aFirstArgStr = pDesc->maDefArgNames[0];
416 aFirstArgStr = comphelper::string::strip(aFirstArgStr, ' ');
417 aFirstArgStr = aFirstArgStr.replaceAll(" ", "_");
418 aArgStr = aFirstArgStr;
419 if ( nArgs != VAR_ARGS && nArgs != PAIRED_VAR_ARGS )
420 { // no VarArgs or Fix plus VarArgs, but not VarArgs only
421 sal_uInt16 nFix;
422 if (nArgs >= PAIRED_VAR_ARGS)
423 nFix = nArgs - PAIRED_VAR_ARGS + 2;
424 else if (nArgs >= VAR_ARGS)
425 nFix = nArgs - VAR_ARGS + 1;
426 else
427 nFix = nArgs;
428 for ( sal_uInt16 nArg = 1;
429 nArg < nFix && !pDesc->pDefArgFlags[nArg].bOptional; nArg++ )
431 aArgStr.append("; ");
432 OUString sTmp = pDesc->maDefArgNames[nArg];
433 sTmp = comphelper::string::strip(sTmp, ' ');
434 sTmp = sTmp.replaceAll(" ", "_");
435 aArgStr.append(sTmp);
440 if (pHdl)
442 if (pHdl->GetEditString().isEmpty())
444 aString = "=" + xFuncList->get_selected_text();
446 EditView *pEdView=pHdl->GetActiveView();
447 if(pEdView!=nullptr) // @ needed because of crash during setting a name
449 if(nArgs>0)
451 pHdl->InsertFunction(aString);
452 pEdView->InsertText(aArgStr.makeStringAndClear(),true);
453 ESelection aESel=pEdView->GetSelection();
454 aESel.end.nIndex = aESel.start.nIndex + aFirstArgStr.getLength();
455 pEdView->SetSelection(aESel);
456 pHdl->DataChanged();
458 else
460 aString += "()";
461 pEdView->InsertText(aString);
462 pHdl->DataChanged();
466 InitLRUList();
468 if ( pCurSh )
470 vcl::Window* pShellWnd = pCurSh->GetWindow();
472 if ( pShellWnd )
473 pShellWnd->GrabFocus();
478 /*************************************************************************
479 #* Handle: ModifyHdl
480 #*------------------------------------------------------------------------
482 #* Class: ScFunctionWin
484 #* Function: Handles changes in the search text
486 #************************************************************************/
488 IMPL_LINK_NOARG(ScFunctionWin, ModifyHdl, weld::Entry&, void)
490 if (xCatBox->get_active() == 0)
492 xCatBox->set_active(1);
493 xHelpButton->set_sensitive(false);
495 OUString searchStr = m_xSearchString->get_text();
496 UpdateFunctionList(searchStr);
497 SetDescription();
500 /*************************************************************************
501 #* Handle: KeyInputHdl
502 #*------------------------------------------------------------------------
504 #* Class: ScFunctionWin
506 #* Function: Processes key inputs when the search entry has focus
508 #************************************************************************/
510 IMPL_LINK(ScFunctionWin, KeyInputHdl, const KeyEvent&, rEvent, bool)
512 bool bHandled = false;
514 switch (rEvent.GetKeyCode().GetCode())
516 case KEY_RETURN:
518 DoEnter(true);
519 bHandled = true;
521 break;
522 case KEY_DOWN:
524 int nNewIndex = std::min(xFuncList->get_selected_index() + 1, xFuncList->n_children() - 1);
525 xFuncList->select(nNewIndex);
526 SetDescription();
527 bHandled = true;
529 break;
530 case KEY_UP:
532 int nNewIndex = std::max(xFuncList->get_selected_index() - 1, 0);
533 xFuncList->select(nNewIndex);
534 SetDescription();
535 bHandled = true;
537 break;
538 case KEY_ESCAPE:
540 // Escape in an empty search field should move focus to the document,
541 // adhering to Sidebar guidelines
542 if (m_xSearchString->get_text().isEmpty())
544 if (SfxViewShell* pCurSh = SfxViewShell::Current())
546 vcl::Window* pShellWnd = pCurSh->GetWindow();
548 if (pShellWnd)
549 pShellWnd->GrabFocusToDocument();
551 bHandled = true;
552 break;
554 m_xSearchString->set_text(u""_ustr);
555 UpdateFunctionList(u""_ustr);
556 bHandled = true;
558 break;
559 case KEY_F1:
561 const ScFuncDesc* pDesc = weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id());
562 OUString sHelpId;
563 if (pDesc)
564 sHelpId = pDesc->getHelpId();
566 if (!sHelpId.isEmpty())
567 m_xSearchString->set_help_id(sHelpId);
568 else
569 m_xSearchString->set_help_id(m_aSearchHelpId);
570 bHandled = false;
572 break;
575 return bHandled;
578 /*************************************************************************
579 #* Handle: SelComboHdl
580 #*------------------------------------------------------------------------
582 #* Class: ScFunctionWin
584 #* Function: A change of the category will update the list of functions.
586 #* Input: ---
588 #* Output: ---
590 #************************************************************************/
592 IMPL_LINK_NOARG(ScFunctionWin, SelComboHdl, weld::ComboBox&, void)
594 if (xCatBox->get_active() == 0)
595 m_xSearchString->set_text(u""_ustr);
596 xHelpButton->set_sensitive(xCatBox->get_active() != 1);
597 OUString searchStr = m_xSearchString->get_text();
598 UpdateFunctionList(searchStr);
599 SetDescription();
602 IMPL_LINK_NOARG(ScFunctionWin, SelTreeHdl, weld::TreeView&, void)
604 bool bSensitivity = weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id());
605 xHelpButton->set_sensitive(bSensitivity);
606 SetDescription();
609 /*************************************************************************
610 #* Handle: SetSelectionClickHdl
611 #*------------------------------------------------------------------------
613 #* Class: ScFunctionWin
615 #* Function: A change of the category will update the list of functions.
617 #* Input: ---
619 #* Output: ---
621 #************************************************************************/
623 IMPL_LINK_NOARG( ScFunctionWin, SetSelectionClickHdl, weld::Button&, void )
625 DoEnter(); // saves the input
628 /*************************************************************************
629 #* Handle: SetHelpClickHdl
630 #*------------------------------------------------------------------------
632 #* Class: ScFunctionWin
634 #* Function: Get selected function's official help.
636 #* Input: ---
638 #* Output: ---
640 #************************************************************************/
642 IMPL_LINK_NOARG( ScFunctionWin, SetHelpClickHdl, weld::Button&, void )
644 if (const auto pDesc = weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id()))
646 if (Help* pHelp = Application::GetHelp())
648 const OUString sHelpId = pDesc->getHelpId();
649 if (!sHelpId.isEmpty())
651 pHelp->Start(sHelpId);
657 IMPL_LINK_NOARG(ScFunctionWin, SetSimilarityToggleHdl, weld::Toggleable&, void)
659 OUString searchStr = m_xSearchString->get_text();
660 UpdateFunctionList(searchStr);
661 SetDescription();
664 IMPL_LINK_NOARG( ScFunctionWin, SetRowActivatedHdl, weld::TreeView&, bool )
666 DoEnter(true); // saves the input
667 return true;
670 void EnglishFunctionNameChange::setProperty(const css::uno::Any &rProperty)
672 ConfigurationListenerProperty::setProperty(rProperty);
673 m_pFunctionWin->InitLRUList();
674 m_pFunctionWin->UpdateFunctionList(u""_ustr);
677 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */