Stub debug client gui.
Change-Id: Ib422c66bc36245e1fc3c450765d7555da5c8dda0
This commit is contained in:
parent
68f73b5aa1
commit
d442da0789
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,3 +3,5 @@ html/*
|
||||
*.pyc
|
||||
pid/*
|
||||
|
||||
# ide
|
||||
.idea
|
||||
|
53
bin/secop-gui
Executable file
53
bin/secop-gui
Executable file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# *****************************************************************************
|
||||
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
import sys
|
||||
from os import path
|
||||
|
||||
# Add import path for inplace usage
|
||||
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
|
||||
|
||||
from secop.gui.mainwindow import MainWindow
|
||||
from secop import loggers
|
||||
|
||||
from PyQt4.QtGui import QApplication
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
|
||||
loggers.initLogging('gui', 'debug')
|
||||
|
||||
app = QApplication(argv)
|
||||
|
||||
win = MainWindow()
|
||||
win.show()
|
||||
|
||||
return app.exec_()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
||||
|
@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# *****************************************************************************
|
||||
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
import sip
|
||||
sip.setapi('QString', 2)
|
||||
sip.setapi('QVariant', 2)
|
@ -29,6 +29,7 @@ import threading
|
||||
import Queue
|
||||
|
||||
from secop import loggers
|
||||
from secop.validators import validator_from_str
|
||||
from secop.lib import mkthread
|
||||
from secop.lib.parsing import parse_time, format_time
|
||||
from secop.protocol.encoding import ENCODERS
|
||||
@ -137,7 +138,7 @@ class Client(object):
|
||||
describing_data = {}
|
||||
stopflag = False
|
||||
|
||||
def __init__(self, opts):
|
||||
def __init__(self, opts, autoconnect=True):
|
||||
self.log = loggers.log.getChild('client', True)
|
||||
self._cache = dict()
|
||||
if 'device' in opts:
|
||||
@ -164,13 +165,15 @@ class Client(object):
|
||||
# mapping the modulename to a dict mapping the parameter names to their values
|
||||
# note: the module value is stored as the value of the parameter value
|
||||
# of the module
|
||||
self.cache = dict()
|
||||
|
||||
self._syncLock = threading.RLock()
|
||||
self._thread = threading.Thread(target=self._run)
|
||||
self._thread.daemon = True
|
||||
self._thread.start()
|
||||
|
||||
if autoconnect:
|
||||
self.startup()
|
||||
|
||||
def _run(self):
|
||||
while not self.stopflag:
|
||||
try:
|
||||
@ -247,7 +250,7 @@ class Client(object):
|
||||
self.log.warning("deprecated specifier %r" % spec)
|
||||
spec = '%s:value' % spec
|
||||
modname, pname = spec.split(':', 1)
|
||||
self.cache.setdefault(modname, {})[pname] = Value(*data)
|
||||
self._cache.setdefault(modname, {})[pname] = Value(*data)
|
||||
if spec in self.callbacks:
|
||||
for func in self.callbacks[spec]:
|
||||
try:
|
||||
@ -265,6 +268,22 @@ class Client(object):
|
||||
run.add(func)
|
||||
self.single_shots[spec].difference_update(run)
|
||||
|
||||
def _getDescribingModuleData(self, module):
|
||||
return self.describingModulesData[module]
|
||||
|
||||
def _getDescribingParameterData(self, module, parameter):
|
||||
return self._getDescribingModuleData(module)['parameters'][parameter]
|
||||
|
||||
def _issueDescribe(self):
|
||||
_, self.equipment_id, self.describing_data = self.communicate(
|
||||
'describe')
|
||||
|
||||
for module, moduleData in self.describing_data['modules'].items():
|
||||
for parameter, parameterData in moduleData['parameters'].items():
|
||||
validator = validator_from_str(parameterData['validator'])
|
||||
self.describing_data['modules'][module]['parameters'] \
|
||||
[parameter]['validator'] = validator
|
||||
|
||||
def register_callback(self, module, parameter, cb):
|
||||
self.log.debug(
|
||||
'registering callback %r for %s:%s' %
|
||||
@ -343,14 +362,36 @@ class Client(object):
|
||||
# XXX: further notification-callbacks needed ???
|
||||
|
||||
def startup(self, async=False):
|
||||
_, self.equipment_id, self.describing_data = self.communicate(
|
||||
'describe')
|
||||
self._issueDescribe()
|
||||
# always fill our cache
|
||||
self.communicate('activate')
|
||||
# deactivate updates if not wanted
|
||||
if not async:
|
||||
self.communicate('deactivate')
|
||||
|
||||
def queryCache(self, module, parameter=None):
|
||||
result = self._cache.get(module, {})
|
||||
|
||||
if parameter is not None:
|
||||
result = result[parameter]
|
||||
|
||||
return result
|
||||
|
||||
def setParameter(self, module, parameter, value):
|
||||
validator = self._getDescribingParameterData(module,
|
||||
parameter)['validator']
|
||||
|
||||
value = validator(value)
|
||||
self.communicate('change', '%s:%s' % (module, parameter), value)
|
||||
|
||||
@property
|
||||
def describingData(self):
|
||||
return self.describing_data
|
||||
|
||||
@property
|
||||
def describingModulesData(self):
|
||||
return self.describingData['modules']
|
||||
|
||||
@property
|
||||
def equipmentId(self):
|
||||
return self.equipment_id
|
||||
|
@ -74,7 +74,8 @@ class PARAM(object):
|
||||
readonly=self.readonly,
|
||||
value=self.value,
|
||||
timestamp=self.timestamp,
|
||||
validator=repr(self.validator),
|
||||
validator=str(self.validator) if not isinstance(
|
||||
self.validator, type) else self.validator.__name__
|
||||
)
|
||||
|
||||
|
||||
|
0
secop/gui/__init__.py
Normal file
0
secop/gui/__init__.py
Normal file
136
secop/gui/mainwindow.py
Normal file
136
secop/gui/mainwindow.py
Normal file
@ -0,0 +1,136 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# *****************************************************************************
|
||||
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from PyQt4.QtGui import QMainWindow, QInputDialog, QTreeWidgetItem
|
||||
from PyQt4.QtCore import pyqtSignature as qtsig, QObject, pyqtSignal
|
||||
|
||||
from secop.gui.util import loadUi
|
||||
from secop.gui.nodectrl import NodeCtrl
|
||||
from secop.gui.modulectrl import ModuleCtrl
|
||||
from secop.client.baseclient import Client as SECNode
|
||||
|
||||
ITEM_TYPE_NODE = QTreeWidgetItem.UserType + 1
|
||||
ITEM_TYPE_MODULE = QTreeWidgetItem.UserType + 2
|
||||
ITEM_TYPE_PARAMETER = QTreeWidgetItem.UserType + 3
|
||||
|
||||
|
||||
class QSECNode(SECNode, QObject):
|
||||
newData = pyqtSignal(str, str, object) # module, parameter, data
|
||||
|
||||
def __init__(self, opts, autoconnect=False, parent=None):
|
||||
SECNode.__init__(self, opts, autoconnect)
|
||||
QObject.__init__(self, parent)
|
||||
|
||||
self.startup(True)
|
||||
self._subscribeCallbacks()
|
||||
|
||||
def _subscribeCallbacks(self):
|
||||
for module in self.modules:
|
||||
self._subscribeModuleCallback(module)
|
||||
|
||||
def _subscribeModuleCallback(self, module):
|
||||
for parameter in self.getParameters(module):
|
||||
self._subscribeParameterCallback(module, parameter)
|
||||
|
||||
def _subscribeParameterCallback(self, module, parameter):
|
||||
self.register_callback(module, parameter, self._newDataReceived)
|
||||
|
||||
def _newDataReceived(self, module, parameter, data):
|
||||
self.newData.emit(module, parameter, data)
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(MainWindow, self).__init__(parent)
|
||||
|
||||
loadUi(self, 'mainwindow.ui')
|
||||
|
||||
self.splitter.setStretchFactor(0, 1)
|
||||
self.splitter.setStretchFactor(1, 70)
|
||||
|
||||
self._nodes = {}
|
||||
self._nodeCtrls = {}
|
||||
self._currentWidget = self.splitter.widget(1).layout().takeAt(0)
|
||||
|
||||
# add localhost if available
|
||||
self._addNode('localhost')
|
||||
|
||||
@qtsig('')
|
||||
def on_actionAdd_SEC_node_triggered(self):
|
||||
host, ok = QInputDialog.getText(self, 'Add SEC node',
|
||||
'Enter SEC node hostname:')
|
||||
|
||||
if not ok:
|
||||
return
|
||||
|
||||
self._addNode(host)
|
||||
|
||||
def on_treeWidget_currentItemChanged(self, current, previous):
|
||||
if current.type() == ITEM_TYPE_NODE:
|
||||
self._displayNode(current.text(0))
|
||||
elif current.type() == ITEM_TYPE_MODULE:
|
||||
self._displayModule(current.parent().text(0), current.text(0))
|
||||
|
||||
def _addNode(self, host):
|
||||
|
||||
# create client
|
||||
port = 10767
|
||||
if ':' in host:
|
||||
host, port = host.split(':', 1)
|
||||
port = int(port)
|
||||
node = QSECNode({'connectto':host, 'port':port}, parent=self)
|
||||
host = '%s:%d' % (host, port)
|
||||
|
||||
self._nodes[host] = node
|
||||
|
||||
# fill tree
|
||||
nodeItem = QTreeWidgetItem(None, [host], ITEM_TYPE_NODE)
|
||||
|
||||
for module in sorted(node.modules):
|
||||
moduleItem = QTreeWidgetItem(nodeItem, [module], ITEM_TYPE_MODULE)
|
||||
for param in sorted(node.getParameters(module)):
|
||||
paramItem = QTreeWidgetItem(moduleItem, [param],
|
||||
ITEM_TYPE_PARAMETER)
|
||||
|
||||
self.treeWidget.addTopLevelItem(nodeItem)
|
||||
|
||||
def _displayNode(self, node):
|
||||
|
||||
ctrl = self._nodeCtrls.get(node, None)
|
||||
|
||||
if ctrl is None:
|
||||
ctrl = self._nodeCtrls[node] = NodeCtrl(self._nodes[node])
|
||||
|
||||
self._replaceCtrlWidget(ctrl)
|
||||
|
||||
def _displayModule(self, node, module):
|
||||
self._replaceCtrlWidget(ModuleCtrl(self._nodes[node], module))
|
||||
|
||||
def _replaceCtrlWidget(self, new):
|
||||
old = self.splitter.widget(1).layout().takeAt(0)
|
||||
if old:
|
||||
old.widget().hide()
|
||||
self.splitter.widget(1).layout().addWidget(new)
|
||||
new.show()
|
||||
self._currentWidget = new
|
86
secop/gui/modulectrl.py
Normal file
86
secop/gui/modulectrl.py
Normal file
@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# *****************************************************************************
|
||||
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from PyQt4.QtGui import QWidget, QLabel
|
||||
from PyQt4.QtCore import pyqtSignature as qtsig, Qt, pyqtSignal
|
||||
|
||||
from secop.gui.util import loadUi
|
||||
|
||||
class ParameterButtons(QWidget):
|
||||
setRequested = pyqtSignal(str, str, str) # module, parameter, setpoint
|
||||
|
||||
def __init__(self, module, parameter, initval='', parent=None):
|
||||
super(ParameterButtons, self).__init__(parent)
|
||||
loadUi(self, 'parambuttons.ui')
|
||||
|
||||
self._module = module
|
||||
self._parameter = parameter
|
||||
|
||||
self.currentLineEdit.setText(str(initval))
|
||||
|
||||
def on_setPushButton_clicked(self):
|
||||
self.setRequested.emit(self._module, self._parameter,
|
||||
self.setLineEdit.text())
|
||||
|
||||
|
||||
class ModuleCtrl(QWidget):
|
||||
def __init__(self, node, module, parent=None):
|
||||
super(ModuleCtrl, self).__init__(parent)
|
||||
loadUi(self, 'modulectrl.ui')
|
||||
self._node = node
|
||||
self._module = module
|
||||
|
||||
self._paramWidgets = {} # widget cache do avoid garbage collection
|
||||
|
||||
self.moduleNameLabel.setText(module)
|
||||
self._initModuleWidgets()
|
||||
|
||||
self._node.newData.connect(self._updateValue)
|
||||
|
||||
def _initModuleWidgets(self):
|
||||
initValues = self._node.queryCache(self._module)
|
||||
row = 0
|
||||
|
||||
font = self.font()
|
||||
font.setBold(True)
|
||||
|
||||
for param in sorted(self._node.getParameters(self._module)):
|
||||
label = QLabel(param + ':')
|
||||
label.setFont(font)
|
||||
|
||||
buttons = ParameterButtons(self._module, param,
|
||||
initValues[param].value)
|
||||
buttons.setRequested.connect(self._node.setParameter)
|
||||
|
||||
self.paramGroupBox.layout().addWidget(label, row, 0)
|
||||
self.paramGroupBox.layout().addWidget(buttons, row, 1)
|
||||
|
||||
self._paramWidgets[param] = (label, buttons)
|
||||
|
||||
row += 1
|
||||
|
||||
def _updateValue(self, module, parameter, value):
|
||||
if module != self._module:
|
||||
return
|
||||
|
||||
self._paramWidgets[parameter][1].currentLineEdit.setText(str(value[0]))
|
92
secop/gui/nodectrl.py
Normal file
92
secop/gui/nodectrl.py
Normal file
@ -0,0 +1,92 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# *****************************************************************************
|
||||
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
import pprint
|
||||
|
||||
from PyQt4.QtGui import QWidget, QTextCursor, QFont, QFontMetrics
|
||||
from PyQt4.QtCore import pyqtSignature as qtsig, Qt
|
||||
|
||||
from secop.gui.util import loadUi
|
||||
|
||||
class NodeCtrl(QWidget):
|
||||
def __init__(self, node, parent=None):
|
||||
super(NodeCtrl, self).__init__(parent)
|
||||
loadUi(self, 'nodectrl.ui')
|
||||
|
||||
self._node = node
|
||||
|
||||
self.contactPointLabel.setText(self._node.contactPoint)
|
||||
self.equipmentIdLabel.setText(self._node.equipmentId)
|
||||
self.protocolVersionLabel.setText(self._node.protocolVersion)
|
||||
self._clearLog()
|
||||
|
||||
@qtsig('')
|
||||
def on_sendPushButton_clicked(self):
|
||||
msg = self.msgLineEdit.text().strip()
|
||||
|
||||
if not msg:
|
||||
return
|
||||
|
||||
self._addLogEntry('<span style="font-weight:bold">Request:</span> '
|
||||
'%s:' % msg, raw=True)
|
||||
msg = msg.split(' ', 2)
|
||||
reply = self._node.syncCommunicate(*msg)
|
||||
self._addLogEntry(reply, newline=True, pretty=True)
|
||||
|
||||
@qtsig('')
|
||||
def on_clearPushButton_clicked(self):
|
||||
self._clearLog()
|
||||
|
||||
def _clearLog(self):
|
||||
self.logTextBrowser.clear()
|
||||
|
||||
self._addLogEntry('SECoP Communication Shell')
|
||||
self._addLogEntry('=========================')
|
||||
self._addLogEntry('', newline=True)
|
||||
|
||||
def _addLogEntry(self, msg, newline=False, pretty=False, raw=False):
|
||||
|
||||
if pretty:
|
||||
msg = pprint.pformat(msg, width=self._getLogWidth())
|
||||
|
||||
if not raw:
|
||||
msg = '<pre>%s</pre>' % Qt.escape(str(msg)).replace('\n', '<br />')
|
||||
|
||||
content = ''
|
||||
if self.logTextBrowser.toPlainText():
|
||||
content = self.logTextBrowser.toHtml()
|
||||
content += msg
|
||||
|
||||
if newline:
|
||||
content += '<br />'
|
||||
|
||||
self.logTextBrowser.setHtml(content)
|
||||
self.logTextBrowser.moveCursor(QTextCursor.End)
|
||||
|
||||
def _getLogWidth(self):
|
||||
fontMetrics = QFontMetrics(QFont('Monospace'))
|
||||
# calculate max avail characters by using an a (which is possible
|
||||
# due to monospace)
|
||||
result = self.logTextBrowser.width() / fontMetrics.width('a')
|
||||
return result
|
||||
|
118
secop/gui/ui/mainwindow.ui
Normal file
118
secop/gui/ui/mainwindow.ui
Normal file
@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1228</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>secop-gui</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeWidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2"/>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1228</width>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionAdd_SEC_node"/>
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionAbout"/>
|
||||
<addaction name="actionAbout_Qt"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionAdd_SEC_node"/>
|
||||
</widget>
|
||||
<action name="actionAdd_SEC_node">
|
||||
<property name="text">
|
||||
<string>Add SEC node</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExit">
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout">
|
||||
<property name="text">
|
||||
<string>About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout_Qt">
|
||||
<property name="text">
|
||||
<string>About Qt</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
99
secop/gui/ui/modulectrl.ui
Normal file
99
secop/gui/ui/modulectrl.ui
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>230</width>
|
||||
<height>121</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<italic>false</italic>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Module name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="moduleNameLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="paramGroupBox">
|
||||
<property name="title">
|
||||
<string>Parameters:</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
153
secop/gui/ui/nodectrl.ui
Normal file
153
secop/gui/ui/nodectrl.ui
Normal file
@ -0,0 +1,153 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>652</width>
|
||||
<height>490</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>652</width>
|
||||
<height>490</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Contact point:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="contactPointLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Equipment ID:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="equipmentIdLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Protocol version:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="protocolVersionLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="msgLineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>>>></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="sendPushButton">
|
||||
<property name="text">
|
||||
<string>Send</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="clearPushButton">
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QTextBrowser" name="logTextBrowser">
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>msgLineEdit</sender>
|
||||
<signal>returnPressed()</signal>
|
||||
<receiver>sendPushButton</receiver>
|
||||
<slot>animateClick()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>387</x>
|
||||
<y>459</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>498</x>
|
||||
<y>462</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
74
secop/gui/ui/parambuttons.ui
Normal file
74
secop/gui/ui/parambuttons.ui
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>730</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="horizontalSpacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Current: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="currentLineEdit">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>256</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Set: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLineEdit" name="setLineEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>256</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="setPushButton">
|
||||
<property name="text">
|
||||
<string>Set</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
33
secop/gui/util.py
Normal file
33
secop/gui/util.py
Normal file
@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# *****************************************************************************
|
||||
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from os import path
|
||||
|
||||
from PyQt4 import uic
|
||||
|
||||
|
||||
uipath = path.dirname(__file__)
|
||||
|
||||
|
||||
def loadUi(widget, uiname, subdir='ui'):
|
||||
uic.loadUi(path.join(uipath, subdir, uiname), widget)
|
@ -61,6 +61,7 @@ def mkthread(func, *args, **kwds):
|
||||
t.start()
|
||||
return t
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "minimal testing: lib"
|
||||
d = attrdict(a=1, b=2)
|
||||
|
@ -278,7 +278,7 @@ class Dispatcher(object):
|
||||
def _getParamValue(self, modulename, pname):
|
||||
moduleobj = self.get_module(modulename)
|
||||
if moduleobj is None:
|
||||
raise NoSuchmoduleError(module=modulename)
|
||||
raise NoSuchModuleError(module=modulename)
|
||||
|
||||
pobj = moduleobj.PARAMS.get(pname, None)
|
||||
if pobj is None:
|
||||
|
@ -30,6 +30,7 @@
|
||||
# if a validator does a mapping, it normally maps to the external representation (used for print/log/protocol/...)
|
||||
# to get the internal representation (for the code), call method convert
|
||||
|
||||
|
||||
class ProgrammingError(Exception):
|
||||
pass
|
||||
|
||||
@ -156,7 +157,7 @@ class vector(object):
|
||||
|
||||
def __init__(self, *args):
|
||||
self.validators = args
|
||||
self.argstr = ', '.join([repr(e) for e in args])
|
||||
self.argstr = ', '.join([validator_to_str(e) for e in args])
|
||||
|
||||
def __call__(self, args):
|
||||
if len(args) != len(self.validators):
|
||||
@ -173,7 +174,7 @@ class record(object):
|
||||
|
||||
def __init__(self, **kwds):
|
||||
self.validators = args
|
||||
self.argstr = ', '.join([repr(e) for e in kwds.items()])
|
||||
self.argstr = ', '.join([validator_to_str(e) for e in kwds.items()])
|
||||
|
||||
def __call__(self, arg):
|
||||
if len(args) != len(self.validators):
|
||||
@ -190,7 +191,7 @@ class oneof(object):
|
||||
|
||||
def __init__(self, *args):
|
||||
self.oneof = args
|
||||
self.argstr = ', '.join([repr(e) for e in args])
|
||||
self.argstr = ', '.join([validator_to_str(e) for e in args])
|
||||
|
||||
def __call__(self, arg):
|
||||
for v in self.oneof:
|
||||
@ -247,3 +248,12 @@ class enum(object):
|
||||
|
||||
def convert(self, arg):
|
||||
return self.mapping.get(arg, arg)
|
||||
|
||||
|
||||
def validator_to_str(validator):
|
||||
return str(validator) if not isinstance(validator, type) \
|
||||
else validator.__name__
|
||||
|
||||
|
||||
def validator_from_str(validator_str):
|
||||
return eval(validator_str)
|
||||
|
Loading…
x
Reference in New Issue
Block a user