kde-workspace/plasma/generic/dataengines/applicationjobs/kuiserverengine.cpp
2014-11-13 19:30:51 +02:00

380 lines
9.8 KiB
C++

/*
* 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 <KJob>
#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(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<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("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 "kuiserverengine.moc"