/* * Copyright © 2008 Rob Scheepmaker * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License version 2 as * published by the Free Software Foundation * * 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "jobviewadaptor.h" #include "jobviewserveradaptor.h" #include "kuiserverengine.h" #include "jobcontrol.h" #include #include #include #include uint JobView::s_jobId = 0; static const int UPDATE_INTERVAL = 100; 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) { m_jobId = ++s_jobId; setObjectName(QString("Job %1").arg(s_jobId)); new JobViewV2Adaptor(this); m_objectPath.setPath(QString("/DataEngine/applicationjobs/JobView_%1").arg(m_jobId)); QDBusConnection::sessionBus().registerObject(m_objectPath.path(), this); setSuspended(false); } JobView::~JobView() { QDBusConnection::sessionBus().unregisterObject(m_objectPath.path(), QDBusConnection::UnregisterTree); } uint JobView::jobId() const { return m_jobId; } void JobView::scheduleUpdate() { if (!m_updateTimer.isActive()) { m_updateTimer.start(UPDATE_INTERVAL, this); } } void JobView::timerEvent(QTimerEvent *event) { if (event->timerId() == m_updateTimer.timerId()) { m_updateTimer.stop(); checkForUpdate(); if (m_state == Stopped) { emit becameUnused(objectName()); } } else { Plasma::DataContainer::timerEvent(event); } } void JobView::terminate(const QString &errorMessage) { setData("error", errorMessage); QTimer::singleShot(0, this, SLOT(finished())); } void JobView::finished() { if (m_state != Stopped) { m_state = Stopped; setData("state", "stopped"); setData("speed", QVariant()); setData("numericSpeed", QVariant()); scheduleUpdate(); } } JobView::State JobView::state() { return m_state; } void JobView::setSuspended(bool suspended) { if (suspended) { if (m_state != Suspended) { m_state = Suspended; setData("state", "suspended"); setData("speed", QVariant()); setData("numericSpeed", QVariant()); scheduleUpdate(); } } else if (m_state != Running) { m_state = Running; setData("state", "running"); setData("speed", speedString()); setData("numericSpeed", m_speed); scheduleUpdate(); } } int JobView::unitId(const QString &unit) { int id = 0; if (m_unitMap.contains(unit)) { id = m_unitMap.value(unit); } else { id = m_unitId; setData(QString("totalUnit%1").arg(id), unit); setData(QString("totalAmount%1").arg(id), 0); setData(QString("processedUnit%1").arg(id), unit); setData(QString("processedAmount%1").arg(id), 0); m_unitMap.insert(unit, m_unitId); if (unit == "bytes") { m_bytesUnitId = id; } ++m_unitId; scheduleUpdate(); } return id; } void JobView::updateEta() { if (m_speed < 1) { setData("eta", 0); return; } if (m_totalBytes < 1) { setData("eta", 0); return; } const qlonglong remaining = 1000 * (m_totalBytes - m_processedBytes); setData("eta", remaining / m_speed); } void JobView::setTotalAmount(qlonglong amount, const QString &unit) { const int id = unitId(unit); const QString amountString = QString("totalAmount%1").arg(id); const qlonglong prevTotal = data().value(amountString).toLongLong(); if (prevTotal != amount) { if (id == m_bytesUnitId) { m_totalBytes = amount; updateEta(); } setData(amountString, amount); scheduleUpdate(); } } void JobView::setProcessedAmount(qlonglong amount, const QString &unit) { const int id = unitId(unit); const QString processedString = QString("processedAmount%1").arg(id); const qlonglong prevTotal = data().value(processedString).toLongLong(); if (prevTotal != amount) { if (id == m_bytesUnitId) { m_processedBytes = amount; updateEta(); } setData(processedString, amount); scheduleUpdate(); } } void JobView::setDestUrl(const QDBusVariant & destUrl) { Q_UNUSED(destUrl); } void JobView::setPercent(uint percent) { if (m_percent != percent) { m_percent = percent; setData("percentage", m_percent); scheduleUpdate(); } } void JobView::setSpeed(qlonglong bytesPerSecond) { if (m_speed != bytesPerSecond) { m_speed = bytesPerSecond; setData("speed", speedString()); setData("numericSpeed", m_speed); if (m_bytesUnitId > -1) { updateEta(); } scheduleUpdate(); } } QString JobView::speedString() const { return i18nc("Byes per second", "%1/s", KGlobal::locale()->formatByteSize(m_speed)); } void JobView::setInfoMessage(const QString &infoMessage) { if (data().value("infoMessage") != infoMessage) { setData("infoMessage", infoMessage); scheduleUpdate(); } } bool JobView::setDescriptionField(uint number, const QString &name, const QString &value) { const QString labelString = QString("label%1").arg(number); const QString labelNameString = QString("labelName%1").arg(number); if (!data().contains(labelNameString) || data().value(labelString) != value) { setData(labelNameString, name); setData(labelString, value); scheduleUpdate(); } return true; } void JobView::clearDescriptionField(uint number) { const QString labelString = QString("label%1").arg(number); const QString labelNameString = QString("labelName%1").arg(number); setData(labelNameString, QVariant()); setData(labelString, QVariant()); scheduleUpdate(); } void JobView::setAppName(const QString &appName) { // don't need to update, this is only set once at creation setData("appName", appName); } void JobView::setAppIconName(const QString &appIconName) { // don't need to update, this is only set once at creation setData("appIconName", appIconName); } void JobView::setCapabilities(int capabilities) { if (m_capabilities != uint(capabilities)) { m_capabilities = capabilities; setData("suspendable", m_capabilities & KJob::Suspendable); setData("killable", m_capabilities & KJob::Killable); scheduleUpdate(); } } QDBusObjectPath JobView::objectPath() const { return m_objectPath; } void JobView::requestStateChange(State state) { switch (state) { case Running: emit resumeRequested(); break; case Suspended: emit suspendRequested(); break; case Stopped: emit cancelRequested(); break; default: break; } } 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, SIGNAL(timeout()), this, SLOT(processPendingJobs())); } 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) { JobView *jobView = new JobView(this); jobView->setAppName(appName); jobView->setAppIconName(appIconName); jobView->setCapabilities(capabilities); connect(jobView, SIGNAL(becameUnused(QString)), this, SLOT(removeSource(QString))); m_pendingJobs << jobView; m_pendingJobsTimer.start(); return jobView->objectPath(); } void KuiserverEngine::processPendingJobs() { foreach (JobView *jobView, m_pendingJobs) { if (jobView->state() == JobView::Stopped) { delete jobView; } else { addSource(jobView); } } 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); } } void KuiserverEngine::init() { // register with the Job UI Serer to receive notifications of jobs becoming available QDBusInterface interface("org.kde.kuiserver", "/JobViewServer"/* object to connect to */, ""/* use the default interface */, QDBusConnection::sessionBus(), this); interface.asyncCall(QLatin1String("registerService"), QDBusConnection::sessionBus().baseService(), "/DataEngine/applicationjobs/JobWatcher"); } K_EXPORT_PLASMA_DATAENGINE(kuiserver, KuiserverEngine) #include "moc_kuiserverengine.cpp"