diff --git a/src/calibre/gui2/dialogs/jobs.ui b/src/calibre/gui2/dialogs/jobs.ui
index de2d78db73..e2e345ca28 100644
--- a/src/calibre/gui2/dialogs/jobs.ui
+++ b/src/calibre/gui2/dialogs/jobs.ui
@@ -14,7 +14,7 @@
Active Jobs
-
+
:/images/jobs.svg:/images/jobs.svg
@@ -57,6 +57,13 @@
+ -
+
+
+ Stop &all jobs
+
+
+
@@ -67,7 +74,7 @@
-
+
diff --git a/src/calibre/gui2/jobs.py b/src/calibre/gui2/jobs.py
index 2cd25e1b4e..1d86910e15 100644
--- a/src/calibre/gui2/jobs.py
+++ b/src/calibre/gui2/jobs.py
@@ -193,6 +193,12 @@ class JobManager(QAbstractTableModel):
_('Job has already run')).exec_()
self.server.kill_job(job)
+ def kill_all_jobs(self):
+ for job in self.jobs:
+ if isinstance(job, DeviceJob) or job.duration is not None:
+ continue
+ self.server.kill_job(job)
+
def terminate_all_jobs(self):
self.server.killall()
@@ -230,6 +236,8 @@ class JobsDialog(QDialog, Ui_JobsDialog):
self.kill_job)
self.connect(self.details_button, SIGNAL('clicked()'),
self.show_details)
+ self.connect(self.stop_all_jobs_button, SIGNAL('clicked()'),
+ self.kill_all_jobs)
self.connect(self, SIGNAL('kill_job(int, PyQt_PyObject)'),
self.jobs_view.model().kill_job)
self.pb_delegate = ProgressBarDelegate(self)
@@ -247,7 +255,8 @@ class JobsDialog(QDialog, Ui_JobsDialog):
self.jobs_view.show_details(index)
return
-
+ def kill_all_jobs(self):
+ self.model.kill_all_jobs()
def closeEvent(self, e):
self.jobs_view.write_settings()
diff --git a/src/calibre/gui2/tools.py b/src/calibre/gui2/tools.py
index 4ff6cccb25..33bf465fd2 100644
--- a/src/calibre/gui2/tools.py
+++ b/src/calibre/gui2/tools.py
@@ -156,8 +156,6 @@ def convert_bulk_ebook(parent, db, book_ids, out_format=None):
dtitle = repr(mi.title)
desc = _('Convert book %d of %d (%s)') % (i + 1, total, dtitle)
- desc = _('Convert book %d of %d (%s)') % (i + 1, total, repr(mi.title))
-
args = [in_file, out_file.name, lrecs]
temp_files.append(out_file)
jobs.append(('gui_convert', args, desc, d.output_format.upper(), book_id, temp_files))
@@ -178,6 +176,7 @@ def convert_bulk_ebook(parent, db, book_ids, out_format=None):
'source format was found.') % (len(res), total),
msg).exec_()
+ jobs.reverse()
return jobs, changed, bad
def fetch_scheduled_recipe(recipe, script):
diff --git a/src/calibre/utils/ipc/job.py b/src/calibre/utils/ipc/job.py
index ec33c54231..16ce85ace6 100644
--- a/src/calibre/utils/ipc/job.py
+++ b/src/calibre/utils/ipc/job.py
@@ -30,6 +30,7 @@ class BaseJob(object):
self.done2 = None
self.killed = False
self.failed = False
+ self.kill_on_start = False
self.start_time = None
self.result = None
self.duration = None
diff --git a/src/calibre/utils/ipc/server.py b/src/calibre/utils/ipc/server.py
index c00f2479c9..4d2c4496bb 100644
--- a/src/calibre/utils/ipc/server.py
+++ b/src/calibre/utils/ipc/server.py
@@ -170,6 +170,7 @@ class Server(Thread):
except Empty:
pass
+ # Get notifications from worker process
for worker in self.workers:
while True:
try:
@@ -179,6 +180,7 @@ class Server(Thread):
except Empty:
break
+ # Remove finished jobs
for worker in [w for w in self.workers if not w.is_alive]:
self.workers.remove(worker)
job = worker.job
@@ -191,19 +193,27 @@ class Server(Thread):
job.duration = time.time() - job.start_time
self.changed_jobs_queue.put(job)
+ # Start new workers
if len(self.pool) + len(self.workers) < self.pool_size:
try:
self.pool.append(self.launch_worker())
except Exception:
pass
+ # Start waiting jobs
if len(self.pool) > 0 and len(self.waiting_jobs) > 0:
job = self.waiting_jobs.pop()
- worker = self.pool.pop()
job.start_time = time.time()
- worker.start_job(job)
- self.workers.append(worker)
- job.log_path = worker.log_path
+ if job.kill_on_start:
+ job.duration = 0.0
+ job.returncode = 1
+ job.killed = job.failed = True
+ job.result = None
+ else:
+ worker = self.pool.pop()
+ worker.start_job(job)
+ self.workers.append(worker)
+ job.log_path = worker.log_path
self.changed_jobs_queue.put(job)
while True:
@@ -217,11 +227,13 @@ class Server(Thread):
self.kill_queue.put(job)
def killall(self):
- for job in self.workers:
- self.kill_queue.put(job)
+ for worker in self.workers:
+ self.kill_queue.put(worker.job)
def _kill_job(self, job):
- if job.start_time is None: return
+ if job.start_time is None:
+ job.kill_on_start = True
+ return
for worker in self.workers:
if job is worker.job:
worker.kill()