diff --git a/gui/include/Actions/ActionsGuiController.h b/gui/include/Actions/ActionsGuiController.h index ccb2da5..16a2cf9 100644 --- a/gui/include/Actions/ActionsGuiController.h +++ b/gui/include/Actions/ActionsGuiController.h @@ -21,6 +21,12 @@ public: void removeAction(const std::shared_ptr &action); + /// Sets a flag to say that the specified menu can be filtered, usually via a FilteringAction + void addFilterForMenu(const QStringList &menuPath); + + /// Returns true if the menu can be filtered + bool isMenuFiltered(const QStringList &menuPath) const; + private: class ActionsGuiControllerPrivate; spimpl::unique_impl_ptr impl; diff --git a/gui/include/Actions/FilteringAction.h b/gui/include/Actions/FilteringAction.h new file mode 100644 index 0000000..05eec06 --- /dev/null +++ b/gui/include/Actions/FilteringAction.h @@ -0,0 +1,19 @@ +#ifndef SCIQLOP_FILTERINGACTION_H +#define SCIQLOP_FILTERINGACTION_H + +#include +#include + +/// A LineEdit inside an action which is able to filter other actions +class FilteringAction : public QWidgetAction { +public: + FilteringAction(QWidget *parent); + + void addActionToFilter(QAction *action); + +private: + class FilteringActionPrivate; + spimpl::unique_impl_ptr impl; +}; + +#endif // SCIQLOP_FILTERINGACTION_H diff --git a/gui/include/Actions/SelectionZoneAction.h b/gui/include/Actions/SelectionZoneAction.h index 93f6b4b..22793a8 100644 --- a/gui/include/Actions/SelectionZoneAction.h +++ b/gui/include/Actions/SelectionZoneAction.h @@ -60,6 +60,13 @@ public: /// The path in the sub menus, if any QStringList subMenuList() const noexcept; + /// Sets if filtering the action is allowed via a FilteringAction + void setAllowedFiltering(bool value); + + /// Returns true if filtering the action is allowed via a FilteringAction. By default it is + /// allowed. + bool isFilteringAllowed() const; + public slots: /// Executes the action void execute(const QVector &item); diff --git a/gui/meson.build b/gui/meson.build index 31ccb6b..0fc02dc 100644 --- a/gui/meson.build +++ b/gui/meson.build @@ -28,7 +28,8 @@ gui_moc_headers = [ 'include/Catalogue/CatalogueSideBarWidget.h', 'include/Catalogue/CatalogueInspectorWidget.h', 'include/Catalogue/CatalogueEventsModel.h', - 'include/Catalogue/CatalogueTreeModel.h' + 'include/Catalogue/CatalogueTreeModel.h', + 'include/Actions/FilteringAction.h' ] gui_ui_files = [ @@ -112,6 +113,7 @@ gui_sources = [ 'src/Visualization/VisualizationSelectionZoneManager.cpp', 'src/Actions/SelectionZoneAction.cpp', 'src/Actions/ActionsGuiController.cpp', + 'src/Actions/FilteringAction.cpp', 'src/Visualization/VisualizationActionManager.cpp', 'src/Visualization/VisualizationMultiZoneSelectionDialog.cpp', 'src/Catalogue/CatalogueExplorer.cpp', diff --git a/gui/src/Actions/ActionsGuiController.cpp b/gui/src/Actions/ActionsGuiController.cpp index 8b9ec9e..1f9c465 100644 --- a/gui/src/Actions/ActionsGuiController.cpp +++ b/gui/src/Actions/ActionsGuiController.cpp @@ -3,6 +3,7 @@ struct ActionsGuiController::ActionsGuiControllerPrivate { QVector > m_SelectionZoneActions; + QSet m_FilteredMenu; }; ActionsGuiController::ActionsGuiController() @@ -39,3 +40,13 @@ void ActionsGuiController::removeAction(const std::shared_ptrm_SelectionZoneActions.removeAll(action); } + +void ActionsGuiController::addFilterForMenu(const QStringList &menuPath) +{ + impl->m_FilteredMenu.insert(menuPath); +} + +bool ActionsGuiController::isMenuFiltered(const QStringList &menuPath) const +{ + return impl->m_FilteredMenu.contains(menuPath); +} diff --git a/gui/src/Actions/FilteringAction.cpp b/gui/src/Actions/FilteringAction.cpp new file mode 100644 index 0000000..e28b567 --- /dev/null +++ b/gui/src/Actions/FilteringAction.cpp @@ -0,0 +1,27 @@ +#include "Actions/FilteringAction.h" + +#include + +struct FilteringAction::FilteringActionPrivate { + QLineEdit *m_FilterLineEdit; + QVector m_FilteredActions; +}; + +FilteringAction::FilteringAction(QWidget *parent) + : QWidgetAction(parent), impl{spimpl::make_unique_impl()} +{ + impl->m_FilterLineEdit = new QLineEdit(parent); + setDefaultWidget(impl->m_FilterLineEdit); + + connect(impl->m_FilterLineEdit, &QLineEdit::textEdited, [this](auto text) { + for (auto action : impl->m_FilteredActions) { + auto match = action->text().contains(text, Qt::CaseInsensitive); + action->setVisible(match); + } + }); +} + +void FilteringAction::addActionToFilter(QAction *action) +{ + impl->m_FilteredActions << action; +} diff --git a/gui/src/Actions/SelectionZoneAction.cpp b/gui/src/Actions/SelectionZoneAction.cpp index 0fcae06..da183b7 100644 --- a/gui/src/Actions/SelectionZoneAction.cpp +++ b/gui/src/Actions/SelectionZoneAction.cpp @@ -15,6 +15,7 @@ struct SelectionZoneAction::SelectionZoneActionPrivate { QKeySequence m_DisplayedShortcut; SelectionZoneAction::ExecuteFunction m_Fun; SelectionZoneAction::EnableFunction m_EnableFun = [](auto zones) { return true; }; + bool m_FilteringAllowed = true; }; SelectionZoneAction::SelectionZoneAction(const QString &name, ExecuteFunction fun) @@ -55,6 +56,16 @@ QStringList SelectionZoneAction::subMenuList() const noexcept return impl->m_SubMenuList; } +void SelectionZoneAction::setAllowedFiltering(bool value) +{ + impl->m_FilteringAllowed = value; +} + +bool SelectionZoneAction::isFilteringAllowed() const +{ + return impl->m_FilteringAllowed; +} + void SelectionZoneAction::execute(const QVector &item) { impl->m_Fun(item); diff --git a/gui/src/Catalogue/CatalogueActionManager.cpp b/gui/src/Catalogue/CatalogueActionManager.cpp index e9ddd63..10f3c8b 100644 --- a/gui/src/Catalogue/CatalogueActionManager.cpp +++ b/gui/src/Catalogue/CatalogueActionManager.cpp @@ -127,6 +127,7 @@ void CatalogueActionManager::installSelectionZoneActions() {CATALOGUE_MENU_NAME, CATALOGUE_CREATE_EVENT_MENU_NAME}, QObject::tr("Without Catalogue"), [this](auto zones) { impl->createEventFromZones(DEFAULT_EVENT_NAME, zones); }); createEventAction->setEnableFunction(impl->createEventEnableFuntion()); + createEventAction->setAllowedFiltering(false); auto createEventInNewCatalogueAction = actionController.addSectionZoneAction( {CATALOGUE_MENU_NAME, CATALOGUE_CREATE_EVENT_MENU_NAME}, QObject::tr("In New Catalogue"), @@ -141,9 +142,11 @@ void CatalogueActionManager::installSelectionZoneActions() impl->createEventFromZones(DEFAULT_EVENT_NAME, zones, newCatalogue); }); createEventInNewCatalogueAction->setEnableFunction(impl->createEventEnableFuntion()); - + createEventInNewCatalogueAction->setAllowedFiltering(false); refreshCreateInCatalogueAction(); + + actionController.addFilterForMenu({CATALOGUE_MENU_NAME, CATALOGUE_CREATE_EVENT_MENU_NAME}); } void CatalogueActionManager::refreshCreateInCatalogueAction() diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index a78a6f2..c77b9a6 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -12,6 +12,7 @@ #include "ui_VisualizationGraphWidget.h" #include +#include #include #include #include @@ -245,7 +246,7 @@ VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget &VisualizationGraphWidget::onMouseDoubleClick); connect(ui->widget->xAxis, static_cast( &QCPAxis::rangeChanged), - this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection); + this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection); // Activates menu when right clicking on the graph ui->widget->setContextMenuPolicy(Qt::CustomContextMenu); @@ -707,32 +708,51 @@ void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept QHash subMenus; QHash subMenusEnabled; + QHash filteredMenu; for (auto zoneAction : zoneActions) { auto isEnabled = zoneAction->isEnabled(selectedItems); auto menu = &graphMenu; + QString menuPath; for (auto subMenuName : zoneAction->subMenuList()) { - if (!subMenus.contains(subMenuName)) { + menuPath += '/'; + menuPath += subMenuName; + + if (!subMenus.contains(menuPath)) { menu = menu->addMenu(subMenuName); - subMenus[subMenuName] = menu; - subMenusEnabled[subMenuName] = isEnabled; + subMenus[menuPath] = menu; + subMenusEnabled[menuPath] = isEnabled; } else { - menu = subMenus.value(subMenuName); + menu = subMenus.value(menuPath); if (isEnabled) { // The sub menu is enabled if at least one of its actions is enabled - subMenusEnabled[subMenuName] = true; + subMenusEnabled[menuPath] = true; } } } + FilteringAction *filterAction = nullptr; + if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) { + filterAction = filteredMenu.value(menuPath); + if (!filterAction) { + filterAction = new FilteringAction{this}; + filteredMenu[menuPath] = filterAction; + menu->addAction(filterAction); + } + } + auto action = menu->addAction(zoneAction->name()); action->setEnabled(isEnabled); action->setShortcut(zoneAction->displayedShortcut()); QObject::connect(action, &QAction::triggered, [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); }); + + if (filterAction && zoneAction->isFilteringAllowed()) { + filterAction->addActionToFilter(action); + } } for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {