File indexing completed on 2024-05-19 05:37:49

0001 /*
0002     SPDX-FileCopyrightText: 2010 Chani Armitage <chani@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "activityengine.h"
0008 #include "activityservice.h"
0009 
0010 #include <plasmaactivities/controller.h>
0011 #include <plasmaactivities/info.h>
0012 
0013 #include <QApplication>
0014 #include <QDBusServiceWatcher>
0015 
0016 #define ACTIVITYMANAGER_SERVICE "org.kde.kactivitymanagerd"
0017 #define ACTIVITYRANKING_OBJECT "/ActivityRanking"
0018 
0019 ActivityEngine::ActivityEngine(QObject *parent)
0020     : Plasma5Support::DataEngine(parent)
0021 {
0022     init();
0023 }
0024 
0025 void ActivityEngine::init()
0026 {
0027     if (qApp->applicationName() == QLatin1String("plasma-netbook")) {
0028         // hack for the netbook
0029         // FIXME can I read a setting or something instead?
0030     } else {
0031         m_activityController = new KActivities::Controller(this);
0032         m_currentActivity = m_activityController->currentActivity();
0033         const QStringList activities = m_activityController->activities();
0034         // setData("allActivities", activities);
0035         for (const QString &id : activities) {
0036             insertActivity(id);
0037         }
0038 
0039         connect(m_activityController, &KActivities::Controller::activityAdded, this, &ActivityEngine::activityAdded);
0040         connect(m_activityController, &KActivities::Controller::activityRemoved, this, &ActivityEngine::activityRemoved);
0041         connect(m_activityController, &KActivities::Controller::currentActivityChanged, this, &ActivityEngine::currentActivityChanged);
0042 
0043         // some convenience sources for times when checking every activity source would suck
0044         // it starts with _ so that it can easily be filtered out of sources()
0045         // maybe I should just make it not included in sources() instead?
0046         m_runningActivities = m_activityController->activities(KActivities::Info::Running);
0047         setData(QStringLiteral("Status"), QStringLiteral("Current"), m_currentActivity);
0048         setData(QStringLiteral("Status"), QStringLiteral("Running"), m_runningActivities);
0049 
0050         m_watcher = new QDBusServiceWatcher(ACTIVITYMANAGER_SERVICE,
0051                                             QDBusConnection::sessionBus(),
0052                                             QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration,
0053                                             this);
0054 
0055         connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &ActivityEngine::enableRanking);
0056         connect(m_watcher, &QDBusServiceWatcher::serviceUnregistered, this, &ActivityEngine::disableRanking);
0057 
0058         if (QDBusConnection::sessionBus().interface()->isServiceRegistered(ACTIVITYMANAGER_SERVICE)) {
0059             enableRanking();
0060         }
0061     }
0062 }
0063 
0064 void ActivityEngine::insertActivity(const QString &id)
0065 {
0066     // id -> name, icon, state
0067     KActivities::Info *activity = new KActivities::Info(id, this);
0068     m_activities[id] = activity;
0069     setData(id, QStringLiteral("Name"), activity->name());
0070     setData(id, QStringLiteral("Icon"), activity->icon());
0071     setData(id, QStringLiteral("Current"), m_currentActivity == id);
0072 
0073     QString state;
0074     switch (activity->state()) {
0075     case KActivities::Info::Running:
0076         state = QLatin1String("Running");
0077         break;
0078     case KActivities::Info::Starting:
0079         state = QLatin1String("Starting");
0080         break;
0081     case KActivities::Info::Stopping:
0082         state = QLatin1String("Stopping");
0083         break;
0084     case KActivities::Info::Stopped:
0085         state = QLatin1String("Stopped");
0086         break;
0087     case KActivities::Info::Invalid:
0088     default:
0089         state = QLatin1String("Invalid");
0090     }
0091     setData(id, QStringLiteral("State"), state);
0092     setData(id, QStringLiteral("Score"), m_activityScores.value(id));
0093 
0094     connect(activity, &KActivities::Info::infoChanged, this, &ActivityEngine::activityDataChanged);
0095     connect(activity, &KActivities::Info::stateChanged, this, &ActivityEngine::activityStateChanged);
0096 
0097     m_runningActivities << id;
0098 }
0099 
0100 void ActivityEngine::disableRanking()
0101 {
0102     delete m_activityRankingClient;
0103 }
0104 
0105 void ActivityEngine::enableRanking()
0106 {
0107     m_activityRankingClient = new org::kde::ActivityManager::ActivityRanking(ACTIVITYMANAGER_SERVICE, ACTIVITYRANKING_OBJECT, QDBusConnection::sessionBus());
0108     connect(m_activityRankingClient, &org::kde::ActivityManager::ActivityRanking::rankingChanged, this, &ActivityEngine::rankingChanged);
0109 
0110     QDBusMessage msg = QDBusMessage::createMethodCall(ACTIVITYMANAGER_SERVICE,
0111                                                       ACTIVITYRANKING_OBJECT,
0112                                                       QStringLiteral("org.kde.ActivityManager.ActivityRanking"),
0113                                                       QStringLiteral("activities"));
0114     QDBusPendingReply<ActivityDataList> reply = QDBusConnection::sessionBus().asyncCall(msg);
0115     QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
0116     QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &ActivityEngine::activityScoresReply);
0117 }
0118 
0119 void ActivityEngine::activityScoresReply(QDBusPendingCallWatcher *watcher)
0120 {
0121     QDBusPendingReply<ActivityDataList> reply = *watcher;
0122     if (reply.isError()) {
0123         qDebug() << "Error getting activity scores: " << reply.error().message();
0124     } else {
0125         setActivityScores(reply.value());
0126     }
0127 
0128     watcher->deleteLater();
0129 }
0130 
0131 void ActivityEngine::rankingChanged(const QStringList &topActivities, const ActivityDataList &activities)
0132 {
0133     Q_UNUSED(topActivities)
0134 
0135     setActivityScores(activities);
0136 }
0137 
0138 void ActivityEngine::setActivityScores(const ActivityDataList &activities)
0139 {
0140     QSet<QString> presentActivities;
0141     m_activityScores.clear();
0142 
0143     for (const ActivityData &activity : activities) {
0144         if (m_activities.contains(activity.id)) {
0145             setData(activity.id, QStringLiteral("Score"), activity.score);
0146         }
0147         presentActivities.insert(activity.id);
0148         m_activityScores[activity.id] = activity.score;
0149     }
0150 
0151     const auto controllerActivities = m_activityController->activities();
0152     for (const QString &activityId : controllerActivities) {
0153         if (!presentActivities.contains(activityId) && m_activities.contains(activityId)) {
0154             setData(activityId, QStringLiteral("Score"), 0);
0155         }
0156     }
0157 }
0158 
0159 void ActivityEngine::activityAdded(const QString &id)
0160 {
0161     insertActivity(id);
0162     setData(QStringLiteral("Status"), QStringLiteral("Running"), m_runningActivities);
0163 }
0164 
0165 void ActivityEngine::activityRemoved(const QString &id)
0166 {
0167     removeSource(id);
0168     KActivities::Info *activity = m_activities.take(id);
0169     if (activity) {
0170         delete activity;
0171     }
0172     m_runningActivities.removeAll(id);
0173     setData(QStringLiteral("Status"), QStringLiteral("Running"), m_runningActivities);
0174 }
0175 
0176 void ActivityEngine::currentActivityChanged(const QString &id)
0177 {
0178     setData(m_currentActivity, QStringLiteral("Current"), false);
0179     m_currentActivity = id;
0180     setData(id, QStringLiteral("Current"), true);
0181     setData(QStringLiteral("Status"), QStringLiteral("Current"), id);
0182 }
0183 
0184 void ActivityEngine::activityDataChanged()
0185 {
0186     KActivities::Info *activity = qobject_cast<KActivities::Info *>(sender());
0187     if (!activity) {
0188         return;
0189     }
0190     setData(activity->id(), QStringLiteral("Name"), activity->name());
0191     setData(activity->id(), QStringLiteral("Icon"), activity->icon());
0192     setData(activity->id(), QStringLiteral("Current"), m_currentActivity == activity->id());
0193     setData(activity->id(), QStringLiteral("Score"), m_activityScores.value(activity->id()));
0194 }
0195 
0196 void ActivityEngine::activityStateChanged()
0197 {
0198     KActivities::Info *activity = qobject_cast<KActivities::Info *>(sender());
0199     const QString id = activity->id();
0200     if (!activity) {
0201         return;
0202     }
0203     QString state;
0204     switch (activity->state()) {
0205     case KActivities::Info::Running:
0206         state = QLatin1String("Running");
0207         break;
0208     case KActivities::Info::Starting:
0209         state = QLatin1String("Starting");
0210         break;
0211     case KActivities::Info::Stopping:
0212         state = QLatin1String("Stopping");
0213         break;
0214     case KActivities::Info::Stopped:
0215         state = QLatin1String("Stopped");
0216         break;
0217     case KActivities::Info::Invalid:
0218     default:
0219         state = QLatin1String("Invalid");
0220     }
0221     setData(id, QStringLiteral("State"), state);
0222 
0223     if (activity->state() == KActivities::Info::Running) {
0224         if (!m_runningActivities.contains(id)) {
0225             m_runningActivities << id;
0226         }
0227     } else {
0228         m_runningActivities.removeAll(id);
0229     }
0230 
0231     setData(QStringLiteral("Status"), QStringLiteral("Running"), m_runningActivities);
0232 }
0233 
0234 Plasma5Support::Service *ActivityEngine::serviceForSource(const QString &source)
0235 {
0236     // FIXME validate the name
0237     ActivityService *service = new ActivityService(m_activityController, source);
0238     service->setParent(this);
0239     return service;
0240 }
0241 
0242 K_PLUGIN_CLASS_WITH_JSON(ActivityEngine, "plasma-dataengine-activities.json")
0243 
0244 #include "activityengine.moc"