secop-gui based on secop.client.Client
instead of secop.client.baseclient.Client Change-Id: I869a3a9ecba40382908b4741ef055a0c5afe018f Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/22471 Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
@ -24,13 +24,14 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from secop.client.baseclient import Client as SECNode
|
import secop.client
|
||||||
from secop.gui.modulectrl import ModuleCtrl
|
from secop.gui.modulectrl import ModuleCtrl
|
||||||
from secop.gui.nodectrl import NodeCtrl
|
from secop.gui.nodectrl import NodeCtrl
|
||||||
from secop.gui.paramview import ParameterView
|
from secop.gui.paramview import ParameterView
|
||||||
from secop.gui.qt import QInputDialog, QMainWindow, QMessageBox, \
|
from secop.gui.qt import QInputDialog, QMainWindow, QMessageBox, \
|
||||||
QObject, QTreeWidgetItem, pyqtSignal, pyqtSlot
|
QObject, QTreeWidgetItem, pyqtSignal, pyqtSlot, QBrush, QColor
|
||||||
from secop.gui.util import loadUi
|
from secop.gui.util import loadUi, Value
|
||||||
|
from secop.lib import formatExtendedTraceback
|
||||||
|
|
||||||
ITEM_TYPE_NODE = QTreeWidgetItem.UserType + 1
|
ITEM_TYPE_NODE = QTreeWidgetItem.UserType + 1
|
||||||
ITEM_TYPE_GROUP = QTreeWidgetItem.UserType + 2
|
ITEM_TYPE_GROUP = QTreeWidgetItem.UserType + 2
|
||||||
@ -38,34 +39,78 @@ ITEM_TYPE_MODULE = QTreeWidgetItem.UserType + 3
|
|||||||
ITEM_TYPE_PARAMETER = QTreeWidgetItem.UserType + 4
|
ITEM_TYPE_PARAMETER = QTreeWidgetItem.UserType + 4
|
||||||
|
|
||||||
|
|
||||||
class QSECNode(SECNode, QObject):
|
class QSECNode(QObject):
|
||||||
newData = pyqtSignal(str, str, object) # module, parameter, data
|
newData = pyqtSignal(str, str, object) # module, parameter, data
|
||||||
|
stateChange = pyqtSignal(str, bool, str) # node name, online, connection state
|
||||||
|
unhandledMsg = pyqtSignal(str) # message
|
||||||
|
logEntry = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, opts, autoconnect=False, parent=None):
|
def __init__(self, uri, parent=None):
|
||||||
SECNode.__init__(self, opts, autoconnect)
|
|
||||||
QObject.__init__(self, parent)
|
QObject.__init__(self, parent)
|
||||||
|
self.conn = conn = secop.client.SecopClient(uri)
|
||||||
|
conn.validate_data = True
|
||||||
|
self.log = conn.log
|
||||||
|
self.contactPoint = conn.uri
|
||||||
|
conn.connect()
|
||||||
|
self.equipmentId = conn.properties['equipment_id']
|
||||||
|
self.nodename = '%s (%s)' % (self.equipmentId, conn.uri)
|
||||||
|
self.modules = conn.modules
|
||||||
|
self.properties = self.conn.properties
|
||||||
|
self.protocolVersion = conn.secop_version
|
||||||
|
conn.register(None, self) # generic callback
|
||||||
|
|
||||||
self.startup(True)
|
# provide methods from old baseclient for making other gui code work
|
||||||
self._subscribeCallbacks()
|
|
||||||
|
|
||||||
def _subscribeCallbacks(self):
|
def getParameters(self, module):
|
||||||
for module in self.modules:
|
return self.modules[module]['parameters']
|
||||||
self._subscribeModuleCallback(module)
|
|
||||||
|
|
||||||
def _subscribeModuleCallback(self, module):
|
def getCommands(self, module):
|
||||||
for parameter in self.getParameters(module):
|
return self.modules[module]['commands']
|
||||||
self._subscribeParameterCallback(module, parameter)
|
|
||||||
|
|
||||||
def _subscribeParameterCallback(self, module, parameter):
|
def getModuleProperties(self, module):
|
||||||
self.register_callback(module, parameter, self._newDataReceived)
|
return self.modules[module]['properties']
|
||||||
|
|
||||||
def _newDataReceived(self, module, parameter, data):
|
def getProperties(self, module, parameter):
|
||||||
self.newData.emit(module, parameter, data)
|
props = self.modules[module]['parameters'][parameter]
|
||||||
|
if 'unit' in props['datainfo']:
|
||||||
|
props['unit'] = props['datainfo']['unit']
|
||||||
|
return self.modules[module]['parameters'][parameter]
|
||||||
|
|
||||||
|
def setParameter(self, module, parameter, value):
|
||||||
|
self.conn.setParameter(module, parameter, value)
|
||||||
|
|
||||||
|
def getParameter(self, module, parameter):
|
||||||
|
return self.conn.getParameter(module, parameter, True)
|
||||||
|
|
||||||
|
def execCommand(self, module, command, arg):
|
||||||
|
return self.conn.execCommand(module, command, arg)
|
||||||
|
|
||||||
|
def queryCache(self, module):
|
||||||
|
return {k: Value(*self.conn.cache[(module, k)])
|
||||||
|
for k in self.modules[module]['parameters']}
|
||||||
|
|
||||||
|
def syncCommunicate(self, action, ident='', data=None):
|
||||||
|
reply = self.conn.request(action, ident, data)
|
||||||
|
return secop.client.encode_msg_frame(*reply).decode('utf-8')
|
||||||
|
|
||||||
|
def decode_message(self, msg):
|
||||||
|
# decode_msg needs bytes as input
|
||||||
|
return secop.client.decode_msg(msg.encode('utf-8'))
|
||||||
|
|
||||||
|
def _getDescribingParameterData(self, module, parameter):
|
||||||
|
return self.modules[module]['parameters'][parameter]
|
||||||
|
|
||||||
|
def updateEvent(self, module, parameter, value, timestamp, readerror):
|
||||||
|
self.newData.emit(module, parameter, Value(value, timestamp, readerror))
|
||||||
|
|
||||||
|
def nodeStateChange(self, online, state):
|
||||||
|
self.stateChange.emit(self.nodename, online, state)
|
||||||
|
|
||||||
|
def unhandledMessage(self, *msg):
|
||||||
|
self.unhandledMsg.emit('%s %s %r' % msg)
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
askReopenSignal = pyqtSignal(str, str)
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(MainWindow, self).__init__(parent)
|
super(MainWindow, self).__init__(parent)
|
||||||
|
|
||||||
@ -83,7 +128,6 @@ class MainWindow(QMainWindow):
|
|||||||
self._paramCtrls = {}
|
self._paramCtrls = {}
|
||||||
self._topItems = {}
|
self._topItems = {}
|
||||||
self._currentWidget = self.splitter.widget(1).layout().takeAt(0)
|
self._currentWidget = self.splitter.widget(1).layout().takeAt(0)
|
||||||
self.askReopenSignal.connect(self.askReopen)
|
|
||||||
|
|
||||||
# add localhost (if available) and SEC nodes given as arguments
|
# add localhost (if available) and SEC nodes given as arguments
|
||||||
args = sys.argv[1:]
|
args = sys.argv[1:]
|
||||||
@ -95,7 +139,8 @@ class MainWindow(QMainWindow):
|
|||||||
try:
|
try:
|
||||||
self._addNode(host)
|
self._addNode(host)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(formatExtendedTraceback())
|
||||||
|
print('error in addNode: %r' % e)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def on_actionAdd_SEC_node_triggered(self):
|
def on_actionAdd_SEC_node_triggered(self):
|
||||||
@ -132,32 +177,24 @@ class MainWindow(QMainWindow):
|
|||||||
def _removeSubTree(self, toplevel_item):
|
def _removeSubTree(self, toplevel_item):
|
||||||
self.treeWidget.invisibleRootItem().removeChild(toplevel_item)
|
self.treeWidget.invisibleRootItem().removeChild(toplevel_item)
|
||||||
|
|
||||||
def _nodeDisconnected_callback(self, nodename, host):
|
def _set_node_state(self, nodename, online, state):
|
||||||
node = self._nodes[nodename]
|
node = self._nodes[nodename]
|
||||||
self._removeSubTree(self._topItems[node])
|
if online:
|
||||||
del self._topItems[node]
|
self._topItems[node].setBackground(0, QBrush(QColor('white')))
|
||||||
node.quit()
|
else:
|
||||||
self.askReopenSignal.emit(nodename, host)
|
self._topItems[node].setBackground(0, QBrush(QColor('orange')))
|
||||||
|
# TODO: make connection state be a separate row
|
||||||
def askReopen(self, nodename, host):
|
node.contactPoint = '%s (%s)' % (node.conn.uri, state)
|
||||||
result = QMessageBox.question(self.parent(), 'connection closed',
|
if nodename in self._nodeCtrls:
|
||||||
'connection to %s closed, reopen?' % nodename)
|
self._nodeCtrls[nodename].contactPointLabel.setText(node.contactPoint)
|
||||||
if result == QMessageBox.Yes:
|
|
||||||
self._addNode(host)
|
|
||||||
|
|
||||||
def _addNode(self, host):
|
def _addNode(self, host):
|
||||||
|
|
||||||
# create client
|
# create client
|
||||||
port = 10767
|
node = QSECNode(host, parent=self)
|
||||||
if ':' in host:
|
nodename = node.nodename
|
||||||
host, port = host.split(':', 1)
|
|
||||||
port = int(port)
|
|
||||||
node = QSECNode({'host': host, 'port': port}, parent=self)
|
|
||||||
host = '%s:%d' % (host, port)
|
|
||||||
|
|
||||||
nodename = '%s (%s)' % (node.equipmentId, host)
|
|
||||||
self._nodes[nodename] = node
|
self._nodes[nodename] = node
|
||||||
node.register_shutdown_callback(self._nodeDisconnected_callback, nodename, host)
|
|
||||||
|
|
||||||
# fill tree
|
# fill tree
|
||||||
nodeItem = QTreeWidgetItem(None, [nodename], ITEM_TYPE_NODE)
|
nodeItem = QTreeWidgetItem(None, [nodename], ITEM_TYPE_NODE)
|
||||||
@ -171,11 +208,13 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
self.treeWidget.addTopLevelItem(nodeItem)
|
self.treeWidget.addTopLevelItem(nodeItem)
|
||||||
self._topItems[node] = nodeItem
|
self._topItems[node] = nodeItem
|
||||||
|
node.stateChange.connect(self._set_node_state)
|
||||||
|
|
||||||
def _displayNode(self, node):
|
def _displayNode(self, node):
|
||||||
ctrl = self._nodeCtrls.get(node, None)
|
ctrl = self._nodeCtrls.get(node, None)
|
||||||
if ctrl is None:
|
if ctrl is None:
|
||||||
ctrl = self._nodeCtrls[node] = NodeCtrl(self._nodes[node])
|
ctrl = self._nodeCtrls[node] = NodeCtrl(self._nodes[node])
|
||||||
|
self._nodes[node].unhandledMsg.connect(ctrl._addLogEntry)
|
||||||
|
|
||||||
self._replaceCtrlWidget(ctrl)
|
self._replaceCtrlWidget(ctrl)
|
||||||
|
|
||||||
|
@ -65,8 +65,7 @@ class CommandDialog(QDialog):
|
|||||||
|
|
||||||
def showCommandResultDialog(command, args, result, extras=''):
|
def showCommandResultDialog(command, args, result, extras=''):
|
||||||
m = QMessageBox()
|
m = QMessageBox()
|
||||||
if not args:
|
args = '' if args is None else repr(args)
|
||||||
args = ''
|
|
||||||
m.setText('calling: %s(%s)\nyielded: %r\nqualifiers: %s' %
|
m.setText('calling: %s(%s)\nyielded: %r\nqualifiers: %s' %
|
||||||
(command, args, result, extras))
|
(command, args, result, extras))
|
||||||
m.exec_()
|
m.exec_()
|
||||||
@ -159,8 +158,6 @@ class ModuleCtrl(QWidget):
|
|||||||
self._node.newData.connect(self._updateValue)
|
self._node.newData.connect(self._updateValue)
|
||||||
|
|
||||||
def _execCommand(self, command, args=None):
|
def _execCommand(self, command, args=None):
|
||||||
if not args:
|
|
||||||
args = tuple()
|
|
||||||
try:
|
try:
|
||||||
result, qualifiers = self._node.execCommand(
|
result, qualifiers = self._node.execCommand(
|
||||||
self._module, command, args)
|
self._module, command, args)
|
||||||
@ -222,7 +219,7 @@ class ModuleCtrl(QWidget):
|
|||||||
'datatype', None)
|
'datatype', None)
|
||||||
# yes: create a widget for this as well
|
# yes: create a widget for this as well
|
||||||
labelstr, buttons = self._makeEntry(
|
labelstr, buttons = self._makeEntry(
|
||||||
group, initValues[param].value, datatype=datatype, nolabel=True, checkbox=checkbox, invert=True)
|
group, initValues[param], datatype=datatype, nolabel=True, checkbox=checkbox, invert=True)
|
||||||
checkbox.setText(labelstr)
|
checkbox.setText(labelstr)
|
||||||
|
|
||||||
# add to Layout (yes: ignore the label!)
|
# add to Layout (yes: ignore the label!)
|
||||||
@ -240,7 +237,7 @@ class ModuleCtrl(QWidget):
|
|||||||
initval = None
|
initval = None
|
||||||
print("Warning: %r not in initValues!" % param_)
|
print("Warning: %r not in initValues!" % param_)
|
||||||
else:
|
else:
|
||||||
initval = initValues[param_].value
|
initval = initValues[param_]
|
||||||
datatype = self._node.getProperties(
|
datatype = self._node.getProperties(
|
||||||
self._module, param_).get(
|
self._module, param_).get(
|
||||||
'datatype', None)
|
'datatype', None)
|
||||||
@ -261,7 +258,7 @@ class ModuleCtrl(QWidget):
|
|||||||
self._module, param).get(
|
self._module, param).get(
|
||||||
'datatype', None)
|
'datatype', None)
|
||||||
label, buttons = self._makeEntry(
|
label, buttons = self._makeEntry(
|
||||||
param, initValues[param].value, datatype=datatype)
|
param, initValues[param], datatype=datatype)
|
||||||
|
|
||||||
# add to Layout
|
# add to Layout
|
||||||
self.paramGroupBox.layout().addWidget(label, row, 0)
|
self.paramGroupBox.layout().addWidget(label, row, 0)
|
||||||
@ -359,7 +356,7 @@ class ModuleCtrl(QWidget):
|
|||||||
def _updateValue(self, module, parameter, value):
|
def _updateValue(self, module, parameter, value):
|
||||||
if module != self._module:
|
if module != self._module:
|
||||||
return
|
return
|
||||||
# value is [data, qualifiers]
|
# value is is type secop.gui.mainwindow.Value
|
||||||
# note: update subwidgets with the data portion only
|
# note: update subwidgets with the data portion only
|
||||||
# note: paramwidgets[..][1] is a ParameterView from secop.gui.params
|
# note: paramwidgets[..][1] is a ParameterView from secop.gui.params
|
||||||
self._paramWidgets[parameter][1].updateValue(value[0])
|
self._paramWidgets[parameter][1].updateValue(value)
|
||||||
|
@ -31,7 +31,8 @@ from secop.datatypes import EnumType, StringType
|
|||||||
from secop.errors import SECoPError
|
from secop.errors import SECoPError
|
||||||
from secop.gui.qt import QFont, QFontMetrics, QLabel, \
|
from secop.gui.qt import QFont, QFontMetrics, QLabel, \
|
||||||
QMessageBox, QTextCursor, QWidget, pyqtSlot, toHtmlEscaped
|
QMessageBox, QTextCursor, QWidget, pyqtSlot, toHtmlEscaped
|
||||||
from secop.gui.util import loadUi
|
from secop.gui.util import loadUi, Value
|
||||||
|
import secop.lib
|
||||||
|
|
||||||
|
|
||||||
class NodeCtrl(QWidget):
|
class NodeCtrl(QWidget):
|
||||||
@ -45,13 +46,15 @@ class NodeCtrl(QWidget):
|
|||||||
self.contactPointLabel.setText(self._node.contactPoint)
|
self.contactPointLabel.setText(self._node.contactPoint)
|
||||||
self.equipmentIdLabel.setText(self._node.equipmentId)
|
self.equipmentIdLabel.setText(self._node.equipmentId)
|
||||||
self.protocolVersionLabel.setText(self._node.protocolVersion)
|
self.protocolVersionLabel.setText(self._node.protocolVersion)
|
||||||
self.nodeDescriptionLabel.setText(self._node.describingData['properties'].get(
|
self.nodeDescriptionLabel.setText(self._node.properties.get('description',
|
||||||
'description', 'no description available'))
|
'no description available'))
|
||||||
self._clearLog()
|
self._clearLog()
|
||||||
|
|
||||||
# now populate modules tab
|
# now populate modules tab
|
||||||
self._init_modules_tab()
|
self._init_modules_tab()
|
||||||
|
|
||||||
|
node.logEntry.connect(self._addLogEntry)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def on_sendPushButton_clicked(self):
|
def on_sendPushButton_clicked(self):
|
||||||
msg = self.msgLineEdit.text().strip()
|
msg = self.msgLineEdit.text().strip()
|
||||||
@ -72,12 +75,19 @@ class NodeCtrl(QWidget):
|
|||||||
stuff, indent=2, separators=(',', ':'), sort_keys=True))
|
stuff, indent=2, separators=(',', ':'), sort_keys=True))
|
||||||
self._addLogEntry(reply, newline=True, pretty=False)
|
self._addLogEntry(reply, newline=True, pretty=False)
|
||||||
else:
|
else:
|
||||||
self._addLogEntry(reply, newline=True, pretty=True)
|
self._addLogEntry(reply, newline=True, pretty=False)
|
||||||
except SECoPError as e:
|
except SECoPError as e:
|
||||||
|
einfo = e.args[0] if len(e.args) == 1 else json.dumps(e.args)
|
||||||
self._addLogEntry(
|
self._addLogEntry(
|
||||||
'error %s %s' % (e.name, json.dumps(e.args)),
|
'%s: %s' % (e.name, einfo),
|
||||||
newline=True,
|
newline=True,
|
||||||
pretty=True,
|
pretty=False,
|
||||||
|
error=True)
|
||||||
|
except Exception as e:
|
||||||
|
self._addLogEntry(
|
||||||
|
'error when sending %r: %r' % (msg, e),
|
||||||
|
newline=True,
|
||||||
|
pretty=False,
|
||||||
error=True)
|
error=True)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@ -154,6 +164,7 @@ class NodeCtrl(QWidget):
|
|||||||
else:
|
else:
|
||||||
widget = QLabel('Unsupported Interfaceclass %r' % interfaces)
|
widget = QLabel('Unsupported Interfaceclass %r' % interfaces)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
print(secop.lib.formatExtendedTraceback())
|
||||||
widget = QLabel('Bad configured Module %s! (%s)' % (modname, e))
|
widget = QLabel('Bad configured Module %s! (%s)' % (modname, e))
|
||||||
|
|
||||||
|
|
||||||
@ -184,16 +195,19 @@ class ReadableWidget(QWidget):
|
|||||||
|
|
||||||
# XXX: avoid a nasty race condition, mainly biting on M$
|
# XXX: avoid a nasty race condition, mainly biting on M$
|
||||||
for i in range(15):
|
for i in range(15):
|
||||||
if 'status' in self._node.describing_data['modules'][module]['accessibles']:
|
if 'status' in self._node.modules[module]['parameters']:
|
||||||
break
|
break
|
||||||
sleep(0.01*i)
|
sleep(0.01*i)
|
||||||
|
|
||||||
self._status_type = self._node.getProperties(
|
self._status_type = self._node.getProperties(
|
||||||
self._module, 'status').get('datatype')
|
self._module, 'status').get('datatype')
|
||||||
|
|
||||||
params = self._node.getProperties(self._module, 'value')
|
try:
|
||||||
datatype = params.get('datatype', StringType())
|
props = self._node.getProperties(self._module, 'target')
|
||||||
self._is_enum = isinstance(datatype, EnumType)
|
datatype = props.get('datatype', StringType())
|
||||||
|
self._is_enum = isinstance(datatype, EnumType)
|
||||||
|
except KeyError:
|
||||||
|
self._is_enum = False
|
||||||
|
|
||||||
loadUi(self, 'modulebuttons.ui')
|
loadUi(self, 'modulebuttons.ui')
|
||||||
|
|
||||||
@ -214,37 +228,26 @@ class ReadableWidget(QWidget):
|
|||||||
self._node.newData.connect(self._updateValue)
|
self._node.newData.connect(self._updateValue)
|
||||||
|
|
||||||
def _get(self, pname, fallback=Ellipsis):
|
def _get(self, pname, fallback=Ellipsis):
|
||||||
params = self._node.queryCache(self._module)
|
|
||||||
if pname in params:
|
|
||||||
return params[pname].value
|
|
||||||
try:
|
try:
|
||||||
# if queried, we get the qualifiers as well, but don't want them
|
return Value(*self._node.getParameter(self._module, pname))
|
||||||
# here
|
except Exception as e:
|
||||||
|
# happens only, if there is no response form read request
|
||||||
mlzlog.getLogger('cached values').warn(
|
mlzlog.getLogger('cached values').warn(
|
||||||
'no cached value for %s:%s' % (self._module, pname))
|
'no cached value for %s:%s %r' % (self._module, pname, e))
|
||||||
val = self._node.getParameter(self._module, pname)[0]
|
return Value(fallback)
|
||||||
return val
|
|
||||||
except Exception:
|
|
||||||
self._node.log.exception()
|
|
||||||
if fallback is not Ellipsis:
|
|
||||||
return fallback
|
|
||||||
raise
|
|
||||||
|
|
||||||
def _init_status_widgets(self):
|
def _init_status_widgets(self):
|
||||||
self.update_status(self._get('status', (999, '<not supported>')), {})
|
self.update_status(self._get('status', (400, '<not supported>')))
|
||||||
# XXX: also connect update_status signal to LineEdit ??
|
# XXX: also connect update_status signal to LineEdit ??
|
||||||
|
|
||||||
def update_status(self, status, qualifiers=None):
|
def update_status(self, status):
|
||||||
display_string = self._status_type.members[0]._enum[status[0]].name
|
self.statusLineEdit.setText(str(status))
|
||||||
if status[1]:
|
|
||||||
display_string += ':' + status[1]
|
|
||||||
self.statusLineEdit.setText(display_string)
|
|
||||||
# may change meaning of cmdPushButton
|
# may change meaning of cmdPushButton
|
||||||
|
|
||||||
def _init_current_widgets(self):
|
def _init_current_widgets(self):
|
||||||
self.update_current(self._get('value', ''), {})
|
self.update_current(self._get('value', ''))
|
||||||
|
|
||||||
def update_current(self, value, qualifiers=None):
|
def update_current(self, value):
|
||||||
self.currentLineEdit.setText(str(value))
|
self.currentLineEdit.setText(str(value))
|
||||||
|
|
||||||
def _init_target_widgets(self):
|
def _init_target_widgets(self):
|
||||||
@ -253,18 +256,18 @@ class ReadableWidget(QWidget):
|
|||||||
self.targetComboBox.setHidden(True)
|
self.targetComboBox.setHidden(True)
|
||||||
self.cmdPushButton.setHidden(True)
|
self.cmdPushButton.setHidden(True)
|
||||||
|
|
||||||
def update_target(self, target, qualifiers=None):
|
def update_target(self, target):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _updateValue(self, module, parameter, value):
|
def _updateValue(self, module, parameter, value):
|
||||||
if module != self._module:
|
if module != self._module:
|
||||||
return
|
return
|
||||||
if parameter == 'status':
|
if parameter == 'status':
|
||||||
self.update_status(*value)
|
self.update_status(value)
|
||||||
elif parameter == 'value':
|
elif parameter == 'value':
|
||||||
self.update_current(*value)
|
self.update_current(value)
|
||||||
elif parameter == 'target':
|
elif parameter == 'target':
|
||||||
self.update_target(*value)
|
self.update_target(value)
|
||||||
|
|
||||||
|
|
||||||
class DrivableWidget(ReadableWidget):
|
class DrivableWidget(ReadableWidget):
|
||||||
@ -278,28 +281,30 @@ class DrivableWidget(ReadableWidget):
|
|||||||
# normal types: disable Combobox
|
# normal types: disable Combobox
|
||||||
self.targetComboBox.setHidden(True)
|
self.targetComboBox.setHidden(True)
|
||||||
target = self._get('target', None)
|
target = self._get('target', None)
|
||||||
if target:
|
if target.value is not None:
|
||||||
if isinstance(target, list) and isinstance(target[1], dict):
|
if isinstance(target.value, list) and isinstance(target.value[1], dict):
|
||||||
self.update_target(target[0])
|
self.update_target(Value(target.value[0]))
|
||||||
else:
|
else:
|
||||||
self.update_target(target)
|
self.update_target(target)
|
||||||
|
|
||||||
def update_current(self, value, qualifiers=None):
|
def update_current(self, value):
|
||||||
if self._is_enum:
|
self.currentLineEdit.setText(str(value))
|
||||||
member = self._map[self._revmap[value]]
|
#elif self._is_enum:
|
||||||
self.currentLineEdit.setText('%s.%s (%d)' % (member.enum.name, member.name, member.value))
|
# member = self._map[self._revmap[value.value]]
|
||||||
else:
|
# self.currentLineEdit.setText('%s.%s (%d)' % (member.enum.name, member.name, member.value))
|
||||||
self.currentLineEdit.setText(str(value))
|
|
||||||
|
|
||||||
def update_target(self, target, qualifiers=None):
|
def update_target(self, target):
|
||||||
if self._is_enum:
|
if self._is_enum:
|
||||||
|
if target.readerror:
|
||||||
|
return
|
||||||
# update selected item
|
# update selected item
|
||||||
if target in self._revmap:
|
value = target.value
|
||||||
self.targetComboBox.setCurrentIndex(self._revmap[target])
|
if value in self._revmap:
|
||||||
|
self.targetComboBox.setCurrentIndex(self._revmap[value])
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
"%s: Got invalid target value %r!" %
|
"%s: Got invalid target value %r!" %
|
||||||
(self._module, target))
|
(self._module, value))
|
||||||
else:
|
else:
|
||||||
self.targetLineEdit.setText(str(target))
|
self.targetLineEdit.setText(str(target))
|
||||||
|
|
||||||
|
@ -79,8 +79,6 @@ class GenericParameterWidget(ParameterWidget):
|
|||||||
self.setLineEdit.text())
|
self.setLineEdit.text())
|
||||||
|
|
||||||
def updateValue(self, value):
|
def updateValue(self, value):
|
||||||
if self._datatype:
|
|
||||||
value = self._datatype.import_value(value)
|
|
||||||
self.currentLineEdit.setText(str(value))
|
self.currentLineEdit.setText(str(value))
|
||||||
|
|
||||||
|
|
||||||
@ -113,12 +111,7 @@ class EnumParameterWidget(GenericParameterWidget):
|
|||||||
self.setRequested.emit(self._module, self._paramcmd, member)
|
self.setRequested.emit(self._module, self._paramcmd, member)
|
||||||
|
|
||||||
def updateValue(self, value):
|
def updateValue(self, value):
|
||||||
try:
|
self.currentLineEdit.setText(str(value))
|
||||||
member = self._map[self._revmap[int(value)]]
|
|
||||||
self.currentLineEdit.setText('%s.%s (%d)' % (member.enum.name, member.name, member.value))
|
|
||||||
except Exception:
|
|
||||||
self.currentLineEdit.setText('undefined Value: %r' % value)
|
|
||||||
print(formatExtendedStack())
|
|
||||||
|
|
||||||
|
|
||||||
class GenericCmdWidget(ParameterWidget):
|
class GenericCmdWidget(ParameterWidget):
|
||||||
|
@ -31,3 +31,23 @@ uipath = path.dirname(__file__)
|
|||||||
|
|
||||||
def loadUi(widget, uiname, subdir='ui'):
|
def loadUi(widget, uiname, subdir='ui'):
|
||||||
uic.loadUi(path.join(uipath, subdir, uiname), widget)
|
uic.loadUi(path.join(uipath, subdir, uiname), widget)
|
||||||
|
|
||||||
|
class Value:
|
||||||
|
def __init__(self, value, timestamp=None, readerror=None):
|
||||||
|
self.value = value
|
||||||
|
self.timestamp = timestamp
|
||||||
|
self.readerror = readerror
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""for display"""
|
||||||
|
if self.readerror:
|
||||||
|
return str('!!' + str(self.readerror) + '!!')
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
args = (self.value,)
|
||||||
|
if self.timestamp:
|
||||||
|
args += (self.timestamp,)
|
||||||
|
if self.readerror:
|
||||||
|
args += (self.readerror,)
|
||||||
|
return 'Value%s' % repr(args)
|
||||||
|
Reference in New Issue
Block a user