diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index ae25dead4e..f69788e849 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -271,6 +271,9 @@ class Dispatcher(QObject): Convenience class to use Qt signals with arbitrary python callables. By default, ensures that a function call always happens in the thread this Dispatcher was created in. + + Note that if you create the Dispatcher in a thread without an event loop of + its own, the function call will happen in the GUI thread (I think). ''' dispatch_signal = pyqtSignal(object, object) @@ -292,11 +295,20 @@ class FunctionDispatcher(QObject): ''' Convenience class to use Qt signals with arbitrary python functions. By default, ensures that a function call always happens in the - thread this Dispatcher was created in. + thread this FunctionDispatcher was created in. + + Note that you must create FunctionDispatcher objects in the GUI thread. ''' dispatch_signal = pyqtSignal(object, object, object) def __init__(self, func, queued=True, parent=None): + global gui_thread + if gui_thread is None: + gui_thread = QThread.currentThread() + if not is_gui_thread(): + raise ValueError( + 'You can only create a FunctionDispatcher in the GUI thread') + QObject.__init__(self, parent) self.func = func typ = Qt.QueuedConnection @@ -305,10 +317,9 @@ class FunctionDispatcher(QObject): self.dispatch_signal.connect(self.dispatch, type=typ) self.q = Queue.Queue() self.lock = threading.Lock() - self.calling_thread = QThread.currentThread() def __call__(self, *args, **kwargs): - if self.calling_thread == QThread.currentThread(): + if is_gui_thread(): return self.func(*args, **kwargs) with self.lock: self.dispatch_signal.emit(self.q, args, kwargs) diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index eb35e937c0..ab02a183c6 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -6,18 +6,18 @@ __copyright__ = '2008, Kovid Goyal ' import os, traceback, Queue, time, cStringIO, re, sys from threading import Thread -from PyQt4.Qt import QMenu, QAction, QActionGroup, QIcon, SIGNAL, \ - Qt, pyqtSignal, QDialog, QObject +from PyQt4.Qt import (QMenu, QAction, QActionGroup, QIcon, SIGNAL, + Qt, pyqtSignal, QDialog, QObject) -from calibre.customize.ui import available_input_formats, available_output_formats, \ - device_plugins +from calibre.customize.ui import (available_input_formats, available_output_formats, + device_plugins) from calibre.devices.interface import DevicePlugin from calibre.devices.errors import UserFeedback, OpenFeedback from calibre.gui2.dialogs.choose_format_device import ChooseFormatDeviceDialog from calibre.utils.ipc.job import BaseJob from calibre.devices.scanner import DeviceScanner -from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \ - warning_dialog, info_dialog, choose_dir, FunctionDispatcher +from calibre.gui2 import (config, error_dialog, Dispatcher, dynamic, + warning_dialog, info_dialog, choose_dir, FunctionDispatcher) from calibre.ebooks.metadata import authors_to_string from calibre import preferred_encoding, prints, force_unicode, as_unicode from calibre.utils.filenames import ascii_filename @@ -35,8 +35,9 @@ class DeviceJob(BaseJob): # {{{ def __init__(self, func, done, job_manager, args=[], kwargs={}, description=''): - BaseJob.__init__(self, description, done=done) + BaseJob.__init__(self, description) self.func = func + self.callback_on_done = done self.args, self.kwargs = args, kwargs self.exception = None self.job_manager = job_manager @@ -50,6 +51,10 @@ class DeviceJob(BaseJob): # {{{ def job_done(self): self.duration = time.time() - self.start_time self.percent = 1 + try: + self.callback_on_done(self) + except: + pass self.job_manager.changed_queue.put(self) def report_progress(self, percent, msg=''): diff --git a/src/calibre/gui2/email.py b/src/calibre/gui2/email.py index c8adeb7d31..4b4c920a7e 100644 --- a/src/calibre/gui2/email.py +++ b/src/calibre/gui2/email.py @@ -11,8 +11,8 @@ from binascii import unhexlify from functools import partial from itertools import repeat -from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \ - config as email_config +from calibre.utils.smtp import (compose_mail, sendmail, extract_email_address, + config as email_config) from calibre.utils.filenames import ascii_filename from calibre.customize.ui import available_input_formats, available_output_formats from calibre.ebooks.metadata import authors_to_string @@ -67,8 +67,8 @@ class Sendmail(object): from_ = opts.from_ if not from_: from_ = 'calibre ' - msg = compose_mail(from_, to, text, subject, open(attachment, 'rb'), - aname) + with lopen(attachment, 'rb') as f: + msg = compose_mail(from_, to, text, subject, f, aname) efrom, eto = map(extract_email_address, (from_, to)) eto = [eto] sendmail(msg, efrom, eto, localhost=None,