491c96d37eb45ebff1a8a5a8bdd3e7b777f7c750
[gonvert] / src / util / qore_utils.py
1 import logging
2
3 from PyQt4 import QtCore
4
5 import misc
6
7
8 _moduleLogger = logging.getLogger(__name__)
9
10
11 class QThread44(QtCore.QThread):
12         """
13         This is to imitate QThread in Qt 4.4+ for when running on older version
14         See http://labs.trolltech.com/blogs/2010/06/17/youre-doing-it-wrong
15         (On Lucid I have Qt 4.7 and this is still an issue)
16         """
17
18         def __init__(self, parent = None):
19                 QtCore.QThread.__init__(self, parent)
20
21         def run(self):
22                 self.exec_()
23
24
25 class _ParentThread(QtCore.QObject):
26
27         def __init__(self, pool):
28                 QtCore.QObject.__init__(self)
29                 self._pool = pool
30
31         @QtCore.pyqtSlot(object)
32         @misc.log_exception(_moduleLogger)
33         def _on_task_complete(self, taskResult):
34                 on_success, on_error, isError, result = taskResult
35                 if not self._pool._isRunning:
36                         if isError:
37                                 _moduleLogger.error("Masking: %s" % (result, ))
38                         isError = True
39                         result = StopIteration("Cancelling all callbacks")
40                 callback = on_success if not isError else on_error
41                 try:
42                         callback(result)
43                 except Exception:
44                         _moduleLogger.exception("Callback errored")
45
46
47 class _WorkerThread(QtCore.QObject):
48
49         taskComplete  = QtCore.pyqtSignal(object)
50
51         def __init__(self, pool):
52                 QtCore.QObject.__init__(self)
53                 self._pool = pool
54
55         @QtCore.pyqtSlot(object)
56         @misc.log_exception(_moduleLogger)
57         def _on_task_added(self, task):
58                 if not self._pool._isRunning:
59                         _moduleLogger.error("Dropping task")
60
61                 func, args, kwds, on_success, on_error = task
62
63                 try:
64                         result = func(*args, **kwds)
65                         isError = False
66                 except Exception, e:
67                         _moduleLogger.error("Error, passing it back to the main thread")
68                         result = e
69                         isError = True
70
71                 taskResult = on_success, on_error, isError, result
72                 self.taskComplete.emit(taskResult)
73
74         @QtCore.pyqtSlot()
75         @misc.log_exception(_moduleLogger)
76         def _on_stop_requested(self):
77                 self._pool._thread.quit()
78
79
80 class AsyncPool(QtCore.QObject):
81
82         _addTask = QtCore.pyqtSignal(object)
83         _stopPool = QtCore.pyqtSignal()
84
85         def __init__(self):
86                 QtCore.QObject.__init__(self)
87                 self._thread = QThread44()
88                 self._isRunning = True
89                 self._parent = _ParentThread(self)
90                 self._worker = _WorkerThread(self)
91                 self._worker.moveToThread(self._thread)
92
93                 self._addTask.connect(self._worker._on_task_added)
94                 self._worker.taskComplete.connect(self._parent._on_task_complete)
95                 self._stopPool.connect(self._worker._on_stop_requested)
96
97         def start(self):
98                 self._thread.start()
99
100         def stop(self):
101                 self._isRunning = False
102                 self._stopPool.emit()
103
104         def add_task(self, func, args, kwds, on_success, on_error):
105                 assert self._isRunning, "Task queue not started"
106                 task = func, args, kwds, on_success, on_error
107                 self._addTask.emit(task)