From: dish Date: Wed, 6 Mar 2024 14:21:00 +0000 (+0000) Subject: [bos #40644][CEA](2024-T1) Feature search. X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=9eaf078b92fa0997da9cde91955bbd8c92c842e1;p=modules%2Fgui.git [bos #40644][CEA](2024-T1) Feature search. Fix search list update. --- diff --git a/src/LightApp/resources/LightApp.xml b/src/LightApp/resources/LightApp.xml index ac829fc9c..bfaad0d7e 100644 --- a/src/LightApp/resources/LightApp.xml +++ b/src/LightApp/resources/LightApp.xml @@ -285,6 +285,7 @@ + diff --git a/src/Qtx/QtxFeatureSearch.cxx b/src/Qtx/QtxFeatureSearch.cxx index 6a87cfe6d..839b5827a 100644 --- a/src/Qtx/QtxFeatureSearch.cxx +++ b/src/Qtx/QtxFeatureSearch.cxx @@ -36,8 +36,159 @@ #include +QtxFeatureSearchDialog::QtxFeatureSearchDialog(QWidget* theParent) +: QDialog(theParent) +{ + setMinimumWidth(500); + setWindowTitle(tr("Search action")); + QVBoxLayout* layout = new QVBoxLayout(this); + + myQueryLineEdit = new QLineEdit(this); + layout->addWidget(myQueryLineEdit); + myQueryLineEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + setFocusProxy(myQueryLineEdit); + + QHBoxLayout* searchOptionsLayout = new QHBoxLayout(this); + layout->addLayout(searchOptionsLayout); + myIncludeUnavailableActionsCB = new QCheckBox(tr("Unavailable actions"), this); + myIncludeUnavailableActionsCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + myIncludeUnavailableActionsCB->setCheckState(Qt::CheckState::Checked); + myActionSearcher.includeDisabledActions(true); + myIncludeInactiveModulesCB = new QCheckBox(tr("Inactive modules"), this); + myIncludeInactiveModulesCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + myIncludeInactiveModulesCB->setCheckState(Qt::CheckState::Unchecked); + searchOptionsLayout->addWidget(myIncludeUnavailableActionsCB); + searchOptionsLayout->addWidget(myIncludeInactiveModulesCB); + + myFoundActionsTree = new QtxFoundActionTree(); + layout->addWidget(myFoundActionsTree); + + connect(myQueryLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(onQueryChanged(const QString&))); + connect(myIncludeUnavailableActionsCB, SIGNAL(stateChanged(int)), this, SLOT(onSearchOptionUnavailableActionsChanged(int))); + connect(myIncludeInactiveModulesCB, SIGNAL(stateChanged(int)), this, SLOT(onSearchOptionInactiveModulesChanged(int))); +} + +void QtxFeatureSearchDialog::setActiveModuleID(const QString& theModuleID) +{ + myActiveModuleID = theModuleID; + if(myActionSearcher.setIncludedModuleIDs(std::set({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID}))) + updateUI(); +} + +void QtxFeatureSearchDialog::onQueryChanged(const QString& theQuery) +{ + if (myActionSearcher.setQuery(theQuery)) + updateUI(); +} + +void QtxFeatureSearchDialog::onSearchOptionUnavailableActionsChanged(int theState) +{ + ShCutDbg("QtxFeatureSearchDialog::onSearchOptionUnavailableActionsChanged"); + + if (myActionSearcher.includeDisabledActions(theState == Qt::CheckState::Checked)) + updateUI(); +} + +void QtxFeatureSearchDialog::onSearchOptionInactiveModulesChanged(int theState) +{ + bool resultsChanged = false; + if (theState == Qt::CheckState::Checked) + resultsChanged = myActionSearcher.setIncludedModuleIDs(SUIT_ShortcutMgr::get()->getShortcutContainer().getIDsOfAllModules()); + else + resultsChanged = myActionSearcher.setIncludedModuleIDs(std::set({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID})); + + if (resultsChanged) + updateUI(); +} + +void QtxFeatureSearchDialog::updateUI() +{ + myFoundActionsTree->updateItems(myActionSearcher.getSearchResults()); +} + + + QtxFoundActionTree::QtxFoundActionTree() -{} +{ + setColumnCount(2); + setSelectionMode(QAbstractItemView::SingleSelection); + setSortingEnabled(false); // Items are sorted in the same way, as in ShortcutContainer. + header()->setSectionResizeMode(QHeaderView::Interactive); + { + QMap labelMap; + labelMap[QtxFoundActionTree::ElementIdx::Name] = tr("Action"); + labelMap[QtxFoundActionTree::ElementIdx::ToolTip] = tr("Description"); + setHeaderLabels(labelMap.values()); + } + setExpandsOnDoubleClick(false); // Open shortcut editor on double click instead. + setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + setColumnWidth(QtxFoundActionTree::ElementIdx::Name, 120); + setColumnWidth(QtxFoundActionTree::ElementIdx::Name, 250); + setMinimumHeight(300); + + setWindowFlags(windowFlags() | Qt::FramelessWindowHint); + + connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onItemDoubleClicked(QTreeWidgetItem*, int))); +} + +void QtxFoundActionTree::updateItems(const std::map>& theAssets) +{ + clear(); + + const auto shortcutMgr = SUIT_ShortcutMgr::get(); + const QString lang = SUIT_ShortcutMgr::getLang(); + + for (const auto& moduleIDAndAssets : theAssets) { + const QString& moduleID = moduleIDAndAssets.first; + const auto& moduleAssets = moduleIDAndAssets.second; + if (moduleAssets.empty()) + continue; + + const auto moduleItem = new QtxFoundActionTreeFolder(moduleID); + moduleItem->setAssets(shortcutMgr->getModuleAssets(moduleID), lang); + addTopLevelItem(moduleItem); + moduleItem->setFlags(Qt::ItemIsEnabled); + for (const auto& actionIDAndAssets : moduleAssets) { + const QString& inModuleActionID = actionIDAndAssets.first; + const SUIT_ActionSearcher::AssetsAndSearchData& assetsAndSearchData = actionIDAndAssets.second; + + auto actionItem = QtxFoundActionTreeAction::create(moduleID, inModuleActionID); + if (!actionItem) { + ShCutDbg("QtxFoundActionTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\"."); + continue; + } + + actionItem->setAssets(assetsAndSearchData.myAssets, lang); + moduleItem->addChild(actionItem); + } + moduleItem->setExpanded(true); // Make tree expanded on first show. + } +} + +std::pair QtxFoundActionTree::findModuleFolderItem(const QString& theModuleID) const +{ + for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) { + QtxFoundActionTreeFolder* moduleItem = static_cast(topLevelItem(moduleIdx)); + if (moduleItem->myModuleID == theModuleID) + return std::pair(moduleItem, moduleIdx); + } + return std::pair(nullptr, -1); +} + +void QtxFoundActionTree::onItemDoubleClicked(QTreeWidgetItem* theItem, int theColIdx) +{ + { + QtxFoundActionTreeItem* const item = static_cast(theItem); + // Do not react if folder-item is clicked. + if (item->type() != QtxFoundActionTreeItem::Type::Action) + return; + } + + QtxFoundActionTreeAction* const actionItem = static_cast(theItem); + actionItem->trigger(); +} QtxFoundActionTreeItem::QtxFoundActionTreeItem(const QString& theModuleID) @@ -124,6 +275,8 @@ QtxFoundActionTreeAction::QtxFoundActionTreeAction(const QString& theModuleID, c void QtxFoundActionTreeAction::setAssets(std::shared_ptr theAssets, const QString& theLang) { + ShCutDbg("QtxFoundActionTreeAction::setAssets()"); + if (!theAssets) return; @@ -143,11 +296,12 @@ void QtxFoundActionTreeAction::setAssets(std::shared_ptrgetActions(myModuleID, myInModuleActionID); + ShCutDbg("QtxFoundActionTreeAction::isEnabled(): num of actions = " + QString::number(actions.size())); return std::find_if(actions.begin(), actions.end(), [](const QAction* const theAction){ return theAction->isEnabled(); }) != actions.end(); } @@ -192,71 +350,3 @@ void QtxFoundActionTreeAction::trigger() const action->trigger(); } } - - -QtxFeatureSearchDialog::QtxFeatureSearchDialog(QWidget* theParent) -: QDialog(theParent) -{ - setMinimumWidth(500); - setWindowTitle(tr("Search action")); - QVBoxLayout* layout = new QVBoxLayout(this); - - myQueryLineEdit = new QLineEdit(this); - layout->addWidget(myQueryLineEdit); - myQueryLineEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - setFocusProxy(myQueryLineEdit); - - QHBoxLayout* searchOptionsLayout = new QHBoxLayout(this); - layout->addLayout(searchOptionsLayout); - myIncludeUnavailableActionsCB = new QCheckBox(tr("Unavailable actions"), this); - myIncludeUnavailableActionsCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - myIncludeUnavailableActionsCB->setCheckState(Qt::CheckState::Checked); - myIncludeInactiveModulesCB = new QCheckBox(tr("Inactive modules"), this); - myIncludeInactiveModulesCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - myIncludeInactiveModulesCB->setCheckState(Qt::CheckState::Unchecked); - searchOptionsLayout->addWidget(myIncludeUnavailableActionsCB); - searchOptionsLayout->addWidget(myIncludeInactiveModulesCB); - - myFoundActionsTree = new QtxFoundActionTree(); - layout->addWidget(myFoundActionsTree); - - connect(myQueryLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(onQueryChanged(const QString&))); - connect(myIncludeUnavailableActionsCB, SIGNAL(stateChanged(Qt::CheckState)), this, SLOT(onSearchOptionUnavailableActionsChanged(Qt::CheckState))); - connect(myIncludeInactiveModulesCB, SIGNAL(stateChanged(Qt::CheckState)), this, SLOT(onSearchOptionInactiveModulesChanged(Qt::CheckState))); -} - -void QtxFeatureSearchDialog::setActiveModuleID(const QString& theModuleID) -{ - if(myActionSearcher.setIncludedModuleIDs(std::set({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID}))) - updateUI(); -} - -void QtxFeatureSearchDialog::onQueryChanged(const QString& theQuery) -{ - if (myActionSearcher.setQuery(theQuery)) - updateUI(); -} - -void QtxFeatureSearchDialog::onSearchOptionUnavailableActionsChanged(Qt::CheckState theState) -{ - if (myActionSearcher.includeDisabledActions(theState == Qt::CheckState::Checked)) - updateUI(); -} - -void QtxFeatureSearchDialog::onSearchOptionInactiveModulesChanged(Qt::CheckState theState) -{ - bool resultsChanged = false; - if (theState == Qt::CheckState::Checked) - resultsChanged = myActionSearcher.setIncludedModuleIDs(SUIT_ShortcutMgr::get()->getShortcutContainer().getIDsOfAllModules()); - else - resultsChanged = myActionSearcher.setIncludedModuleIDs(std::set({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID})); - - if (resultsChanged) - updateUI(); -} - -void QtxFeatureSearchDialog::updateUI() -{ - -} - diff --git a/src/Qtx/QtxFeatureSearch.h b/src/Qtx/QtxFeatureSearch.h index ea6827005..c5d3ac56b 100644 --- a/src/Qtx/QtxFeatureSearch.h +++ b/src/Qtx/QtxFeatureSearch.h @@ -31,6 +31,43 @@ #include +class QCheckBox; +class QLineEdit; +class QLabel; +class QPushButton; +class QtxFoundActionTree; + + +class QTX_EXPORT QtxFeatureSearchDialog : public QDialog +{ + Q_OBJECT + +public: + QtxFeatureSearchDialog(QWidget* theParent); + QtxFeatureSearchDialog(const QtxFeatureSearchDialog&) = delete; + QtxFeatureSearchDialog& operator=(const QtxFeatureSearchDialog&) = delete; + virtual ~QtxFeatureSearchDialog() = default; + + void setActiveModuleID(const QString& theModuleID = SUIT_ShortcutMgr::ROOT_MODULE_ID); + +private slots: + void onQueryChanged(const QString& theKeyword); + void onSearchOptionUnavailableActionsChanged(int); + void onSearchOptionInactiveModulesChanged(int); + +private: + void updateUI(); + + QLineEdit* myQueryLineEdit; + QCheckBox* myIncludeUnavailableActionsCB; + QCheckBox* myIncludeInactiveModulesCB; + QtxFoundActionTree* myFoundActionsTree; + + QString myActiveModuleID; + SUIT_ActionSearcher myActionSearcher; +}; + + class QtxFoundActionTreeItem; class QtxFoundActionTreeFolder; class QtxFoundActionTreeAction;; @@ -52,39 +89,18 @@ public: ToolTip }; - enum class SortOrder { - Ascending, - Descending - }; - QtxFoundActionTree(); QtxFoundActionTree(const QtxFoundActionTree&) = delete; QtxFoundActionTree& operator=(const QtxFoundActionTree&) = delete; virtual ~QtxFoundActionTree() = default; - void sort(QtxFoundActionTree::SortKey theKey, QtxFoundActionTree::SortOrder theOrder); + void updateItems(const std::map>& theAssets); private: - void updateItems(); std::pair findModuleFolderItem(const QString& theModuleID) const; - std::set> getSortedChildren(QtxFoundActionTreeFolder* theParentItem); - - void insertChild( - QtxFoundActionTreeFolder* theParentItem, - std::set>& theSortedChildren, - QtxFoundActionTreeItem* theChildItem - ); - private slots: void onItemDoubleClicked(QTreeWidgetItem* theWidgetItem, int theColIdx); - -public: - static const QList> DEFAULT_SORT_SCHEMA; - -private: - QtxFoundActionTree::SortKey mySortKey; - QtxFoundActionTree::SortOrder mySortOrder; }; @@ -152,40 +168,4 @@ public: const QString myInModuleActionID; }; - -class QCheckBox; -class QLineEdit; -class QLabel; -class QPushButton; - - -class QTX_EXPORT QtxFeatureSearchDialog : public QDialog -{ - Q_OBJECT - -public: - QtxFeatureSearchDialog(QWidget* theParent); - QtxFeatureSearchDialog(const QtxFeatureSearchDialog&) = delete; - QtxFeatureSearchDialog& operator=(const QtxFeatureSearchDialog&) = delete; - virtual ~QtxFeatureSearchDialog() = default; - - void setActiveModuleID(const QString& theModuleID); - -private slots: - void onQueryChanged(const QString& theKeyword); - void onSearchOptionUnavailableActionsChanged(Qt::CheckState theState); - void onSearchOptionInactiveModulesChanged(Qt::CheckState theState); - -private: - void updateUI(); - - QLineEdit* myQueryLineEdit; - QCheckBox* myIncludeUnavailableActionsCB; - QCheckBox* myIncludeInactiveModulesCB; - QtxFoundActionTree* myFoundActionsTree; - - QString myActiveModuleID; - SUIT_ActionSearcher myActionSearcher; -}; - #endif // QTXFEATURESEARCH_H diff --git a/src/SUIT/SUIT_ShortcutMgr.cxx b/src/SUIT/SUIT_ShortcutMgr.cxx index 8be5094cc..068414e3f 100644 --- a/src/SUIT/SUIT_ShortcutMgr.cxx +++ b/src/SUIT/SUIT_ShortcutMgr.cxx @@ -1903,7 +1903,7 @@ void SUIT_ShortcutMgr::setAssetsFromResources(QString theLanguage) auto itAssets = moduleActionAssets.find(inModuleActionID); if (itAssets == moduleActionAssets.end()) { auto pAssets = std::shared_ptr(new SUIT_ActionAssets(actionAssets)); - itAssets = moduleActionAssets.emplace(actionID, pAssets).first; + itAssets = moduleActionAssets.emplace(inModuleActionID, pAssets).first; } else itAssets->second->merge(actionAssets, true); @@ -1981,18 +1981,17 @@ void SUIT_SentenceMatcher::setUseExactWordOrder(bool theOn) return; myUseExactWordOrder = theOn; - if (!myWords || theOn) + if (theOn) { + myPermutatedSentences.clear(); + myFuzzyPermutatedSentences.clear(); return; - - if (!myPermutatedSentences) { - myPermutatedSentences.reset(new QList()); - SUIT_SentenceMatcher::makePermutatedSentences(*myWords, *myPermutatedSentences); } - if (myUseFuzzyWords && !myFuzzyPermutatedSentences) { - myFuzzyPermutatedSentences.reset(new QList()); - SUIT_SentenceMatcher::makePermutatedSentences(*myFuzzyWords, *myFuzzyPermutatedSentences); - } + if (myPermutatedSentences.isEmpty()) + SUIT_SentenceMatcher::makePermutatedSentences(myWords, myPermutatedSentences); + + if (myUseFuzzyWords && myFuzzyPermutatedSentences.isEmpty()) + SUIT_SentenceMatcher::makePermutatedSentences(myFuzzyWords, myFuzzyPermutatedSentences); } void SUIT_SentenceMatcher::setUseFuzzyWords(bool theOn) @@ -2001,15 +2000,18 @@ void SUIT_SentenceMatcher::setUseFuzzyWords(bool theOn) return; myUseFuzzyWords = theOn; - if (!myWords || !theOn || myFuzzyWords) + if (myWords.isEmpty() || !theOn) { + myFuzzyWords.clear(); + myFuzzyPermutatedSentences.clear(); return; + } - myFuzzyWords.reset(new QStringList()); - SUIT_SentenceMatcher::makeFuzzyWords(*myWords, *myFuzzyWords); + myFuzzyWords.clear(); + SUIT_SentenceMatcher::makeFuzzyWords(myWords, myFuzzyWords); if (!myUseExactWordOrder) { - myFuzzyPermutatedSentences.reset(new QList()); - SUIT_SentenceMatcher::makePermutatedSentences(*myFuzzyWords, *myFuzzyPermutatedSentences); + myFuzzyPermutatedSentences.clear(); + SUIT_SentenceMatcher::makePermutatedSentences(myFuzzyWords, myFuzzyPermutatedSentences); } } @@ -2025,46 +2027,22 @@ void SUIT_SentenceMatcher::setQuery(QString theQuery) return; myQuery = theQuery; - - { // Set exact words. - if (myWords) - myWords->clear(); - else - myWords.reset(new QStringList()); - - *myWords = theQuery.split(" ", QString::SkipEmptyParts); - } + myWords = theQuery.split(" ", QString::SkipEmptyParts); { // Set permutated sentences. - if (myUseExactWordOrder) - myPermutatedSentences.reset(nullptr); - else { - if (!myPermutatedSentences) - myPermutatedSentences.reset(new QList()); - - SUIT_SentenceMatcher::makePermutatedSentences(*myWords, *myPermutatedSentences); - } + myPermutatedSentences.clear(); + if (!myUseExactWordOrder) + SUIT_SentenceMatcher::makePermutatedSentences(myWords, myPermutatedSentences); } // Set fuzzy words and sentences. - if (myUseFuzzyWords) { - if (!myFuzzyWords) - myFuzzyWords.reset(new QStringList()); - - SUIT_SentenceMatcher::makeFuzzyWords(*myWords, *myFuzzyWords); + myFuzzyWords.clear(); + myFuzzyPermutatedSentences.clear(); - if (myUseExactWordOrder) - myFuzzyPermutatedSentences.reset(nullptr); - else { - if (!myFuzzyPermutatedSentences) - myFuzzyPermutatedSentences.reset(new QList()); - - SUIT_SentenceMatcher::makePermutatedSentences(*myFuzzyWords, *myFuzzyPermutatedSentences); - } - } - else { - myFuzzyWords.reset(nullptr); - myFuzzyPermutatedSentences.reset(nullptr); + if (myUseFuzzyWords) { + SUIT_SentenceMatcher::makeFuzzyWords(myWords, myFuzzyWords); + if (!myUseExactWordOrder) + SUIT_SentenceMatcher::makePermutatedSentences(myFuzzyWords, myFuzzyPermutatedSentences); } } @@ -2072,23 +2050,23 @@ size_t SUIT_SentenceMatcher::match(const QString& theInputString) const { size_t n = 0; if (myUseExactWordOrder) { - n = SUIT_SentenceMatcher::match(theInputString, *myWords, myIsCaseSensitive); + n = SUIT_SentenceMatcher::match(theInputString, myWords, myIsCaseSensitive); if (n > 0) return n; if (myUseFuzzyWords) { - n = SUIT_SentenceMatcher::match(theInputString, *myFuzzyWords, myIsCaseSensitive); + n = SUIT_SentenceMatcher::match(theInputString, myFuzzyWords, myIsCaseSensitive); if (n > 0) return n; } } else /* if match with permutated query sentences */ { - n = SUIT_SentenceMatcher::match(theInputString, *myPermutatedSentences, myIsCaseSensitive); + n = SUIT_SentenceMatcher::match(theInputString, myPermutatedSentences, myIsCaseSensitive); if (n > 0) return n; if (myUseFuzzyWords) { - n = SUIT_SentenceMatcher::match(theInputString, *myFuzzyPermutatedSentences, myIsCaseSensitive); + n = SUIT_SentenceMatcher::match(theInputString, myFuzzyPermutatedSentences, myIsCaseSensitive); if (n > 0) return n; } @@ -2097,6 +2075,29 @@ size_t SUIT_SentenceMatcher::match(const QString& theInputString) const return n; } +QString SUIT_SentenceMatcher::toString() const +{ + QString res = QString("myUseExactWordOrder: ") + (myUseExactWordOrder ? "true" : "false") + ";\n"; + res += QString("myUseFuzzyWords: ") + (myUseFuzzyWords ? "true" : "false") + ";\n"; + res += QString("myIsCaseSensitive: ") + (myIsCaseSensitive ? "true" : "false") + ";\n"; + res += QString("myQuery: ") + myQuery + ";\n"; + res += QString("myWords: ") + myWords.join(", ") + ";\n"; + res += QString("myFuzzyWords: ") + myFuzzyWords.join(", ") + ";\n"; + + res += "myPermutatedSentences:\n"; + for (const auto& sentence : myPermutatedSentences) { + res += "\t" + sentence.join(", ") + ";\n"; + } + + res += "myFuzzyPermutatedSentences:\n"; + for (const auto& sentence : myFuzzyPermutatedSentences) { + res += "\t" + sentence.join(", ") + ";\n"; + } + + res += "."; + return res; +} + /*static*/ bool SUIT_SentenceMatcher::makePermutatedSentences(const QStringList& theWords, QList& theSentences) { theSentences.clear(); @@ -2187,7 +2188,7 @@ size_t SUIT_SentenceMatcher::match(const QString& theInputString) const if (n > 0) return n; - if (theSentences.size()) + if (theSentences.size() > 0) return SUIT_SentenceMatcher::matchAtLeastOneWord(theInputString, theSentences[0], theCaseSensitive); else return 0; @@ -2198,6 +2199,25 @@ SUIT_ActionSearcher::AssetsAndSearchData::AssetsAndSearchData(std::shared_ptrtoJSON(assetsJSON); + oJsonObject["myAssets"] = assetsJSON; + } +} + +QString SUIT_ActionSearcher::AssetsAndSearchData::toString() const +{ + QJsonObject json; + toJSON(json); + QJsonDocument doc(json); + return QString(doc.toJson(QJsonDocument::Indented)); +} + SUIT_ActionSearcher::SUIT_ActionSearcher() { myIncludedModuleIDs = { SUIT_ShortcutMgr::ROOT_MODULE_ID }; @@ -2210,17 +2230,19 @@ SUIT_ActionSearcher::SUIT_ActionSearcher() bool SUIT_ActionSearcher::setIncludedModuleIDs(std::set theIncludedModuleIDs) { + ShCutDbg("SUIT_ActionSearcher::setIncludedModuleIDs"); + if (myIncludedModuleIDs == theIncludedModuleIDs) return false; myIncludedModuleIDs = theIncludedModuleIDs; bool res = false; - // Erase search results with excluded modules. Erase IDs of modules, which are already in search results, from theIncludedModuleIDs. + // Erase search results from excluded modules. Erase IDs of modules, which are already in search results, from theIncludedModuleIDs. for (auto itFound = mySearchResults.begin(); itFound != mySearchResults.end(); ) { const auto itModuleID = theIncludedModuleIDs.find(itFound->first); if (itModuleID == theIncludedModuleIDs.end()) { - mySearchResults.erase(itFound); + itFound = mySearchResults.erase(itFound); res = true; } else { @@ -2247,20 +2269,28 @@ bool SUIT_ActionSearcher::setIncludedModuleIDs(std::set theIncludedModu } } + ShCutDbg() && ShCutDbg(toString()); + return res; } bool SUIT_ActionSearcher::includeDisabledActions(bool theOn) { + ShCutDbg("SUIT_ActionSearcher::includeDisabledActions"); + if (myIncludeDisabledActions == theOn) return false; myIncludeDisabledActions = theOn; + bool res; if (myIncludeDisabledActions) - return extendResults(); + res = extendResults(); else - return filterResults().first; + res = filterResults().first; + + ShCutDbg() && ShCutDbg(toString()); + return res; } bool SUIT_ActionSearcher::setFieldsToMatch(const std::set& theFields) @@ -2292,12 +2322,16 @@ bool SUIT_ActionSearcher::setFieldsToMatch(const std::set>& SUIT_ActionSearcher::getSearchResults() const @@ -2329,6 +2371,8 @@ const std::map SUIT_ActionSearcher::filter() { + ShCutDbg("SUIT_ActionSearcher::filter()"); + auto res = std::pair(false, false); for (const auto& moduleIDAndAssets : SUIT_ShortcutMgr::get()->getActionAssets()) { @@ -2389,7 +2433,7 @@ std::pair SUIT_ActionSearcher::filterResults() SUIT_ActionSearcher::AssetsAndSearchData& assetsAndSearchData = itActionIDAndAssets->second; const size_t n = matchAction(moduleID, inModuleActionID, assetsAndSearchData.myAssets); if (n == 0) { - actionIDsAndAssets.erase(itActionIDAndAssets); + itActionIDAndAssets = actionIDsAndAssets.erase(itActionIDAndAssets); res.first = true; } else { @@ -2402,7 +2446,7 @@ std::pair SUIT_ActionSearcher::filterResults() } if (actionIDsAndAssets.empty()) - mySearchResults.erase(itFoundModuleIDAndAssets); + itFoundModuleIDAndAssets = mySearchResults.erase(itFoundModuleIDAndAssets); else itFoundModuleIDAndAssets++; } @@ -2412,6 +2456,8 @@ std::pair SUIT_ActionSearcher::filterResults() bool SUIT_ActionSearcher::extendResults() { + ShCutDbg("SUIT_ActionSearcher::extendResults()"); + bool res = false; for (const auto& moduleIDAndAssets : SUIT_ShortcutMgr::get()->getActionAssets()) { const auto& moduleID = moduleIDAndAssets.first; @@ -2430,8 +2476,10 @@ bool SUIT_ActionSearcher::extendResults() continue; // Action is already in search results. } + ShCutDbg() && ShCutDbg("SUIT_ActionSearcher::extendResults(): " + moduleID + "/" + inModuleActionID + "." ); const size_t n = matchAction(moduleID, inModuleActionID, actionIDAndAssets.second); if (n > 0) { + ShCutDbg("SUIT_ActionSearcher::extendResults(): match"); if (itFoundModuleIDAndAssets == mySearchResults.end()) itFoundModuleIDAndAssets = mySearchResults.emplace(moduleID, std::map()).first; @@ -2445,6 +2493,11 @@ bool SUIT_ActionSearcher::extendResults() size_t SUIT_ActionSearcher::matchAction(const QString& theModuleID, const QString& theInModuleActionID, std::shared_ptr theAssets) { + if (!theAssets) { + ShCutDbg("WARNING: SUIT_ActionSearcher::matchAction: theAssets is nullptr."); + return 0; + } + if (!myIncludeDisabledActions) { const auto& actions = SUIT_ShortcutMgr::get()->getActions(theModuleID, theInModuleActionID); const bool actionEnabled = std::find_if(actions.begin(), actions.end(), [](const QAction* const theAction){ return theAction->isEnabled(); } ) != actions.end(); @@ -2476,4 +2529,40 @@ size_t SUIT_ActionSearcher::matchAction(const QString& theModuleID, const QStrin } return false; +} + +QString SUIT_ActionSearcher::toString() const +{ + QString res; + + res += "myMatcher: {\n"; + res += myMatcher.toString(); + res += "};\n"; + + res += "myIncludedModuleIDs: "; + for (const QString& moduleID : myIncludedModuleIDs) { + res += moduleID + ", "; + } + res += ";\n"; + + res += QString("myIncludeDisabledActions: ") + (myIncludeDisabledActions ? "true" : "false") + ";\n"; + + res += "myFieldsToMatch: "; + for (const auto& field : myFieldsToMatch) { + res += QString::number(int(field)) + ", "; + } + res += ";\n"; + + res += "mySearchResults:\n"; + for (const auto& moduleIDAndAssets : mySearchResults ) { + res += "\tModule ID: " + moduleIDAndAssets.first + ":\n"; + for (const auto& actionIDAndAssets : moduleIDAndAssets.second) { + const auto& assetsAndSearchData = actionIDAndAssets.second; + res += "\t\tAction ID: " + actionIDAndAssets.first + ": {"; + res += "\t\t: " + actionIDAndAssets.second.toString(); + res += "\t\t}"; + } + } + + return res; } \ No newline at end of file diff --git a/src/SUIT/SUIT_ShortcutMgr.h b/src/SUIT/SUIT_ShortcutMgr.h index ea4d287d4..49dfdf16d 100644 --- a/src/SUIT/SUIT_ShortcutMgr.h +++ b/src/SUIT/SUIT_ShortcutMgr.h @@ -505,6 +505,8 @@ public: /*! \returns number of matched words. */ size_t match(const QString& theInputString) const; + QString toString() const; + private: static bool makePermutatedSentences(const QStringList& theWords, QList& theSentences); static void makeFuzzyWords(const QStringList& theWords, QStringList& theFuzzyWords); @@ -531,11 +533,11 @@ private: bool myIsCaseSensitive; QString myQuery; - std::unique_ptr myWords; // It is also original search sentence. - std::unique_ptr> myPermutatedSentences; + QStringList myWords; // It is also original search sentence. + QList myPermutatedSentences; - std::unique_ptr myFuzzyWords; // Regexes. - std::unique_ptr> myFuzzyPermutatedSentences; + QStringList myFuzzyWords; // Regexes. + QList myFuzzyPermutatedSentences; }; @@ -563,6 +565,9 @@ public: std::shared_ptr myAssets; size_t myNumOfMatchingWords; + + void toJSON(QJsonObject& oJsonObject) const; + QString toString() const; }; /*! Default config: @@ -613,6 +618,8 @@ private: size_t matchAction(const QString& theModuleID, const QString& theInModuleActionID, std::shared_ptr theAssets); + QString toString() const; + std::set myIncludedModuleIDs; bool myIncludeDisabledActions; diff --git a/src/SUIT/resources/action_assets.json b/src/SUIT/resources/action_assets.json index eefb7012c..4e8a50a89 100644 --- a/src/SUIT/resources/action_assets.json +++ b/src/SUIT/resources/action_assets.json @@ -390,6 +390,23 @@ } } }, + "/PRP_DESK_FIND_ACTION": { + "iconPath": "", + "langDependentAssets": { + "en": { + "name": "Find action", + "tooltip": "Opens action search dialog" + }, + "fr": { + "name": "Trouver une action", + "tooltip": "Ouvre la boîte de dialogue de recherche d'action" + }, + "ja": { + "name": "検索アクション", + "tooltip": "アクション検索ダイアログを開きます" + } + } + }, "/PRP_DESK_CONNECT": { "iconPath": "", "langDependentAssets": { diff --git a/src/SalomeApp/SalomeApp_Application.cxx b/src/SalomeApp/SalomeApp_Application.cxx index 3768626aa..fa4054c3d 100644 --- a/src/SalomeApp/SalomeApp_Application.cxx +++ b/src/SalomeApp/SalomeApp_Application.cxx @@ -73,6 +73,7 @@ #include #include +#include #include @@ -107,6 +108,7 @@ #include #include +#include #include @@ -363,6 +365,11 @@ void SalomeApp_Application::createActions() tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ), /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) ); + //! Find action dialog + createAction( FindActionId, tr( "TOT_DESK_FIND_ACTION" ), QIcon(), + tr( "MEN_DESK_FIND_ACTION" ), tr( "PRP_DESK_FIND_ACTION" ), + QKeySequence::UnknownKey, desk, false, this, SLOT( onFindAction() ), "/PRP_DESK_FIND_ACTION" ); + createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(), tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ), QKeySequence::UnknownKey, desk, false, this, SLOT( onLoadDoc() ), "/PRP_DESK_CONNECT" ); @@ -395,6 +402,7 @@ void SalomeApp_Application::createActions() int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 ); createMenu( CatalogGenId, toolsMenu, 10, -1 ); createMenu( RegDisplayId, toolsMenu, 10, -1 ); + createMenu( FindActionId, toolsMenu, 10, -1 ); createMenu( separator(), toolsMenu, -1, 15, -1 ); createExtraActions(); @@ -1574,6 +1582,25 @@ void SalomeApp_Application::onRegDisplay() regWnd->activateWindow(); } +/*!Display Action Search dialog */ +void SalomeApp_Application::onFindAction() +{ + const auto pActiveModule = activeModule(); + if (pActiveModule && pActiveModule->name() == "PARAVIS") { + return; + // ParaViS module has its own action search dialog (Quick Launch dialog). + // Keep this conditional block until ParaViS's actions are not added to ShortcutMgr resource and asset files. + } + + QtxFeatureSearchDialog aDlg( desktop() ); + if (pActiveModule) + aDlg.setActiveModuleID(pActiveModule->name()); + else + aDlg.setActiveModuleID(); + + aDlg.exec(); +} + /*!find original object by double click on item */ void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj ) { diff --git a/src/SalomeApp/SalomeApp_Application.h b/src/SalomeApp/SalomeApp_Application.h index bd5c92019..5a78e279e 100644 --- a/src/SalomeApp/SalomeApp_Application.h +++ b/src/SalomeApp/SalomeApp_Application.h @@ -71,7 +71,7 @@ class SALOMEAPPIMPL_EXPORT SalomeApp_Application : public LightApp_Application public: enum { MenuToolsId = 5 }; enum { DumpStudyId = LightApp_Application::UserID, LoadScriptId, PropertiesId, - CatalogGenId, RegDisplayId, SaveGUIStateId, ConnectId, DisconnectId, + CatalogGenId, RegDisplayId, FindActionId, SaveGUIStateId, ConnectId, DisconnectId, UserID }; typedef enum { WT_NoteBook = LightApp_Application::WT_User, @@ -192,6 +192,7 @@ private slots: void onCatalogGen(); void onRegDisplay(); + void onFindAction(); void onOpenWith(); void onExtAction(); diff --git a/src/SalomeApp/resources/SalomeApp_msg_en.ts b/src/SalomeApp/resources/SalomeApp_msg_en.ts index d75e202a2..b130ca897 100644 --- a/src/SalomeApp/resources/SalomeApp_msg_en.ts +++ b/src/SalomeApp/resources/SalomeApp_msg_en.ts @@ -164,6 +164,10 @@ Launch a new session or close the study. MEN_DESK_REGISTRY_DISPLAY Registry &Display + + MEN_DESK_FIND_ACTION + Find action + TOT_DESK_FILE_LOAD_SCRIPT Load python script @@ -237,6 +241,10 @@ Do you want to reload it ? PRP_DESK_REGISTRY_DISPLAY Displays content of the Registry CORBA server + + PRP_DESK_FIND_ACTION + Opens action search dialog + APPCLOSE_DESCRIPTION Do you want to save study before closing? @@ -261,6 +269,10 @@ Do you want to reload it ? TOT_DESK_REGISTRY_DISPLAY Registry display + + TOT_DESK_FIND_ACTION + Find action + OBJ_BROWSER_COLUMN_0 Entry diff --git a/src/SalomeApp/resources/SalomeApp_msg_fr.ts b/src/SalomeApp/resources/SalomeApp_msg_fr.ts index ac9e08e95..e73006c23 100644 --- a/src/SalomeApp/resources/SalomeApp_msg_fr.ts +++ b/src/SalomeApp/resources/SalomeApp_msg_fr.ts @@ -164,6 +164,10 @@ Lancez une nouvelle session ou fermez l'étude en cours. MEN_DESK_REGISTRY_DISPLAY Affichage du registre CORBA + + MEN_DESK_FIND_ACTION + Trouver une action + TOT_DESK_FILE_LOAD_SCRIPT Exécuter un script python @@ -237,6 +241,10 @@ Voulez-vous le recharger ? PRP_DESK_REGISTRY_DISPLAY Visualiser le contenu du registre du serveur CORBA + + PRP_DESK_FIND_ACTION + Ouvre la boîte de dialogue de recherche d'action + APPCLOSE_DESCRIPTION Voulez-vous sauvegarder l'étude avant de quitter ? @@ -261,6 +269,10 @@ Voulez-vous le recharger ? TOT_DESK_REGISTRY_DISPLAY Visualiser le registre CORBA + + TOT_DESK_FIND_ACTION + Trouver une action + OBJ_BROWSER_COLUMN_0 Entrée diff --git a/src/SalomeApp/resources/SalomeApp_msg_ja.ts b/src/SalomeApp/resources/SalomeApp_msg_ja.ts index 7dab9b3a4..6bc1b7851 100644 --- a/src/SalomeApp/resources/SalomeApp_msg_ja.ts +++ b/src/SalomeApp/resources/SalomeApp_msg_ja.ts @@ -164,6 +164,10 @@ MEN_DESK_REGISTRY_DISPLAY レジストリの表示(&D) + + MEN_DESK_FIND_ACTION + 検索アクション + TOT_DESK_FILE_LOAD_SCRIPT Python スクリプトを実行 @@ -236,6 +240,10 @@ PRP_DESK_REGISTRY_DISPLAY CORBAサーバーの登録内容を表示 + + PRP_DESK_FIND_ACTION + アクション検索ダイアログを開きます + APPCLOSE_DESCRIPTION 閉じる、または閉じる前にスタディをアンロードしますか? @@ -260,6 +268,10 @@ TOT_DESK_REGISTRY_DISPLAY レジストリの表示 + + TOT_DESK_FIND_ACTION + 検索アクション + OBJ_BROWSER_COLUMN_0 エントリ