You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
399 lines
11 KiB
399 lines
11 KiB
/* |
|
* Copyright © 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> |
|
* |
|
* 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 <QDBusConnection> |
|
#include <QUrl> |
|
|
|
#include <KJob> |
|
#include <KFormat> |
|
#include <klocalizedstring.h> |
|
|
|
#include <Plasma/DataEngine> |
|
|
|
|
|
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(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); |
|
} |
|
|
|
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(QStringLiteral("errorText"), errorMessage); |
|
QTimer::singleShot(0, this, &JobView::finished); |
|
} |
|
|
|
void JobView::finished() |
|
{ |
|
if (m_state != Stopped) { |
|
m_state = Stopped; |
|
setData(QStringLiteral("state"), "stopped"); |
|
setData(QStringLiteral("speed"), QVariant()); |
|
setData(QStringLiteral("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(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(); |
|
} |
|
} |
|
|
|
void JobView::setError(uint errorCode) |
|
{ |
|
setData(QStringLiteral("error"), errorCode); |
|
} |
|
|
|
int JobView::unitId(const QString &unit) |
|
{ |
|
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_unitId; |
|
scheduleUpdate(); |
|
} |
|
|
|
return id; |
|
} |
|
|
|
void JobView::updateEta() |
|
{ |
|
if (m_speed < 1) { |
|
setData(QStringLiteral("eta"), 0); |
|
return; |
|
} |
|
|
|
if (m_totalBytes < 1) { |
|
setData(QStringLiteral("eta"), 0); |
|
return; |
|
} |
|
|
|
const qlonglong remaining = 1000 * (m_totalBytes - m_processedBytes); |
|
setData(QStringLiteral("eta"), remaining / m_speed); |
|
} |
|
|
|
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(); |
|
} |
|
|
|
setData(amountString, amount); |
|
scheduleUpdate(); |
|
} |
|
} |
|
|
|
void JobView::setProcessedAmount(qlonglong amount, const QString &unit) |
|
{ |
|
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(); |
|
} |
|
|
|
setData(processedString, amount); |
|
scheduleUpdate(); |
|
} |
|
} |
|
|
|
void JobView::setDestUrl(const QDBusVariant & destUrl) |
|
{ |
|
setData(QStringLiteral("destUrl"), destUrl.variant().toUrl()); |
|
} |
|
|
|
void JobView::setPercent(uint percent) |
|
{ |
|
if (m_percent != percent) { |
|
m_percent = percent; |
|
setData(QStringLiteral("percentage"), m_percent); |
|
scheduleUpdate(); |
|
} |
|
} |
|
|
|
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(); |
|
} |
|
} |
|
|
|
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(); |
|
} |
|
} |
|
|
|
bool JobView::setDescriptionField(uint number, const QString &name, const QString &value) |
|
{ |
|
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(); |
|
} |
|
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); |
|
|
|
setData(labelNameString, QVariant()); |
|
setData(labelString, QVariant()); |
|
setData(labelFileNameString, QVariant()); |
|
scheduleUpdate(); |
|
} |
|
|
|
void JobView::setAppName(const QString &appName) |
|
{ |
|
// don't need to update, this is only set once at creation |
|
setData(QStringLiteral("appName"), appName); |
|
} |
|
|
|
void JobView::setAppIconName(const QString &appIconName) |
|
{ |
|
// don't need to update, this is only set once at creation |
|
setData(QStringLiteral("appIconName"), appIconName); |
|
} |
|
|
|
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(); |
|
} |
|
} |
|
|
|
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, &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) |
|
{ |
|
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(); |
|
} |
|
|
|
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<JobView *>(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(QStringLiteral("org.kde.kuiserver"), QStringLiteral("/JobViewServer")/* object to connect to */, |
|
QLatin1String("")/* use the default interface */, QDBusConnection::sessionBus(), this); |
|
interface.asyncCall(QLatin1String("registerService"), QDBusConnection::sessionBus().baseService(), "/DataEngine/applicationjobs/JobWatcher"); |
|
} |
|
|
|
K_EXPORT_PLASMA_DATAENGINE_WITH_JSON(kuiserver, KuiserverEngine, "plasma-dataengine-applicationjobs.json") |
|
|
|
#include "kuiserverengine.moc"
|
|
|