From 9e6afffbec00c2be66d4e8627c1ab1f11ccdc623 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 3 Mar 2023 14:35:32 +0100 Subject: [PATCH] gui: move QSECNode to separate module Change-Id: Iaba98c6c74adec7c3de952cc703430c5756dfbe4 Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30569 Tested-by: Jenkins Automated Tests Reviewed-by: Georg Brandl --- frappy/gui/connection.py | 109 +++++++++++++++++++++++++++++++++++++++ frappy/gui/mainwindow.py | 98 ++++------------------------------- 2 files changed, 119 insertions(+), 88 deletions(-) create mode 100644 frappy/gui/connection.py diff --git a/frappy/gui/connection.py b/frappy/gui/connection.py new file mode 100644 index 00000000..df39c369 --- /dev/null +++ b/frappy/gui/connection.py @@ -0,0 +1,109 @@ +# -*- 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 +# +# ***************************************************************************** + +import frappy.client +from frappy.gui.qt import QObject, pyqtSignal +from frappy.gui.util import Value + + +class QSECNode(QObject): + 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, uri, parent_logger, parent=None): + super().__init__(parent) + self.log = parent_logger.getChild(uri) + self.conn = conn = frappy.client.SecopClient(uri, self.log) + conn.validate_data = True + self.contactPoint = conn.uri + conn.connect() + self.equipmentId = conn.properties['equipment_id'] + self.log.info('Switching to logger %s', self.equipmentId) + self.log.name = '.'.join((parent_logger.name, self.equipmentId)) + self.nodename = '%s (%s)' % (self.equipmentId, conn.uri) + self.modules = conn.modules + self.properties = self.conn.properties + self.protocolVersion = conn.secop_version + self.log.debug('SECoP Version: %s', conn.secop_version) + conn.register_callback(None, self.updateEvent, self.nodeStateChange, + self.unhandledMessage) + + # provide methods from old baseclient for making other gui code work + def reconnect(self): + if self.conn.online: + self.conn.disconnect(shutdown=False) + self.conn.connect() + + def getParameters(self, module): + return self.modules[module]['parameters'] + + def getCommands(self, module): + return self.modules[module]['commands'] + + def getModuleProperties(self, module): + return self.modules[module]['properties'] + + def getProperties(self, module, parameter): + 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): + # TODO: change the widgets for complex types to no longer use strings + datatype = self.conn.modules[module]['parameters'][parameter]['datatype'] + self.conn.setParameter(module, parameter, datatype.from_string(value)) + + def getParameter(self, module, parameter): + return self.conn.getParameter(module, parameter, True) + + def execCommand(self, module, command, argument): + return self.conn.execCommand(module, command, argument) + + 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) + # pylint: disable=not-an-iterable + return frappy.client.encode_msg_frame(*reply).decode('utf-8') + + def decode_message(self, msg): + # decode_msg needs bytes as input + return frappy.client.decode_msg(msg.encode('utf-8')) + + def _getDescribingParameterData(self, module, parameter): + # print(module, parameter, self.modules[module]['parameters']) + 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, action, specifier, data): + self.unhandledMsg.emit('%s %s %r' % (action, specifier, data)) diff --git a/frappy/gui/mainwindow.py b/frappy/gui/mainwindow.py index 1afc7449..5f3499b5 100644 --- a/frappy/gui/mainwindow.py +++ b/frappy/gui/mainwindow.py @@ -21,15 +21,15 @@ # # ***************************************************************************** -import frappy.client import frappy.version -from frappy.gui.qt import QInputDialog, QMainWindow, QMessageBox, QObject, \ +from frappy.gui.qt import QInputDialog, QMainWindow, QMessageBox, \ QTreeWidgetItem, pyqtSignal, pyqtSlot, QWidget, QSettings, QAction, \ QShortcut, QKeySequence -from frappy.gui.util import Value, Colors, loadUi +from frappy.gui.util import Colors, loadUi from frappy.gui.logwindow import LogWindow from frappy.gui.tabwidget import TearOffTabWidget from frappy.gui.nodewidget import NodeWidget +from frappy.gui.connection import QSECNode ITEM_TYPE_NODE = QTreeWidgetItem.UserType + 1 ITEM_TYPE_GROUP = QTreeWidgetItem.UserType + 2 @@ -37,91 +37,10 @@ ITEM_TYPE_MODULE = QTreeWidgetItem.UserType + 3 ITEM_TYPE_PARAMETER = QTreeWidgetItem.UserType + 4 -class QSECNode(QObject): - 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, uri, parent_logger, parent=None): - super().__init__(parent) - self.log = parent_logger.getChild(uri) - self.conn = conn = frappy.client.SecopClient(uri, self.log) - conn.validate_data = True - self.contactPoint = conn.uri - conn.connect() - self.equipmentId = conn.properties['equipment_id'] - self.log.info('Switching to logger %s', self.equipmentId) - self.log.name = '.'.join((parent_logger.name, self.equipmentId)) - self.nodename = '%s (%s)' % (self.equipmentId, conn.uri) - self.modules = conn.modules - self.properties = self.conn.properties - self.protocolVersion = conn.secop_version - self.log.debug('SECoP Version: %s', conn.secop_version) - conn.register_callback(None, self.updateEvent, self.nodeStateChange, self.unhandledMessage) - - # provide methods from old baseclient for making other gui code work - def reconnect(self): - if self.conn.online: - self.conn.disconnect(shutdown=False) - self.conn.connect() - - def getParameters(self, module): - return self.modules[module]['parameters'] - - def getCommands(self, module): - return self.modules[module]['commands'] - - def getModuleProperties(self, module): - return self.modules[module]['properties'] - - def getProperties(self, module, parameter): - 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): - # TODO: change the widgets for complex types to no longer use strings - datatype = self.conn.modules[module]['parameters'][parameter]['datatype'] - self.conn.setParameter(module, parameter, datatype.from_string(value)) - - def getParameter(self, module, parameter): - return self.conn.getParameter(module, parameter, True) - - def execCommand(self, module, command, argument): - return self.conn.execCommand(module, command, argument) - - 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) - # pylint: disable=not-an-iterable - return frappy.client.encode_msg_frame(*reply).decode('utf-8') - - def decode_message(self, msg): - # decode_msg needs bytes as input - return frappy.client.decode_msg(msg.encode('utf-8')) - - def _getDescribingParameterData(self, module, parameter): - #print(module, parameter, self.modules[module]['parameters']) - 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, action, specifier, data): - self.unhandledMsg.emit('%s %s %r' % (action, specifier, data)) - - class Greeter(QWidget): recentClearBtn = pyqtSignal() addnodes = pyqtSignal(list) + def __init__(self, parent=None): super().__init__(parent) loadUi(self, 'greeter.ui') @@ -152,6 +71,7 @@ class Greeter(QWidget): class MainWindow(QMainWindow): recentNodesChanged = pyqtSignal() + def __init__(self, hosts, logger, parent=None): super().__init__(parent) @@ -170,7 +90,8 @@ class MainWindow(QMainWindow): self.tab = TearOffTabWidget(self, self, self, self) self.tab.setTabsClosable(True) self.tab.tabCloseRequested.connect(self._handleTabClose) - self.shortcut = QShortcut(QKeySequence("Ctrl+W"), self, self.tab.close_current) + self.shortcut = QShortcut(QKeySequence("Ctrl+W"), self, + self.tab.close_current) self.setCentralWidget(self.tab) self._nodes = {} @@ -219,8 +140,9 @@ class MainWindow(QMainWindow): @pyqtSlot() def on_actionAdd_SEC_node_triggered(self): - host, ok = QInputDialog.getText(self, 'Add SEC node', - 'Enter SEC node URI (or just hostname:port):') + host, ok = QInputDialog.getText( + self, 'Add SEC node', + 'Enter SEC node URI (or just hostname:port):') if not ok: return