Group :: Sistema/Bibliotecas
RPM: plasma5-libksysguard
Main Changelog Spec Patches Sources Download Gear Bugs e FR Repocop
Patch: alt-killbtn.patch
Download
Download
commit 8de2ffd5ebfc0ba90cf829675e07ae35ff2ea82a
Author: Oleg Solovyov <mcpain@altlinux.org>
Date: Wed Oct 24 09:59:54 2018 +0300
- processui: implement a killbutton
diff --git a/libksysguard/processui/ProcessModel.cpp b/libksysguard/processui/ProcessModel.cpp
--- a/libksysguard/processui/ProcessModel.cpp
+++ b/libksysguard/processui/ProcessModel.cpp
@@ -1004,6 +1004,7 @@ static inline QVariant columnAlignment(c
case ProcessModel::HeadingVmSize:
case ProcessModel::HeadingIoWrite:
case ProcessModel::HeadingIoRead:
+ case ProcessModel::HeadingKillBtn:
case ProcessModel::HeadingVmPSS:
return QVariant(Qt::AlignRight | Qt::AlignVCenter);
case ProcessModel::HeadingTty:
@@ -2077,6 +2078,7 @@ void ProcessModel::setupHeader() {
headings << i18nc("process heading", "Relative Start Time");
headings << i18nc("process heading", "NNP");
headings << i18nc("process heading", "Command");
+ headings << i18nc("process heading", "Kill Button");
#if HAVE_X11
if (d->mIsX11) {
headings << i18nc("process heading", "X11 Memory");
diff --git a/libksysguard/processui/ProcessModel.h b/libksysguard/processui/ProcessModel.h
--- a/libksysguard/processui/ProcessModel.h
+++ b/libksysguard/processui/ProcessModel.h
@@ -142,7 +142,7 @@ class KSYSGUARD_EXPORT ProcessModel : pu
* setup header function, and make sure you increase PROCESSHEADERVERSION. This will ensure
* that old saved settings won't be used
*/
-#define PROCESSHEADERVERSION 10
+#define PROCESSHEADERVERSION 11
enum { HeadingName=0,
HeadingUser,
HeadingPid,
@@ -158,6 +158,7 @@ class KSYSGUARD_EXPORT ProcessModel : pu
HeadingStartTime,
HeadingNoNewPrivileges,
HeadingCommand,
+ HeadingKillBtn,
HeadingXMemory,
HeadingXTitle,
HeadingCGroup,
diff --git a/libksysguard/processui/ksysguardprocesslist.cpp b/libksysguard/processui/ksysguardprocesslist.cpp
--- a/libksysguard/processui/ksysguardprocesslist.cpp
+++ b/libksysguard/processui/ksysguardprocesslist.cpp
@@ -74,6 +74,97 @@
#ifdef DO_MODELCHECK
#include "modeltest.h"
#endif
+KillButtonDelegate::KillButtonDelegate(QObject *parent) {
+ if(QTreeView *treeView = qobject_cast<QTreeView*>(parent))
+ {
+ m_treeView = treeView;
+ m_btn = new QPushButton(i18n("Terminate process"), treeView);
+ m_btn->hide();
+ m_counter = 0;
+ }
+}
+
+void KillButtonDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index) const
+{
+ m_btn->setGeometry(opt.rect);
+ m_btn->setText(i18n("Terminate process"));
+ if(opt.state == QStyle::State_Selected)
+ {
+ painter->fillRect(opt.rect, opt.palette.highlight());
+ }
+ QPixmap map = m_btn->grab();
+ painter->drawPixmap(opt.rect.x(), opt.rect.y(), map);
+}
+
+QSize KillButtonDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ return m_btn->sizeHint();
+}
+
+bool KillButtonDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
+{
+ if (event->type() == QEvent::MouseMove) {
+ if (index != m_lastUnderMouse) {
+ if (m_lastUnderMouse.isValid()) {
+ //model->setData(m_lastUnderMouse, (int)Normal, Qt::UserRole);
+ //emit needsUpdate(m_lastUnderMouse);
+ }
+ if (index.isValid() && index.column() == ProcessModel::HeadingKillBtn) {
+ //model->setData(index, (int)Hovered, Qt::UserRole);
+ //emit needsUpdate(index);
+ m_lastUnderMouse = index;
+ } else {
+ m_lastUnderMouse = QModelIndex();
+ }
+ }
+ }
+ if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) {
+ if (index != m_lastUnderMouse) {
+ if (m_lastUnderMouse.isValid()) {
+ //model->setData(m_lastUnderMouse, (int)Normal, Qt::UserRole);
+ //emit needsUpdate(m_lastUnderMouse);
+ }
+ if (index.isValid() && index.column() == ProcessModel::HeadingKillBtn) {
+ //model->setData(index, (int)Pressed, Qt::UserRole);
+ //emit needsUpdate(index);
+ qDebug() << "Emitting clicked and changing m_lastUnderMouse";
+ emit clicked(index);
+ m_lastUnderMouse = index;
+ } else {
+ m_lastUnderMouse = QModelIndex();
+ }
+ } else {
+ if (m_lastUnderMouse.isValid()) {
+ //model->setData(m_lastUnderMouse, (int)Pressed, Qt::UserRole);
+ //emit needsUpdate(m_lastUnderMouse);
+ qDebug() << "Emitting clicked";
+ emit clicked(m_lastUnderMouse);
+ }
+ }
+ }
+ if (event->type() == QEvent::MouseButtonRelease) {
+ if (index != m_lastUnderMouse) {
+ if (m_lastUnderMouse.isValid()) {
+ //model->setData(m_lastUnderMouse, (int)Normal, Qt::UserRole);
+ //emit needsUpdate(m_lastUnderMouse);
+ }
+ if (index.isValid() && index.column() == ProcessModel::HeadingKillBtn) {
+ //model->setData(index, (int)Hovered, Qt::UserRole);
+ //emit needsUpdate(index);
+ m_lastUnderMouse = index;
+ } else {
+ m_lastUnderMouse = QModelIndex();
+ }
+ } else {
+ if (m_lastUnderMouse.isValid()) {
+ //model->setData(m_lastUnderMouse, (int)Hovered, Qt::UserRole);
+ //emit needsUpdate(m_lastUnderMouse);
+ }
+ }
+ }
+ return QStyledItemDelegate::editorEvent(event, model, option, index);
+}
+
class ProgressBarItemDelegate : public QStyledItemDelegate
{
public:
@@ -313,6 +404,9 @@ KSysGuardProcessList::KSysGuardProcessLi
new ModelTest(&d->mModel, this);
#endif
d->mUi->treeView->setItemDelegate(new ProgressBarItemDelegate(d->mUi->treeView));
+ KillButtonDelegate *delegate = new KillButtonDelegate(d->mUi->treeView);
+ d->mUi->treeView->setItemDelegateForColumn(ProcessModel::HeadingKillBtn, delegate);
+ connect(delegate, &KillButtonDelegate::clicked, this, &KSysGuardProcessList::killProcess);
d->mUi->treeView->header()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(d->mUi->treeView->header(), &QWidget::customContextMenuRequested, this, &KSysGuardProcessList::showColumnContextMenu);
@@ -347,6 +441,7 @@ KSysGuardProcessList::KSysGuardProcessLi
d->mUi->treeView->header()->hideSection(ProcessModel::HeadingIoRead);
d->mUi->treeView->header()->hideSection(ProcessModel::HeadingIoWrite);
d->mUi->treeView->header()->hideSection(ProcessModel::HeadingXMemory);
+ d->mUi->treeView->header()->hideSection(ProcessModel::HeadingKillBtn);
d->mUi->treeView->header()->hideSection(ProcessModel::HeadingCGroup);
d->mUi->treeView->header()->hideSection(ProcessModel::HeadingMACContext);
d->mUi->treeView->header()->hideSection(ProcessModel::HeadingVmPSS);
@@ -736,7 +831,7 @@ void KSysGuardProcessList::showColumnCon
break;
}
}
- if(anyOtherVisibleColumns) {
+ if(anyOtherVisibleColumns && index != ProcessModel::HeadingKillBtn) {
//selected a column. Give the option to hide it
action = new QAction(&menu);
action->setData(-index-1); //We set data to be negative (and minus 1) to hide a column, and positive to show a column
@@ -750,7 +845,7 @@ void KSysGuardProcessList::showColumnCon
if(d->mUi->treeView->header()->sectionsHidden()) {
for(int i = 0; i < num_headings; ++i) {
- if(d->mUi->treeView->header()->isSectionHidden(i)) {
+ if(d->mUi->treeView->header()->isSectionHidden(i) && i != ProcessModel::HeadingKillBtn) {
#ifndef HAVE_XRES
if(i == ProcessModel::HeadingXMemory)
continue;
@@ -1351,32 +1446,43 @@ bool KSysGuardProcessList::killProcesses
return false;
}
+void KSysGuardProcessList::killProcess(const QModelIndex index)
+{
+ qDebug() << "Row" << index.row();
+ QModelIndex realIndex = d->mFilterModel.mapToSource(index);
+ KSysGuard::Process *process = d->mModel.getProcessAtIndex(realIndex.row());
+ long long pid = process->pid();
+ qDebug() << "Adding pid" << pid;
+ QList< long long> list;
+ list << pid;
+ sendSignalToProcesses(list, SIGTERM, true);
+ //connect(d->mUi->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KSysGuardProcessList::killSelectedProcesses);
+ //d->mUi->treeView->selectionModel()->select(index, QItemSelectionModel::Rows);
+}
+
void KSysGuardProcessList::killSelectedProcesses()
{
sendSignalToSelectedProcesses(SIGTERM, true);
+ //disconnect(d->mUi->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KSysGuardProcessList::killSelectedProcesses);
}
-void KSysGuardProcessList::sendSignalToSelectedProcesses(int sig, bool confirm)
+void KSysGuardProcessList::sendSignalToProcesses(const QList<long long > &pids, int sig, bool confirm)
{
- QModelIndexList selectedIndexes = d->mUi->treeView->selectionModel()->selectedRows();
- QStringList selectedAsStrings;
- QList< long long> selectedPids;
-
- QList<KSysGuard::Process *> processes = selectedProcesses();
- foreach(KSysGuard::Process *process, processes) {
- selectedPids << process->pid();
+ QStringList asStrings;
+ foreach(long long pid, pids) {
if (!confirm)
continue;
- QString name = d->mModel.getStringForProcess(process);
- selectedAsStrings << name;
+ QString name = d->mModel.getStringForProcess(d->mModel.getProcess(pid));
+ qDebug() << "String" << name;
+ asStrings << name;
}
- if (selectedPids.isEmpty()) {
+ if (pids.isEmpty()) {
if (confirm)
KMessageBox::sorry(this, i18n("You must select a process first."));
return;
} else if (confirm && (sig == SIGTERM || sig == SIGKILL)) {
- int count = selectedAsStrings.count();
+ int count = asStrings.count();
QString msg;
QString title;
QString dontAskAgainKey;
@@ -1397,7 +1503,7 @@ void KSysGuardProcessList::sendSignalToS
closeButton = i18n("Kill");
}
- int res = KMessageBox::warningContinueCancelList(this, msg, selectedAsStrings,
+ int res = KMessageBox::warningContinueCancelList(this, msg, asStrings,
title,
KGuiItem(closeButton, QStringLiteral("process-stop")),
KStandardGuiItem::cancel(),
@@ -1409,10 +1515,10 @@ void KSysGuardProcessList::sendSignalToS
//We have shown a GUI dialog box, which processes events etc.
//So processes is NO LONGER VALID
- if (!killProcesses(selectedPids, sig))
+ if (!killProcesses(pids, sig))
return;
if (sig == SIGTERM || sig == SIGKILL) {
- foreach (long long pid, selectedPids) {
+ foreach (long long pid, pids) {
KSysGuard::Process *process = d->mModel.getProcess(pid);
if (process)
process->timeKillWasSent().start();
@@ -1422,6 +1528,24 @@ void KSysGuardProcessList::sendSignalToS
updateList();
}
+void KSysGuardProcessList::sendSignalToSelectedProcesses(int sig, bool confirm)
+{
+ QModelIndexList selectedIndexes = d->mUi->treeView->selectionModel()->selectedRows();
+ QStringList selectedAsStrings;
+ QList< long long> selectedPids;
+
+ QList<KSysGuard::Process *> processes = selectedProcesses();
+ foreach(KSysGuard::Process *process, processes) {
+ selectedPids << process->pid();
+ if (!confirm)
+ continue;
+ QString name = d->mModel.getStringForProcess(process);
+ selectedAsStrings << name;
+ }
+
+ sendSignalToProcesses(selectedPids, sig, confirm);
+}
+
bool KSysGuardProcessList::showTotals() const {
return d->mModel.showTotals();
}
diff --git a/libksysguard/processui/ksysguardprocesslist.h b/libksysguard/processui/ksysguardprocesslist.h
index 9e04f19..cbff357 100644
--- a/libksysguard/processui/ksysguardprocesslist.h
+++ b/libksysguard/processui/ksysguardprocesslist.h
@@ -26,6 +26,8 @@
#include <QWidget>
#include <QMetaType>
+#include <QStyledItemDelegate>
+#include <QPushButton>
#include <KConfigGroup>
@@ -46,6 +48,26 @@ struct KSysGuardProcessListPrivate;
* update rate and the process filter. The buttons are used to force
* an immediate update and to kill a process.
*/
+class KillButtonDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+ public:
+ KillButtonDelegate(QObject *parent);
+ void paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index) const override;
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+ bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
+
+ Q_SIGNALS:
+ void clicked(QModelIndex index);
+
+ private:
+ QModelIndex m_lastUnderMouse;
+ QPushButton *m_btn;
+ QTreeView *m_treeView;
+ QPersistentModelIndex currentEditedCellIndex;
+ int m_counter;
+};
+
class Q_DECL_EXPORT KSysGuardProcessList : public QWidget
{
Q_OBJECT
@@ -136,6 +158,17 @@ class Q_DECL_EXPORT KSysGuardProcessList : public QWidget
*/
void sendSignalToSelectedProcesses(int sig, bool confirm);
+ /** Send a signal to a given processes.
+ * @p pids A list of PIDs that should be sent the signal
+ * @p confirm - If true, pops up a dialog box to confirm with the user
+ */
+ void sendSignalToProcesses(const QList< long long> &pids, int sig, bool confirm);
+
+ /** Send a signal to a given process.
+ * @p index Index of a given process allowing a user to kill it.
+ */
+ void killProcess(const QModelIndex index);
+
/** Send a signal to a list of given processes.
* @p pids A list of PIDs that should be sent the signal
* @p sig The signal to send.