summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcpascual <cpascual@cells.es>2014-10-23 11:08:47 +0200
committerzreszela <zreszela@cells.es>2015-02-03 13:54:38 +0100
commita93f51b1b882818afa05c96947bb54955cd412a3 (patch)
tree41f05ffe2b89e991e1d4170a65599ffdabd62115 /src
parent3c172850b9a10d527819d18565ddd0c29e3febe1 (diff)
Implement feat-155: better API and docs for MacroButton
- substitute MacroButton.toggleProgress by MacroButton.showProgress - add MacroButton.connectArgEditors - prefix some effectively-private slot names with "_" - document all public API - reimplement MacroButtonAbortDoor - simplify example code
Diffstat (limited to 'src')
-rw-r--r--src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py221
1 files changed, 116 insertions, 105 deletions
diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py
index 4cf8940b..821a47ce 100644
--- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py
+++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py
@@ -24,7 +24,7 @@
##############################################################################
"""
-macrobutton.py:
+This module provides a button for executing macros
"""
__all__ = ['MacroButton']
@@ -35,15 +35,19 @@ import uuid
import PyTango
import taurus
-from taurus.core import TaurusEventType
+from taurus.core import TaurusEventType, TaurusDevice
from taurus.external.qt import Qt
from taurus.qt.qtgui.container import TaurusWidget
+from taurus.qt.qtgui.base import TaurusBaseWidget
from taurus.qt.qtgui.dialog import ProtectTaurusMessageBox
from taurus.core.util.colors import DEVICE_STATE_PALETTE
from taurus.qt.qtgui.util.ui import UILoadable
class DoorStateListener(Qt.QObject):
+ '''A listener of Change and periodic events from a Door State attribute.
+ It converts the received Tango events and emits a Qt signal
+ '''
__pyqtSignals__ = ["doorStateChanged"]
@@ -56,22 +60,12 @@ class DoorStateListener(Qt.QObject):
@UILoadable(with_ui='ui')
class MacroButton(TaurusWidget):
- ''' This class is intended to be used as a button to execute macros.
- The model must be a valid door.
-
- ..note:: Not implemented but will be needed: set an icon
-
- ..note::
+ ''' A button to execute/pause/stop macros. The model must be a valid door.
- It may be useful to have a slot update_macro_param that any qwidget signal may be
- connected to. The only condition might be that the sender widget should have an
- attribute 'widget.macro_param_index' in order to determine where the value has
- to be added.
+ .. todo:: Not implemented but will be needed: set an icon
- ..note::
-
- It may be useful to have all the streams from qdoor available somehow
- (right-click?)
+ .. todo:: It may be useful to have all the streams from qdoor available
+ somehow (right-click?)
'''
__pyqtSignals__ = ['statusUpdated', 'resultUpdated']
@@ -89,30 +83,45 @@ class MacroButton(TaurusWidget):
self.ui.progress.setValue(0)
self.ui.button.setCheckable(True)
- self.connect(self.ui.button, Qt.SIGNAL('clicked()'), self.button_clicked)
+ self.connect(self.ui.button, Qt.SIGNAL('clicked()'),
+ self._onButtonClicked)
def toggleProgress(self, visible):
+ '''deprecated'''
+ self.warning('toggleProgress is deprecated. Use showProgress')
+ self.showProgress(visible)
+
+ def showProgress(self, visible):
+ '''Set wether the progress bar is shown
+
+ :param visible: (bool) If True, the progress bar is shown. Otherwise it
+ is hidden'''
self.ui.progress.setVisible(visible)
def setModel(self, model):
+ '''
+ reimplemented from :class:`TaurusWidget`. A door device name is
+ expected as the model
+ '''
TaurusWidget.setModel(self, model)
if self.door is not None:
- self.disconnect(self.door, Qt.SIGNAL('macroStatusUpdated'), self.statusUpdated)
- self.disconnect(self.door, Qt.SIGNAL('resultUpdated'), self.resultUpdated)
+ self.disconnect(self.door, Qt.SIGNAL('macroStatusUpdated'), self._statusUpdated)
+ self.disconnect(self.door, Qt.SIGNAL('resultUpdated'), self._resultUpdated)
self.door.getAttribute('State').removeListener(self.door_state_listener)
try: self.door = taurus.Device(model)
except: return
- self.connect(self.door, Qt.SIGNAL('macroStatusUpdated'), self.statusUpdated)
- self.connect(self.door, Qt.SIGNAL('resultUpdated'), self.resultUpdated)
+ self.connect(self.door, Qt.SIGNAL('macroStatusUpdated'), self._statusUpdated)
+ self.connect(self.door, Qt.SIGNAL('resultUpdated'), self._resultUpdated)
# Manage Door Tango States
self.door_state_listener = DoorStateListener()
- self.connect(self.door_state_listener, Qt.SIGNAL('doorStateChanged'), self.doorStateChanged)
+ self.connect(self.door_state_listener, Qt.SIGNAL('doorStateChanged'), self._doorStateChanged)
self.door.getAttribute('State').addListener(self.door_state_listener)
- def doorStateChanged(self, state):
+ def _doorStateChanged(self, state):
+ '''slot called on door state changes'''
color = '#' + DEVICE_STATE_PALETTE.hex(state)
stylesheet = 'QFrame{border: 4px solid %s;}' % color
self.ui.frame.setStyleSheet(stylesheet)
@@ -126,7 +135,8 @@ class MacroButton(TaurusWidget):
self.ui.progress.setEnabled(door_available)
- def statusUpdated(self, *args):
+ def _statusUpdated(self, *args):
+ '''slot called on status changes'''
# SHOULD SEE THE DOCUMENTATION ABOUT THE ARGS AND ALSO THE STATUS STATE MACHINE
# ARGS FORMAT IS (GUESSING WITH PRINT STATEMENTS)
# e.g. ((<sardana.taurus.core.tango.sardana.macro.Macro object at 0x7f29300bc210>, [{u'step': 100.0, u'state': u'stop', u'range': [0.0, 100.0], u'id': u'b226f5e8-c807-11e0-8abe-001d0969db5b'}]),)
@@ -161,7 +171,8 @@ class MacroButton(TaurusWidget):
self.emit(Qt.SIGNAL('statusUpdated'), status_dict)
- def resultUpdated(self, *args):
+ def _resultUpdated(self, *args):
+ '''slot called on result changes'''
# ARGS APPEAR TO BE EMPTY... SHOULD THEY CONTAIN THE RESULT ?!?!?!
# I have to rely on the 'macro object' received in the last status update
if self.running_macro is None:
@@ -170,32 +181,68 @@ class MacroButton(TaurusWidget):
self.emit(Qt.SIGNAL('resultUpdated'), result)
def setText(self, text):
+ '''set the button text
+
+ :param text: (str) text for the button
+ '''
self.setButtonText(text)
- def setButtonText(self, text):
+ def setButtonText(self, text):
+ '''same as :meth:`setText`
+ '''
# SHOULD ALSO BE POSSIBLE TO SET AN ICON
self.ui.button.setText(text)
- def setMacroName(self, macro_name):
- self.macro_name = str(macro_name)
+ def setMacroName(self, name):
+ '''set the name of the macro to be executed
+
+ :param name: (str) text for the button
+ '''
+ self.macro_name = str(name)
def updateMacroArgument(self, index, value):
+ '''change a given argument
+
+ :param index: (int) positional index for this argument
+ :param value: (str) value for this argument
+ '''
+ #make sure that the macro_args is at least as long as index
while len(self.macro_args) < index + 1:
self.macro_args.append('')
-
+ #update the given argument
self.macro_args[index] = str(value)
-
+
def updateMacroArgumentFromSignal(self, index, obj, signal):
- self.connect(obj, signal, functools.partial(self.updateMacroArgument, index))
+ '''deprecated'''
+ msg = 'updateMacroArgumentFromSignal is deprecated. connectArgEditors'
+ self.warning(msg)
+ self.connect(obj, signal,
+ functools.partial(self.updateMacroArgument, index))
+
+ def connectArgEditors(self, signals):
+ '''Associate signals to argument changes.
+
+ :param signals: (seq<tuple>) An ordered sequence of (`obj`, `sig`)
+ tuples , where `obj` is a parameter editor object and
+ `sig` is a signature for a signal emitted by `obj` which
+ provides the value of a parameter as its argument.
+ Each (`obj`, `sig`) tuple is associated to parameter
+ corresponding to its position in the `signals` sequence.
+ '''
+
+ for i,(obj,sig) in enumerate(signals):
+ self.connect(obj, Qt.SIGNAL(sig),
+ functools.partial(self.updateMacroArgument, i))
- def button_clicked(self):
+ def _onButtonClicked(self):
if self.ui.button.isChecked():
self.runMacro()
else:
self.abort()
- @ProtectTaurusMessageBox(msg='An error occurred trying to execute the macro.')
+ @ProtectTaurusMessageBox(msg='Error while executing the macro.')
def runMacro(self):
+ '''execute the macro with the current arguments'''
if self.door is None:
return
@@ -215,6 +262,7 @@ class MacroButton(TaurusWidget):
raise e
def abort(self):
+ '''abort the macro.'''
if self.door is None:
return
self.door.PauseMacro()
@@ -235,42 +283,35 @@ class MacroButton(TaurusWidget):
@classmethod
def getQtDesignerPluginInfo(cls):
+ '''reimplemented from :class:`TaurusWidget`'''
return {'container': False,
'group': 'Taurus Sardana',
'module': 'taurus.qt.qtgui.extra_macroexecutor',
'icon': ':/designer/pushbutton.png'}
-
-class MacroButtonAbortDoor(TaurusWidget):
+class MacroButtonAbortDoor(Qt.QPushButton, TaurusBaseWidget):
+ '''A button for aborting macros on a door'''
+ #todo: why not inheriting from (TaurusBaseComponent, Qt.QPushButton)?
def __init__(self, parent=None, designMode=False):
- TaurusWidget.__init__(self, parent, designMode)
- self.setLayout(Qt.QGridLayout())
- self.layout().setMargin(0)
- self.layout().setSpacing(0)
-
- self.btn_abort = Qt.QPushButton('Abort')
- sizePolicy = Qt.QSizePolicy(Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Expanding)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- self.btn_abort.setSizePolicy(sizePolicy)
-
- self.door = None
- self.btn_abort.setToolTip('Abort Macro')
-
- self.layout().addWidget(self.btn_abort, 0, 0)
- self.connect(self.btn_abort, Qt.SIGNAL('clicked()'), self.abort)
-
- def setModel(self, model):
- TaurusWidget.setModel(self, model)
- try: self.door = taurus.Device(model)
- except: self.door = None
+ name = self.__class__.__name__
+ self.call__init__wo_kw(Qt.QPushButton, parent)
+ self.call__init__(TaurusBaseWidget, name, designMode=designMode)
+
+ self.setText('Abort')
+ self.setToolTip('Abort Macro')
+ self.connect(self, Qt.SIGNAL('clicked()'), self.abort)
+
+ def getModelClass(self):
+ '''reimplemented from :class:`TaurusBaseWidget`'''
+ return TaurusDevice
@ProtectTaurusMessageBox(msg='An error occurred trying to abort the macro.')
def abort(self):
- if self.door is not None:
- self.door.stopMacro()
-
+ '''stops macros'''
+ door = self.getModelObj()
+ if door is not None:
+ door.stopMacro()
if __name__ == '__main__':
@@ -298,42 +339,23 @@ if __name__ == '__main__':
w.setLayout(Qt.QGridLayout())
col = 0
- clear_button = Qt.QPushButton('clear')
- w.layout().addWidget(clear_button, 0, col, 2, 1)
-
- col += 1
w.layout().addWidget(Qt.QLabel('macro name'), 0, col)
macro_name = Qt.QLineEdit()
w.layout().addWidget(macro_name, 1, col)
- col += 1
- w.layout().addWidget(Qt.QLabel('arg0'), 0, col)
- arg0 = Qt.QLineEdit()
- w.layout().addWidget(arg0, 1, col)
+ _argEditors = []
+ for a in range(5):
+ col += 1
+ w.layout().addWidget(Qt.QLabel('arg0'), 0, col)
+ argEdit = Qt.QLineEdit()
+ w.layout().addWidget(argEdit, 1, col)
+ _argEditors.append(argEdit)
- col += 1
- w.layout().addWidget(Qt.QLabel('arg1'), 0, col)
- arg1 = Qt.QLineEdit()
- w.layout().addWidget(arg1, 1, col)
-
- col += 1
- w.layout().addWidget(Qt.QLabel('arg2'), 0, col)
- arg2 = Qt.QLineEdit()
- w.layout().addWidget(arg2, 1, col)
-
- col += 1
- w.layout().addWidget(Qt.QLabel('arg3'), 0, col)
- arg3 = Qt.QLineEdit()
- w.layout().addWidget(arg3, 1, col)
-
- col += 1
- w.layout().addWidget(Qt.QLabel('arg4'), 0, col)
- arg4 = Qt.QLineEdit()
- w.layout().addWidget(arg4, 1, col)
from sardana.taurus.qt.qtcore.tango.sardana.macroserver import registerExtensions
registerExtensions()
mb = MacroButton()
+
mb.setModel(door_name)
w.layout().addWidget(mb, 2, 0, 2, 7)
@@ -348,20 +370,18 @@ if __name__ == '__main__':
w.layout().addWidget(show_progress, 5, 0)
mb_abort = MacroButtonAbortDoor()
+
mb_abort.setModel(door_name)
+
w.layout().addWidget(mb_abort, 5, 1)
# Change macro name
Qt.QObject.connect(macro_name, Qt.SIGNAL('textChanged(QString)'), mb.setMacroName)
Qt.QObject.connect(macro_name, Qt.SIGNAL('textChanged(QString)'), mb.setButtonText)
-
- # Change Nth macro argument
- mb.updateMacroArgumentFromSignal(0, arg0, Qt.SIGNAL('textChanged(QString)'))
- mb.updateMacroArgumentFromSignal(1, arg1, Qt.SIGNAL('textChanged(QString)'))
- mb.updateMacroArgumentFromSignal(2, arg2, Qt.SIGNAL('textChanged(QString)'))
- mb.updateMacroArgumentFromSignal(3, arg3, Qt.SIGNAL('textChanged(QString)'))
- mb.updateMacroArgumentFromSignal(4, arg4, Qt.SIGNAL('textChanged(QString)'))
-
+
+ # connect the argument editors
+ signals = [(e, 'textChanged(QString)') for e in _argEditors]
+ mb.connectArgEditors(signals)
def update_result(result):
result_label.setText(str(result))
@@ -370,16 +390,10 @@ if __name__ == '__main__':
visible = show_progress.isChecked()
mb.toggleProgress(visible)
- def clear_params():
- for line_edit in [macro_name, arg0, arg1, arg2, arg3, arg4]:
- line_edit.setText('')
-
# Toggle progressbar
Qt.QObject.connect(show_progress, Qt.SIGNAL('stateChanged(int)'), toggle_progress)
# Update possible macro result
Qt.QObject.connect(mb, Qt.SIGNAL('resultUpdated'), update_result)
- # Clear parameters
- Qt.QObject.connect(clear_button, Qt.SIGNAL('clicked()'), clear_params)
# Obtain a demo motor
try:
@@ -392,11 +406,8 @@ if __name__ == '__main__':
# Since everything is now connected, the parameters will be updated
macro_name.setText('ascan')
- arg0.setText(demo_motor_name)
- arg1.setText('1')
- arg2.setText('10')
- arg3.setText('5')
- arg4.setText('0.1')
+ for e,v in zip(_argEditors, 'mot25 1 10 5 0.1'.split()):
+ e.setText(v)
w.show()
sys.exit(app.exec_())