diff --git a/applets/kicker/CMakeLists.txt b/applets/kicker/CMakeLists.txt --- a/applets/kicker/CMakeLists.txt +++ b/applets/kicker/CMakeLists.txt @@ -18,6 +18,7 @@ plugin/actionlist.cpp plugin/appentry.cpp plugin/appsmodel.cpp + plugin/allappsmodel.cpp plugin/computermodel.cpp plugin/contactentry.cpp plugin/containmentinterface.cpp diff --git a/applets/kicker/plugin/allappsmodel.h b/applets/kicker/plugin/allappsmodel.h new file mode 100644 --- /dev/null +++ b/applets/kicker/plugin/allappsmodel.h @@ -0,0 +1,45 @@ +/* + * + * Copyright (C) 2019 Tomaz Canabrava + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ALLAPPSMODEL_H +#define ALLAPPSMODEL_H + +#include "appsmodel.h" + +#include + +class AbstractEntry; + +/** + * This model represents a flat list of all executables installed that can be shown in a Menu. + */ +class AllAppsModel : public AppsModel +{ +public: + /** + * Default constructor + */ + AllAppsModel(); + ~AllAppsModel() override; + void refresh() override; + +private: + QList m_originalEntries; +}; + +#endif // ALLAPPSMODEL_H diff --git a/applets/kicker/plugin/allappsmodel.cpp b/applets/kicker/plugin/allappsmodel.cpp new file mode 100644 --- /dev/null +++ b/applets/kicker/plugin/allappsmodel.cpp @@ -0,0 +1,112 @@ +/* + * + * Copyright (C) 2019 Tomaz Canabrava + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "allappsmodel.h" +#include "rootmodel.h" + +#include + +AllAppsModel::AllAppsModel() +{ + refresh(); +} + +AllAppsModel::~AllAppsModel() +{ + // The AppsModel takes care of deleting the m_entryList, + // if we let the filtered list there we have double-frees. + m_entryList = m_originalEntries; +} + +namespace { +/* Fetches all apps from the current model, some entries could + * also be Models, so we check for the RunnableType + */ +QList appEntriesFromModel(AbstractModel *model) { + QList apps; + for (int j = 0; j < model->count(); ++j) { + AppEntry *appEntry = static_cast(model->index(j, 0).internalPointer()); + + if (appEntry->name().isEmpty() || appEntry->type() != AbstractGroupEntry::EntryType::RunnableType) { + continue; + } + + apps.append(appEntry); + } + return apps; +} + +/* Fetches all models from the current model, and extracts the apps from them. This is recursive + * so we can have multiple depness of menus and extract from all of them. + */ +QList modelEntriesFromModel(AbstractModel *model) { + QList apps = appEntriesFromModel(model); + + for (int i = 0; i < model->count(); ++i) { + GroupEntry *subGroupEntry = static_cast(model->index(i, 0).internalPointer()); + AbstractModel *subModel = subGroupEntry->childModel(); + if (subModel) { + apps += modelEntriesFromModel(subModel); + } + } + return apps; +} + +/* goes thru a list of AbstractEntries figuring out what's an app, what's a menu item + * extracting all the apps and returning the result. + */ +QList setupFlatModel(const QList &roots) +{ + QList apps; + foreach (const AbstractEntry *groupEntry, roots) { + AbstractModel *model = groupEntry->childModel(); + if (!model) continue; + + apps += modelEntriesFromModel(model); + } + + return apps; +} + +} // namespace + +void AllAppsModel::refresh() +{ + if (!m_complete) { + return; + } + beginResetModel(); + + if (m_originalEntries.count()) { + m_entryList = m_originalEntries; + } + + refreshInternal(); + m_originalEntries = m_entryList; + m_entryList = setupFlatModel(m_originalEntries); + + sortEntries(); + + /* Remove duplicates */ + auto last = std::unique(std::begin(m_entryList), std::end(m_entryList), + [](AbstractEntry *a, AbstractEntry *b) { return a->name() == b->name(); }); + + m_entryList.erase(last, std::end(m_entryList)); + + endResetModel(); +} diff --git a/applets/kicker/plugin/appsmodel.h b/applets/kicker/plugin/appsmodel.h --- a/applets/kicker/plugin/appsmodel.h +++ b/applets/kicker/plugin/appsmodel.h @@ -121,6 +121,7 @@ protected: void refreshInternal(); + void sortEntries(); bool m_complete; @@ -140,7 +141,6 @@ private: void processServiceGroup(KServiceGroup::Ptr group); - void sortEntries(); bool m_autoPopulate; diff --git a/applets/kicker/plugin/kickerplugin.cpp b/applets/kicker/plugin/kickerplugin.cpp --- a/applets/kicker/plugin/kickerplugin.cpp +++ b/applets/kicker/plugin/kickerplugin.cpp @@ -36,6 +36,7 @@ #include "systemsettings.h" #include "wheelinterceptor.h" #include "windowsystem.h" +#include "allappsmodel.h" #include @@ -46,6 +47,7 @@ qmlRegisterType(); qmlRegisterType(uri, 0, 1, "AppsModel"); + qmlRegisterType(uri, 0, 1, "AllAppsModel"); qmlRegisterType(uri, 0, 1, "ComputerModel"); qmlRegisterType(uri, 0, 1, "ContainmentInterface"); qmlRegisterType(uri, 0, 1, "DragHelper");