3 from __future__ import with_statement
9 QtCore = qt_compat.QtCore
14 _moduleLogger = logging.getLogger(__name__)
17 class QThread44(QtCore.QThread):
19 This is to imitate QThread in Qt 4.4+ for when running on older version
20 See http://labs.trolltech.com/blogs/2010/06/17/youre-doing-it-wrong
21 (On Lucid I have Qt 4.7 and this is still an issue)
24 def __init__(self, parent = None):
25 QtCore.QThread.__init__(self, parent)
31 class _WorkerThread(QtCore.QObject):
33 _taskComplete = qt_compat.Signal(object)
35 def __init__(self, futureThread):
36 QtCore.QObject.__init__(self)
37 self._futureThread = futureThread
38 self._futureThread._addTask.connect(self._on_task_added)
39 self._taskComplete.connect(self._futureThread._on_task_complete)
41 @qt_compat.Slot(object)
42 def _on_task_added(self, task):
43 self.__on_task_added(task)
45 @misc.log_exception(_moduleLogger)
46 def __on_task_added(self, task):
47 if not self._futureThread._isRunning:
48 _moduleLogger.error("Dropping task")
50 func, args, kwds, on_success, on_error = task
53 result = func(*args, **kwds)
56 _moduleLogger.error("Error, passing it back to the main thread")
60 taskResult = on_success, on_error, isError, result
61 self._taskComplete.emit(taskResult)
64 class FutureThread(QtCore.QObject):
66 _addTask = qt_compat.Signal(object)
69 QtCore.QObject.__init__(self)
70 self._thread = QThread44()
71 self._isRunning = False
72 self._worker = _WorkerThread(self)
73 self._worker.moveToThread(self._thread)
77 self._isRunning = True
80 self._isRunning = False
83 def add_task(self, func, args, kwds, on_success, on_error):
84 assert self._isRunning, "Task queue not started"
85 task = func, args, kwds, on_success, on_error
86 self._addTask.emit(task)
88 @qt_compat.Slot(object)
89 def _on_task_complete(self, taskResult):
90 self.__on_task_complete(taskResult)
92 @misc.log_exception(_moduleLogger)
93 def __on_task_complete(self, taskResult):
94 on_success, on_error, isError, result = taskResult
95 if not self._isRunning:
97 _moduleLogger.error("Masking: %s" % (result, ))
99 result = StopIteration("Cancelling all callbacks")
100 callback = on_success if not isError else on_error
104 _moduleLogger.exception("Callback errored")
107 def create_single_column_list_model(columnName, **kwargs):
109 >>> class Single(object): pass
110 >>> SingleListModel = create_single_column_list_model("s")
111 >>> slm = SingleListModel([Single(), Single(), Single()])
114 class SingleColumnListModel(QtCore.QAbstractListModel):
116 def __init__(self, l = None):
117 QtCore.QAbstractListModel.__init__(self)
118 self._list = l if l is not None else []
119 self.setRoleNames({0: columnName})
122 return len(self._list)
124 def __getitem__(self, key):
125 return self._list[key]
127 def __setitem__(self, key, value):
128 with scoped_model_reset(self):
129 self._list[key] = value
131 def __delitem__(self, key):
132 with scoped_model_reset(self):
136 return iter(self._list)
139 return '<%s (%s)>' % (
140 self.__class__.__name__,
144 def rowCount(self, parent=QtCore.QModelIndex()):
145 return len(self._list)
147 def data(self, index, role):
148 if index.isValid() and role == 0:
149 return self._list[index.row()]
153 SingleColumnListModel.__name__ = kwargs["name"]
155 return SingleColumnListModel
158 def create_tupled_list_model(*columnNames, **kwargs):
160 >>> class Column0(object): pass
161 >>> class Column1(object): pass
162 >>> class Column2(object): pass
163 >>> MultiColumnedListModel = create_tupled_list_model("c0", "c1", "c2")
164 >>> mclm = MultiColumnedListModel([(Column0(), Column1(), Column2())])
167 class TupledListModel(QtCore.QAbstractListModel):
169 def __init__(self, l = None):
170 QtCore.QAbstractListModel.__init__(self)
171 self._list = l if l is not None else []
172 self.setRoleNames(dict(enumerate(columnNames)))
175 return len(self._list)
177 def __getitem__(self, key):
178 return self._list[key]
180 def __setitem__(self, key, value):
181 with scoped_model_reset(self):
182 self._list[key] = value
184 def __delitem__(self, key):
185 with scoped_model_reset(self):
189 return iter(self._list)
192 return '<%s (%s)>' % (
193 self.__class__.__name__,
194 ', '.join(columnNames),
197 def rowCount(self, parent=QtCore.QModelIndex()):
198 return len(self._list)
200 def data(self, index, role):
201 if index.isValid() and 0 <= role and role < len(columnNames):
202 return self._list[index.row()][role]
206 TupledListModel.__name__ = kwargs["name"]
208 return TupledListModel
211 @contextlib.contextmanager
212 def scoped_model_reset(model):
213 model.beginResetModel()
217 model.endResetModel()
220 def create_qobject(*classDef, **kwargs):
222 >>> Car = create_qobject(
226 ... ('inStock', bool),
230 <class '__main__.AutoQObject'>
232 >>> c = Car(model='Fiesta', brand='Ford', year=1337)
233 >>> print c.model, c.brand, c.year, c.inStock
234 Fiesta Ford 1337 False
236 <Car (model='Fiesta', brand='Ford', year=1337, inStock=False)>
240 >>> print c.model, c.brand, c.year, c.inStock
241 Fiesta Ford 1337 True
243 <Car (model='Fiesta', brand='Ford', year=1337, inStock=True)>
246 class AutoQObject(QtCore.QObject):
248 def __init__(self, **initKwargs):
249 QtCore.QObject.__init__(self)
250 for key, val in classDef:
251 setattr(self, '_'+key, initKwargs.get(key, val()))
255 '%s=%r' % (key, getattr(self, '_'+key))
256 for key, value in classDef
258 return '<%s (%s)>' % (
259 kwargs.get('name', self.__class__.__name__),
263 for key, value in classDef:
264 nfy = locals()['_nfy_'+key] = qt_compat.Signal()
268 return self.__dict__['_'+key]
273 setattr(self, '_'+key, value)
274 getattr(self, '_nfy_'+key).emit()
277 setter = locals()['_set_'+key] = _set(key)
278 getter = locals()['_get_'+key] = _get(key)
280 locals()[key] = qt_compat.Property(value, getter, setter, notify=nfy)
281 del nfy, _get, _set, getter, setter
286 class QObjectProxy(object):
288 Proxy for accessing properties and slots as attributes
290 This class acts as a proxy for the object for which it is
291 created, and makes property access more Pythonic while
292 still allowing access to slots (as member functions).
294 Attribute names starting with '_' are not proxied.
297 def __init__(self, rootObject):
298 self._rootObject = rootObject
299 m = self._rootObject.metaObject()
302 for i in xrange(m.propertyCount())
305 def __getattr__(self, key):
306 value = self._rootObject.property(key)
308 # No such property, so assume we call a slot
309 if value is None and key not in self._properties:
310 return getattr(self._rootObject, key)
314 def __setattr__(self, key, value):
315 if key.startswith('_'):
316 object.__setattr__(self, key, value)
318 self._rootObject.setProperty(key, value)
321 if __name__ == "__main__":
323 print doctest.testmod()