diff --git a/applets/appmenu/plugin/CMakeLists.txt b/applets/appmenu/plugin/CMakeLists.txt --- a/applets/appmenu/plugin/CMakeLists.txt +++ b/applets/appmenu/plugin/CMakeLists.txt @@ -10,6 +10,7 @@ Qt5::Quick KF5::Plasma KF5::WindowSystem + KF5::I18n PW::LibTaskManager dbusmenuqt) diff --git a/applets/appmenu/plugin/appmenumodel.h b/applets/appmenu/plugin/appmenumodel.h --- a/applets/appmenu/plugin/appmenumodel.h +++ b/applets/appmenu/plugin/appmenumodel.h @@ -22,6 +22,7 @@ #ifndef APPMENUMODEL_H #define APPMENUMODEL_H +#include #include #include #include @@ -65,6 +66,7 @@ QRect screenGeometry() const; void setScreenGeometry(QRect geometry); + QList flatActionList(); signals: void requestActivateIndex(int index); @@ -93,6 +95,11 @@ WId m_delayedMenuWindowId = 0; QPointer m_menu; + QPointer m_searchAction; + QList m_currentSearchActions; + + void removeSearchActionsFromMenu(); + void insertSearchActionsIntoMenu(const QString &filter = QString()); QDBusServiceWatcher *m_serviceWatcher; QString m_serviceName; diff --git a/applets/appmenu/plugin/appmenumodel.cpp b/applets/appmenu/plugin/appmenumodel.cpp --- a/applets/appmenu/plugin/appmenumodel.cpp +++ b/applets/appmenu/plugin/appmenumodel.cpp @@ -29,6 +29,12 @@ #include #include #include +#include +#include +#include + +#include +#include #include #include @@ -79,6 +85,26 @@ emit modelNeedsUpdate(); } }); + + m_searchAction = new QAction(this); + m_searchAction->setText(i18n("Search")); + m_searchAction->setObjectName(QStringLiteral("appmenu")); + + auto searchMenu = new QMenu; + auto searchAction = new QWidgetAction(this); + auto searchBar = new QLineEdit; + searchBar->setPlaceholderText(i18n("Search...")); + searchBar->setMinimumWidth(200); + connect(searchBar, &QLineEdit::textChanged, [=]() mutable { + insertSearchActionsIntoMenu(searchBar->text()); + connect(this, &AppMenuModel::modelNeedsUpdate, this, [this, searchBar]() mutable { + }); + insertSearchActionsIntoMenu(searchBar->text()); + }); + searchAction->setDefaultWidget(searchBar); + searchMenu->addAction(searchAction); + searchMenu->addSeparator(); + m_searchAction->setMenu(searchMenu); } AppMenuModel::~AppMenuModel() = default; @@ -127,7 +153,29 @@ return 0; } - return m_menu->actions().count(); + return m_menu->actions().count()+1; +} + +void AppMenuModel::removeSearchActionsFromMenu() +{ + for (const auto &action: m_currentSearchActions) { + m_searchAction->menu()->removeAction(action); + } + m_currentSearchActions = QList(); +} + +void AppMenuModel::insertSearchActionsIntoMenu(const QString &filter) +{ + if (filter == QString()) { + return; + } + auto actions = flatActionList(); + for (const auto &action: actions) { + if (action->text().contains(filter, Qt::CaseInsensitive)) { + m_searchAction->menu()->addAction(action); + m_currentSearchActions << m_searchAction; + } + } } void AppMenuModel::update() @@ -162,15 +210,36 @@ return roleNames; } +QList AppMenuModel::flatActionList() +{ + QList ret; + if (!m_menuAvailable || !m_menu) { + return ret; + } + for (auto &action: m_menu->findChildren()) { + if (action->menu() == nullptr) { + ret << action; + } + } + return ret; +} + QVariant AppMenuModel::data(const QModelIndex &index, int role) const { const int row = index.row(); if (row < 0 || !m_menuAvailable || !m_menu) { return QVariant(); } const auto actions = m_menu->actions(); - if (row >= actions.count()) { + if (row == actions.count()) { + if (role == MenuRole) { + return m_searchAction->text(); + } else if (role == ActionRole) { + return QVariant::fromValue((void*)m_searchAction); + } + } + if (row > actions.count()) { return QVariant(); }