diff --git a/applets/kicker/plugin/actionlist.h b/applets/kicker/plugin/actionlist.h --- a/applets/kicker/plugin/actionlist.h +++ b/applets/kicker/plugin/actionlist.h @@ -57,4 +57,12 @@ QVariantList recentDocumentActions(KService::Ptr service); bool handleRecentDocumentAction(KService::Ptr service, const QString &actionId, const QVariant &argument); +bool canEditApplication(const QString &entryPath); +void editApplication(const QString &entryPath, const QString &menuId); +QVariantList editApplicationAction(const KService::Ptr &service); +bool handleEditApplicationAction(const QString &actionId, const KService::Ptr &service); + +QVariantList appstreamActions(const KService::Ptr &service); +bool handleAppstreamActions(const QString &actionId, const QVariant &argument); + } diff --git a/applets/kicker/plugin/actionlist.cpp b/applets/kicker/plugin/actionlist.cpp --- a/applets/kicker/plugin/actionlist.cpp +++ b/applets/kicker/plugin/actionlist.cpp @@ -19,20 +19,29 @@ ***************************************************************************/ #include "actionlist.h" +#include "menuentryeditor.h" + +#include #include +#include #include #include #include +#include #include #include #include #include #include "containmentinterface.h" +#ifdef HAVE_APPSTREAMQT +#include +#endif + namespace KAStats = KActivities::Stats; using namespace KAStats; @@ -308,4 +317,89 @@ return (KRun::runService(*service, QList() << QUrl(argument), QApplication::activeWindow()) != 0); } +Q_GLOBAL_STATIC(MenuEntryEditor, menuEntryEditor) + +bool canEditApplication(const QString &entryPath) +{ + return menuEntryEditor->canEdit(entryPath); +} + +void editApplication(const QString &entryPath, const QString &menuId) +{ + menuEntryEditor->edit(entryPath, menuId); +} + +QVariantList editApplicationAction(const KService::Ptr &service) +{ + QVariantList actionList; + + if (canEditApplication(service->entryPath())) { + QVariantMap editAction = Kicker::createActionItem(i18n("Edit Application..."), "editApplication"); + editAction["icon"] = "kmenuedit"; // TODO: Using the KMenuEdit icon might be misleading. + actionList << editAction; + } + + return actionList; +} + +bool handleEditApplicationAction(const QString &actionId, const KService::Ptr &service) +{ + + if (service && actionId == "editApplication" && canEditApplication(service->entryPath())) { + Kicker::editApplication(service->entryPath(), service->menuId()); + + return true; + } + + return false; +} + +#ifdef HAVE_APPSTREAMQT +Q_GLOBAL_STATIC(AppStream::Pool, appstreamPool) +#endif + +QVariantList appstreamActions(const KService::Ptr &service) +{ + QVariantList ret; + +#ifdef HAVE_APPSTREAMQT + const KService::Ptr appStreamHandler = KMimeTypeTrader::self()->preferredService(QStringLiteral("x-scheme-handler/appstream")); + + // Don't show action if we can't find any app to handle appstream:// URLs. + if (!appStreamHandler) { + if (!KProtocolInfo::isHelperProtocol(QStringLiteral("appstream")) + || KProtocolInfo::exec(QStringLiteral("appstream")).isEmpty()) { + return ret; + } + } + + if (!appstreamPool.exists()) { + appstreamPool->load(); + } + + const auto components = appstreamPool->componentsById(service->desktopEntryName()+QLatin1String(".desktop")); + for(const auto &component: components) { + const QString componentId = component.id(); + + QVariantMap appstreamAction = Kicker::createActionItem(i18nc("@action opens a software center with the application", "Manage '%1'...", component.name()), "manageApplication", QVariant(QStringLiteral("appstream://") + componentId)); + appstreamAction[QStringLiteral("icon")] = QStringLiteral("applications-other"); + ret << appstreamAction; + } +#else + Q_UNUSED(service) +#endif + + return ret; +} + +bool handleAppstreamActions(const QString &actionId, const QVariant &argument) +{ + if (actionId == "manageApplication") { + return QDesktopServices::openUrl(QUrl(argument.toString())); + } + + return false; +} + + } diff --git a/applets/kicker/plugin/appentry.cpp b/applets/kicker/plugin/appentry.cpp --- a/applets/kicker/plugin/appentry.cpp +++ b/applets/kicker/plugin/appentry.cpp @@ -22,15 +22,12 @@ #include "actionlist.h" #include "appsmodel.h" #include "containmentinterface.h" -#include "menuentryeditor.h" #include -#include #include #include #include -#include #if HAVE_X11 #include #endif @@ -40,21 +37,14 @@ #include #include #include -#include #include #include #include #include #include #include -#ifdef HAVE_APPSTREAMQT -#include -#endif - -MenuEntryEditor *AppEntry::m_menuEntryEditor = nullptr; - AppEntry::AppEntry(AbstractModel *owner, KService::Ptr service, NameFormat nameFormat) : AbstractEntry(owner) , m_service(service) @@ -89,10 +79,6 @@ } else { m_description = nameFromService(m_service, GenericNameOnly); } - - if (!m_menuEntryEditor) { - m_menuEntryEditor = new MenuEntryEditor(); - } } bool AppEntry::isValid() const @@ -142,39 +128,6 @@ return true; } -#ifdef HAVE_APPSTREAMQT -Q_GLOBAL_STATIC(AppStream::Pool, appstreamPool) - -QVariantList appstreamActions(const KService::Ptr &service) -{ - QVariantList ret; - - const KService::Ptr appStreamHandler = KMimeTypeTrader::self()->preferredService(QStringLiteral("x-scheme-handler/appstream")); - - // Don't show action if we can't find any app to handle appstream:// URLs. - if (!appStreamHandler) { - if (!KProtocolInfo::isHelperProtocol(QStringLiteral("appstream")) - || KProtocolInfo::exec(QStringLiteral("appstream")).isEmpty()) { - return ret; - } - } - - if (!appstreamPool.exists()) { - appstreamPool->load(); - } - - const auto components = appstreamPool->componentsById(service->desktopEntryName()+QLatin1String(".desktop")); - for(const auto &component: components) { - const QString componentId = component.id(); - - QVariantMap appstreamAction = Kicker::createActionItem(i18nc("@action opens a software center with the application", "Manage '%1'...", component.name()), "manageApplication", QVariant(QStringLiteral("appstream://") + componentId)); - appstreamAction[QStringLiteral("icon")] = QStringLiteral("applications-other"); - ret << appstreamAction; - } - return ret; -} -#endif - QVariantList AppEntry::actions() const { QVariantList actionList; @@ -205,19 +158,11 @@ return actionList; } - if (m_menuEntryEditor->canEdit(m_service->entryPath())) { - actionList << Kicker::createSeparatorActionItem(); - - QVariantMap editAction = Kicker::createActionItem(i18n("Edit Application..."), "editApplication"); - editAction["icon"] = "kmenuedit"; // TODO: Using the KMenuEdit icon might be misleading. - actionList << editAction; - } - -#ifdef HAVE_APPSTREAMQT if (m_service->isApplication()) { - actionList << appstreamActions(m_service); + actionList << Kicker::createSeparatorActionItem(); + actionList << Kicker::editApplicationAction(m_service); + actionList << Kicker::appstreamActions(m_service); } -#endif QQmlPropertyMap *appletConfig = qobject_cast(appletInterface->property("configuration").value()); @@ -260,12 +205,10 @@ if (Kicker::handleAddLauncherAction(actionId, appletInterface, m_service)) { return true; - } else if (actionId == "editApplication" && m_menuEntryEditor->canEdit(m_service->entryPath())) { - m_menuEntryEditor->edit(m_service->entryPath(), m_service->menuId()); - + } else if (Kicker::handleEditApplicationAction(actionId, m_service)) { + return true; + } else if (Kicker::handleAppstreamActions(actionId, argument)) { return true; - } else if (actionId == "manageApplication") { - return QDesktopServices::openUrl(QUrl(argument.toString())); } else if (actionId == "_kicker_jumpListAction") { return KRun::run(argument.toString(), {}, nullptr, m_service->name(), m_service->icon()); } diff --git a/applets/kicker/plugin/runnermatchesmodel.cpp b/applets/kicker/plugin/runnermatchesmodel.cpp --- a/applets/kicker/plugin/runnermatchesmodel.cpp +++ b/applets/kicker/plugin/runnermatchesmodel.cpp @@ -29,6 +29,8 @@ #include #include +#include + RunnerMatchesModel::RunnerMatchesModel(const QString &runnerId, const QString &name, Plasma::RunnerManager *manager, QObject *parent) : AbstractModel(parent) @@ -104,24 +106,38 @@ actionList << Kicker::createSeparatorActionItem(); } - KService::Ptr service = KService::serviceByStorageId(match.data().toString()); + const KService::Ptr service = KService::serviceByStorageId(match.data().toString()); + if (service) { const QVariantList &jumpListActions = Kicker::jumpListActions(service); if (!jumpListActions.isEmpty()) { actionList << jumpListActions << Kicker::createSeparatorActionItem(); } QObject *appletInterface = static_cast(parent())->appletInterface(); + const bool systemImmutable = appletInterface->property("immutability").toInt() == Plasma::Types::SystemImmutable; + const QVariantList &addLauncherActions = Kicker::createAddLauncherActionList(appletInterface, service); - if (!addLauncherActions.isEmpty()) { + if (!systemImmutable && !addLauncherActions.isEmpty()) { actionList << addLauncherActions << Kicker::createSeparatorActionItem(); } const QVariantList &recentDocuments = Kicker::recentDocumentActions(service); if (!recentDocuments.isEmpty()) { actionList << recentDocuments << Kicker::createSeparatorActionItem(); } + + // Don't allow adding launchers, editing, hiding, or uninstalling applications + // when system is immutable. + if (systemImmutable) { + return actionList; + } + + if (service->isApplication()) { + actionList << Kicker::editApplicationAction(service); + actionList << Kicker::appstreamActions(service); + } } return actionList; @@ -149,10 +165,14 @@ QObject *appletInterface = static_cast(parent())->appletInterface(); - KService::Ptr service = KService::serviceByStorageId(match.data().toString()); + const KService::Ptr service = KService::serviceByStorageId(match.data().toString()); if (Kicker::handleAddLauncherAction(actionId, appletInterface, service)) { return true; + } else if (Kicker::handleEditApplicationAction(actionId, service)) { + return true; + } else if (Kicker::handleAppstreamActions(actionId, argument)) { + return true; } else if (actionId == QLatin1String("_kicker_jumpListAction")) { return KRun::run(argument.toString(), {}, nullptr, service ? service->name() : QString(), service ? service->icon() : QString()); } else if (actionId == QLatin1String("_kicker_recentDocument")