groupedelements.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. """
  2. Module to easily group elements of a gui
  3. """
  4. from PyQt4 import QtGui
  5. import warnings
  6. from itertools import chain
  7. class GroupWarning(Warning):
  8. """
  9. General Warning Class for GroupedObjects
  10. """
  11. pass
  12. warnings.simplefilter('always', GroupWarning)
  13. class GroupedObjects:
  14. """
  15. This class enables grouping of objects to easily access them as groups throughout the gui.
  16. """
  17. def __init__(self):
  18. """
  19. Initialise this object
  20. :return:
  21. """
  22. self._objects = {}
  23. self._status = {}
  24. self.warn = False
  25. self.autoremove = False
  26. self.exception_on_deleted = False
  27. self.notify_deletion = False
  28. def setFlags(self, flagDict):
  29. """
  30. Set Flags that define the behaviour of GroupedObjects in various events.
  31. :param flagDict: Dictionary containing the Flags.
  32. Possible Flags are: (They are to be of type bool)
  33. warn: If an element is deleted and the corresponding entry is encountered by setEnabled, a
  34. Warning is raised if warn is True
  35. autoremove: If an element is deleted and the corresponding entry is encountered by setEnabled,
  36. the Element will be removed from GroupedObjects if autoremove is True
  37. exception_on_deleted: If an element is deleted and the corresponding entry is encountered by
  38. setEnabled an Exception will be raised if exception_on_deleted is True
  39. notify_deletion: If this is set to True a notification will be printed to STDOUT whenever an
  40. autoremove is performed (see above)
  41. :return: -
  42. """
  43. self.warn = flagDict.get('warn', False)
  44. self.autoremove = flagDict.get('autoremove', False)
  45. self.exception_on_deleted = flagDict.get('exception_on_deleted', False)
  46. self.notify_deletion = flagDict.get('notify_deletion', False)
  47. def createEmptyGroup(self, group):
  48. """
  49. Create an empty group
  50. :param group: (str) the name of the group
  51. :return: -
  52. """
  53. if group in self._objects:
  54. raise GroupWarning("Specified Group \""+group+"\" already in list")
  55. else:
  56. self._objects[group] = []
  57. def addItem(self, group, item):
  58. """
  59. Add a item or items to a group and thus register with the GroupedObjects object
  60. :param group: (list or str) List of groups or single group where the item is to be added
  61. :param item: (single item or list) What item/s
  62. :return: -
  63. """
  64. group = group if isinstance(group, list) else [group]
  65. item = item if isinstance(item, list) else [item]
  66. exclude = list(chain(*[self.getElements(i) for i in group]))
  67. for gr in group:
  68. if not (gr in self._status):
  69. self._status[gr] = True
  70. if gr in self._objects and isinstance(self._objects[gr], list):
  71. self._objects[gr].extend(item)
  72. else:
  73. self._objects[gr] = item
  74. if not self._status[gr]: # for the case when the status is set before the object is registered or the object is recreated
  75. self.setEnabled(gr, False, exclude=exclude)
  76. def setChecked(self, group, state):
  77. """
  78. Set the state of all the checkboxes in the group
  79. :param group: What group
  80. :param state: True for checked, False for unchecked
  81. :return: -
  82. """
  83. if group in self._objects:
  84. self._status[group] = state
  85. for obj in self._objects[group]:
  86. if isinstance(obj, QtGui.QCheckBox):
  87. obj.setChecked(state)
  88. else:
  89. warnings.warn("Specified Group \""+group+"\" not in list", GroupWarning, stacklevel=2)
  90. def setEnabled(self, group, state, exclude=None):
  91. """
  92. Set the state of all the items in the group
  93. :param group: What group
  94. :param state: True for enabled, False for disabled
  95. :param exclude: Exclude this item
  96. :return: -
  97. """
  98. to_remove = []
  99. if group in self._objects:
  100. self._status[group] = state
  101. if self._objects[group] == []: # untested if explicit test for empty list is necessary
  102. return
  103. for obj in self._objects[group]:
  104. try:
  105. if exclude and obj in exclude:
  106. continue
  107. if isinstance(obj, QtGui.QAction):
  108. obj.setEnabled(state)
  109. elif isinstance(obj, QtGui.QMenu):
  110. obj.menuAction().setVisible(state)
  111. else:
  112. obj.setEnabled(state)
  113. except RuntimeError, e:
  114. if "deleted" in str(e):
  115. # self.removeItem(group, obj)
  116. if self.autoremove:
  117. to_remove.append([group, obj])
  118. if self.warn:
  119. warnings.warn(str(e), GroupWarning, stacklevel=3)
  120. if self.exception_on_deleted:
  121. raise e
  122. else:
  123. raise e
  124. if to_remove and self.autoremove:
  125. for rm in to_remove:
  126. if self.notify_deletion:
  127. print "Autoremoving element from group '" + rm[0] + "'"
  128. self.removeItem(*rm)
  129. else:
  130. self._status[group] = state
  131. warnings.warn("Specified Group \""+group+"\" not in Elements", GroupWarning, stacklevel=2)
  132. def addMenuItem(self, group, item):
  133. """
  134. Deprecated. Use addItem.
  135. """
  136. self.addItem(group, item)
  137. def addButton(self, group, item):
  138. """
  139. Deprecated. Use addItem.
  140. """
  141. self.addItem(group, item)
  142. def addCheckbox(self, group, item):
  143. """
  144. Deprecated. Use addItem.
  145. """
  146. self.addItem(group, item)
  147. def removeItem(self, group, item):
  148. """
  149. Remove an element from a gropu
  150. :param group: (list or str) list of groups or groupname
  151. :param item: (list or item) list of items or item to remove
  152. :return: -
  153. """
  154. groups = group if isinstance(group, list) else [group]
  155. items = item if isinstance(item, list) else [item]
  156. for gr in groups:
  157. if not gr in self._objects:
  158. # return
  159. continue
  160. for it in items:
  161. if it in self._objects[gr]:
  162. del self._objects[gr][self._objects[gr].index(it)]
  163. def removeGroup(self, group):
  164. """
  165. Remove a group from GroupedObjects. If the group is not registered, a warning will be raised.
  166. :param group: (str) the group to remove
  167. :return:
  168. """
  169. if group in self._objects:
  170. del self._objects[group]
  171. else:
  172. warnings.warn("Group was not registered - Nothing removed", GroupWarning, stacklevel=2)
  173. def emptyGroup(self, group):
  174. """
  175. Unregister all elements from group. (This will delete the group and recreate it.
  176. :param group: (str) the group to clean out.
  177. :return: -
  178. """
  179. self.removeGroup(group)
  180. self.createEmptyGroup(group)
  181. def getElements(self, group):
  182. """
  183. Get the elements of a group as list.
  184. :param group: (str) the gorup you want the elements of
  185. :return: (list) Elements in group
  186. """
  187. if group in self._objects:
  188. return self._objects[group]
  189. else:
  190. return []
  191. def isEnabled(self, group):
  192. """
  193. Check if a group is enabled.
  194. :param group: (str) the gorup to check.
  195. :return: (bool) State of group
  196. """
  197. if group in self._status:
  198. return self._status[group]
  199. else:
  200. return True # Default for elements is enabled
  201. class LivePlotWindows():
  202. """
  203. Container class to hold open LivePlotWindows.
  204. Added LivePlotWindows will automatically be plotted to on the event of new data.
  205. """
  206. def __init__(self):
  207. self.plotWindows = {}
  208. def addWindow(self, board_id, window):
  209. """
  210. Register a Window.
  211. :param window: (PlotWidget) The window to be added.
  212. :return: -
  213. """
  214. if board_id in self.plotWindows:
  215. self.plotWindows[board_id].append(window)
  216. else:
  217. self.plotWindows[board_id] = [window, ]
  218. def getWindows(self, board_id):
  219. """
  220. Get the list of registered plot windows.
  221. :return: (list) List of plotWindows
  222. """
  223. return self.plotWindows[board_id]
  224. def hasWindows(self, board_id):
  225. """
  226. Check if Windows are registered.
  227. :return: (bool) True if there are windows and False if not.
  228. """
  229. if board_id in self.plotWindows and len(self.plotWindows[board_id]) > 0:
  230. return True
  231. else:
  232. return False
  233. def removeWindow(self, board_id, window):
  234. """
  235. Remove a window from open plot windows
  236. :param window: the window to remove
  237. :return:
  238. """
  239. del self.plotWindows[board_id][self.plotWindows[board_id].index(window)]
  240. # Every Element is acessible through every Variable set here. Checkboxes, Buttons and MenuItems variables are set
  241. # to improve readability of the code. They refer to the same Object
  242. class Proxy(object):
  243. def __init__(self, target):
  244. object.__setattr__(self, 'target', target)
  245. def __setattr__(self, key, value):
  246. setattr(object.__getattribute__(self, 'target')[object.__getattribute__(self, 'id')], key, value)
  247. def __set_id__(self, id):
  248. object.__setattr__(self, 'id', id)
  249. def __getattr__(self, item):
  250. if item == '__set_id__':
  251. return object.__getattribute__(self, item)
  252. else:
  253. return getattr(object.__getattribute__(self, 'target')[object.__getattribute__(self, 'id')], item)
  254. Elements = Checkboxes = Buttons = MenuItems = GroupedObjects()
  255. live_plot_windows = LivePlotWindows()