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); // Items
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   connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onItemExecuted(QTreeWidgetItem*, int)));
143 }
144
145 /*! \brief Compensates lack of std::distance(), which is introduced in C++17.
146 \returns -1, if theIt does not belong to the  */
147 template <class Container>
148 size_t indexOf(
149   const Container& theContainer,
150   const typename Container::iterator& theIt
151 ) {
152   auto it = theContainer.begin();
153   size_t distance = 0;
154   while (it != theContainer.end()) {
155     if (it == theIt)
156       return distance;
157
158     it++;
159     distance++;
160   }
161   return -1;
162 }
163
164 void SUIT_FoundActionTree::updateItems(const std::map<QString, std::map<QString, SUIT_ActionSearcher::AssetsAndSearchData>>& theAssets)
165 {
166   std::set<QString> shownModuleIDs; // To sort module-items by their IDs.
167
168   // Remove shown module items, if updated search results have no matching actions from these modules.
169   for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); ) {
170     SUIT_FoundActionTreeModule* moduleItem = static_cast<SUIT_FoundActionTreeModule*>(topLevelItem(moduleIdx));
171     myModuleItemExpansionStates[moduleItem->myModuleID] = moduleItem->isExpanded();
172
173     const auto itUpdatedAssetsOfShownModule = theAssets.find(moduleItem->myModuleID);
174     if (itUpdatedAssetsOfShownModule == theAssets.end()) {
175       delete takeTopLevelItem(moduleIdx);
176       continue;
177     }
178
179     if (itUpdatedAssetsOfShownModule->second.empty()) {
180       delete takeTopLevelItem(moduleIdx);
181       continue;
182     }
183
184     shownModuleIDs.emplace(moduleItem->myModuleID);
185     moduleIdx++;
186   }
187
188   const auto shortcutMgr = SUIT_ShortcutMgr::get();
189   const QString lang = SUIT_ShortcutMgr::getLang();
190
191   SUIT_FoundActionTreeAction* preselectedActionItem = nullptr;
192
193   for (const auto& moduleIDAndAssets : theAssets) {
194     const QString& moduleID = moduleIDAndAssets.first;
195     const auto& moduleAssets = moduleIDAndAssets.second;
196     if (moduleAssets.empty())
197       continue;
198
199     const auto moduleItemAndIdx = findModuleItem(moduleID);
200     SUIT_FoundActionTreeModule* moduleItem = moduleItemAndIdx.first;
201     if (!moduleItem) {
202       moduleItem = new SUIT_FoundActionTreeModule(moduleID);
203       moduleItem->setAssetsAndSearchData(SUIT_ActionSearcher::AssetsAndSearchData(shortcutMgr->getModuleAssets(moduleID)), lang);
204
205       const auto emplaceRes = shownModuleIDs.emplace(moduleID);
206       insertTopLevelItem(indexOf(shownModuleIDs, emplaceRes.first), moduleItem);
207
208       moduleItem->setFlags(Qt::ItemIsEnabled);
209
210       const auto itExpansionState = myModuleItemExpansionStates.find(moduleID);
211       if (itExpansionState == myModuleItemExpansionStates.end())
212         moduleItem->setExpanded(true); // Make module item expanded at first appearance.
213       else
214         moduleItem->setExpanded(itExpansionState->second);
215     }
216     else /* if the tree has the module-item */ {
217       const auto actionItems = moduleItem->takeChildren();
218       for (const auto actionItem : actionItems) {
219         delete actionItem;
220       }
221     }
222
223     // Fill module item with action items.
224     auto sortedActionItems = createActionSetWithComparator();
225     for (const auto& actionIDAndAssets : moduleAssets) {
226       const QString& inModuleActionID = actionIDAndAssets.first;
227       const SUIT_ActionSearcher::AssetsAndSearchData& assetsAndSearchData = actionIDAndAssets.second;
228
229       auto actionItem = SUIT_FoundActionTreeAction::create(moduleID, inModuleActionID);
230       if (!actionItem) {
231         ShCutDbg("SUIT_FoundActionTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
232         continue;
233       }
234
235       actionItem->setAssetsAndSearchData(assetsAndSearchData, lang);
236       sortedActionItems.emplace(actionItem);
237     }
238
239     SUIT_FoundActionTreeAction* preselectedActionItemCand = nullptr;
240     for (const auto actionItem : sortedActionItems) {
241       moduleItem->addChild(actionItem);
242
243       // Consider first ranked available action in the module (if user did not collapsed it) as a candidate for preselected action.
244       if (!preselectedActionItemCand && moduleItem->isExpanded() && actionItem->isEnabledBufferedValue())
245         preselectedActionItemCand = actionItem;
246     }
247
248     if (preselectedActionItem) {
249       if (preselectedActionItemCand) {
250         if (preselectedActionItemCand->matchMetrics() < preselectedActionItem->matchMetrics())
251           preselectedActionItem = preselectedActionItemCand;
252       }
253     }
254     else
255       preselectedActionItem = preselectedActionItemCand;
256   }
257
258   if (preselectedActionItem)
259     setCurrentItem(preselectedActionItem);
260 }
261
262 void SUIT_FoundActionTree::sort(SUIT_FoundActionTree::SortKey theKey, SUIT_FoundActionTree::SortOrder theOrder)
263 {
264   if (theKey == mySortKey && theOrder == mySortOrder)
265     return;
266
267   mySortKey == theKey;
268   mySortOrder = theOrder;
269
270   for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
271     const auto moduleItem = static_cast<SUIT_FoundActionTreeModule*>(topLevelItem(moduleIdx));
272
273     auto sortedActionItems = createActionSetWithComparator();
274     for (int childIdx = 0; childIdx < moduleItem->childCount(); childIdx++) {
275       SUIT_FoundActionTreeAction* const actionItem = static_cast<SUIT_FoundActionTreeAction*>(moduleItem->child(childIdx));
276       sortedActionItems.emplace(actionItem);
277     }
278
279     moduleItem->takeChildren();
280
281     for (const auto actionItem : sortedActionItems) {
282       moduleItem->addChild(actionItem);
283     }
284   }
285 }
286
287 void SUIT_FoundActionTree::keyPressEvent(QKeyEvent* theEvent)
288 {
289   const auto key = theEvent->key();
290   const auto selectedItem = currentItem();
291   if ((key == Qt::Key_Enter || key == Qt::Key_Return) && selectedItem)
292     onItemExecuted(selectedItem, SUIT_FoundActionTree::ElementIdx::Name);
293   else
294     QTreeWidget::keyPressEvent(theEvent);
295 }
296
297 bool SUIT_FoundActionTree::eventFilter(QObject* theQObject, QEvent* theEvent)
298 {
299   if (theEvent->type() == QEvent::KeyPress) {
300     QKeyEvent* const keyEvent = static_cast<QKeyEvent*>(theEvent);
301     const auto key = keyEvent->key();
302
303     if (key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Up || key == Qt::Key_Down) {
304       keyPressEvent(keyEvent);
305       return true;
306     }
307   }
308
309   return false;
310 }
311
312 std::pair<SUIT_FoundActionTreeModule*, int> SUIT_FoundActionTree::findModuleItem(const QString& theModuleID) const
313 {
314   for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
315     SUIT_FoundActionTreeModule* moduleItem = static_cast<SUIT_FoundActionTreeModule*>(topLevelItem(moduleIdx));
316     if (moduleItem->myModuleID == theModuleID)
317       return std::pair<SUIT_FoundActionTreeModule*, int>(moduleItem, moduleIdx);
318   }
319   return std::pair<SUIT_FoundActionTreeModule*, int>(nullptr, -1);
320 }
321
322 std::set<SUIT_FoundActionTreeAction*, std::function<bool(SUIT_FoundActionTreeAction*, SUIT_FoundActionTreeAction*)>> SUIT_FoundActionTree::createActionSetWithComparator() const
323 {
324   QList<std::pair<SUIT_FoundActionTree::SortKey, SUIT_FoundActionTree::SortOrder>> sortSchema = SUIT_FoundActionTree::DEFAULT_SORT_SCHEMA;
325   {
326     for (auto itSameKey = sortSchema.begin(); itSameKey != sortSchema.end(); itSameKey++) {
327       if (itSameKey->first == mySortKey) {
328         sortSchema.erase(itSameKey);
329         break;
330       }
331     }
332     sortSchema.push_front(std::pair<SUIT_FoundActionTree::SortKey, SUIT_FoundActionTree::SortOrder>(mySortKey, mySortOrder));
333   }
334
335   static const QCollator collator;
336   const std::function<bool(SUIT_FoundActionTreeAction*, SUIT_FoundActionTreeAction*)> comparator =
337   [sortSchema, &collator](const SUIT_FoundActionTreeAction* theItemA, const SUIT_FoundActionTreeAction* theItemB) {
338     for (const auto& keyAndOrder : sortSchema) {
339       const QVariant fieldOfA = theItemA->getValue(keyAndOrder.first);
340       const QVariant fieldOfB = theItemB->getValue(keyAndOrder.first);
341
342       bool* const fieldOfAIsDouble = new bool(false);
343       bool* const fieldOfBIsDouble = new bool(false);
344       const double matchMetricsA = fieldOfA.toDouble(fieldOfAIsDouble);
345       const double matchMetricsB = fieldOfB.toDouble(fieldOfBIsDouble);
346       if (fieldOfAIsDouble && fieldOfBIsDouble) {
347         const double res = matchMetricsA - matchMetricsB;
348         if (std::abs(res) > std::numeric_limits<double>::epsilon())
349           return keyAndOrder.second == SUIT_FoundActionTree::SortOrder::Ascending ? res < 0 : res > 0;
350       }
351       else {
352         const int res = collator.compare(fieldOfA.toString(), fieldOfB.toString());
353         if (res != 0)
354           return keyAndOrder.second == SUIT_FoundActionTree::SortOrder::Ascending ? res < 0 : res > 0;
355       }
356     }
357     return false;
358   };
359
360   return std::set<SUIT_FoundActionTreeAction*, std::function<bool(SUIT_FoundActionTreeAction*, SUIT_FoundActionTreeAction*)>>(comparator);
361 }
362
363 void SUIT_FoundActionTree::onItemExecuted(QTreeWidgetItem* theItem, int theColIdx)
364 {
365   SUIT_FoundActionTreeItem* const item = static_cast<SUIT_FoundActionTreeItem*>(theItem);
366   if (item->type() == SUIT_FoundActionTreeItem::Type::Action) {
367     SUIT_FoundActionTreeAction* const actionItem = static_cast<SUIT_FoundActionTreeAction*>(theItem);
368     if (actionItem->trigger())
369       static_cast<SUIT_FindActionDialog*>(parentWidget())->accept();
370   }
371   else /* if (item->type() == SUIT_FoundActionTreeItem::Type::Module) */ {
372     item->setExpanded(!item->isExpanded());
373   }
374 }
375
376 /*static*/ const QList<std::pair<SUIT_FoundActionTree::SortKey, SUIT_FoundActionTree::SortOrder>> SUIT_FoundActionTree::DEFAULT_SORT_SCHEMA =
377 {
378   {SUIT_FoundActionTree::SortKey::MatchMetrics, SUIT_FoundActionTree::SortOrder::Ascending},
379   {SUIT_FoundActionTree::SortKey::Name, SUIT_FoundActionTree::SortOrder::Ascending},
380   {SUIT_FoundActionTree::SortKey::ToolTip, SUIT_FoundActionTree::SortOrder::Ascending},
381   {SUIT_FoundActionTree::SortKey::ID, SUIT_FoundActionTree::SortOrder::Ascending}
382 };
383
384
385 SUIT_FoundActionTreeItem::SUIT_FoundActionTreeItem(const QString& theModuleID)
386 : QTreeWidgetItem(), myModuleID(theModuleID)
387 { }
388
389 QString SUIT_FoundActionTreeItem::name() const
390 {
391   return text(SUIT_FoundActionTree::ElementIdx::Name);
392 }
393
394 QString SUIT_FoundActionTreeItem::toolTip() const
395 {
396   return text(SUIT_FoundActionTree::ElementIdx::ToolTip);
397 }
398
399
400 SUIT_FoundActionTreeModule::SUIT_FoundActionTreeModule(const QString& theModuleID)
401 : SUIT_FoundActionTreeItem(theModuleID)
402 {
403   QFont f = font(SUIT_FoundActionTree::ElementIdx::Name);
404   f.setBold(true);
405   setFont(SUIT_FoundActionTree::ElementIdx::Name, f);
406   setText(SUIT_FoundActionTree::ElementIdx::Name, theModuleID);
407 }
408
409 void SUIT_FoundActionTreeModule::setAssetsAndSearchData(const SUIT_ActionSearcher::AssetsAndSearchData& theAssetsAndSD, const QString& theLang)
410 {
411   if (!theAssetsAndSD.myAssets)
412     return;
413
414   setIcon(SUIT_FoundActionTree::ElementIdx::Name, theAssetsAndSD.myAssets->myIcon);
415
416   const auto& ldaMap = theAssetsAndSD.myAssets->myLangDependentAssets;
417   if (ldaMap.empty()) {
418     setText(SUIT_FoundActionTree::ElementIdx::Name, myModuleID);
419     return;
420   }
421
422   auto itLDA = ldaMap.find(theLang);
423   if (itLDA == ldaMap.end())
424     itLDA = ldaMap.begin();
425
426   const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
427   const QString& name = lda.myName.isEmpty() ? myModuleID : lda.myName;
428   setText(SUIT_FoundActionTree::ElementIdx::Name, name);
429 }
430
431 QVariant SUIT_FoundActionTreeModule::getValue(SUIT_FoundActionTree::SortKey theKey) const
432 {
433   switch (theKey) {
434     case SUIT_FoundActionTree::SortKey::MatchMetrics:
435       return double(0);
436     case SUIT_FoundActionTree::SortKey::ID:
437       return myModuleID;
438     case SUIT_FoundActionTree::SortKey::Name:
439       return name();
440     case SUIT_FoundActionTree::SortKey::ToolTip:
441       return toolTip();
442     default:
443       return QString();
444   }
445 }
446
447 bool SUIT_FoundActionTreeModule::isEnabled() const
448 {
449   return true;
450 }
451
452
453 SUIT_FoundActionTreeAction::SUIT_FoundActionTreeAction(const QString& theModuleID, const QString& theInModuleActionID)
454 : SUIT_FoundActionTreeItem(theModuleID), myInModuleActionID(theInModuleActionID),
455   myMatchMetrics(std::numeric_limits<double>::infinity()), myIsEnabledBufferedValue(false)
456 {
457   setText(SUIT_FoundActionTree::ElementIdx::Name, theInModuleActionID);
458 }
459
460 /*static*/ SUIT_FoundActionTreeAction* SUIT_FoundActionTreeAction::create(const QString& theModuleID, const QString& theInModuleActionID)
461 {
462   if (theInModuleActionID.isEmpty()) {
463     ShCutDbg("SUIT_FoundActionTreeItem: attempt to create item with empty action ID.");
464     return nullptr;
465   }
466
467   return new SUIT_FoundActionTreeAction(theModuleID, theInModuleActionID);
468 }
469
470 void SUIT_FoundActionTreeAction::setAssetsAndSearchData(const SUIT_ActionSearcher::AssetsAndSearchData& theAssetsAndSD, const QString& theLang)
471 {
472   if (!theAssetsAndSD.myAssets)
473     return;
474
475   setIcon(SUIT_FoundActionTree::ElementIdx::Name, theAssetsAndSD.myAssets->myIcon);
476
477   const auto& ldaMap = theAssetsAndSD.myAssets->myLangDependentAssets;
478   if (ldaMap.empty()) {
479     setText(SUIT_FoundActionTree::ElementIdx::Name, myInModuleActionID);
480     return;
481   }
482
483   auto itLDA = ldaMap.find(theLang);
484   if (itLDA == ldaMap.end())
485     itLDA = ldaMap.begin();
486
487   const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
488   const QString& name = lda.myName.isEmpty() ? myInModuleActionID : lda.myName;
489   setText(SUIT_FoundActionTree::ElementIdx::Name, name);
490
491   setText(SUIT_FoundActionTree::ElementIdx::ToolTip, lda.myToolTip);
492
493   if (isEnabled()) {
494     setToolTip(
495       SUIT_FoundActionTree::ElementIdx::Name,
496       SUIT_FoundActionTree::tr("Double click to start")
497     );
498
499     setToolTip(
500       SUIT_FoundActionTree::ElementIdx::ToolTip,
501       SUIT_FoundActionTree::tr("Double click to start")
502     );
503   }
504   else {
505     static const QBrush greyedOutBrush = QBrush(Qt::gray);
506     setForeground(SUIT_FoundActionTree::ElementIdx::Name,    greyedOutBrush);
507     setForeground(SUIT_FoundActionTree::ElementIdx::ToolTip, greyedOutBrush);
508   }
509
510   myMatchMetrics = theAssetsAndSD.matchMetrics();
511 }
512
513 QVariant SUIT_FoundActionTreeAction::getValue(SUIT_FoundActionTree::SortKey theKey) const
514 {
515   switch (theKey) {
516     case SUIT_FoundActionTree::SortKey::MatchMetrics:
517       return myMatchMetrics;
518     case SUIT_FoundActionTree::SortKey::ID:
519       return myInModuleActionID;
520     case SUIT_FoundActionTree::SortKey::Name:
521       return name();
522     case SUIT_FoundActionTree::SortKey::ToolTip:
523       return toolTip();
524     default:
525       return QString();
526   }
527 }
528
529 bool SUIT_FoundActionTreeAction::isEnabled() const
530 {
531   const auto& actions = SUIT_ShortcutMgr::get()->getActions(myModuleID, myInModuleActionID);
532   myIsEnabledBufferedValue = std::find_if(actions.begin(), actions.end(), [](const QAction* const theAction){ return theAction->isEnabled(); }) != actions.end();
533   return myIsEnabledBufferedValue;
534 }
535
536 bool SUIT_FoundActionTreeAction::trigger() const
537 {
538   bool res = false;
539   const auto& actions = SUIT_ShortcutMgr::get()->getActions(myModuleID, myInModuleActionID);
540   for (const auto& action : actions) {
541     if (action->isEnabled()) {
542       action->trigger();
543       res = true;
544     }
545   }
546   return res;
547 }