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