diff --git a/secop/client/baseclient.py b/secop/client/baseclient.py
index e36e66a..871fccd 100644
--- a/secop/client/baseclient.py
+++ b/secop/client/baseclient.py
@@ -386,6 +386,10 @@ class Client(object):
datatype = get_datatype(parameterData['datatype'])
self.describing_data['modules'][module]['parameters'] \
[parameter]['datatype'] = datatype
+ for cmdname, cmdData in moduleData[
+ 'commands'].items():
+ cmdData['arguments'] = map(get_datatype, cmdData['arguments'])
+ cmdData['resulttype'] = get_datatype(cmdData['resulttype'])
except Exception as exc:
print(formatException(verbose=True))
raise
@@ -548,9 +552,9 @@ class Client(object):
def getCommands(self, module):
return self.describing_data['modules'][module]['commands']
- def execCommand(self, module, command, args=None):
+ def execCommand(self, module, command, args):
# ignore reply message + reply specifier, only return data
- return self._communicate('do', '%s:%s' % (module, command), self.encode_message(args) if args else None)[2]
+ return self._communicate('do', '%s:%s' % (module, command), list(args) if args else None)[2]
def getProperties(self, module, parameter):
return self.describing_data['modules'][module]['parameters'][parameter]
diff --git a/secop/gui/modulectrl.py b/secop/gui/modulectrl.py
index 45a4a9c..38527da 100644
--- a/secop/gui/modulectrl.py
+++ b/secop/gui/modulectrl.py
@@ -29,6 +29,46 @@ from PyQt4.QtCore import pyqtSignature as qtsig, Qt, pyqtSignal
from secop.gui.util import loadUi
from secop.gui.params import ParameterView
+from secop.datatypes import *
+
+from PyQt4.QtGui import QDialog, QPushButton, QLabel, QApplication, QLineEdit,\
+ QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QCheckBox, QRadioButton, \
+ QVBoxLayout, QGridLayout, QScrollArea, QFrame
+
+from secop.gui.valuewidgets import get_widget
+
+
+class CommandDialog(QDialog):
+ def __init__(self, cmdname, arglist, parent=None):
+ super(CommandDialog, self).__init__(parent)
+ loadUi(self, 'cmddialog.ui')
+
+ self.setWindowTitle('Arguments for %s' % cmdname)
+ row = 0
+
+ self._labels = []
+ self.widgets = []
+ for row, dtype in enumerate(arglist):
+ l = QLabel(repr(dtype))
+ l.setWordWrap(True)
+ w = get_widget(dtype, readonly=False)
+ self.gridLayout.addWidget(l, row, 0)
+ self.gridLayout.addWidget(w, row, 1)
+ self._labels.append(l)
+ self.widgets.append(w)
+
+ self.gridLayout.setRowStretch(len(arglist), 1)
+ self.setModal(True)
+ self.resize(self.sizeHint())
+
+ def get_value(self):
+ return [w.get_value() for w in self.widgets]
+
+ def exec_(self):
+ if super(CommandDialog, self).exec_():
+ return self.get_value()
+
+
def showCommandResultDialog(command, args, result, extras=''):
m = QMessageBox()
@@ -69,7 +109,6 @@ class ParameterGroup(QWidget):
self._row += 1
def on_toggle_clicked(self):
- print("ParameterGroup.on_toggle_clicked")
if self.paramGroupBox.isChecked():
for w in self._widgets:
w.show()
@@ -78,19 +117,6 @@ class ParameterGroup(QWidget):
w.hide()
-class CommandArgumentsDialog(QDialog):
-
- def __init__(self, commandname, argtypes, parent=None):
- super(CommandArgumentsDialog, self).__init__(parent)
-
- # XXX: fill in apropriate widgets + OK/Cancel
-
- def exec_(self):
- print('CommandArgumentsDialog result is', super(
- CommandArgumentsDialog, self).exec_())
- return None # XXX: if there were arguments, return them after validation or None for 'Cancel'
-
-
class CommandButton(QButton):
def __init__(self, cmdname, cmdinfo, cb, parent=None):
@@ -108,10 +134,10 @@ class CommandButton(QButton):
def on_pushButton_pressed(self):
self.setEnabled(False)
- if self._argintypes or 1:
- args = CommandArgumentsDialog(self._cmdname, self._argintypes)
+ if self._argintypes:
+ dlg = CommandDialog(self._cmdname, self._argintypes)
+ args = dlg.exec_()
if args: # not 'Cancel' clicked
- print('############# %s', args)
self._cb(self._cmdname, args)
else:
# no need for arguments
@@ -140,17 +166,10 @@ class ModuleCtrl(QWidget):
self._node.newData.connect(self._updateValue)
def _execCommand(self, command, args=None):
- if args: # try to validate input
- # XXX: check datatypes with their validators?
- import ast
- try:
- args = ast.literal_eval(args)
- except Exception as e:
- return showErrorDialog(e)
if not args:
args = tuple()
result, qualifiers = self._node.execCommand(
- self._module, command, *args)
+ self._module, command, args)
showCommandResultDialog(command, args, result, qualifiers)
def _initModuleWidgets(self):
diff --git a/secop/gui/nodectrl.py b/secop/gui/nodectrl.py
index a21476b..1beb771 100644
--- a/secop/gui/nodectrl.py
+++ b/secop/gui/nodectrl.py
@@ -138,7 +138,18 @@ class NodeCtrl(QWidget):
else:
interfaces = modprops['interfaces']
description = modprops['description']
- unit = self._node.getProperties(modname, 'value').get('unit', '')
+
+ # fallback: allow (now) invalid 'Driveable'
+ if 'Drivable' in interfaces or 'Driveable' in interfaces:
+ widget = DrivableWidget(self._node, modname, self)
+ unit = self._node.getProperties(modname, 'value').get('unit', '')
+ elif 'Readable' in interfaces:
+ widget = ReadableWidget(self._node, modname, self)
+ unit = self._node.getProperties(modname, 'value').get('unit', '')
+ else:
+ widget = QLabel('Unsupported Interfaceclass %r' % interfaces)
+ unit = ''
+
if unit:
labelstr = '%s (%s):' % (modname, unit)
@@ -147,14 +158,6 @@ class NodeCtrl(QWidget):
label = QLabel(labelstr)
label.setFont(labelfont)
- # fallback: allow (now) invalid 'Driveable'
- if 'Drivable' in interfaces or 'Driveable' in interfaces:
- widget = DrivableWidget(self._node, modname, self)
- elif 'Readable' in interfaces:
- widget = ReadableWidget(self._node, modname, self)
- else:
- widget = QLabel('Unsupported Interfaceclasses %r' % interfaces)
-
if description:
widget.setToolTip(description)
diff --git a/secop/gui/ui/cmddialog.ui b/secop/gui/ui/cmddialog.ui
new file mode 100644
index 0000000..f9488af
--- /dev/null
+++ b/secop/gui/ui/cmddialog.ui
@@ -0,0 +1,88 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 262
+ 135
+
+
+
+ Dialog
+
+
+ -
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 242
+ 76
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ Dialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ Dialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/secop/gui/valuewidgets.py b/secop/gui/valuewidgets.py
new file mode 100644
index 0000000..cb6fc1b
--- /dev/null
+++ b/secop/gui/valuewidgets.py
@@ -0,0 +1,264 @@
+# -*- 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:
+# Enrico Faulhaber
+#
+# *****************************************************************************
+
+from secop.datatypes import *
+
+from PyQt4.QtGui import QDialog, QPushButton, QLabel, QApplication, QLineEdit,\
+ QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QCheckBox, QRadioButton, \
+ QVBoxLayout, QGridLayout, QScrollArea, QFrame
+
+from secop.gui.util import loadUi
+
+
+# XXX: implement live validators !!!!
+
+class StringWidget(QLineEdit):
+ def __init__(self, datatype, readonly=False, parent=None):
+ super(StringWidget, self).__init__(parent)
+ self.datatype = datatype
+ if readonly:
+ self.setEnabled(False)
+
+ def get_value(self):
+ res = self.text()
+ return self.datatype.validate(res)
+
+ def set_value(self, value):
+ self.setText(value)
+
+
+class BlobWidget(StringWidget):
+ # XXX: make an editable hex-table ?
+ pass
+
+# or derive from widget and switch between combobox and radiobuttons?
+class EnumWidget(QComboBox):
+ def __init__(self, datatype, readonly=False, parent=None):
+ super(EnumWidget, self).__init__(parent)
+ self.datatype = datatype
+
+ self._map = {}
+ self._revmap = {}
+ for idx, (val, name) in enumerate(datatype.entries.items()):
+ self._map[idx] = (name, val)
+ self._revmap[name] = idx
+ self._revmap[val] = idx
+ self.addItem(name, val)
+ # XXX: fill Combobox from datatype
+
+ def get_value(self):
+ # XXX: return integer corresponding to the selected item
+ return self._map[self.currentIndex()][1]
+
+ def set_value(self, value):
+ self.setCurrentIndex(self._revmap[value])
+
+
+class BoolWidget(QCheckBox):
+ def __init__(self, datatype, readonly=False, parent=None):
+ super(BoolWidget, self).__init__(parent)
+ self.datatype = datatype
+ if readonly:
+ self.setEnabled(False)
+
+ def get_value(self):
+ return self.isChecked()
+
+ def set_value(self, value):
+ self.setChecked(bool(value))
+
+
+class IntWidget(QSpinBox):
+ def __init__(self, datatype, readonly=False, parent=None):
+ super(IntWidget, self).__init__(parent)
+ self.datatype = datatype
+ if readonly:
+ self.setEnabled(False)
+ self.setMaximum(datatype.max)
+ self.setMinimum(datatype.min)
+
+ def get_value(self):
+ return int(self.value())
+
+ def set_value(self, value):
+ self.setValue(int(value))
+
+
+class FloatWidget(QDoubleSpinBox):
+ def __init__(self, datatype, readonly=False, parent=None):
+ super(FloatWidget, self).__init__(parent)
+ self.datatype = datatype
+ if readonly:
+ self.setEnabled(False)
+ self.setMaximum(datatype.max)
+ self.setMinimum(datatype.min)
+ self.setDecimals(12)
+
+ def get_value(self):
+ return float(self.value())
+
+ def set_value(self, value):
+ self.setValue(float(value))
+
+
+class TupleWidget(QFrame):
+ def __init__(self, datatype, readonly=False, parent=None):
+ super(TupleWidget, self).__init__(parent)
+
+ self.datatypes = datatype.subtypes
+
+ self.layout = QVBoxLayout()
+ self.subwidgets = []
+ for t in self.datatypes:
+ w = get_widget(t, readonly=readonly, parent=self)
+ w.show()
+ self.layout.addWidget(w)
+ self.subwidgets.append(w)
+ self.setLayout(self.layout)
+ self.show()
+ self.update()
+
+ def get_value(self):
+ return [v.validate(w.get_value()) for w,v in zip(self.subwidgets, self.datatypes)]
+
+ def set_value(self, value):
+ for w, v in zip(self.subwidgets, value):
+ w.set_value(value)
+
+
+class StructWidget(QGroupBox):
+ def __init__(self, datatype, readonly=False, parent=None):
+ super(StructWidget, self).__init__(parent)
+
+ self.layout = QGridLayout()
+ self.subwidgets = {}
+ self.datatypes = []
+ self._labels = []
+ for idx, name in enumerate(sorted(datatype.named_subtypes)):
+ dt = datatype.named_subtypes[name]
+ w = get_widget(dt, readonly=readonly, parent=self)
+ l = QLabel(name)
+ self.layout.addWidget(l, idx, 0)
+ self.layout.addWidget(w, idx, 1)
+ self._labels.append(l)
+ self.subwidgets[name] = (w, dt)
+ self.datatypes.append(dt)
+ self.setLayout(self.layout)
+
+ def get_value(self):
+ res = {}
+ for name, entry in self.subwidgets.items():
+ w, dt = entry
+ res[name] = dt.validate(w.get_value())
+ return res
+
+ def set_value(self, value):
+ for k, v in value.items():
+ entry = self.subwidgets[k]
+ w, dt = entry
+ w.set_value(dt.validate(v))
+
+
+class ArrayWidget(QGroupBox):
+ def __init__(self, datatype, readonly=False, parent=None):
+ super(ArrayWidget, self).__init__(parent)
+ self.datatype = datatype.subtype
+
+ self.layout = QVBoxLayout()
+ self.subwidgets = []
+ for i in range(datatype.maxsize):
+ w = get_widget(self.datatype, readonly=readonly, parent=self)
+ self.layout.addWidget(w)
+ self.subwidgets.append(w)
+ self.setLayout(self.layout)
+
+ def get_value(self):
+ return [self.datatype.validate(w.get_value()) for w in self.subwidgets]
+
+ def set_value(self, values):
+ for w, v in zip(self.subwidgets, values):
+ w.set_value(v)
+
+
+
+def get_widget(datatype, readonly=False, parent=None):
+ return {FloatRange: FloatWidget,
+ IntRange: IntWidget,
+ StringType: StringWidget,
+ BLOBType: BlobWidget,
+ EnumType: EnumWidget,
+ BoolType: BoolWidget,
+ TupleOf: TupleWidget,
+ StructOf: StructWidget,
+ ArrayOf: ArrayWidget,
+ }.get(datatype.__class__)(datatype, readonly, parent)
+
+
+class msg(QDialog):
+ def __init__(self, stuff, parent=None):
+ super(msg, self).__init__(parent)
+ loadUi(self, 'cmddialog.ui')
+ print(dir(self))
+ self.setWindowTitle('Please enter the arguments for calling command "blubb()"')
+ row = 0
+ # self.gridLayout.addWidget(QLabel('String'), row, 0); self.gridLayout.addWidget(StringWidget(StringType()), row, 1); row += 1
+ # self.gridLayout.addWidget(QLabel('Blob'), row, 0); self.gridLayout.addWidget(BlobWidget(BLOBType()), row, 1); row += 1
+ # self.gridLayout.addWidget(QLabel('Enum'), row, 0); self.gridLayout.addWidget(EnumWidget(EnumType(a=1,b=9)), row, 1); row += 1
+ # self.gridLayout.addWidget(QLabel('Bool'), row, 0); self.gridLayout.addWidget(BoolWidget(BoolType()), row, 1); row += 1
+ # self.gridLayout.addWidget(QLabel('int'), row, 0); self.gridLayout.addWidget(IntWidget(IntRange(0,9)), row, 1); row += 1
+ # self.gridLayout.addWidget(QLabel('float'), row, 0); self.gridLayout.addWidget(FloatWidget(FloatRange(-9,9)), row, 1); row += 1
+
+ #self.gridLayout.addWidget(QLabel('tuple'), row, 0);
+ #dt = TupleOf(BoolType(), EnumType(a=2,b=3))
+ #w = TupleWidget(dt)
+ #self.gridLayout.addWidget(w, row, 1)
+ #row+=1
+
+ #self.gridLayout.addWidget(QLabel('array'), row, 0);
+ #dt = ArrayOf(IntRange(0,10), 10)
+ #w = ArrayWidget(dt)
+ #self.gridLayout.addWidget(w, row, 1)
+ #row+=1
+
+ self.gridLayout.addWidget(QLabel('struct'), row, 0);
+ dt = StructOf(i=IntRange(0,10), f=FloatRange(), b=BoolType())
+ w = StructWidget(dt)
+ self.gridLayout.addWidget(w, row, 1)
+ row+=1
+
+ self.gridLayout.addWidget(QLabel('stuff'), row, 0, 1, 0); row += 1 # at pos (0,0) span 2 cols, 1 row
+ self.gridLayout.setRowStretch(row, 1)
+ self.setModal(True)
+
+ def accept(self):
+ print('accepted')
+ super(msg, self).accept()
+
+ def reject(self):
+ print('rejected')
+ super(msg, self).reject()
+
+ def done(self, how):
+ print('done(%r)' % how)
+ return super(msg, self).done(how)
+