diff --git a/dataengines/applicationjobs/CMakeLists.txt b/dataengines/applicationjobs/CMakeLists.txt --- a/dataengines/applicationjobs/CMakeLists.txt +++ b/dataengines/applicationjobs/CMakeLists.txt @@ -6,18 +6,15 @@ jobaction.cpp ) -qt5_add_dbus_interface(kuiserver_engine_SRCS ${CMAKE_SOURCE_DIR}/kuiserver/org.kde.kuiserver.xml kuiserverinterface) -qt5_add_dbus_adaptor(kuiserver_engine_SRCS ${CMAKE_SOURCE_DIR}/kuiserver/org.kde.JobView.xml kuiserverengine.h JobView jobviewadaptor ) -qt5_add_dbus_adaptor(kuiserver_engine_SRCS ${KJOBWIDGETS_DBUS_INTERFACES_DIR}/kf5_org.kde.JobViewServer.xml kuiserverengine.h KuiserverEngine jobviewserveradaptor ) - add_library(plasma_engine_applicationjobs MODULE ${kuiserver_engine_SRCS}) target_link_libraries(plasma_engine_applicationjobs Qt5::DBus KF5::CoreAddons KF5::I18n KF5::KIOCore KF5::Plasma KF5::Service + PW::LibNotificationManager ) kcoreaddons_desktop_to_json(plasma_engine_applicationjobs plasma-dataengine-applicationjobs.desktop) diff --git a/dataengines/applicationjobs/jobaction.h b/dataengines/applicationjobs/jobaction.h --- a/dataengines/applicationjobs/jobaction.h +++ b/dataengines/applicationjobs/jobaction.h @@ -21,26 +21,35 @@ #include "kuiserverengine.h" +#include + #include +#include "job.h" + +namespace NotificationManager +{ +class Job; +} + class JobAction : public Plasma::ServiceJob { Q_OBJECT public: - JobAction(JobView *jobView, + JobAction(NotificationManager::Job *job, const QString& operation, QMap& parameters, QObject* parent = nullptr) - : ServiceJob(jobView->objectName(), operation, parameters, parent), - m_jobView(jobView) + : ServiceJob(KuiserverEngine::sourceName(job), operation, parameters, parent), + m_job(job) { } void start() override; private: - JobView *m_jobView; + QPointer m_job; }; #endif //JOBVIEW_H diff --git a/dataengines/applicationjobs/jobaction.cpp b/dataengines/applicationjobs/jobaction.cpp --- a/dataengines/applicationjobs/jobaction.cpp +++ b/dataengines/applicationjobs/jobaction.cpp @@ -27,7 +27,7 @@ { qDebug() << "Trying to perform the action" << operationName(); - if (!m_jobView) { + if (!m_job) { setErrorText(i18nc("%1 is the subject (can be anything) upon which the job is performed", "The JobView for %1 cannot be found", destination())); setError(-1); @@ -37,18 +37,12 @@ //TODO: check with capabilities before performing actions. if (operationName() == QLatin1String("resume")) { - m_jobView->requestStateChange(JobView::Running); + m_job->resume(); } else if (operationName() == QLatin1String("suspend")) { - m_jobView->requestStateChange(JobView::Suspended); + m_job->suspend(); } else if (operationName() == QLatin1String("stop")) { - m_jobView->requestStateChange(JobView::Stopped); - //in case the app crashed and won't call terminate on the jobview. - m_jobView->setError(KIO::ERR_USER_CANCELED); - m_jobView->terminate(i18n("Job canceled by user.")); + m_job->kill(); } emitResult(); } - - - diff --git a/dataengines/applicationjobs/jobcontrol.h b/dataengines/applicationjobs/jobcontrol.h --- a/dataengines/applicationjobs/jobcontrol.h +++ b/dataengines/applicationjobs/jobcontrol.h @@ -21,21 +21,23 @@ #include -class JobView; +#include + +#include "job.h" class JobControl : public Plasma::Service { Q_OBJECT public: - JobControl(QObject* parent, JobView *jobview); + JobControl(QObject *parent, NotificationManager::Job *job); protected: Plasma::ServiceJob* createJob(const QString& operation, QMap& parameters) override; private: - JobView *m_jobView; + QPointer m_job; }; diff --git a/dataengines/applicationjobs/jobcontrol.cpp b/dataengines/applicationjobs/jobcontrol.cpp --- a/dataengines/applicationjobs/jobcontrol.cpp +++ b/dataengines/applicationjobs/jobcontrol.cpp @@ -20,19 +20,18 @@ #include "jobaction.h" #include "kuiserverengine.h" -JobControl::JobControl(QObject* parent, JobView *jobView) +using namespace NotificationManager; + +JobControl::JobControl(QObject* parent, Job *job) : Plasma::Service(parent), - m_jobView(jobView) + m_job(job) { setName(QStringLiteral("applicationjobs")); - setDestination(jobView->objectName()); + setDestination(KuiserverEngine::sourceName(job)); } Plasma::ServiceJob* JobControl::createJob(const QString& operation, QMap& parameters) { - return new JobAction(m_jobView, operation, parameters, this); + return new JobAction(m_job, operation, parameters, this); } - - - diff --git a/dataengines/applicationjobs/kuiserverengine.h b/dataengines/applicationjobs/kuiserverengine.h --- a/dataengines/applicationjobs/kuiserverengine.h +++ b/dataengines/applicationjobs/kuiserverengine.h @@ -19,14 +19,17 @@ #ifndef KUISERVERENGINE_H #define KUISERVERENGINE_H -#include -#include -#include +#include #include #include -class JobView; +#include "jobsmodel.h" + +namespace NotificationManager +{ + class Job; +} namespace Plasma { @@ -36,109 +39,61 @@ class KuiserverEngine : public Plasma::DataEngine { Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.kde.JobViewServer") public: KuiserverEngine(QObject* parent, const QVariantList& args); ~KuiserverEngine() override; void init(); - QDBusObjectPath requestView(const QString &appName, const QString &appIconName, - int capabilities); Plasma::Service* serviceForSource(const QString& source) override; -private Q_SLOTS: - void processPendingJobs(); - -private: - QTimer m_pendingJobsTimer; - QList m_pendingJobs; -}; - -class JobView : public Plasma::DataContainer -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.kde.JobViewV2") - -public: - enum State { - UnknownState = -1, - Running = 0, - Suspended = 1, - Stopped = 2 - }; - - explicit JobView(QObject *parent = nullptr); - ~JobView() override; - - uint jobId() const; - JobView::State state(); - - void setTotalAmount(qlonglong amount, const QString &unit); - QString totalAmountSize() const; - QString totalAmountFiles() const; - - void setProcessedAmount(qlonglong amount, const QString &unit); - - void setSpeed(qlonglong bytesPerSecond); - QString speedString() const; - - void setInfoMessage(const QString &infoMessage); - QString infoMessage() const; - - bool setDescriptionField(uint number, const QString &name, const QString &value); - void clearDescriptionField(uint number); - - void setAppName(const QString &appName); - void setAppIconName(const QString &appIconName); - void setCapabilities(int capabilities); - void setPercent(uint percent); - void setSuspended(bool suspended); - void setError(uint errorCode); - void setDestUrl(const QDBusVariant &destUrl); - - void terminate(const QString &errorMessage); - - QDBusObjectPath objectPath() const; - - void requestStateChange(State state); - -public Q_SLOTS: - void finished(); - -Q_SIGNALS: - void suspendRequested(); - void resumeRequested(); - void cancelRequested(); - -protected: - void timerEvent(QTimerEvent *event) override; + static QString sourceName(NotificationManager::Job *job); + static uint jobId(const QString &sourceName); private: - void scheduleUpdate(); - void updateEta(); - int unitId(const QString &unit); - - QDBusObjectPath m_objectPath; - QBasicTimer m_updateTimer; - - uint m_capabilities; - uint m_percent; - uint m_jobId; - - // for ETA calculation we cache these values - qlonglong m_speed; - qlonglong m_totalBytes; - qlonglong m_processedBytes; - - State m_state; - - QMap m_unitMap; - int m_bytesUnitId; - int m_unitId; - - static uint s_jobId; + template void connectJobField( + NotificationManager::Job *job, + T (NotificationManager::Job::*getter)() const, + signal changeSignal, + const QString &targetFieldName) + { + // Set value initially in case we missed the first change + const QString source = sourceName(job); + setData(source, targetFieldName, ((job)->*getter)()); + // and then listen for changes + connect(job, changeSignal, this, [=] { + setData(source, targetFieldName, ((job)->*getter)()); + }); + } + + void updateDescriptionField( + NotificationManager::Job *job, + int number, + QString (NotificationManager::Job::*labelGetter)() const, + QString (NotificationManager::Job::*valueGetter)() const + ); + + void updateUnit( + NotificationManager::Job *job, + int number, + const QString &unit, + qulonglong (NotificationManager::Job::*processedGetter)() const, + qulonglong (NotificationManager::Job::*totalGetter)() const + ); + + void registerJob(NotificationManager::Job *job); + void removeJob(NotificationManager::Job *job); + + static QString speedString(qulonglong speed); + + void updateState(NotificationManager::Job *job); + void updateSpeed(NotificationManager::Job *job); + void updateEta(NotificationManager::Job *job); + + NotificationManager::JobsModel::Ptr m_jobsModel; + + QVector m_jobs; }; #endif diff --git a/dataengines/applicationjobs/kuiserverengine.cpp b/dataengines/applicationjobs/kuiserverengine.cpp --- a/dataengines/applicationjobs/kuiserverengine.cpp +++ b/dataengines/applicationjobs/kuiserverengine.cpp @@ -16,382 +16,267 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "jobviewadaptor.h" -#include "jobviewserveradaptor.h" -#include "kuiserverinterface.h" #include "kuiserverengine.h" #include "jobcontrol.h" -#include #include #include #include -#include +#include #include +#include "notifications.h" +#include "jobsmodel.h" -uint JobView::s_jobId = 0; +#include -static const int UPDATE_INTERVAL = 100; +using namespace NotificationManager; -JobView::JobView(QObject* parent) - : Plasma::DataContainer(parent), - m_capabilities(-1), - m_percent(0), - m_speed(0), - m_totalBytes(0), - m_processedBytes(0), - m_state(UnknownState), - m_bytesUnitId(-1), - m_unitId(0) +KuiserverEngine::KuiserverEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args) { - m_jobId = ++s_jobId; - setObjectName(QStringLiteral("Job %1").arg(s_jobId)); - - new JobViewV2Adaptor(this); - - m_objectPath.setPath(QStringLiteral("/DataEngine/applicationjobs/JobView_%1").arg(m_jobId)); - QDBusConnection::sessionBus().registerObject(m_objectPath.path(), this); - - setSuspended(false); + init(); } -JobView::~JobView() +KuiserverEngine::~KuiserverEngine() { - QDBusConnection::sessionBus().unregisterObject(m_objectPath.path(), QDBusConnection::UnregisterTree); -} -uint JobView::jobId() const -{ - return m_jobId; } -void JobView::scheduleUpdate() +QString KuiserverEngine::sourceName(Job *job) { - if (!m_updateTimer.isActive()) { - m_updateTimer.start(UPDATE_INTERVAL, this); - } + return QStringLiteral("Job %1").arg(job->id()); } -void JobView::timerEvent(QTimerEvent *event) +uint KuiserverEngine::jobId(const QString &sourceName) { - if (event->timerId() == m_updateTimer.timerId()) { - m_updateTimer.stop(); - checkForUpdate(); - - if (m_state == Stopped) { - emit becameUnused(objectName()); - } - } else { - Plasma::DataContainer::timerEvent(event); - } + return sourceName.midRef(4 /*length of Job + space*/).toUInt(); } -void JobView::terminate(const QString &errorMessage) -{ - setData(QStringLiteral("errorText"), errorMessage); - QTimer::singleShot(0, this, &JobView::finished); -} - -void JobView::finished() +Plasma::Service* KuiserverEngine::serviceForSource(const QString& source) { - if (m_state != Stopped) { - m_state = Stopped; - setData(QStringLiteral("state"), "stopped"); - setData(QStringLiteral("speed"), QVariant()); - setData(QStringLiteral("numericSpeed"), QVariant()); - scheduleUpdate(); + const uint id = jobId(source); + if (!id) { + return DataEngine::serviceForSource(source); } -} -JobView::State JobView::state() -{ - return m_state; -} + auto it = std::find_if(m_jobs.constBegin(), m_jobs.constBegin(), [&id](Job *job) { + return job->id() == id; + }); -void JobView::setSuspended(bool suspended) -{ - if (suspended) { - if (m_state != Suspended) { - m_state = Suspended; - setData(QStringLiteral("state"), "suspended"); - setData(QStringLiteral("speed"), QVariant()); - setData(QStringLiteral("numericSpeed"), QVariant()); - scheduleUpdate(); - } - } else if (m_state != Running) { - m_state = Running; - setData(QStringLiteral("state"), "running"); - setData(QStringLiteral("speed"), speedString()); - setData(QStringLiteral("numericSpeed"), m_speed); - scheduleUpdate(); + if (it == m_jobs.constEnd()) { + return DataEngine::serviceForSource(source); } -} -void JobView::setError(uint errorCode) -{ - setData(QStringLiteral("error"), errorCode); + return new JobControl(this, *it); } -int JobView::unitId(const QString &unit) +void KuiserverEngine::init() { - int id = 0; - if (m_unitMap.contains(unit)) { - id = m_unitMap.value(unit); - } else { - id = m_unitId; - setData(QStringLiteral("totalUnit%1").arg(id), unit); - setData(QStringLiteral("totalAmount%1").arg(id), 0); - setData(QStringLiteral("processedUnit%1").arg(id), unit); - setData(QStringLiteral("processedAmount%1").arg(id), 0); - m_unitMap.insert(unit, m_unitId); - - if (unit == QLatin1String("bytes")) { - m_bytesUnitId = id; - } + m_jobsModel = JobsModel::createJobsModel(); + // don't init, applicationjobs engine should just passively listen + //m_jobsModel->init(); - ++m_unitId; - scheduleUpdate(); - } + connect(m_jobsModel.data(), &Notifications::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) { + for (int i = first; i <= last; ++i) { + const QModelIndex idx = m_jobsModel->index(first, 0, parent); + Job *job = idx.data(Notifications::JobDetailsRole).value(); + registerJob(job); + } + }); - return id; + connect(m_jobsModel.data(), &Notifications::rowsAboutToBeRemoved, this, [this](const QModelIndex &parent, int first, int last) { + for (int i = first; i <= last; ++i) { + const QModelIndex idx = m_jobsModel->index(first, 0, parent); + Job *job = idx.data(Notifications::JobDetailsRole).value(); + removeJob(job); + } + }); } -void JobView::updateEta() +void KuiserverEngine::updateDescriptionField( + Job *job, + int number, + QString (Job::*labelGetter)() const, + QString (Job::*valueGetter)() const) { - if (m_speed < 1) { - setData(QStringLiteral("eta"), 0); - return; - } - - if (m_totalBytes < 1) { - setData(QStringLiteral("eta"), 0); - return; - } + const QString source = sourceName(job); + const QString labelString = QStringLiteral("label%1").arg(number); + const QString labelNameString = QStringLiteral("labelName%1").arg(number); + const QString labelFileNameString = QStringLiteral("labelFileName%1").arg(number); - const qlonglong remaining = 1000 * (m_totalBytes - m_processedBytes); - setData(QStringLiteral("eta"), remaining / m_speed); -} + const QString label = ((job)->*labelGetter)(); + const QString value = ((job)->*valueGetter)(); -void JobView::setTotalAmount(qlonglong amount, const QString &unit) -{ - const int id = unitId(unit); - const QString amountString = QStringLiteral("totalAmount%1").arg(id); - const qlonglong prevTotal = data().value(amountString).toLongLong(); - if (prevTotal != amount) { - if (id == m_bytesUnitId) { - m_totalBytes = amount; - updateEta(); - } + if (label.isEmpty() && value.isEmpty()) { + setData(source, labelString, QVariant()); + setData(source, labelNameString, QVariant()); + setData(source, labelFileNameString, QVariant()); + } else { + setData(source, labelNameString, label); + setData(source, labelString, value); - setData(amountString, amount); - scheduleUpdate(); + const QUrl url = QUrl::fromUserInput(value, QString(), QUrl::AssumeLocalFile); + setData(source, labelFileNameString, url.toString(QUrl::PreferLocalFile | QUrl::RemoveFragment | QUrl::RemoveQuery)); } + setData(source, labelString); } -void JobView::setProcessedAmount(qlonglong amount, const QString &unit) +void KuiserverEngine::updateUnit( + Job *job, + int number, + const QString &unit, + qulonglong (NotificationManager::Job::*processedGetter)() const, + qulonglong (NotificationManager::Job::*totalGetter)() const) { - const int id = unitId(unit); - const QString processedString = QStringLiteral("processedAmount%1").arg(id); - const qlonglong prevTotal = data().value(processedString).toLongLong(); - if (prevTotal != amount) { - if (id == m_bytesUnitId) { - m_processedBytes = amount; - if (!m_totalBytes && m_processedBytes && (m_percent != 0)) { - m_totalBytes = m_processedBytes / m_percent * 100; - const QString totalAmountString = QStringLiteral("totalAmount%1").arg(id); - setData(totalAmountString, m_totalBytes); - } - updateEta(); - } + const QString source = sourceName(job); - setData(processedString, amount); - scheduleUpdate(); - } + setData(source, QStringLiteral("totalUnit%1").arg(number), unit); + setData(source, QStringLiteral("totalAmount%1").arg(number), ((job)->*totalGetter)()); + setData(source, QStringLiteral("processedUnit%1").arg(number), unit); + setData(source, QStringLiteral("processedAmount%1").arg(number), ((job)->*processedGetter)()); } -void JobView::setDestUrl(const QDBusVariant & destUrl) +void KuiserverEngine::registerJob(Job *job) { - setData(QStringLiteral("destUrl"), destUrl.variant().toUrl()); -} - -void JobView::setPercent(uint percent) -{ - if (m_percent != percent) { - m_percent = percent; - setData(QStringLiteral("percentage"), m_percent); - scheduleUpdate(); + if (m_jobs.contains(job)) { // shouldn't really happen + return; } -} -void JobView::setSpeed(qlonglong bytesPerSecond) -{ - if (m_speed != bytesPerSecond) { - m_speed = bytesPerSecond; - setData(QStringLiteral("speed"), speedString()); - setData(QStringLiteral("numericSpeed"), m_speed); - - if (m_bytesUnitId > -1) { - updateEta(); - } - - scheduleUpdate(); + const QString source = sourceName(job); + + setData(source, QStringLiteral("appName"), job->desktopEntry());// job->applicationName()); + setData(source, QStringLiteral("appIconName"), job->applicationIconName()); + setData(source, QStringLiteral("suspendable"), job->suspendable()); + setData(source, QStringLiteral("killable"), job->killable()); + updateState(job); + + connect(job, &Job::stateChanged, this, [this, job] { + updateState(job); + }); + connect(job, &Job::speedChanged, this, [this, job] { + updateEta(job); + }); + + connectJobField(job, &Job::summary, &Job::summaryChanged, QStringLiteral("infoMessage")); + connectJobField(job, &Job::percentage, &Job::percentageChanged, QStringLiteral("percentage")); + connectJobField(job, &Job::error, &Job::errorChanged, QStringLiteral("error")); + connectJobField(job, &Job::errorText, &Job::errorTextChanged, QStringLiteral("errorText")); + connectJobField(job, &Job::destUrl, &Job::destUrlChanged, QStringLiteral("destUrl")); + + static const struct { + int number; + QString (Job::*labelGetter)() const; + void (Job::*labelSignal)(); + QString (Job::*valueGetter)() const; + void (Job::*valueSignal)(); + } s_descriptionFields[] = { + {0, &Job::descriptionLabel1, &Job::descriptionLabel1Changed, &Job::descriptionValue1, &Job::descriptionValue1Changed}, + {1, &Job::descriptionLabel2, &Job::descriptionLabel2Changed, &Job::descriptionValue2, &Job::descriptionValue2Changed}, + }; + + for (auto fields : s_descriptionFields) { + updateDescriptionField(job, fields.number, fields.labelGetter, fields.valueGetter); + connect(job, fields.labelSignal, this, [=] { + updateDescriptionField(job, fields.number, fields.labelGetter, fields.valueGetter); + }); + connect(job, fields.valueSignal, this, [=] { + updateDescriptionField(job, fields.number, fields.labelGetter, fields.valueGetter); + }); } -} - -QString JobView::speedString() const -{ - return i18nc("Bytes per second", "%1/s", KFormat().formatByteSize(m_speed)); -} -void JobView::setInfoMessage(const QString &infoMessage) -{ - if (data().value(QStringLiteral("infoMessage")) != infoMessage) { - setData(QStringLiteral("infoMessage"), infoMessage); - scheduleUpdate(); + static const struct { + // Previously the dataengine counted units up but for simplicity a fixed number is assigned to each unit + int number; + QString unit; + qulonglong (Job::*processedGetter)() const; + void (Job::*processedSignal)(); + qulonglong (Job::*totalGetter)() const; + void (Job::*totalSignal)(); + } s_unitsFields[] = { + {0, QStringLiteral("bytes"), &Job::processedBytes, &Job::processedBytesChanged, &Job::totalBytes, &Job::totalBytesChanged}, + {1, QStringLiteral("files"), &Job::processedFiles, &Job::processedFilesChanged, &Job::totalFiles, &Job::totalFilesChanged}, + {2, QStringLiteral("dirs"), &Job::processedDirectories, &Job::processedDirectoriesChanged, &Job::totalDirectories, &Job::totalDirectoriesChanged} + }; + + for (auto fields : s_unitsFields) { + updateUnit(job, fields.number, fields.unit, fields.processedGetter, fields.totalGetter); + connect(job, fields.processedSignal, this, [=] { + updateUnit(job, fields.number, fields.unit, fields.processedGetter, fields.totalGetter); + }); + connect(job, fields.totalSignal, this, [=] { + updateUnit(job, fields.number, fields.unit, fields.processedGetter, fields.totalGetter); + }); } + + m_jobs.append(job); } -bool JobView::setDescriptionField(uint number, const QString &name, const QString &value) +void KuiserverEngine::removeJob(Job *job) { - const QString labelString = QStringLiteral("label%1").arg(number); - const QString labelNameString = QStringLiteral("labelName%1").arg(number); - const QString labelFileNameString = QStringLiteral("labelFileName%1").arg(number); - - if (!data().contains(labelNameString) || data().value(labelString) != value) { - setData(labelNameString, name); - setData(labelString, value); - QUrl url = QUrl::fromUserInput(value, QString(), QUrl::AssumeLocalFile); - setData(labelFileNameString, url.toString(QUrl::PreferLocalFile | QUrl::RemoveFragment | QUrl::RemoveQuery)); - scheduleUpdate(); + if (!job || !m_jobs.contains(job)) { + return; } - return true; -} -void JobView::clearDescriptionField(uint number) -{ - const QString labelString = QStringLiteral("label%1").arg(number); - const QString labelNameString = QStringLiteral("labelName%1").arg(number); - const QString labelFileNameString = QStringLiteral("labelFileName%1").arg(number); + m_jobs.removeOne(job); - setData(labelNameString, QVariant()); - setData(labelString, QVariant()); - setData(labelFileNameString, QVariant()); - scheduleUpdate(); + const QString source = sourceName(job); + removeSource(source); } -void JobView::setAppName(const QString &appName) +QString KuiserverEngine::speedString(qulonglong speed) { - // don't need to update, this is only set once at creation - setData(QStringLiteral("appName"), appName); + return i18nc("Bytes per second", "%1/s", KFormat().formatByteSize(speed)); } -void JobView::setAppIconName(const QString &appIconName) +void KuiserverEngine::updateState(Job *job) { - // don't need to update, this is only set once at creation - setData(QStringLiteral("appIconName"), appIconName); -} + const QString source = sourceName(job); -void JobView::setCapabilities(int capabilities) -{ - if (m_capabilities != uint(capabilities)) { - m_capabilities = capabilities; - setData(QStringLiteral("suspendable"), m_capabilities & KJob::Suspendable); - setData(QStringLiteral("killable"), m_capabilities & KJob::Killable); - scheduleUpdate(); + QString stateString; + switch (job->state()) { + case Notifications::JobStateRunning: + stateString = QStringLiteral("running"); + updateSpeed(job); + break; + case Notifications::JobStateSuspended: + stateString = QStringLiteral("suspended"); + setData(source, QStringLiteral("speed"), QVariant()); + setData(source, QStringLiteral("numericSpeed"), QVariant()); + break; + case Notifications::JobStateStopped: + stateString = QStringLiteral("stopped"); + break; } -} -QDBusObjectPath JobView::objectPath() const -{ - return m_objectPath; -} + setData(source, QStringLiteral("state"), stateString); -void JobView::requestStateChange(State state) -{ - switch (state) { - case Running: - emit resumeRequested(); - break; - case Suspended: - emit suspendRequested(); - break; - case Stopped: - emit cancelRequested(); - break; - default: - break; + if (job->state() == Notifications::JobStateStopped) { + removeJob(job); } } -KuiserverEngine::KuiserverEngine(QObject* parent, const QVariantList& args) - : Plasma::DataEngine(parent, args) -{ - new JobViewServerAdaptor(this); - - QDBusConnection bus = QDBusConnection::sessionBus(); - bus.registerObject(QLatin1String("/DataEngine/applicationjobs/JobWatcher"), this); - - setMinimumPollingInterval(500); - - m_pendingJobsTimer.setSingleShot(true); - m_pendingJobsTimer.setInterval(500); - connect(&m_pendingJobsTimer, &QTimer::timeout, this, &KuiserverEngine::processPendingJobs); - init(); -} - -KuiserverEngine::~KuiserverEngine() -{ - QDBusConnection::sessionBus() - .unregisterObject(QLatin1String("/DataEngine/applicationjobs/JobWatcher"), QDBusConnection::UnregisterTree); - qDeleteAll(m_pendingJobs); -} - -QDBusObjectPath KuiserverEngine::requestView(const QString &appName, - const QString &appIconName, int capabilities) +void KuiserverEngine::updateSpeed(Job *job) { - JobView *jobView = new JobView(this); - jobView->setAppName(appName); - jobView->setAppIconName(appIconName); - jobView->setCapabilities(capabilities); - connect(jobView, &Plasma::DataContainer::becameUnused, this, &KuiserverEngine::removeSource); - - m_pendingJobs << jobView; - m_pendingJobsTimer.start(); - - return jobView->objectPath(); + const QString source = sourceName(job); + setData(source, QStringLiteral("speed"), speedString(job->speed())); + setData(source, QStringLiteral("numericSpeed"), job->speed()); + updateEta(job); } -void KuiserverEngine::processPendingJobs() +void KuiserverEngine::updateEta(Job *job) { - foreach (JobView *jobView, m_pendingJobs) { - if (jobView->state() == JobView::Stopped) { - delete jobView; - } else { - addSource(jobView); - } - } + const QString source = sourceName(job); - m_pendingJobs.clear(); -} - -Plasma::Service* KuiserverEngine::serviceForSource(const QString& source) -{ - JobView *jobView = qobject_cast(containerForSource(source)); - if (jobView) { - return new JobControl(this, jobView); - } else { - return DataEngine::serviceForSource(source); + if (job->speed() < 1 || job->totalBytes() < 1) { + setData(source, QStringLiteral("eta"), 0); + return; } -} -void KuiserverEngine::init() -{ - // register with the Job UI Server to receive notifications of jobs becoming available - OrgKdeKuiserverInterface ksmserver(QStringLiteral("org.kde.kuiserver"), QStringLiteral("/JobViewServer"), QDBusConnection::sessionBus()); - ksmserver.registerService(QDBusConnection::sessionBus().baseService(), QStringLiteral("/DataEngine/applicationjobs/JobWatcher")); + const qlonglong remaining = 1000 * (job->totalBytes() - job->processedBytes()); + setData(source, QStringLiteral("eta"), remaining / job->speed()); } K_EXPORT_PLASMA_DATAENGINE_WITH_JSON(kuiserver, KuiserverEngine, "plasma-dataengine-applicationjobs.json")