From efd0209ce6193bd54626bf97a405da6d6fca36b1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 15 Nov 2011 11:25:00 +0530 Subject: [PATCH] Jobs list: Add the ability to hide jobs, useful if you have run a lot of jobs and the list is getting crowded. Fixes #883734 (Clear Jobs) --- src/calibre/gui2/dialogs/jobs.ui | 31 ++++++++++++--- src/calibre/gui2/jobs.py | 66 +++++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/calibre/gui2/dialogs/jobs.ui b/src/calibre/gui2/dialogs/jobs.ui index 95d0585cf0..0893a8be8b 100644 --- a/src/calibre/gui2/dialogs/jobs.ui +++ b/src/calibre/gui2/dialogs/jobs.ui @@ -17,8 +17,8 @@ :/images/jobs.png:/images/jobs.png - - + + Qt::NoContextMenu @@ -40,27 +40,48 @@ - + &Stop selected jobs - + + + + &Hide selected jobs + + + + Show job &details - + + + + Show &all jobs + + + + Stop &all non device jobs + + + + &Hide all jobs + + + diff --git a/src/calibre/gui2/jobs.py b/src/calibre/gui2/jobs.py index 07b05afdc3..ae3f93647c 100644 --- a/src/calibre/gui2/jobs.py +++ b/src/calibre/gui2/jobs.py @@ -14,7 +14,7 @@ from PyQt4.Qt import (QAbstractTableModel, QVariant, QModelIndex, Qt, QTimer, pyqtSignal, QIcon, QDialog, QAbstractItemDelegate, QApplication, QSize, QStyleOptionProgressBarV2, QString, QStyle, QToolTip, QFrame, QHBoxLayout, QVBoxLayout, QSizePolicy, QLabel, QCoreApplication, QAction, - QByteArray) + QByteArray, QSortFilterProxyModel) from calibre.utils.ipc.server import Server from calibre.utils.ipc.job import ParallelJob @@ -26,6 +26,8 @@ from calibre.gui2.dialogs.job_view_ui import Ui_Dialog from calibre.gui2.progress_indicator import ProgressIndicator from calibre.gui2.threaded_jobs import ThreadedJobServer, ThreadedJob +HIDE_ROLE = Qt.UserRole + 1 + class JobManager(QAbstractTableModel): # {{{ job_added = pyqtSignal(int) @@ -91,7 +93,7 @@ class JobManager(QAbstractTableModel): # {{{ def data(self, index, role): try: - if role not in (Qt.DisplayRole, Qt.DecorationRole): + if role not in (Qt.DisplayRole, Qt.DecorationRole, HIDE_ROLE): return NONE row, col = index.row(), index.column() job = self.jobs[row] @@ -121,6 +123,9 @@ class JobManager(QAbstractTableModel): # {{{ if job.killed or job.failed: return self.error_icon return self.done_icon + if role == HIDE_ROLE: + return QVariant('h' if getattr(job, 'hidden_in_gui', False) + else 's') except: import traceback traceback.print_exc() @@ -251,6 +256,18 @@ class JobManager(QAbstractTableModel): # {{{ else: job.kill_on_start = True + def hide_jobs(self, rows): + for r in rows: + self.jobs[r].hidden_in_gui = True + for r in rows: + self.dataChanged.emit(self.index(r, 0), self.index(r, 0)) + + def show_hidden_jobs(self): + for j in self.jobs: + j.hidden_in_gui = False + for r in xrange(len(self.jobs)): + self.dataChanged.emit(self.index(r, 0), self.index(r, 0)) + def kill_job(self, row, view): job = self.jobs[row] if isinstance(job, DeviceJob): @@ -450,8 +467,12 @@ class JobsDialog(QDialog, Ui_JobsDialog): QDialog.__init__(self, window) Ui_JobsDialog.__init__(self) self.setupUi(self) - self.jobs_view.setModel(model) self.model = model + self.proxy_model = QSortFilterProxyModel(self) + self.proxy_model.setSourceModel(self.model) + self.proxy_model.setFilterRole(HIDE_ROLE) + self.proxy_model.setFilterFixedString('s') + self.jobs_view.setModel(self.proxy_model) self.setWindowModality(Qt.NonModal) self.setWindowTitle(__appname__ + _(' - Jobs')) self.details_button.clicked.connect(self.show_details) @@ -461,6 +482,9 @@ class JobsDialog(QDialog, Ui_JobsDialog): self.jobs_view.setItemDelegateForColumn(2, self.pb_delegate) self.jobs_view.doubleClicked.connect(self.show_job_details) self.jobs_view.horizontalHeader().setMovable(True) + self.hide_button.clicked.connect(self.hide_selected) + self.hide_all_button.clicked.connect(self.hide_all) + self.show_button.clicked.connect(self.show_hidden) self.restore_state() def restore_state(self): @@ -486,11 +510,13 @@ class JobsDialog(QDialog, Ui_JobsDialog): pass def show_job_details(self, index): - row = index.row() - job = self.jobs_view.model().row_to_job(row) - d = DetailView(self, job) - d.exec_() - d.timer.stop() + index = self.proxy_model.mapToSource(index) + if index.isValid(): + row = index.row() + job = self.model.row_to_job(row) + d = DetailView(self, job) + d.exec_() + d.timer.stop() def show_details(self, *args): index = self.jobs_view.currentIndex() @@ -498,8 +524,10 @@ class JobsDialog(QDialog, Ui_JobsDialog): self.show_job_details(index) def kill_job(self, *args): - rows = [index.row() for index in + indices = [self.proxy_model.mapToSource(index) for index in self.jobs_view.selectionModel().selectedRows()] + indices = [i for i in indices if i.isValid()] + rows = [index.row() for index in indices] if not rows: return error_dialog(self, _('No job'), _('No job selected'), show=True) @@ -517,6 +545,26 @@ class JobsDialog(QDialog, Ui_JobsDialog): _('Do you really want to stop all non-device jobs?')): self.model.kill_all_jobs() + def hide_selected(self, *args): + indices = [self.proxy_model.mapToSource(index) for index in + self.jobs_view.selectionModel().selectedRows()] + indices = [i for i in indices if i.isValid()] + rows = [index.row() for index in indices] + if not rows: + return error_dialog(self, _('No job'), + _('No job selected'), show=True) + self.model.hide_jobs(rows) + self.proxy_model.reset() + + def hide_all(self, *args): + self.model.hide_jobs(list(xrange(0, + self.model.rowCount(QModelIndex())))) + self.proxy_model.reset() + + def show_hidden(self, *args): + self.model.show_hidden_jobs() + self.proxy_model.reset() + def closeEvent(self, e): self.save_state() return QDialog.closeEvent(self, e)