Commit 08f894ca authored by Kai Uwe Broulik's avatar Kai Uwe Broulik 🍇

Kill kuiserver

It is supposed to broadcast application job progress to multiple interested parties.
However, effectively it was just plasmashell. Cut the middleman, including its never finished and unused UI,
and talk to plasmashell directly.

The applicationjobs dataengine is adjusted to use the new infrastructure instead.
Since it works only in the same process now, Unity launcher API is used to at least broadcast basic
application progress information for use in e.g. Latte Dock.

Also, introduce JobViewServerV2 and JobViewV3 APIs which are using desktop entries for identification rather
than application names, and more importantly are extensible using a QVariantMap hints, so adding new
fields in the future should be significantly less painful with Frameworks, Applications, and Plasma all having
their own release schedule. :)
parent 789eedc5
......@@ -175,7 +175,6 @@ add_subdirectory(wallpapers)
add_subdirectory(kioslave)
add_subdirectory(ktimezoned)
add_subdirectory(kuiserver)
add_subdirectory(menu)
add_subdirectory(phonon)
......
......@@ -373,8 +373,7 @@ ColumnLayout {
jobState: model.jobState || 0
percentage: model.percentage || 0
error: model.error || 0
errorText: model.errorText || ""
jobError: model.jobError || 0
suspendable: !!model.suspendable
killable: !!model.killable
jobDetails: model.jobDetails || null
......
......@@ -33,8 +33,7 @@ ColumnLayout {
id: jobItem
property int jobState
property int error
property string errorText
property int jobError
property alias percentage: progressBar.value
property alias suspendable: suspendButton.visible
......@@ -56,15 +55,8 @@ ColumnLayout {
spacing: 0
PlasmaComponents.Label {
Layout.fillWidth: true
textFormat: Text.PlainText
wrapMode: Text.WordWrap
text: jobItem.errorText || (jobItem.jobDetails ? jobItem.jobDetails.text : "")
visible: text !== ""
}
RowLayout {
id: progressRow
Layout.fillWidth: true
spacing: units.smallSpacing
......@@ -83,7 +75,6 @@ ColumnLayout {
}
RowLayout {
id: jobActionsRow
spacing: 0
PlasmaComponents.ToolButton {
......@@ -108,6 +99,7 @@ ColumnLayout {
tooltip: checked ? i18nc("A button tooltip; hides item details", "Hide Details")
: i18nc("A button tooltip; expands the item to show details", "Show Details")
checkable: true
enabled: jobItem.jobDetails && jobItem.jobDetails.hasDetails
}
}
}
......@@ -133,7 +125,7 @@ ColumnLayout {
property var url: {
if (jobItem.jobState !== NotificationManager.Notifications.JobStateStopped
|| jobItem.error
|| jobItem.jobError
|| !jobItem.jobDetails
|| jobItem.jobDetails.totalFiles <= 0) {
return null;
......@@ -193,7 +185,7 @@ ColumnLayout {
State {
when: jobItem.jobState === NotificationManager.Notifications.JobStateStopped
PropertyChanges {
target: jobActionsRow
target: progressRow
visible: false
}
PropertyChanges {
......
......@@ -60,8 +60,7 @@ ColumnLayout {
property int jobState
property int percentage
property int error: 0
property string errorText
property int jobError: 0
property bool suspendable
property bool killable
......@@ -241,8 +240,7 @@ ColumnLayout {
active: notificationItem.notificationType === NotificationManager.Notifications.JobType
sourceComponent: JobItem {
jobState: notificationItem.jobState
error: notificationItem.error
errorText: notificationItem.errorText
jobError: notificationItem.jobError
percentage: notificationItem.percentage
suspendable: notificationItem.suspendable
killable: notificationItem.killable
......
......@@ -52,8 +52,7 @@ PlasmaCore.Dialog {
property alias jobState: notificationItem.jobState
property alias percentage: notificationItem.percentage
property alias error: notificationItem.error
property alias errorText: notificationItem.errorText
property alias jobError: notificationItem.jobError
property alias suspendable: notificationItem.suspendable
property alias killable: notificationItem.killable
property alias jobDetails: notificationItem.jobDetails
......
......@@ -356,8 +356,7 @@ QtObject {
jobState: model.jobState || 0
percentage: model.percentage || 0
error: model.error || 0
errorText: model.errorText || ""
jobError: model.jobError || 0
suspendable: !!model.suspendable
killable: !!model.killable
jobDetails: model.jobDetails || null
......
......@@ -6,10 +6,6 @@ set(kuiserver_engine_SRCS
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
......@@ -18,6 +14,7 @@ target_link_libraries(plasma_engine_applicationjobs
KF5::KIOCore
KF5::Plasma
KF5::Service
PW::LibNotificationManager
)
kcoreaddons_desktop_to_json(plasma_engine_applicationjobs plasma-dataengine-applicationjobs.desktop)
......
......@@ -27,7 +27,7 @@ void JobAction::start()
{
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 @@ void JobAction::start()
//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();
}
......@@ -21,26 +21,35 @@
#include "kuiserverengine.h"
#include <QPointer>
#include <plasma/servicejob.h>
#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<QString,QVariant>& 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<NotificationManager::Job> m_job;
};
#endif //JOBVIEW_H
......@@ -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<QString,QVariant>& parameters)
{
return new JobAction(m_jobView, operation, parameters, this);
return new JobAction(m_job, operation, parameters, this);
}
......@@ -21,21 +21,23 @@
#include <plasma/service.h>
class JobView;
#include <QPointer>
#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<QString,QVariant>& parameters) override;
private:
JobView *m_jobView;
QPointer<NotificationManager::Job> m_job;
};
......
......@@ -19,14 +19,17 @@
#ifndef KUISERVERENGINE_H
#define KUISERVERENGINE_H
#include <QDBusObjectPath>
#include <QBasicTimer>
#include <QTimer>
#include <QVector>
#include <Plasma/DataContainer>
#include <Plasma/DataEngine>
class JobView;
#include "jobsmodel.h"
namespace NotificationManager
{
class Job;
}
namespace Plasma
{
......@@ -36,7 +39,6 @@ namespace Plasma
class KuiserverEngine : public Plasma::DataEngine
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.JobViewServer")
public:
KuiserverEngine(QObject* parent, const QVariantList& args);
......@@ -44,101 +46,54 @@ public:
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<JobView *> 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<QString, int> m_unitMap;
int m_bytesUnitId;
int m_unitId;
static uint s_jobId;
template<typename T, typename signal> 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<NotificationManager::Job *> m_jobs;
};
#endif
add_definitions(-DTRANSLATION_DOMAIN=\"kuiserver5\")
add_subdirectory( tests )
set(kuiserver_KDEINIT_SRCS
main.cpp
uiserver.cpp
jobview.cpp
progresslistmodel.cpp
progresslistdelegate.cpp
requestviewcallwatcher.cpp
)
set(kuiserver_KDEINIT_PRIVATE
progresslistdelegate_p.h
uiserver_p.h
)
ki18n_wrap_ui(kuiserver_KDEINIT_SRCS configdialog.ui)
#<DBus Stuff>
#<JobView>
set(jobview_xml org.kde.JobView.xml)
qt5_add_dbus_adaptor(kuiserver_KDEINIT_SRCS ${jobview_xml} jobview.h JobView jobviewadaptor )
qt5_add_dbus_interface(kuiserver_KDEINIT_SRCS ${jobview_xml} jobview_interface )
#</JobView>
#<JobViewServer>
set(jobviewserver_xml ${KJOBWIDGETS_DBUS_INTERFACES_DIR}/kf5_org.kde.JobViewServer.xml)
qt5_add_dbus_adaptor(kuiserver_KDEINIT_SRCS ${jobviewserver_xml} progresslistmodel.h ProgressListModel jobviewserveradaptor )
qt5_add_dbus_interface(kuiserver_KDEINIT_SRCS ${jobviewserver_xml} jobviewserver_interface )
#</JobViewServer>
qt5_add_dbus_adaptor(kuiserver_KDEINIT_SRCS org.kde.kuiserver.xml progresslistmodel.h ProgressListModel kuiserveradaptor )
configure_file(org.kde.kuiserver.service.in
${CMAKE_CURRENT_BINARY_DIR}/org.kde.kuiserver.service)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kuiserver.service
DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR} RENAME kf5_org.kde.kuiserver.service)
#</DBus Stuff>
kconfig_add_kcfg_files(kuiserver_KDEINIT_SRCS kuiserversettings.kcfgc)
kf5_add_kdeinit_executable( kuiserver5 ${kuiserver_KDEINIT_SRCS})
if (Q_WS_MAC)
set_target_properties(kuiserver5 PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/Info.plist.template)
set_target_properties(kuiserver5 PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.kuiserver")
set_target_properties(kuiserver5 PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "KDE UI Server")
endif ()
target_link_libraries(kdeinit_kuiserver5
PW::KWorkspace
Qt5::DBus
KF5::ConfigWidgets
KF5::DBusAddons
KF5::ItemViews
KF5::Notifications
KF5::KIOCore
KF5::KIOWidgets
KF5::XmlGui
KF5::I18n
)
install(TARGETS kdeinit_kuiserver5 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
target_link_libraries( kuiserver5 kdeinit_kuiserver5 )
install(TARGETS kuiserver5 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} )
install( FILES kuiserver.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} )
# contains list of debug categories, for kdebugsettings
install(FILES kuiserver.categories DESTINATION ${KDE_INSTALL_CONFDIR})
#! /usr/bin/env bash
$EXTRACTRC *.ui *.kcfg >> rc.cpp
$XGETTEXT *.cpp -o $podir/kuiserver5.pot
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>configurationDialog</class>
<widget class="QWidget" name="configurationDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>337</width>
<height>259</height>
</rect>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>10</number>
</property>
<property name="margin">
<number>9</number>
</property>
<item>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupFinishedJobs">
<property name="title">
<string>Finished Jobs</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>9</number>
</property>
<item>
<widget class="QRadioButton" name="kcfg_radioMove">
<property name="text">
<string>Move them to a different list</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="kcfg_radioRemove">
<property name="text">
<string>Remove them</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupAppearance">
<property name="title">
<string>Appearance</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>9</number>
</property>
<item>
<widget class="QRadioButton" name="kcfg_radioList">
<property name="text">
<string>Show all jobs in a list</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="kcfg_radioTree">
<property name="text">
<string>Show all jobs in a tree</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="kcfg_checkShowSeparateWindows">
<property name="text">
<string>Show separate windows</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>