From e83066631517c50b99b146149ed05ed044cb073d Mon Sep 17 00:00:00 2001 From: Enrico Faulhaber Date: Wed, 11 Apr 2018 11:10:22 +0200 Subject: [PATCH] Support PyQt5 (fallback to PyQt4) Change-Id: I7fa1add00d677e626fee5cd1071dee54d0bf8565 Reviewed-on: https://forge.frm2.tum.de/review/17666 Tested-by: JenkinsCodeReview Reviewed-by: Enrico Faulhaber Tested-by: Enrico Faulhaber --- bin/secop-gui | 8 ++---- secop/gui/mainwindow.py | 6 ++-- secop/gui/modulectrl.py | 15 ++++------ secop/gui/nodectrl.py | 14 ++++----- secop/gui/params/__init__.py | 33 ++++++++++----------- secop/gui/paramview.py | 5 ++-- secop/gui/qt.py | 25 ++++++++++++++++ secop/gui/util.py | 2 +- secop/gui/valuewidgets.py | 56 +++++++++++++----------------------- 9 files changed, 84 insertions(+), 80 deletions(-) create mode 100644 secop/gui/qt.py diff --git a/bin/secop-gui b/bin/secop-gui index 20d7790..568bfd8 100755 --- a/bin/secop-gui +++ b/bin/secop-gui @@ -1,4 +1,5 @@ #!/usr/bin/env python +# pylint: disable=invalid-name # -*- coding: utf-8 -*- # ***************************************************************************** # Copyright (c) 2015-2016 by the authors, see LICENSE @@ -27,15 +28,13 @@ from __future__ import print_function 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 - import mlzlog -from PyQt4.QtGui import QApplication +from secop.gui.qt import QApplication +from secop.gui.mainwindow import MainWindow def main(argv=None): @@ -67,4 +66,3 @@ def main(argv=None): if __name__ == '__main__': sys.exit(main(sys.argv)) - diff --git a/secop/gui/mainwindow.py b/secop/gui/mainwindow.py index f584ed4..733be9d 100644 --- a/secop/gui/mainwindow.py +++ b/secop/gui/mainwindow.py @@ -25,8 +25,8 @@ from __future__ import print_function import sys -from PyQt4.QtGui import QMainWindow, QInputDialog, QTreeWidgetItem, QMessageBox -from PyQt4.QtCore import pyqtSignature as qtsig, QObject, pyqtSignal +from secop.gui.qt import QMainWindow, QInputDialog, QTreeWidgetItem, QMessageBox, \ + pyqtSlot, QObject, pyqtSignal from secop.gui.util import loadUi from secop.gui.nodectrl import NodeCtrl @@ -98,7 +98,7 @@ class MainWindow(QMainWindow): except Exception as e: print(e) - @qtsig('') + @pyqtSlot() def on_actionAdd_SEC_node_triggered(self): host, ok = QInputDialog.getText(self, 'Add SEC node', 'Enter SEC node hostname:') diff --git a/secop/gui/modulectrl.py b/secop/gui/modulectrl.py index 38527da..014c7a8 100644 --- a/secop/gui/modulectrl.py +++ b/secop/gui/modulectrl.py @@ -18,22 +18,19 @@ # # Module authors: # Alexander Lenz +# Enrico Faulhaber # # ***************************************************************************** from __future__ import print_function -from PyQt4.QtGui import QWidget, QLabel, QPushButton as QButton, QLineEdit, QMessageBox, QCheckBox, QSizePolicy, QDialog -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 secop.datatypes import * # pylint: disable=unused-wildcard-import,wildcard-import -from PyQt4.QtGui import QDialog, QPushButton, QLabel, QApplication, QLineEdit,\ - QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QCheckBox, QRadioButton, \ - QVBoxLayout, QGridLayout, QScrollArea, QFrame +from secop.gui.qt import QDialog, QLabel, QCheckBox, QWidget, QMessageBox, \ + QPushButton, QSizePolicy from secop.gui.valuewidgets import get_widget @@ -67,7 +64,7 @@ class CommandDialog(QDialog): def exec_(self): if super(CommandDialog, self).exec_(): return self.get_value() - + return None def showCommandResultDialog(command, args, result, extras=''): @@ -117,7 +114,7 @@ class ParameterGroup(QWidget): w.hide() -class CommandButton(QButton): +class CommandButton(QPushButton): def __init__(self, cmdname, cmdinfo, cb, parent=None): super(CommandButton, self).__init__(parent) diff --git a/secop/gui/nodectrl.py b/secop/gui/nodectrl.py index 8695f24..f96d6ee 100644 --- a/secop/gui/nodectrl.py +++ b/secop/gui/nodectrl.py @@ -25,8 +25,8 @@ import pprint import json from time import sleep -from PyQt4.QtGui import QWidget, QTextCursor, QFont, QFontMetrics, QLabel, QMessageBox -from PyQt4.QtCore import pyqtSignature as qtsig, Qt +from secop.gui.qt import QWidget, QTextCursor, QFont, QFontMetrics, QLabel, \ + QMessageBox, pyqtSlot, toHtmlEscaped from secop.gui.util import loadUi from secop.protocol.errors import SECOPError @@ -51,7 +51,7 @@ class NodeCtrl(QWidget): # now populate modules tab self._init_modules_tab() - @qtsig('') + @pyqtSlot() def on_sendPushButton_clicked(self): msg = self.msgLineEdit.text().strip() @@ -79,7 +79,7 @@ class NodeCtrl(QWidget): pretty=True, error=True) - @qtsig('') + @pyqtSlot() def on_clearPushButton_clicked(self): self._clearLog() @@ -102,11 +102,11 @@ class NodeCtrl(QWidget): if not raw: if error: - msg = '
%s
' % Qt.escape( + msg = '
%s
' % toHtmlEscaped( str(msg)).replace('\n', '
') else: - msg = '
%s
' % Qt.escape(str(msg)).replace('\n', - '
') + msg = '
%s
' % toHtmlEscaped( + str(msg)).replace('\n', '
') content = '' if self.logTextBrowser.toPlainText(): diff --git a/secop/gui/params/__init__.py b/secop/gui/params/__init__.py index 718e540..8c91b3f 100644 --- a/secop/gui/params/__init__.py +++ b/secop/gui/params/__init__.py @@ -21,11 +21,11 @@ # # ***************************************************************************** -from PyQt4.QtGui import QWidget, QLabel, QPushButton as QButton, QLineEdit, QMessageBox, QCheckBox, QSizePolicy -from PyQt4.QtCore import pyqtSignature as qtsig, Qt, pyqtSignal +from secop.gui.qt import QWidget, QLabel, QPushButton as QButton, QLineEdit, \ + QMessageBox, QCheckBox, QSizePolicy, Qt, pyqtSignal from secop.gui.util import loadUi -from secop.datatypes import * +from secop.datatypes import * # pylint: disable=wildcard-import class ParameterWidget(QWidget): @@ -88,11 +88,11 @@ class EnumParameterWidget(GenericParameterWidget): self._map = {} # maps index to enumstring self._revmap = {} # maps enumstring to index index = 0 - for data, entry in sorted(self._datatype.entries.items()): - self.setComboBox.addItem(entry, data) - self._map[index] = entry - self._revmap[entry] = index - self._revmap[data] = index + for enumval, enumname in sorted(self._datatype.entries.items()): + self.setComboBox.addItem(enumname, enumval) + self._map[index] = (enumval, enumname) + self._revmap[enumname] = index + self._revmap[enumval] = index index += 1 if self._readonly: self.setLabel.setEnabled(False) @@ -105,18 +105,19 @@ class EnumParameterWidget(GenericParameterWidget): self.updateValue(str(initvalue)) def on_setPushButton_clicked(self): - self.setRequested.emit( - self._module, self._paramcmd, str( - self._datatype.reversed[ - self._map[ - self.setComboBox.currentIndex()]])) + enumval, enumname = self._map[self.setComboBox.currentIndex()] + self.setRequested.emit(self._module, self._paramcmd, enumname) + self.setRequested.emit(self._module, self._paramcmd, str(enumval)) def updateValue(self, valuestr): try: - self.currentLineEdit.setText( - self._datatype.entries.get( - int(valuestr), valuestr)) + valuestr = int(valuestr) except ValueError: + pass + if valuestr in self._revmap: + index = self._revmap[valuestr] + self.currentLineEdit.setText('(%d): %s' % self._map[index]) + else: self.currentLineEdit.setText('undefined Value: %r' % valuestr) diff --git a/secop/gui/paramview.py b/secop/gui/paramview.py index 11662dc..324670f 100644 --- a/secop/gui/paramview.py +++ b/secop/gui/paramview.py @@ -21,11 +21,10 @@ # # ***************************************************************************** -from PyQt4.QtGui import QWidget, QLabel, QSizePolicy -from PyQt4.QtCore import pyqtSignature as qtsig, Qt, pyqtSignal +from secop.gui.qt import QWidget, QLabel, QSizePolicy from secop.gui.util import loadUi -from secop.datatypes import get_datatype +#from secop.datatypes import get_datatype class ParameterView(QWidget): diff --git a/secop/gui/qt.py b/secop/gui/qt.py new file mode 100644 index 0000000..9cf758b --- /dev/null +++ b/secop/gui/qt.py @@ -0,0 +1,25 @@ +# pylint: disable=unused-import +from __future__ import print_function + +try: + from PyQt5 import uic + from PyQt5.QtCore import Qt, QObject, pyqtSignal, pyqtSlot + from PyQt5.QtGui import QFont, QTextCursor, QFontMetrics + from PyQt5.QtWidgets import QLabel, QWidget, QDialog, QLineEdit, QCheckBox, QPushButton, \ + QSizePolicy, QMainWindow, QMessageBox, QInputDialog, QTreeWidgetItem, QApplication, \ + QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QRadioButton, QVBoxLayout, QHBoxLayout, \ + QGridLayout, QScrollArea, QFrame + + from xml.sax.saxutils import escape as toHtmlEscaped + +except ImportError: + from PyQt4 import uic + from PyQt4.QtCore import Qt, QObject, pyqtSignal, pyqtSlot + from PyQt4.QtGui import QFont, QTextCursor, QFontMetrics, \ + QLabel, QWidget, QDialog, QLineEdit, QCheckBox, QPushButton, \ + QSizePolicy, QMainWindow, QMessageBox, QInputDialog, QTreeWidgetItem, QApplication, \ + QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QRadioButton, QVBoxLayout, QHBoxLayout, \ + QGridLayout, QScrollArea, QFrame + + def toHtmlEscaped(s): + return Qt.escape(s) diff --git a/secop/gui/util.py b/secop/gui/util.py index 1d86c9b..6abe134 100644 --- a/secop/gui/util.py +++ b/secop/gui/util.py @@ -23,7 +23,7 @@ from os import path -from PyQt4 import uic +from secop.gui.qt import uic uipath = path.dirname(__file__) diff --git a/secop/gui/valuewidgets.py b/secop/gui/valuewidgets.py index cb6fc1b..5c73f6c 100644 --- a/secop/gui/valuewidgets.py +++ b/secop/gui/valuewidgets.py @@ -21,11 +21,13 @@ # # ***************************************************************************** -from secop.datatypes import * +from __future__ import print_function -from PyQt4.QtGui import QDialog, QPushButton, QLabel, QApplication, QLineEdit,\ - QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QCheckBox, QRadioButton, \ - QVBoxLayout, QGridLayout, QScrollArea, QFrame +from secop.datatypes import * # pylint: disable=unused-wildcard-import,wildcard-import + +from secop.gui.qt import QDialog, QLabel, QLineEdit,\ + QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QCheckBox, \ + QVBoxLayout, QGridLayout, QFrame from secop.gui.util import loadUi @@ -48,8 +50,8 @@ class StringWidget(QLineEdit): class BlobWidget(StringWidget): - # XXX: make an editable hex-table ? - pass + # XXX: make an editable hex-table ? + pass # or derive from widget and switch between combobox and radiobuttons? class EnumWidget(QComboBox): @@ -126,7 +128,7 @@ class TupleWidget(QFrame): super(TupleWidget, self).__init__(parent) self.datatypes = datatype.subtypes - + self.layout = QVBoxLayout() self.subwidgets = [] for t in self.datatypes: @@ -142,20 +144,20 @@ class TupleWidget(QFrame): 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): + for w, _ 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] + dt = datatype.named_subtypes[name] w = get_widget(dt, readonly=readonly, parent=self) l = QLabel(name) self.layout.addWidget(l, idx, 0) @@ -178,15 +180,15 @@ class StructWidget(QGroupBox): 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): + for _ in range(datatype.maxsize): w = get_widget(self.datatype, readonly=readonly, parent=self) self.layout.addWidget(w) self.subwidgets.append(w) @@ -199,7 +201,7 @@ class ArrayWidget(QGroupBox): for w, v in zip(self.subwidgets, values): w.set_value(v) - + def get_widget(datatype, readonly=False, parent=None): return {FloatRange: FloatWidget, @@ -221,32 +223,15 @@ class msg(QDialog): 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); + 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.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) @@ -261,4 +246,3 @@ class msg(QDialog): def done(self, how): print('done(%r)' % how) return super(msg, self).done(how) -