Salome HOME
[bos #40644][CEA](2024-T1) Feature search.
[modules/gui.git] / src / SUIT / SUIT_FindActionDialog.cxx
1 // Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SUIT_FindActionDialog.h"
21
22 #include <QAction>
23 #include <QWidget>
24 #include <QLayout>
25 #include <QList>
26 #include <QMap>
27 #include <QApplication>
28
29 #include <QCollator>
30
31 #include <QCheckBox>
32 #include <QLineEdit>
33 #include <QBrush>
34 #include <QColor>
35 #include <QHeaderView>
36 #include <QKeyEvent>
37
38 #include <algorithm>
39 #include <limits>
40
41
42 SUIT_FindActionDialog::SUIT_FindActionDialog(QWidget* theParent)
43 : QDialog(theParent)
44 {
45   setMinimumWidth(500);
46   setWindowTitle(tr("Find action"));
47   QVBoxLayout* layout = new QVBoxLayout(this);
48
49   myQueryLineEdit = new QLineEdit(this);
50   layout->addWidget(myQueryLineEdit);
51   myQueryLineEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
52   setFocusProxy(myQueryLineEdit);
53
54   QHBoxLayout* searchOptionsLayout = new QHBoxLayout(this);
55   layout->addLayout(searchOptionsLayout);
56   myIncludeUnavailableActionsCB = new QCheckBox(tr("Unavailable actions"), this);
57   myIncludeUnavailableActionsCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
58   myIncludeUnavailableActionsCB->setCheckState(Qt::CheckState::Checked);
59   myActionSearcher.includeDisabledActions(true);
60   myIncludeInactiveModulesCB = new QCheckBox(tr("Inactive modules"), this);
61   myIncludeInactiveModulesCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
62   myIncludeInactiveModulesCB->setCheckState(Qt::CheckState::Unchecked);
63   searchOptionsLayout->addWidget(myIncludeUnavailableActionsCB);
64   searchOptionsLayout->addWidget(myIncludeInactiveModulesCB);
65
66   myFoundActionsTree = new SUIT_FoundActionTree(this);
67   layout->addWidget(myFoundActionsTree);
68
69   connect(myQueryLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(onQueryChanged(const QString&)));
70   connect(myIncludeUnavailableActionsCB, SIGNAL(stateChanged(int)), this, SLOT(onSearchOptionUnavailableActionsChanged(int)));
71   connect(myIncludeInactiveModulesCB, SIGNAL(stateChanged(int)), this, SLOT(onSearchOptionInactiveModulesChanged(int)));
72
73   myQueryLineEdit->installEventFilter(myFoundActionsTree);
74 }
75
76 void SUIT_FindActionDialog::setActiveModuleID(const QString& theModuleID)
77 {
78   myActiveModuleID = theModuleID;
79   if(myActionSearcher.setIncludedModuleIDs(std::set<QString>({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID})))
80     updateUI();
81 }
82
83 void SUIT_FindActionDialog::onQueryChanged(const QString& theQuery)
84 {
85   if (myActionSearcher.setQuery(theQuery))
86     updateUI();
87 }
88
89 void SUIT_FindActionDialog::onSearchOptionUnavailableActionsChanged(int theState)
90 {
91   if (myActionSearcher.includeDisabledActions(theState == Qt::CheckState::Checked))
92     updateUI();
93 }
94
95 void SUIT_FindActionDialog::onSearchOptionInactiveModulesChanged(int theState)
96 {
97   bool resultsChanged = false;
98   if (theState == Qt::CheckState::Checked) {
99     myIncludeUnavailableActionsCB->setDisabled(true);
100     myIncludeUnavailableActionsCB->setCheckState(Qt::CheckState::Checked);
101     resultsChanged = myActionSearcher.setIncludedModuleIDs(SUIT_ShortcutMgr::get()->getShortcutContainer().getIDsOfAllModules());
102   }
103   else {
104     myIncludeUnavailableActionsCB->setDisabled(false);
105     resultsChanged = myActionSearcher.setIncludedModuleIDs(std::set<QString>({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID}));
106   }
107
108   if (resultsChanged)
109     updateUI();
110 }
111
112 void SUIT_FindActionDialog::updateUI()
113 {
114   myFoundActionsTree->updateItems(myActionSearcher.getSearchResults());
115 }
116
117
118
119 SUIT_FoundActionTree::SUIT_FoundActionTree(SUIT_FindActionDialog* theParent)
120 : QTreeWidget(theParent)
121 {
122   setColumnCount(2);
123   setSelectionMode(QAbstractItemView::SingleSelection);
124   setSortingEnabled(false);
125   header()->setSectionResizeMode(QHeaderView::Interactive);
126   {
127     QMap<int, QString> labelMap;
128     labelMap[SUIT_FoundActionTree::ElementIdx::Name]    = SUIT_FindActionDialog::tr("Action");
129     labelMap[SUIT_FoundActionTree::ElementIdx::ToolTip] = SUIT_FindActionDialog::tr("Description");
130     setHeaderLabels(labelMap.values());
131   }
132   setExpandsOnDoubleClick(false); // Implemented manually.
133   setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
134   setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
135
136   setColumnWidth(SUIT_FoundActionTree::ElementIdx::Name, 120);
137   setColumnWidth(SUIT_FoundActionTree::ElementIdx::Name, 250);
138   setMinimumHeight(300);
139
140   setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
141
142   mySortKey = SUIT_FoundActionTree::SortKey::MatchMetrics;
143   mySortOrder = SUIT_FoundActionTree::SortOrder::Ascending;
144
145   connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onItemExecuted(QTreeWidgetItem*, int)));
146 }
147
148 /*! \brief Compensates lack of std::distance(), which is introduced in C++17.
149 \returns -1, if theIt does not belong to the  */
150 template <class Container>
151 size_t indexOf(
152   const Container& theContainer,
153   const typename Container::iterator& theIt
154 ) {
155   auto it = theContainer.begin();
156   size_t distance = 0;
157   while (it != theContainer.end()) {
158     if (it == theIt)
159       return distance;
160
161     it++;
162     distance++;
163   }
164   return -1;
165 }
166
167 void SUIT_FoundActionTree::updateItems(const std::map<QString, std::map<QString, SUIT_ActionSearcher::AssetsAndSearchData>>& theAssets)
168 {
169   std::set<QString> shownModuleIDs; // To sort module-items by their IDs.
170
171   // Remove shown module items, if updated search results have no matching actions from these modules.
172   for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); ) {
173     SUIT_FoundActionTreeModule* moduleItem = static_cast<SUIT_FoundActionTreeModule*>(topLevelItem(moduleIdx));
174     myModuleItemExpansionStates[moduleItem->myModuleID] = moduleItem->isExpanded();
175
176     const auto itUpdatedAssetsOfShownModule = theAssets.find(moduleItem->myModuleID);
177     if (itUpdatedAssetsOfShownModule == theAssets.end()) {
178       delete takeTopLevelItem(moduleIdx);
179       continue;
180     }
181
182     if (itUpdatedAssetsOfShownModule->second.empty()) {
183       delete takeTopLevelItem(moduleIdx);
184       continue;
185     }
186
187     shownModuleIDs.emplace(moduleItem->myModuleID);
188     moduleIdx++;
189   }
190
191   const auto shortcutMgr = SUIT_ShortcutMgr::get();
192   const QString lang = SUIT_ShortcutMgr::getLang();
193
194   SUIT_FoundActionTreeAction* preselectedActionItem = nullptr;
195
196   for (const auto& moduleIDAndAssets : theAssets) {
197     const QString& moduleID = moduleIDAndAssets.first;
198     const auto& moduleAssets = moduleIDAndAssets.second;
199     if (moduleAssets.empty())
200       continue;
201
202     const auto moduleItemAndIdx = findModuleItem(moduleID);
203     SUIT_FoundActionTreeModule* moduleItem = moduleItemAndIdx.first;
204     if (!moduleItem) {
205       moduleItem = new SUIT_FoundActionTreeModule(moduleID);
206       moduleItem->setAssetsAndSearchData(SUIT_ActionSearcher::AssetsAndSearchData(shortcutMgr->getModuleAssets(moduleID)), lang);
207
208       const auto emplaceRes = shownModuleIDs.emplace(moduleID);
209       insertTopLevelItem(indexOf(shownModuleIDs, emplaceRes.first), moduleItem);
210
211       moduleItem->setFlags(Qt::ItemIsEnabled);
212
213       const auto itExpansionState = myModuleItemExpansionStates.find(moduleID);
214       if (itExpansionState == myModuleItemExpansionStates.end())
215         moduleItem->setExpanded(true); // Make module item expanded at first appearance.
216       else
217         moduleItem->setExpanded(itExpansionState->second);
218     }
219     else /* if the tree has the module-item */ {
220       const auto actionItems = moduleItem->takeChildren();
221       for (const auto actionItem : actionItems) {
222         delete actionItem;
223       }
224     }
225
226     // Fill module item with action items.
227     auto sortedActionItems = createActionSetWithComparator();
228     for (const auto& actionIDAndAssets : moduleAssets) {
229       const QString& inModuleActionID = actionIDAndAssets.first;
230       const SUIT_ActionSearcher::AssetsAndSearchData& assetsAndSearchData = actionIDAndAssets.second;
231
232       auto actionItem = SUIT_FoundActionTreeAction::create(moduleID, inModuleActionID);
233       if (!actionItem) {
234         ShCutDbg("SUIT_FoundActionTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
235         continue;
236       }
237
238       actionItem->setAssetsAndSearchData(assetsAndSearchData, lang);
239       sortedActionItems.emplace(actionItem);
240     }
241
242     SUIT_FoundActionTreeAction* preselectedActionItemCand = nullptr;
243     for (const auto actionItem : sortedActionItems) {
244       moduleItem->addChild(actionItem);
245
246       // Consider first ranked available action in the module (if user did not collapsed it) as a candidate for preselected action.
247       if (!preselectedActionItemCand && moduleItem->isExpanded() && actionItem->isEnabledBufferedValue())
248         preselectedActionItemCand = actionItem;
249     }
250
251     if (preselectedActionItem) {
252       if (preselectedActionItemCand) {
253         if (preselectedActionItemCand->matchMetrics() < preselectedActionItem->matchMetrics())
254           preselectedActionItem = preselectedActionItemCand;
255       }
256     }
257     else
258       preselectedActionItem = preselectedActionItemCand;
259   }
260
261   if (preselectedActionItem)
262     setCurrentItem(preselectedActionItem);
263 }
264
265 void SUIT_FoundActionTree::sort(SUIT_FoundActionTree::SortKey theKey, SUIT_FoundActionTree::SortOrder theOrder)
266 {
267   if (theKey == mySortKey && theOrder == mySortOrder)
268     return;
269
270   mySortKey == theKey;
271   mySortOrder = theOrder;
272
273   for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
274     const auto moduleItem = static_cast<SUIT_FoundActionTreeModule*>(topLevelItem(moduleIdx));
275
276     auto sortedActionItems = createActionSetWithComparator();
277     for (int childIdx = 0; childIdx < moduleItem->childCount(); childIdx++) {
278       SUIT_FoundActionTreeAction* const actionItem = static_cast<SUIT_FoundActionTreeAction*>(moduleItem->child(childIdx));
279       sortedActionItems.emplace(actionItem);
280     }
281
282     moduleItem->takeChildren();
283
284     for (const auto actionItem : sortedActionItems) {
285       moduleItem->addChild(actionItem);
286     }
287   }
288 }
289
290 void SUIT_FoundActionTree::keyPressEvent(QKeyEvent* theEvent)
291 {
292   const auto key = theEvent->key();
293   const auto selectedItem = currentItem();
294   if ((key == Qt::Key_Enter || key == Qt::Key_Return) && selectedItem)
295     onItemExecuted(selectedItem, SUIT_FoundActionTree::ElementIdx::Name);
296   else
297     QTreeWidget::keyPressEvent(theEvent);
298 }
299
300 bool SUIT_FoundActionTree::eventFilter(QObject* theQObject, QEvent* theEvent)
301 {
302   if (theEvent->type() == QEvent::KeyPress) {
303     QKeyEvent* const keyEvent = static_cast<QKeyEvent*>(theEvent);
304     const auto key = keyEvent->key();
305
306     if (key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Up || key == Qt::Key_Down) {
307       keyPressEvent(keyEvent);
308       return true;
309     }
310   }
311
312   return false;
313 }
314
315 std::pair<SUIT_FoundActionTreeModule*, int> SUIT_FoundActionTree::findModuleItem(const QString& theModuleID) const
316 {
317   for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
318     SUIT_FoundActionTreeModule* moduleItem = static_cast<SUIT_FoundActionTreeModule*>(topLevelItem(moduleIdx));
319     if (moduleItem->myModuleID == theModuleID)
320       return std::pair<SUIT_FoundActionTreeModule*, int>(moduleItem, moduleIdx);
321   }
322   return std::pair<SUIT_FoundActionTreeModule*, int>(nullptr, -1);
323 }
324
325 template <typename Float>
326 bool approximatelyEqual(Float a, Float b, Float relativeTol = std::numeric_limits<Float>::epsilon())
327 {
328     return std::abs(a - b) <= ( (std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * relativeTol);
329 }
330
331 std::set<SUIT_FoundActionTreeAction*, std::function<bool(SUIT_FoundActionTreeAction*, SUIT_FoundActionTreeAction*)>> SUIT_FoundActionTree::createActionSetWithComparator() const
332 {
333   QList<std::pair<SUIT_FoundActionTree::SortKey, SUIT_FoundActionTree::SortOrder>> sortSchema = SUIT_FoundActionTree::DEFAULT_SORT_SCHEMA;
334   {
335     for (auto itSameKey = sortSchema.begin(); itSameKey != sortSchema.end(); itSameKey++) {
336       if (itSameKey->first == mySortKey) {
337         sortSchema.erase(itSameKey);
338         break;
339       }
340     }
341     sortSchema.push_front(std::pair<SUIT_FoundActionTree::SortKey, SUIT_FoundActionTree::SortOrder>(mySortKey, mySortOrder));
342   }
343
344   static const QCollator collator;
345   const std::function<bool(SUIT_FoundActionTreeAction*, SUIT_FoundActionTreeAction*)> comparator =
346   [sortSchema, &collator](const SUIT_FoundActionTreeAction* theItemA, const SUIT_FoundActionTreeAction* theItemB) {
347     for (const auto& keyAndOrder : sortSchema) {
348       const QVariant fieldOfA = theItemA->getValue(keyAndOrder.first);
349       const QVariant fieldOfB = theItemB->getValue(keyAndOrder.first);
350
351       bool* const fieldOfAIsDouble = new bool(false);
352       bool* const fieldOfBIsDouble = new bool(false);
353       const double matchMetricsA = fieldOfA.toDouble(fieldOfAIsDouble);
354       const double matchMetricsB = fieldOfB.toDouble(fieldOfBIsDouble);
355       if (*fieldOfAIsDouble && *fieldOfBIsDouble) {
356         if (!approximatelyEqual(matchMetricsA, matchMetricsB)) {
357           const double res = matchMetricsA - matchMetricsB;
358           return keyAndOrder.second == SUIT_FoundActionTree::SortOrder::Ascending ? res < 0 : res > 0;
359         }
360       }
361       else {
362         const int res = collator.compare(fieldOfA.toString(), fieldOfB.toString());
363         if (res != 0)
364           return keyAndOrder.second == SUIT_FoundActionTree::SortOrder::Ascending ? res < 0 : res > 0;
365       }
366     }
367     return false;
368   };
369
370   return std::set<SUIT_FoundActionTreeAction*, std::function<bool(SUIT_FoundActionTreeAction*, SUIT_FoundActionTreeAction*)>>(comparator);
371 }
372
373 void SUIT_FoundActionTree::onItemExecuted(QTreeWidgetItem* theItem, int theColIdx)
374 {
375   SUIT_FoundActionTreeItem* const item = static_cast<SUIT_FoundActionTreeItem*>(theItem);
376   if (item->type() == SUIT_FoundActionTreeItem::Type::Action) {
377     SUIT_FoundActionTreeAction* const actionItem = static_cast<SUIT_FoundActionTreeAction*>(theItem);
378     if (actionItem->trigger())
379       static_cast<SUIT_FindActionDialog*>(parentWidget())->accept();
380   }
381   else /* if (item->type() == SUIT_FoundActionTreeItem::Type::Module) */ {
382     item->setExpanded(!item->isExpanded());
383   }
384 }
385
386 /*static*/ const QList<std::pair<SUIT_FoundActionTree::SortKey, SUIT_FoundActionTree::SortOrder>> SUIT_FoundActionTree::DEFAULT_SORT_SCHEMA =
387 {
388   {SUIT_FoundActionTree::SortKey::MatchMetrics, SUIT_FoundActionTree::SortOrder::Ascending},
389   {SUIT_FoundActionTree::SortKey::Name, SUIT_FoundActionTree::SortOrder::Ascending},
390   {SUIT_FoundActionTree::SortKey::ToolTip, SUIT_FoundActionTree::SortOrder::Ascending},
391   {SUIT_FoundActionTree::SortKey::ID, SUIT_FoundActionTree::SortOrder::Ascending}
392 };
393
394
395 SUIT_FoundActionTreeItem::SUIT_FoundActionTreeItem(const QString& theModuleID)
396 : QTreeWidgetItem(), myModuleID(theModuleID)
397 { }
398
399 QString SUIT_FoundActionTreeItem::name() const
400 {
401   return text(SUIT_FoundActionTree::ElementIdx::Name);
402 }
403
404 QString SUIT_FoundActionTreeItem::toolTip() const
405 {
406   return text(SUIT_FoundActionTree::ElementIdx::ToolTip);
407 }
408
409
410 SUIT_FoundActionTreeModule::SUIT_FoundActionTreeModule(const QString& theModuleID)
411 : SUIT_FoundActionTreeItem(theModuleID)
412 {
413   QFont f = font(SUIT_FoundActionTree::ElementIdx::Name);
414   f.setBold(true);
415   setFont(SUIT_FoundActionTree::ElementIdx::Name, f);
416   setText(SUIT_FoundActionTree::ElementIdx::Name, theModuleID);
417 }
418
419 void SUIT_FoundActionTreeModule::setAssetsAndSearchData(const SUIT_ActionSearcher::AssetsAndSearchData& theAssetsAndSD, const QString& theLang)
420 {
421   if (!theAssetsAndSD.myAssets)
422     return;
423
424   setIcon(SUIT_FoundActionTree::ElementIdx::Name, theAssetsAndSD.myAssets->myIcon);
425
426   const auto& ldaMap = theAssetsAndSD.myAssets->myLangDependentAssets;
427   if (ldaMap.empty()) {
428     setText(SUIT_FoundActionTree::ElementIdx::Name, myModuleID);
429     return;
430   }
431
432   auto itLDA = ldaMap.find(theLang);
433   if (itLDA == ldaMap.end())
434     itLDA = ldaMap.begin();
435
436   const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
437   const QString& name = lda.myName.isEmpty() ? myModuleID : lda.myName;
438   setText(SUIT_FoundActionTree::ElementIdx::Name, name);
439 }
440
441 QVariant SUIT_FoundActionTreeModule::getValue(SUIT_FoundActionTree::SortKey theKey) const
442 {
443   switch (theKey) {
444     case SUIT_FoundActionTree::SortKey::MatchMetrics:
445       return double(0);
446     case SUIT_FoundActionTree::SortKey::ID:
447       return myModuleID;
448     case SUIT_FoundActionTree::SortKey::Name:
449       return name();
450     case SUIT_FoundActionTree::SortKey::ToolTip:
451       return toolTip();
452     default:
453       return QString();
454   }
455 }
456
457 bool SUIT_FoundActionTreeModule::isEnabled() const
458 {
459   return true;
460 }
461
462
463 SUIT_FoundActionTreeAction::SUIT_FoundActionTreeAction(const QString& theModuleID, const QString& theInModuleActionID)
464 : SUIT_FoundActionTreeItem(theModuleID), myInModuleActionID(theInModuleActionID),
465   myMatchMetrics(std::numeric_limits<double>::infinity()), myIsEnabledBufferedValue(false)
466 {
467   setText(SUIT_FoundActionTree::ElementIdx::Name, theInModuleActionID);
468 }
469
470 /*static*/ SUIT_FoundActionTreeAction* SUIT_FoundActionTreeAction::create(const QString& theModuleID, const QString& theInModuleActionID)
471 {
472   if (theInModuleActionID.isEmpty()) {
473     ShCutDbg("SUIT_FoundActionTreeItem: attempt to create item with empty action ID.");
474     return nullptr;
475   }
476
477   return new SUIT_FoundActionTreeAction(theModuleID, theInModuleActionID);
478 }
479
480 void SUIT_FoundActionTreeAction::setAssetsAndSearchData(const SUIT_ActionSearcher::AssetsAndSearchData& theAssetsAndSD, const QString& theLang)
481 {
482   if (!theAssetsAndSD.myAssets)
483     return;
484
485   setIcon(SUIT_FoundActionTree::ElementIdx::Name, theAssetsAndSD.myAssets->myIcon);
486
487   const auto& ldaMap = theAssetsAndSD.myAssets->myLangDependentAssets;
488   if (ldaMap.empty()) {
489     setText(SUIT_FoundActionTree::ElementIdx::Name, myInModuleActionID);
490     return;
491   }
492
493   auto itLDA = ldaMap.find(theLang);
494   if (itLDA == ldaMap.end())
495     itLDA = ldaMap.begin();
496
497   const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
498   const QString& name = lda.myName.isEmpty() ? myInModuleActionID : lda.myName;
499   setText(SUIT_FoundActionTree::ElementIdx::Name, name);
500
501   setText(SUIT_FoundActionTree::ElementIdx::ToolTip, lda.myToolTip);
502
503   if (isEnabled()) {
504     setToolTip(
505       SUIT_FoundActionTree::ElementIdx::Name,
506       SUIT_FoundActionTree::tr("Double click to start")
507     );
508
509     setToolTip(
510       SUIT_FoundActionTree::ElementIdx::ToolTip,
511       SUIT_FoundActionTree::tr("Double click to start")
512     );
513   }
514   else {
515     static const QBrush greyedOutBrush = QBrush(Qt::gray);
516     setForeground(SUIT_FoundActionTree::ElementIdx::Name,    greyedOutBrush);
517     setForeground(SUIT_FoundActionTree::ElementIdx::ToolTip, greyedOutBrush);
518   }
519
520   myMatchMetrics = theAssetsAndSD.matchMetrics();
521 }
522
523 QVariant SUIT_FoundActionTreeAction::getValue(SUIT_FoundActionTree::SortKey theKey) const
524 {
525   switch (theKey) {
526     case SUIT_FoundActionTree::SortKey::MatchMetrics:
527       return myMatchMetrics;
528     case SUIT_FoundActionTree::SortKey::ID:
529       return myInModuleActionID;
530     case SUIT_FoundActionTree::SortKey::Name:
531       return name();
532     case SUIT_FoundActionTree::SortKey::ToolTip:
533       return toolTip();
534     default:
535       return QString();
536   }
537 }
538
539 bool SUIT_FoundActionTreeAction::isEnabled() const
540 {
541   const auto& actions = SUIT_ShortcutMgr::get()->getActions(myModuleID, myInModuleActionID);
542   myIsEnabledBufferedValue = std::find_if(actions.begin(), actions.end(), [](const QAction* const theAction){ return theAction->isEnabled(); }) != actions.end();
543   return myIsEnabledBufferedValue;
544 }
545
546 bool SUIT_FoundActionTreeAction::trigger() const
547 {
548   bool res = false;
549   const auto& actions = SUIT_ShortcutMgr::get()->getActions(myModuleID, myInModuleActionID);
550   for (const auto& action : actions) {
551     if (action->isEnabled()) {
552       action->trigger();
553       res = true;
554     }
555   }
556   return res;
557 }