def __init__(self): QMainWindow.__init__(self) self.ui = Ui_UaModeler() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaModeler") self.settings = QSettings() self._restore_ui_geometri() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.refs_ui.reference_changed.connect( self.tree_ui.reload_current ) # FIXME: shoudl reload a specific node self.attrs_ui = AttrsWidget(self.ui.attrView, show_timestamps=False) self.attrs_ui.error.connect(self.show_error) self.idx_ui = NamespaceWidget(self.ui.namespaceView) self.nodesets_ui = RefNodeSetsWidget(self.ui.refNodeSetsView) self.nodesets_ui.error.connect(self.show_error) self.nodesets_ui.nodeset_added.connect(self.nodesets_change) self.nodesets_ui.nodeset_removed.connect(self.nodesets_change) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.model_mgr = ModelManagerUI(self) self.model_mgr.error.connect(self.show_error) self.model_mgr.titleChanged.connect(self.update_title) self.actions = ActionsManager(self.ui, self.model_mgr) self.setup_context_menu_tree() delegate = BoldDelegate(self, self.tree_ui.model, self.model_mgr.get_new_nodes()) self.ui.treeView.setItemDelegate(delegate) self.ui.treeView.selectionModel().currentChanged.connect( self._update_actions_state) self._recent_files = self.settings.value("recent_files", []) self._recent_files_max_count = int( self.settings.value("recent_files_max_count", 10)) self._recent_files_acts = [ QAction(self, visible=False, triggered=self.open_recent_files) for _ in range(self._recent_files_max_count) ] for act in self._recent_files_acts: self.ui.menuRecentFiles.addAction(act) self._update_recent_files_ui()
def __init__(self, view): self.ui = view self.client = None self._connected = False self.address_list = ["opc.tcp://10.42.0.2:4840/OPCUAproject"] self.security_mode = None self.security_policy = None self.certificate_path = None self.private_key_path = None self.ui.closeEvent = self.closeEvent for addr in self.address_list: self.ui.addressComboBox.addItem(addr) self.tree_ui = TreeWidget(self.ui.treeView) self.attrs_ui = AttrsWidget(self.ui.attrView) #self.refs_ui = RefsWidget(self.ui.refView) self.subscription_window = SubscriptionWindow() self.log_window = LogWindow() self.datachange_ui = DataChangeUI(self, self.subscription_window) #self.ui.treeView.selectionModel().selectionChanged.connect(lambda sel: self.show_refs(sel)) self.ui.treeView.selectionModel().selectionChanged.connect( lambda sel: self.show_attrs(sel)) # self.ui.endpointsButton.clicked.connect(lambda : self.get_endpoints()) # self.ui.connSettingsButton.clicked.connect(lambda : self.show_connection_dialog()) # self.ui.connectButton.clicked.connect(lambda : self.connect()) # self.ui.disconnectButton.clicked.connect(lambda: self.disconnect()) # self.ui.readButton.clicked.connect(lambda : self.read_value()) # self.ui.writeButton.clicked.connect(lambda : self.show_write_dialog()) # self.ui.showReferencesButton.clicked.connect(lambda : self.show_refs_dialog()) # self.ui.showSubscriptionsButton.clicked.connect(lambda : self.show_subs_dialog()) # self.ui.showLogsButton.clicked.connect(lambda : self.show_logs_dialog()) self.ui.actionQuery_endpoints.triggered.connect( lambda: self.get_endpoints()) self.ui.actionConnection_settings.triggered.connect( lambda: self.show_connection_dialog()) self.ui.actionConnect.triggered.connect(lambda: self.connect()) self.ui.actionDisconnect.triggered.connect(lambda: self.disconnect()) self.ui.actionRead.triggered.connect(lambda: self.read_value()) self.ui.actionWrite.triggered.connect(lambda: self.show_write_dialog()) self.ui.actionReferences.triggered.connect( lambda: self.show_refs_dialog()) self.ui.actionSubscriptions.triggered.connect( lambda: self.show_subs_dialog()) self.ui.actionLogs.triggered.connect(lambda: self.show_logs_dialog())
def __init__(self): QMainWindow.__init__(self) self.ui = Ui_UaModeler() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaModeler") self.settings = QSettings() self._restore_ui_geometri() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView, show_timestamps=False) self.attrs_ui.error.connect(self.show_error) self.idx_ui = NamespaceWidget(self.ui.namespaceView) self.nodesets_ui = RefNodeSetsWidget(self.ui.refNodeSetsView) self.nodesets_ui.error.connect(self.show_error) self.nodesets_ui.nodeset_added.connect(self.nodesets_change) self.nodesets_ui.nodeset_removed.connect(self.nodesets_change) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.model_mgr = ModelManagerUI(self) self.model_mgr.error.connect(self.show_error) self.actions = ActionsManager(self.ui, self.model_mgr) self.setup_context_menu_tree() delegate = BoldDelegate(self, self.tree_ui.model, self.model_mgr.get_new_nodes()) self.ui.treeView.setItemDelegate(delegate) self.ui.treeView.selectionModel().currentChanged.connect( self._update_actions_state)
def __init__(self): QMainWindow.__init__(self) self.ui = Ui_UaModeler() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaModeler") self.settings = QSettings() self._restore_ui_geometri() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.refs_ui.reference_changed.connect(self.tree_ui.reload_current) # FIXME: shoudl reload a specific node self.attrs_ui = AttrsWidget(self.ui.attrView, show_timestamps=False) self.attrs_ui.error.connect(self.show_error) self.idx_ui = NamespaceWidget(self.ui.namespaceView) self.nodesets_ui = RefNodeSetsWidget(self.ui.refNodeSetsView) self.nodesets_ui.error.connect(self.show_error) self.nodesets_ui.nodeset_added.connect(self.nodesets_change) self.nodesets_ui.nodeset_removed.connect(self.nodesets_change) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.model_mgr = ModelManagerUI(self) self.model_mgr.error.connect(self.show_error) self.model_mgr.titleChanged.connect(self.update_title) self.actions = ActionsManager(self.ui, self.model_mgr) self.setup_context_menu_tree() delegate = BoldDelegate(self, self.tree_ui.model, self.model_mgr.get_new_nodes()) self.ui.treeView.setItemDelegate(delegate) self.ui.treeView.selectionModel().currentChanged.connect(self._update_actions_state) self._recent_files = self.settings.value("recent_files", []) self._recent_files_max_count = int(self.settings.value("recent_files_max_count", 10)) self._recent_files_acts = [QAction(self, visible=False, triggered=self.open_recent_files) for _ in range(self._recent_files_max_count)] for act in self._recent_files_acts: self.ui.menuRecentFiles.addAction(act) self._update_recent_files_ui()
class TestAttrsWidget(unittest.TestCase): def setUp(self): self.server = Server() self.server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/") self.server.start() self.widget = AttrsWidget(QTreeView()) def tearDown(self): self.server.stop() def find_item(self, text): idxlist = self.widget.model.match(self.widget.model.index(0, 0), Qt.DisplayRole, text, 1, Qt.MatchExactly | Qt.MatchRecursive) idx = idxlist[0] return idx def modify_item(self, text, val, match_to_use=0): """ modify the current item and set its displayed value to 'val' """ idxlist = self.widget.model.match(self.widget.model.index(0, 0), Qt.DisplayRole, text, match_to_use + 1, Qt.MatchExactly | Qt.MatchRecursive) if not idxlist: raise RuntimeError("Item with text '{}' not found".format(text)) idx = idxlist[match_to_use] self.widget.view.setCurrentIndex(idx) idx = idx.sibling(idx.row(), 1) self.widget.view.edit(idx) editor = self.widget.view.focusWidget() if not editor: print(app.focusWidget()) print("NO EDITOR WIDGET") #QTest.keyClick(self.widget.view, Qt.Key_Return) from IPython import embed embed() raise RuntimeError( "Could not get editor widget!, it does not have the focus") if hasattr(editor, "current_node"): editor.current_node = val elif hasattr(editor, "setCurrentText"): editor.setCurrentText(val) else: editor.setText(val) self.widget.view.commitData(editor) self.widget.view.closeEditor(editor, QAbstractItemDelegate.NoHint) self.widget.view.reset() def modify_value(self, val): self.modify_item("Value", val, 1) def test_display_objects_node(self): objects = self.server.nodes.objects self.widget.show_attrs(objects) self.modify_item("BrowseName", "5:titi") self.assertEqual(objects.get_browse_name().to_string(), "5:titi") self.modify_item("BrowseName", "0:Objects") # restore states for other tests def test_display_var_double(self): objects = self.server.nodes.objects myvar = objects.add_variable(1, "myvar1", 9.99, ua.VariantType.Double) self.widget.show_attrs(myvar) self.modify_value("8.45") self.assertEqual(myvar.get_value(), 8.45) def test_display_var_bytes(self): objects = self.server.nodes.objects myvar = objects.add_variable(1, "myvar_bytes", b"jkl", ua.VariantType.ByteString) self.widget.show_attrs(myvar) self.modify_value("titi") self.assertEqual(myvar.get_value(), b"titi") def test_change_data_type(self): objects = self.server.nodes.objects myvar = objects.add_variable(1, "myvar1", 9.99, ua.VariantType.Double) self.widget.show_attrs(myvar) dtype = myvar.get_data_type() self.assertEqual(dtype, ua.NodeId(ua.ObjectIds.Double)) new_dtype = ua.NodeId(ua.ObjectIds.String) self.modify_item("DataType", self.server.get_node(new_dtype)) self.assertEqual(myvar.get_data_type(), new_dtype) # now try to write a value which is a string self.modify_value("mystring") self.assertEqual(myvar.get_value(), "mystring") def test_change_value_rank( self): # need to find a way to modify combo box with QTest objects = self.server.nodes.objects myvar = objects.add_variable(1, "myvar1", 9.99, ua.VariantType.Double) self.widget.show_attrs(myvar) rank = myvar.get_value_rank() self.modify_item("ValueRank", "ThreeDimensions") self.assertEqual(myvar.get_value_rank(), ua.ValueRank.ThreeDimensions)
def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # fix stuff imposible to do in qtdesigner # remove dock titlebar for addressbar w = QWidget() self.ui.addrDockWidget.setTitleBarWidget(w) # tabify some docks self.tabifyDockWidget(self.ui.evDockWidget, self.ui.subDockWidget) self.tabifyDockWidget(self.ui.subDockWidget, self.ui.refDockWidget) # we only show statusbar in case of errors self.ui.statusBar.hide() # load settings, seconds arg is default self.settings = QSettings("FreeOpcUa", "FreeOpcUaClient") self._address_list = self.settings.value("address_list", ["opc.tcp://localhost:4840", "opc.tcp://localhost:53530/OPCUA/SimulationServer/"]) self._address_list_max_count = int(self.settings.value("address_list_max_count", 10)) # init widgets for addr in self._address_list: self.ui.addrComboBox.insertItem(-1, addr) self.uaclient = UaClient() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.datachange_ui = DataChangeUI(self, self.uaclient) self.event_ui = EventUI(self, self.uaclient) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.actionCopyPath.triggered.connect(self.tree_ui.copy_path) self.ui.actionCopyNodeId.triggered.connect(self.tree_ui.copy_nodeid) # add items to context menu self.ui.treeView.addAction(self.ui.actionCopyPath) self.ui.treeView.addAction(self.ui.actionCopyNodeId) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.ui.attrRefreshButton.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) self.restoreState(self.settings.value("main_window_state", b"", type="QByteArray")) self.ui.connectButton.clicked.connect(self._connect) self.ui.disconnectButton.clicked.connect(self._disconnect) # self.ui.treeView.expanded.connect(self._fit) self.ui.actionConnect.triggered.connect(self._connect) self.ui.actionDisconnect.triggered.connect(self._disconnect) self.ui.modeComboBox.addItem("None") self.ui.modeComboBox.addItem("Sign") self.ui.modeComboBox.addItem("SignAndEncrypt") self.ui.policyComboBox.addItem("None") self.ui.policyComboBox.addItem("Basic128RSA15") self.ui.policyComboBox.addItem("Basic256") self.ui.policyComboBox.addItem("Basic256SHA256")
class Window(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # fix stuff imposible to do in qtdesigner # remove dock titlebar for addressbar w = QWidget() self.ui.addrDockWidget.setTitleBarWidget(w) # tabify some docks self.tabifyDockWidget(self.ui.evDockWidget, self.ui.subDockWidget) self.tabifyDockWidget(self.ui.subDockWidget, self.ui.refDockWidget) # we only show statusbar in case of errors self.ui.statusBar.hide() # load settings, seconds arg is default self.settings = QSettings("FreeOpcUa", "FreeOpcUaClient") self._address_list = self.settings.value("address_list", ["opc.tcp://localhost:4840", "opc.tcp://localhost:53530/OPCUA/SimulationServer/"]) self._address_list_max_count = int(self.settings.value("address_list_max_count", 10)) # init widgets for addr in self._address_list: self.ui.addrComboBox.insertItem(-1, addr) self.uaclient = UaClient() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.datachange_ui = DataChangeUI(self, self.uaclient) self.event_ui = EventUI(self, self.uaclient) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.actionCopyPath.triggered.connect(self.tree_ui.copy_path) self.ui.actionCopyNodeId.triggered.connect(self.tree_ui.copy_nodeid) # add items to context menu self.ui.treeView.addAction(self.ui.actionCopyPath) self.ui.treeView.addAction(self.ui.actionCopyNodeId) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.ui.attrRefreshButton.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) self.restoreState(self.settings.value("main_window_state", b"", type="QByteArray")) self.ui.connectButton.clicked.connect(self._connect) self.ui.disconnectButton.clicked.connect(self._disconnect) # self.ui.treeView.expanded.connect(self._fit) self.ui.actionConnect.triggered.connect(self._connect) self.ui.actionDisconnect.triggered.connect(self._disconnect) self.ui.modeComboBox.addItem("None") self.ui.modeComboBox.addItem("Sign") self.ui.modeComboBox.addItem("SignAndEncrypt") self.ui.policyComboBox.addItem("None") self.ui.policyComboBox.addItem("Basic128RSA15") self.ui.policyComboBox.addItem("Basic256") self.ui.policyComboBox.addItem("Basic256SHA256") def show_refs(self, idx): node = self.get_current_node(idx) if node: self.refs_ui.show_refs(node) def show_attrs(self, idx): if not isinstance(idx, QModelIndex): idx = None node = self.get_current_node(idx) if node: self.attrs_ui.show_attrs(node) def show_error(self, msg, level=1): print("showing error: ", msg, level) self.ui.statusBar.show() self.ui.statusBar.setStyleSheet("QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def get_uaclient(self): return self.uaclient def _connect(self): uri = self.ui.addrComboBox.currentText() try: self.uaclient.connect(uri) except Exception as ex: self.show_error(ex) raise self._update_address_list(uri) self.tree_ui.set_root_node(self.uaclient.client.get_root_node()) def _update_address_list(self, uri): if uri == self._address_list[0]: return if uri in self._address_list: self._address_list.remove(uri) self._address_list.insert(0, uri) if len(self._address_list) > self._address_list_max_count: self._address_list.pop(-1) def _disconnect(self): try: self.uaclient.disconnect() except Exception as ex: self.show_error(ex) raise finally: self.tree_ui.clear() self.refs_ui.clear() self.attrs_ui.clear() self.datachange_ui.clear() self.event_ui.clear() def closeEvent(self, event): self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("address_list", self._address_list) self._disconnect() event.accept()
class UaModeler(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_UaModeler() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # we only show statusbar in case of errors self.ui.statusBar.hide() # load settings, seconds arg is default self.settings = QSettings("FreeOpcUa", "OpcUaModeler") self.server = Server() self.server.set_endpoint( "opc.tcp://0.0.0.0:48400/freeopcua/uamodeler/") self.server.set_server_name("OpcUa Modeler Server") self._new_nodes = [] # the added nodes we will save self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.idx_ui = NamespaceWidget(self.ui.namespaceView) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) #self.restoreState(self.settings.value("main_window_state", b"", type="QByteArray")) self.restoreState(self.settings.value("main_window_state", b"")) self.ui.splitterLeft.restoreState( self.settings.value("splitter_left", b"")) self.ui.splitterRight.restoreState( self.settings.value("splitter_right", b"")) self.ui.splitterCenter.restoreState( self.settings.value("splitter_center", b"")) self.server.start() self.tree_ui.set_root_node(self.server.get_root_node()) self.idx_ui.set_node( self.server.get_node(ua.ObjectIds.Server_NamespaceArray)) # fix icon stuff self.ui.actionAddFolder.setIcon(QIcon(":/folder.svg")) self.ui.actionAddObject.setIcon(QIcon(":/object.svg")) self.ui.actionAddObjectType.setIcon(QIcon(":/object_type.svg")) self.ui.actionAddProperty.setIcon(QIcon(":/property.svg")) self.ui.actionAddVariable.setIcon(QIcon(":/variable.svg")) self.ui.actionAddVariableType.setIcon(QIcon(":/variable_type.svg")) # menu self.ui.treeView.addAction(self.ui.actionAddFolder) self.ui.treeView.addAction(self.ui.actionAddObject) self.ui.treeView.addAction(self.ui.actionAddVariable) self.ui.treeView.addAction(self.ui.actionAddProperty) self.ui.treeView.addAction(self.ui.actionAddObjectType) self.ui.treeView.addAction(self.ui.actionAddVariableType) self.ui.treeView.addAction(self.ui.actionAddDataType) # actions self.ui.actionOpen.triggered.connect(self._open) self.ui.actionSave.triggered.connect(self._save) self.ui.actionAddObjectType.triggered.connect(self._add_object_type) self.ui.actionAddObject.triggered.connect(self._add_object) self.ui.actionAddDataType.triggered.connect(self._add_data_type) self.ui.actionAddVariable.triggered.connect(self._add_variable) self.ui.actionAddProperty.triggered.connect(self._add_property) def _open(self): path = QFileDialog.getOpenFileName(self) f = open(path[0], 'r') xml = f.read() print("should read", xml) def _save(self): raise NotImplementedError def _add_node(self, func_name, node_type=None, default_value=None): node = self.tree_ui.get_current_node() if not node: self.show_error("No node selected") raise RuntimeError("No node selected") args, ok = NewNodeDialog.getArgs(self, func_name, self.server, node_type=node_type, default_value=default_value) print("ARGS are", args) if ok: new_node = getattr(node, func_name)(*args) self._new_nodes.append(new_node) self.tree_ui.reload_current() self.show_refs() def _add_object_type(self): return self._add_node("add_object_type") def _add_object(self): return self._add_node("add_object", node_type=self.server.get_node( ua.ObjectIds.BaseObjectType)) def _add_data_type(self): return self._add_node("add_data_type") def _add_variable(self): return self._add_node("add_variable", default_value=9.99) def _add_property(self): return self._add_node("add_property", default_value=1.11) def show_refs(self, idx=None): node = self.get_current_node(idx) if node: self.refs_ui.show_refs(node) def show_attrs(self, idx=None): if not isinstance(idx, QModelIndex): idx = None node = self.get_current_node(idx) if node: self.attrs_ui.show_attrs(node) def show_error(self, msg, level=1): print("showing error: ", msg, level) self.ui.statusBar.show() self.ui.statusBar.setStyleSheet( "QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def closeEvent(self, event): self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("splitter_left", self.ui.splitterLeft.saveState()) self.settings.setValue("splitter_right", self.ui.splitterRight.saveState()) self.settings.setValue("splitter_center", self.ui.splitterCenter.saveState()) self.server.stop() event.accept()
class Window(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # fix stuff imposible to do in qtdesigner # remove dock titlebar for addressbar w = QWidget() self.ui.addrDockWidget.setTitleBarWidget(w) # tabify some docks self.tabifyDockWidget(self.ui.evDockWidget, self.ui.subDockWidget) self.tabifyDockWidget(self.ui.subDockWidget, self.ui.refDockWidget) self.tabifyDockWidget(self.ui.refDockWidget, self.ui.graphDockWidget) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaClient") self.settings = QSettings() self._address_list = self.settings.value("address_list", [ "opc.tcp://localhost:4840", "opc.tcp://localhost:53530/OPCUA/SimulationServer/" ]) self._address_list_max_count = int( self.settings.value("address_list_max_count", 10)) # init widgets for addr in self._address_list: self.ui.addrComboBox.insertItem(-1, addr) self.uaclient = UaClient() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.setup_context_menu_tree() self.ui.treeView.selectionModel().currentChanged.connect( self._update_actions_state) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.datachange_ui = DataChangeUI(self, self.uaclient) self.event_ui = EventUI(self, self.uaclient) self.graph_ui = GraphUI(self, self.uaclient) self.ui.addrComboBox.currentTextChanged.connect(self._uri_changed) self._uri_changed(self.ui.addrComboBox.currentText() ) # force update for current value at startup self.ui.treeView.selectionModel().selectionChanged.connect( self.show_refs) self.ui.actionCopyPath.triggered.connect(self.tree_ui.copy_path) self.ui.actionCopyNodeId.triggered.connect(self.tree_ui.copy_nodeid) self.ui.actionCall.triggered.connect(self.call_method) self.ui.treeView.selectionModel().selectionChanged.connect( self.show_attrs) self.ui.attrRefreshButton.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) data = self.settings.value("main_window_state", None) if data: self.restoreState(data) self.ui.connectButton.clicked.connect(self.connect) self.ui.disconnectButton.clicked.connect(self.disconnect) # self.ui.treeView.expanded.connect(self._fit) self.ui.actionConnect.triggered.connect(self.connect) self.ui.actionDisconnect.triggered.connect(self.disconnect) self.ui.connectOptionButton.clicked.connect( self.show_connection_dialog) def _uri_changed(self, uri): self.uaclient.load_security_settings(uri) def show_connection_dialog(self): dia = ConnectionDialog(self, self.ui.addrComboBox.currentText()) dia.security_mode = self.uaclient.security_mode dia.security_policy = self.uaclient.security_policy dia.certificate_path = self.uaclient.certificate_path dia.private_key_path = self.uaclient.private_key_path ret = dia.exec_() if ret: self.uaclient.security_mode = dia.security_mode self.uaclient.security_policy = dia.security_policy self.uaclient.certificate_path = dia.certificate_path self.uaclient.private_key_path = dia.private_key_path @trycatchslot def show_refs(self, selection): if isinstance(selection, QItemSelection): if not selection.indexes(): # no selection return node = self.get_current_node() if node: self.refs_ui.show_refs(node) @trycatchslot def show_attrs(self, selection): if isinstance(selection, QItemSelection): if not selection.indexes(): # no selection return node = self.get_current_node() if node: self.attrs_ui.show_attrs(node) def show_error(self, msg): logger.warning("showing error: %s") self.ui.statusBar.show() self.ui.statusBar.setStyleSheet( "QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def get_uaclient(self): return self.uaclient @trycatchslot def connect(self): uri = self.ui.addrComboBox.currentText() try: self.uaclient.connect(uri) except Exception as ex: self.show_error(ex) raise self._update_address_list(uri) self.tree_ui.set_root_node(self.uaclient.client.get_root_node()) self.ui.treeView.setFocus() self.load_current_node() def _update_address_list(self, uri): if uri == self._address_list[0]: return if uri in self._address_list: self._address_list.remove(uri) self._address_list.insert(0, uri) if len(self._address_list) > self._address_list_max_count: self._address_list.pop(-1) def disconnect(self): try: self.uaclient.disconnect() except Exception as ex: self.show_error(ex) raise finally: self.save_current_node() self.tree_ui.clear() self.refs_ui.clear() self.attrs_ui.clear() self.datachange_ui.clear() self.event_ui.clear() def closeEvent(self, event): self.tree_ui.save_state() self.attrs_ui.save_state() self.refs_ui.save_state() self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("address_list", self._address_list) self.disconnect() event.accept() def save_current_node(self): current_node = self.tree_ui.get_current_node() if current_node: mysettings = self.settings.value("current_node", None) if mysettings is None: mysettings = {} uri = self.ui.addrComboBox.currentText() mysettings[uri] = current_node.nodeid.to_string() self.settings.setValue("current_node", mysettings) def load_current_node(self): mysettings = self.settings.value("current_node", None) if mysettings is None: return uri = self.ui.addrComboBox.currentText() if uri in mysettings: nodeid = ua.NodeId.from_string(mysettings[uri]) node = self.uaclient.client.get_node(nodeid) self.tree_ui.expand_to_node(node) def setup_context_menu_tree(self): self.ui.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.treeView.customContextMenuRequested.connect( self._show_context_menu_tree) self._contextMenu = QMenu() self.addAction(self.ui.actionCopyPath) self.addAction(self.ui.actionCopyNodeId) self._contextMenu.addSeparator() self._contextMenu.addAction(self.ui.actionCall) self._contextMenu.addSeparator() def addAction(self, action): self._contextMenu.addAction(action) @trycatchslot def _update_actions_state(self, current, previous): node = self.get_current_node(current) self.ui.actionCall.setEnabled(False) if node: if node.get_node_class() == ua.NodeClass.Method: self.ui.actionCall.setEnabled(True) def _show_context_menu_tree(self, position): node = self.tree_ui.get_current_node() if node: self._contextMenu.exec_( self.ui.treeView.viewport().mapToGlobal(position)) def call_method(self): node = self.get_current_node() dia = CallMethodDialog(self, self.uaclient.client, node) dia.show()
def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # fix stuff imposible to do in qtdesigner # remove dock titlebar for addressbar w = QWidget() self.ui.addrDockWidget.setTitleBarWidget(w) # tabify some docks self.tabifyDockWidget(self.ui.evDockWidget, self.ui.subDockWidget) self.tabifyDockWidget(self.ui.subDockWidget, self.ui.refDockWidget) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaClient") self.settings = QSettings() self._address_list = self.settings.value("address_list", ["opc.tcp://localhost:4840", "opc.tcp://localhost:53530/OPCUA/SimulationServer/"]) self._address_list_max_count = int(self.settings.value("address_list_max_count", 10)) # init widgets for addr in self._address_list: self.ui.addrComboBox.insertItem(-1, addr) self.uaclient = UaClient() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.datachange_ui = DataChangeUI(self, self.uaclient) self.event_ui = EventUI(self, self.uaclient) self.ui.addrComboBox.currentTextChanged.connect(self._uri_changed) self._uri_changed(self.ui.addrComboBox.currentText()) # force update for current value at startup self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.actionCopyPath.triggered.connect(self.tree_ui.copy_path) self.ui.actionCopyNodeId.triggered.connect(self.tree_ui.copy_nodeid) # add items to context menu self.ui.treeView.addAction(self.ui.actionCopyPath) self.ui.treeView.addAction(self.ui.actionCopyNodeId) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.ui.attrRefreshButton.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) data = self.settings.value("main_window_state", None) if data: self.restoreState(data) self.ui.connectButton.clicked.connect(self.connect) self.ui.disconnectButton.clicked.connect(self.disconnect) # self.ui.treeView.expanded.connect(self._fit) self.ui.actionConnect.triggered.connect(self.connect) self.ui.actionDisconnect.triggered.connect(self.disconnect) self.ui.connectOptionButton.clicked.connect(self.show_connection_dialog)
class Window(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # fix stuff imposible to do in qtdesigner # remove dock titlebar for addressbar w = QWidget() self.ui.addrDockWidget.setTitleBarWidget(w) # tabify some docks self.tabifyDockWidget(self.ui.evDockWidget, self.ui.subDockWidget) self.tabifyDockWidget(self.ui.subDockWidget, self.ui.refDockWidget) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaClient") self.settings = QSettings() self._address_list = self.settings.value("address_list", ["opc.tcp://localhost:4840", "opc.tcp://localhost:53530/OPCUA/SimulationServer/"]) self._address_list_max_count = int(self.settings.value("address_list_max_count", 10)) # init widgets for addr in self._address_list: self.ui.addrComboBox.insertItem(-1, addr) self.uaclient = UaClient() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.datachange_ui = DataChangeUI(self, self.uaclient) self.event_ui = EventUI(self, self.uaclient) self.ui.addrComboBox.currentTextChanged.connect(self._uri_changed) self._uri_changed(self.ui.addrComboBox.currentText()) # force update for current value at startup self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.actionCopyPath.triggered.connect(self.tree_ui.copy_path) self.ui.actionCopyNodeId.triggered.connect(self.tree_ui.copy_nodeid) # add items to context menu self.ui.treeView.addAction(self.ui.actionCopyPath) self.ui.treeView.addAction(self.ui.actionCopyNodeId) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.ui.attrRefreshButton.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) data = self.settings.value("main_window_state", None) if data: self.restoreState(data) self.ui.connectButton.clicked.connect(self.connect) self.ui.disconnectButton.clicked.connect(self.disconnect) # self.ui.treeView.expanded.connect(self._fit) self.ui.actionConnect.triggered.connect(self.connect) self.ui.actionDisconnect.triggered.connect(self.disconnect) self.ui.connectOptionButton.clicked.connect(self.show_connection_dialog) def _uri_changed(self, uri): self.uaclient.load_security_settings(uri) def show_connection_dialog(self): dia = ConnectionDialog(self, self.ui.addrComboBox.currentText()) dia.security_mode = self.uaclient.security_mode dia.security_policy = self.uaclient.security_policy dia.certificate_path = self.uaclient.certificate_path dia.private_key_path = self.uaclient.private_key_path ret = dia.exec_() if ret: self.uaclient.security_mode = dia.security_mode self.uaclient.security_policy = dia.security_policy self.uaclient.certificate_path = dia.certificate_path self.uaclient.private_key_path = dia.private_key_path @trycatchslot def show_refs(self, idx): node = self.get_current_node(idx) if node: self.refs_ui.show_refs(node) @trycatchslot def show_attrs(self, idx): if not isinstance(idx, QModelIndex): idx = None node = self.get_current_node(idx) if node: self.attrs_ui.show_attrs(node) def show_error(self, msg): logger.warning("showing error: %s") self.ui.statusBar.show() self.ui.statusBar.setStyleSheet("QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def get_uaclient(self): return self.uaclient @trycatchslot def connect(self): uri = self.ui.addrComboBox.currentText() try: self.uaclient.connect(uri) except Exception as ex: self.show_error(ex) raise self._update_address_list(uri) self.tree_ui.set_root_node(self.uaclient.client.get_root_node()) def _update_address_list(self, uri): if uri == self._address_list[0]: return if uri in self._address_list: self._address_list.remove(uri) self._address_list.insert(0, uri) if len(self._address_list) > self._address_list_max_count: self._address_list.pop(-1) def disconnect(self): try: self.uaclient.disconnect() except Exception as ex: self.show_error(ex) raise finally: self.tree_ui.clear() self.refs_ui.clear() self.attrs_ui.clear() self.datachange_ui.clear() self.event_ui.clear() def closeEvent(self, event): self.attrs_ui.save_state() self.refs_ui.save_state() self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("address_list", self._address_list) self.disconnect() event.accept()
def setUp(self): self.server = Server() self.server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/") self.server.start() self.widget = AttrsWidget(QTreeView())
class TestAttrsWidget(unittest.TestCase): def setUp(self): self.server = Server() self.server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/") self.server.start() self.widget = AttrsWidget(QTreeView()) def tearDown(self): self.server.stop() def find_item(self, text): idxlist = self.widget.model.match(self.widget.model.index(0, 0), Qt.DisplayRole, text, 1, Qt.MatchExactly | Qt.MatchRecursive) idx = idxlist[0] return idx def modify_item(self, text, val, match_to_use=0): """ modify the current item and set its displayed value to 'val' """ idxlist = self.widget.model.match(self.widget.model.index(0, 0), Qt.DisplayRole, text, match_to_use + 1, Qt.MatchExactly | Qt.MatchRecursive) if not idxlist: raise RuntimeError("Item with text '{}' not found".format(text)) idx = idxlist[match_to_use] self.widget.view.setCurrentIndex(idx) idx = idx.sibling(idx.row(), 1) self.widget.view.edit(idx) editor = self.widget.view.focusWidget() if not editor: print(app.focusWidget()) print("NO EDITOR WIDGET") #QTest.keyClick(self.widget.view, Qt.Key_Return) from IPython import embed embed() raise RuntimeError("Could not get editor widget!, it does not have the focus") if hasattr(editor, "_current_node"): editor._current_node = val elif hasattr(editor, "setCurrentText"): editor.setCurrentText(val) else: editor.setText(val) self.widget.view.commitData(editor) self.widget.view.closeEditor(editor, QAbstractItemDelegate.NoHint) self.widget.view.reset() def modify_value(self, val): self.modify_item("Value", val, 1) def test_display_objects_node(self): objects = self.server.nodes.objects self.widget.show_attrs(objects) self.modify_item("BrowseName", "5:titi") self.assertEqual(objects.get_browse_name().to_string(), "5:titi") self.modify_item("BrowseName", "0:Objects") # restore states for other tests def test_display_var_double(self): objects = self.server.nodes.objects myvar = objects.add_variable(1, "myvar1", 9.99, ua.VariantType.Double) self.widget.show_attrs(myvar) self.modify_value("8.45") self.assertEqual(myvar.get_value(), 8.45) def test_display_var_bytes(self): objects = self.server.nodes.objects myvar = objects.add_variable(1, "myvar_bytes", b"jkl", ua.VariantType.ByteString) self.widget.show_attrs(myvar) self.modify_value("titi") self.assertEqual(myvar.get_value(), b"titi") def test_change_data_type(self): objects = self.server.nodes.objects myvar = objects.add_variable(1, "myvar1", 9.99, ua.VariantType.Double) self.widget.show_attrs(myvar) dtype = myvar.get_data_type() self.assertEqual(dtype, ua.NodeId(ua.ObjectIds.Double)) new_dtype = ua.NodeId(ua.ObjectIds.String) self.modify_item("DataType", self.server.get_node(new_dtype)) self.assertEqual(myvar.get_data_type(), new_dtype) # now try to write a value which is a string self.modify_value("mystring") self.assertEqual(myvar.get_value(), "mystring") def test_change_value_rank(self): # need to find a way to modify combo box with QTest objects = self.server.nodes.objects myvar = objects.add_variable(1, "myvar1", 9.99, ua.VariantType.Double) self.widget.show_attrs(myvar) rank = myvar.get_value_rank() self.modify_item("ValueRank", "ThreeDimensions") self.assertEqual(myvar.get_value_rank(), ua.ValueRank.ThreeDimensions)
def __init__(self): QMainWindow.__init__(self) self.ui = Ui_UaModeler() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # we only show statusbar in case of errors self.ui.statusBar.hide() # load settings, seconds arg is default self.settings = QSettings("FreeOpcUa", "OpcUaModeler") self.server = Server() self.server.set_endpoint( "opc.tcp://0.0.0.0:48400/freeopcua/uamodeler/") self.server.set_server_name("OpcUa Modeler Server") self._new_nodes = [] # the added nodes we will save self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.idx_ui = NamespaceWidget(self.ui.namespaceView) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) #self.restoreState(self.settings.value("main_window_state", b"", type="QByteArray")) self.restoreState(self.settings.value("main_window_state", b"")) self.ui.splitterLeft.restoreState( self.settings.value("splitter_left", b"")) self.ui.splitterRight.restoreState( self.settings.value("splitter_right", b"")) self.ui.splitterCenter.restoreState( self.settings.value("splitter_center", b"")) self.server.start() self.tree_ui.set_root_node(self.server.get_root_node()) self.idx_ui.set_node( self.server.get_node(ua.ObjectIds.Server_NamespaceArray)) # fix icon stuff self.ui.actionAddFolder.setIcon(QIcon(":/folder.svg")) self.ui.actionAddObject.setIcon(QIcon(":/object.svg")) self.ui.actionAddObjectType.setIcon(QIcon(":/object_type.svg")) self.ui.actionAddProperty.setIcon(QIcon(":/property.svg")) self.ui.actionAddVariable.setIcon(QIcon(":/variable.svg")) self.ui.actionAddVariableType.setIcon(QIcon(":/variable_type.svg")) # menu self.ui.treeView.addAction(self.ui.actionAddFolder) self.ui.treeView.addAction(self.ui.actionAddObject) self.ui.treeView.addAction(self.ui.actionAddVariable) self.ui.treeView.addAction(self.ui.actionAddProperty) self.ui.treeView.addAction(self.ui.actionAddObjectType) self.ui.treeView.addAction(self.ui.actionAddVariableType) self.ui.treeView.addAction(self.ui.actionAddDataType) # actions self.ui.actionOpen.triggered.connect(self._open) self.ui.actionSave.triggered.connect(self._save) self.ui.actionAddObjectType.triggered.connect(self._add_object_type) self.ui.actionAddObject.triggered.connect(self._add_object) self.ui.actionAddDataType.triggered.connect(self._add_data_type) self.ui.actionAddVariable.triggered.connect(self._add_variable) self.ui.actionAddProperty.triggered.connect(self._add_property)
class ClientController: def __init__(self, view): self.ui = view self.client = None self._connected = False self.address_list = ["opc.tcp://10.42.0.2:4840/OPCUAproject"] self.security_mode = None self.security_policy = None self.certificate_path = None self.private_key_path = None self.ui.closeEvent = self.closeEvent for addr in self.address_list: self.ui.addressComboBox.addItem(addr) self.tree_ui = TreeWidget(self.ui.treeView) self.attrs_ui = AttrsWidget(self.ui.attrView) #self.refs_ui = RefsWidget(self.ui.refView) self.subscription_window = SubscriptionWindow() self.log_window = LogWindow() self.datachange_ui = DataChangeUI(self, self.subscription_window) #self.ui.treeView.selectionModel().selectionChanged.connect(lambda sel: self.show_refs(sel)) self.ui.treeView.selectionModel().selectionChanged.connect( lambda sel: self.show_attrs(sel)) # self.ui.endpointsButton.clicked.connect(lambda : self.get_endpoints()) # self.ui.connSettingsButton.clicked.connect(lambda : self.show_connection_dialog()) # self.ui.connectButton.clicked.connect(lambda : self.connect()) # self.ui.disconnectButton.clicked.connect(lambda: self.disconnect()) # self.ui.readButton.clicked.connect(lambda : self.read_value()) # self.ui.writeButton.clicked.connect(lambda : self.show_write_dialog()) # self.ui.showReferencesButton.clicked.connect(lambda : self.show_refs_dialog()) # self.ui.showSubscriptionsButton.clicked.connect(lambda : self.show_subs_dialog()) # self.ui.showLogsButton.clicked.connect(lambda : self.show_logs_dialog()) self.ui.actionQuery_endpoints.triggered.connect( lambda: self.get_endpoints()) self.ui.actionConnection_settings.triggered.connect( lambda: self.show_connection_dialog()) self.ui.actionConnect.triggered.connect(lambda: self.connect()) self.ui.actionDisconnect.triggered.connect(lambda: self.disconnect()) self.ui.actionRead.triggered.connect(lambda: self.read_value()) self.ui.actionWrite.triggered.connect(lambda: self.show_write_dialog()) self.ui.actionReferences.triggered.connect( lambda: self.show_refs_dialog()) self.ui.actionSubscriptions.triggered.connect( lambda: self.show_subs_dialog()) self.ui.actionLogs.triggered.connect(lambda: self.show_logs_dialog()) def closeEvent(self, event): self.disconnect() def get_endpoints(self): uri = self.ui.addressComboBox.currentText() client = Client(uri, timeout=2) try: edps = client.connect_and_get_server_endpoints() for i, ep in enumerate(edps, start=1): self.log_window.ui.logTextEdit.append('Endpoint %s:' % i) for (n, v) in endpoint_to_strings(ep): self.log_window.ui.logTextEdit.append(' %s: %s' % (n, v)) self.log_window.ui.logTextEdit.append('') except Exception as ex: self.log_window.ui.logTextEdit.append(str(ex)) raise return edps def show_connection_dialog(self): dia = ConnectionDialog(self, self.ui.addressComboBox.currentText()) #dia.security_mode = self.security_mode #dia.security_policy = self.security_policy #dia.certificate_path = self.certificate_path #dia.private_key_path = self.private_key_path ret = dia.exec_() if ret: #self.security_mode = dia.security_mode #self.security_policy = dia.security_policy self.certificate_path = dia.certificate_path self.private_key_path = dia.private_key_path def show_write_dialog(self): node = self.get_current_node() if node.get_node_class() == ua.NodeClass.Variable: dia = WriteDialog(node, self.log_window.ui.logTextEdit) ret = dia.exec_() else: self.log_window.ui.logTextEdit.append( "Only Variable can be written") def connect(self): self.disconnect() uri = self.ui.addressComboBox.currentText() self.log_window.ui.logTextEdit.append( "Connecting to %s with parameters %s, %s, %s, %s" % (uri, self.security_mode, self.security_policy, self.certificate_path, self.private_key_path)) try: self.client = Client(uri) self.client.application_uri = "urn:opcua:python:client" if self.security_mode is not None and self.security_policy is not None: self.client.set_security(getattr( crypto.security_policies, 'SecurityPolicy' + self.security_policy), self.certificate_path, self.private_key_path, mode=getattr(ua.MessageSecurityMode, self.security_mode)) self.client.connect() self._connected = True except Exception as ex: self.log_window.ui.logTextEdit.append(str(ex)) try: self.client.uaclient._uasocket._thread.isAlive() self.tree_ui.set_root_node(self.client.get_root_node()) self.ui.treeView.setFocus() except Exception as ex: print("Connection error") def _reset(self): self.client = None self._connected = False self.datachange_ui._datachange_sub = {} self.datachange_ui._subs_dc = {} def disconnect(self): try: if self._connected: self.log_window.ui.logTextEdit.append( "Disconnecting from server") self._connected = False if self.client: if self.datachange_ui._datachange_sub: sub_ids = list(self.datachange_ui._datachange_sub.keys()) for sub_id in sub_ids: self.datachange_ui.delete_subscription(sub_id) self.client.disconnect() self._reset() except Exception as ex: self.log_window.ui.logTextEdit.append(str(ex)) finally: self.tree_ui.clear() #self.refs_ui.clear() self.attrs_ui.clear() self.datachange_ui.clear() def show_attrs(self, selection): if isinstance(selection, QItemSelection): if not selection.indexes(): # no selection return node = self.get_current_node() if node: self.attrs_ui.show_attrs(node) '''def show_refs(self, selection): if isinstance(selection, QItemSelection): if not selection.indexes(): # no selection return node = self.get_current_node() if node: self.refs_ui.show_refs(node)''' def show_refs_dialog(self): self.references_window = ReferencesWindow(self) self.references_window.show() def show_subs_dialog(self): self.subscription_window.show() def show_logs_dialog(self): self.log_window.show() def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def read_value(self): node = self.get_current_node() try: self.attrs_ui.show_attrs(node) if node.get_node_class() == ua.NodeClass.Variable: value = node.get_value() data = "Node: %s, Value: %s" % (node.get_browse_name(), value) self.log_window.ui.logTextEdit.append(data) except Exception as ex: self.log_window.ui.logTextEdit.append(str(ex))
class Window(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # fix stuff imposible to do in qtdesigner # remove dock titlebar for addressbar w = QWidget() self.ui.addrDockWidget.setTitleBarWidget(w) # tabify some docks self.tabifyDockWidget(self.ui.evDockWidget, self.ui.subDockWidget) self.tabifyDockWidget(self.ui.subDockWidget, self.ui.refDockWidget) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaClient") self.settings = QSettings() self._address_list = self.settings.value("address_list", [ "opc.tcp://localhost:4840", "opc.tcp://localhost:53530/OPCUA/SimulationServer/" ]) self._address_list_max_count = int( self.settings.value("address_list_max_count", 10)) # init widgets for addr in self._address_list: self.ui.addrComboBox.insertItem(-1, addr) self.uaclient = UaClient() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.datachange_ui = DataChangeUI(self, self.uaclient) self.event_ui = EventUI(self, self.uaclient) self.ui.addrComboBox.currentTextChanged.connect(self._uri_changed) self._uri_changed(self.ui.addrComboBox.currentText() ) # force update for current value at startup self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.actionCopyPath.triggered.connect(self.tree_ui.copy_path) self.ui.actionCopyNodeId.triggered.connect(self.tree_ui.copy_nodeid) # add items to context menu self.ui.treeView.addAction(self.ui.actionCopyPath) self.ui.treeView.addAction(self.ui.actionCopyNodeId) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.ui.attrRefreshButton.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) data = self.settings.value("main_window_state", None) if data: self.restoreState(data) self.ui.connectButton.clicked.connect(self.connect) self.ui.disconnectButton.clicked.connect(self.disconnect) # self.ui.treeView.expanded.connect(self._fit) self.ui.actionConnect.triggered.connect(self.connect) self.ui.actionDisconnect.triggered.connect(self.disconnect) self.ui.connectOptionButton.clicked.connect( self.show_connection_dialog) def _uri_changed(self, uri): self.uaclient.load_security_settings(uri) def show_connection_dialog(self): dia = ConnectionDialog(self, self.ui.addrComboBox.currentText()) dia.security_mode = self.uaclient.security_mode dia.security_policy = self.uaclient.security_policy dia.certificate_path = self.uaclient.certificate_path dia.private_key_path = self.uaclient.private_key_path ret = dia.exec_() if ret: self.uaclient.security_mode = dia.security_mode self.uaclient.security_policy = dia.security_policy self.uaclient.certificate_path = dia.certificate_path self.uaclient.private_key_path = dia.private_key_path @trycatchslot def show_refs(self, idx): node = self.get_current_node(idx) if node: self.refs_ui.show_refs(node) @trycatchslot def show_attrs(self, idx): if not isinstance(idx, QModelIndex): idx = None node = self.get_current_node(idx) if node: self.attrs_ui.show_attrs(node) def show_error(self, msg): logger.warning("showing error: %s") self.ui.statusBar.show() self.ui.statusBar.setStyleSheet( "QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def get_uaclient(self): return self.uaclient @trycatchslot def connect(self): uri = self.ui.addrComboBox.currentText() try: self.uaclient.connect(uri) except Exception as ex: self.show_error(ex) raise self._update_address_list(uri) self.tree_ui.set_root_node(self.uaclient.client.get_root_node()) def _update_address_list(self, uri): if uri == self._address_list[0]: return if uri in self._address_list: self._address_list.remove(uri) self._address_list.insert(0, uri) if len(self._address_list) > self._address_list_max_count: self._address_list.pop(-1) def disconnect(self): try: self.uaclient.disconnect() except Exception as ex: self.show_error(ex) raise finally: self.tree_ui.clear() self.refs_ui.clear() self.attrs_ui.clear() self.datachange_ui.clear() self.event_ui.clear() def closeEvent(self, event): self.tree_ui.save_state() self.attrs_ui.save_state() self.refs_ui.save_state() self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("address_list", self._address_list) self.disconnect() event.accept()
class UaModeler(QMainWindow): """ Main class of modeler. Should be as simple as possible, try to push things to other classes or even better python-opcua """ def __init__(self): QMainWindow.__init__(self) self.ui = Ui_UaModeler() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaModeler") self.settings = QSettings() self._restore_ui_geometri() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.refs_ui.reference_changed.connect(self.tree_ui.reload_current) # FIXME: shoudl reload a specific node self.attrs_ui = AttrsWidget(self.ui.attrView, show_timestamps=False) self.attrs_ui.error.connect(self.show_error) self.idx_ui = NamespaceWidget(self.ui.namespaceView) self.nodesets_ui = RefNodeSetsWidget(self.ui.refNodeSetsView) self.nodesets_ui.error.connect(self.show_error) self.nodesets_ui.nodeset_added.connect(self.nodesets_change) self.nodesets_ui.nodeset_removed.connect(self.nodesets_change) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.model_mgr = ModelManagerUI(self) self.model_mgr.error.connect(self.show_error) self.model_mgr.titleChanged.connect(self.update_title) self.actions = ActionsManager(self, self.ui, self.model_mgr) self.setup_context_menu_tree() delegate = BoldDelegate(self, self.tree_ui.model, self.model_mgr.get_new_nodes()) self.ui.treeView.setItemDelegate(delegate) self.ui.treeView.selectionModel().currentChanged.connect(self._update_actions_state) self._recent_files = self.settings.value("recent_files", []) self._recent_files_max_count = int(self.settings.value("recent_files_max_count", 10)) self._recent_files_acts = [QAction(self, visible=False, triggered=self.open_recent_files) for _ in range(self._recent_files_max_count)] for act in self._recent_files_acts: self.ui.menuRecentFiles.addAction(act) self._update_recent_files_ui() def open_recent_files(self): if not self.model_mgr.try_close_model(): return action = self.sender() if action: path = action.data() self.model_mgr.open_file(path) self.update_recent_files(path) def update_recent_files(self, path): if self._recent_files and path == self._recent_files[0]: return if self._recent_files is not None: if path in self._recent_files: self._recent_files.remove(path) self._recent_files.insert(0, path) self._recent_files = self._recent_files[:self._recent_files_max_count] self._update_recent_files_ui() def _update_recent_files_ui(self): if self._recent_files is not None: for idx, path in enumerate(self._recent_files): self._recent_files_acts[idx].setText(path) self._recent_files_acts[idx].setData(path) self._recent_files_acts[idx].setVisible(True) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def get_current_server(self): """ Used by tests """ return self.model_mgr.get_current_server() def clear_all_widgets(self): self.tree_ui.clear() self.refs_ui.clear() self.attrs_ui.clear() self.idx_ui.clear() self.nodesets_ui.clear() @trycatchslot def _update_actions_state(self, current, previous): node = self.get_current_node(current) self.actions.update_actions_states(node) def setup_context_menu_tree(self): self.ui.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.treeView.customContextMenuRequested.connect(self._show_context_menu_tree) self._contextMenu = QMenu() # tree view menu self._contextMenu.addAction(self.ui.actionCopy) self._contextMenu.addAction(self.ui.actionPaste) self._contextMenu.addAction(self.ui.actionDelete) self._contextMenu.addSeparator() self._contextMenu.addAction(self.tree_ui.actionReload) self._contextMenu.addSeparator() self._contextMenu.addAction(self.ui.actionAddFolder) self._contextMenu.addAction(self.ui.actionAddObject) self._contextMenu.addAction(self.ui.actionAddVariable) self._contextMenu.addAction(self.ui.actionAddProperty) self._contextMenu.addAction(self.ui.actionAddMethod) self._contextMenu.addAction(self.ui.actionAddObjectType) self._contextMenu.addAction(self.ui.actionAddVariableType) self._contextMenu.addAction(self.ui.actionAddDataType) def _show_context_menu_tree(self, position): node = self.tree_ui.get_current_node() if node: self._contextMenu.exec_(self.ui.treeView.viewport().mapToGlobal(position)) def _restore_ui_geometri(self): self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) #self.restoreState(self.settings.value("main_window_state", b"", type="QByteArray")) self.restoreState(self.settings.value("main_window_state", bytearray())) self.ui.splitterLeft.restoreState(self.settings.value("splitter_left", bytearray())) self.ui.splitterRight.restoreState(self.settings.value("splitter_right", bytearray())) self.ui.splitterCenter.restoreState(self.settings.value("splitter_center", bytearray())) def update_title(self, path): self.setWindowTitle("FreeOpcUa Modeler " + str(path)) def show_error(self, msg): self.ui.statusBar.show() self.ui.statusBar.setStyleSheet("QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(2500, self.ui.statusBar.hide) def show_msg(self, msg): self.ui.statusBar.show() self.ui.statusBar.setStyleSheet("QStatusBar { background-color : green; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) @trycatchslot def show_refs(self, idx=None): node = self.get_current_node(idx) if node: self.refs_ui.show_refs(node) @trycatchslot def show_attrs(self, idx=None): if not isinstance(idx, QModelIndex): idx = None node = self.get_current_node(idx) if node: self.attrs_ui.show_attrs(node) def nodesets_change(self, data): self.idx_ui.reload() self.tree_ui.reload() self.refs_ui.clear() self.attrs_ui.clear() self.model_mgr.setModified(True) def closeEvent(self, event): if not self.model_mgr.try_close_model(): event.ignore() return self.attrs_ui.save_state() self.refs_ui.save_state() self.tree_ui.save_state() self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("splitter_left", self.ui.splitterLeft.saveState()) self.settings.setValue("splitter_right", self.ui.splitterRight.saveState()) self.settings.setValue("splitter_center", self.ui.splitterCenter.saveState()) self.settings.setValue("recent_files", self._recent_files) event.accept()
class UaModeler(QMainWindow): """ Main class of modeler. Should be as simple as possible, try to push things to other classes or even better python-opcua """ def __init__(self): QMainWindow.__init__(self) self.ui = Ui_UaModeler() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaModeler") self.settings = QSettings() self._restore_ui_geometri() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.refs_ui.reference_changed.connect(self.tree_ui.reload_current) # FIXME: shoudl reload a specific node self.attrs_ui = AttrsWidget(self.ui.attrView, show_timestamps=False) self.attrs_ui.error.connect(self.show_error) self.idx_ui = NamespaceWidget(self.ui.namespaceView) self.nodesets_ui = RefNodeSetsWidget(self.ui.refNodeSetsView) self.nodesets_ui.error.connect(self.show_error) self.nodesets_ui.nodeset_added.connect(self.nodesets_change) self.nodesets_ui.nodeset_removed.connect(self.nodesets_change) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.model_mgr = ModelManagerUI(self) self.model_mgr.error.connect(self.show_error) self.model_mgr.titleChanged.connect(self.update_title) self.actions = ActionsManager(self.ui, self.model_mgr) self.setup_context_menu_tree() delegate = BoldDelegate(self, self.tree_ui.model, self.model_mgr.get_new_nodes()) self.ui.treeView.setItemDelegate(delegate) self.ui.treeView.selectionModel().currentChanged.connect(self._update_actions_state) self._recent_files = self.settings.value("recent_files", []) self._recent_files_max_count = int(self.settings.value("recent_files_max_count", 10)) self._recent_files_acts = [QAction(self, visible=False, triggered=self.open_recent_files) for _ in range(self._recent_files_max_count)] for act in self._recent_files_acts: self.ui.menuRecentFiles.addAction(act) self._update_recent_files_ui() def open_recent_files(self): if not self.model_mgr.try_close_model(): return action = self.sender() if action: path = action.data() self.model_mgr.open_file(path) self.update_recent_files(path) def update_recent_files(self, path): if self._recent_files and path == self._recent_files[0]: return if path in self._recent_files: self._recent_files.remove(path) self._recent_files.insert(0, path) self._recent_files = self._recent_files[:self._recent_files_max_count] self._update_recent_files_ui() def _update_recent_files_ui(self): if not self._recent_files: return for idx, path in enumerate(self._recent_files): self._recent_files_acts[idx].setText(path) self._recent_files_acts[idx].setData(path) self._recent_files_acts[idx].setVisible(True) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def get_current_server(self): """ Used by tests """ return self.model_mgr.get_current_server() def clear_all_widgets(self): self.tree_ui.clear() self.refs_ui.clear() self.attrs_ui.clear() self.idx_ui.clear() self.nodesets_ui.clear() @trycatchslot def _update_actions_state(self, current, previous): node = self.get_current_node(current) self.actions.update_actions_states(node) def setup_context_menu_tree(self): self.ui.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.treeView.customContextMenuRequested.connect(self._show_context_menu_tree) self._contextMenu = QMenu() # tree view menu self._contextMenu.addAction(self.ui.actionCopy) self._contextMenu.addAction(self.ui.actionPaste) self._contextMenu.addAction(self.ui.actionDelete) self._contextMenu.addSeparator() self._contextMenu.addAction(self.tree_ui.actionReload) self._contextMenu.addSeparator() self._contextMenu.addAction(self.ui.actionAddFolder) self._contextMenu.addAction(self.ui.actionAddObject) self._contextMenu.addAction(self.ui.actionAddVariable) self._contextMenu.addAction(self.ui.actionAddProperty) self._contextMenu.addAction(self.ui.actionAddMethod) self._contextMenu.addAction(self.ui.actionAddObjectType) self._contextMenu.addAction(self.ui.actionAddVariableType) self._contextMenu.addAction(self.ui.actionAddDataType) def _show_context_menu_tree(self, position): node = self.tree_ui.get_current_node() if node: self._contextMenu.exec_(self.ui.treeView.viewport().mapToGlobal(position)) def _restore_ui_geometri(self): self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) #self.restoreState(self.settings.value("main_window_state", b"", type="QByteArray")) self.restoreState(self.settings.value("main_window_state", bytearray())) self.ui.splitterLeft.restoreState(self.settings.value("splitter_left", bytearray())) self.ui.splitterRight.restoreState(self.settings.value("splitter_right", bytearray())) self.ui.splitterCenter.restoreState(self.settings.value("splitter_center", bytearray())) def update_title(self, path): self.setWindowTitle("FreeOpcUa Modeler " + str(path)) def show_error(self, msg): self.ui.statusBar.show() self.ui.statusBar.setStyleSheet("QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(2500, self.ui.statusBar.hide) def show_msg(self, msg): self.ui.statusBar.show() self.ui.statusBar.setStyleSheet("QStatusBar { background-color : green; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) @trycatchslot def show_refs(self, idx=None): node = self.get_current_node(idx) if node: self.refs_ui.show_refs(node) @trycatchslot def show_attrs(self, idx=None): if not isinstance(idx, QModelIndex): idx = None node = self.get_current_node(idx) if node: self.attrs_ui.show_attrs(node) def nodesets_change(self, data): self.idx_ui.reload() self.tree_ui.reload() self.refs_ui.clear() self.attrs_ui.clear() self.model_mgr.setModified(True) def closeEvent(self, event): if not self.model_mgr.try_close_model(): event.ignore() return self.attrs_ui.save_state() self.refs_ui.save_state() self.tree_ui.save_state() self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("splitter_left", self.ui.splitterLeft.saveState()) self.settings.setValue("splitter_right", self.ui.splitterRight.saveState()) self.settings.setValue("splitter_center", self.ui.splitterCenter.saveState()) self.settings.setValue("recent_files", self._recent_files) event.accept()
def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # fix stuff imposible to do in qtdesigner # remove dock titlebar for addressbar w = QWidget() self.ui.addrDockWidget.setTitleBarWidget(w) # tabify some docks self.tabifyDockWidget(self.ui.evDockWidget, self.ui.subDockWidget) self.tabifyDockWidget(self.ui.subDockWidget, self.ui.refDockWidget) self.tabifyDockWidget(self.ui.refDockWidget, self.ui.graphDockWidget) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaClient") self.settings = QSettings() self._address_list = self.settings.value("address_list", [ "opc.tcp://localhost:4840", "opc.tcp://localhost:53530/OPCUA/SimulationServer/" ]) self._address_list_max_count = int( self.settings.value("address_list_max_count", 10)) # init widgets for addr in self._address_list: self.ui.addrComboBox.insertItem(-1, addr) self.uaclient = UaClient() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.setup_context_menu_tree() self.ui.treeView.selectionModel().currentChanged.connect( self._update_actions_state) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.datachange_ui = DataChangeUI(self, self.uaclient) self.event_ui = EventUI(self, self.uaclient) self.graph_ui = GraphUI(self, self.uaclient) self.ui.addrComboBox.currentTextChanged.connect(self._uri_changed) self._uri_changed(self.ui.addrComboBox.currentText() ) # force update for current value at startup self.ui.treeView.selectionModel().selectionChanged.connect( self.show_refs) self.ui.actionCopyPath.triggered.connect(self.tree_ui.copy_path) self.ui.actionCopyNodeId.triggered.connect(self.tree_ui.copy_nodeid) self.ui.actionCall.triggered.connect(self.call_method) self.ui.treeView.selectionModel().selectionChanged.connect( self.show_attrs) self.ui.attrRefreshButton.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) data = self.settings.value("main_window_state", None) if data: self.restoreState(data) self.ui.connectButton.clicked.connect(self.connect) self.ui.disconnectButton.clicked.connect(self.disconnect) # self.ui.treeView.expanded.connect(self._fit) self.ui.actionConnect.triggered.connect(self.connect) self.ui.actionDisconnect.triggered.connect(self.disconnect) self.ui.connectOptionButton.clicked.connect( self.show_connection_dialog)
class Window(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # fix stuff imposible to do in qtdesigner # remove dock titlebar for addressbar w = QWidget() self.ui.addrDockWidget.setTitleBarWidget(w) # tabify some docks self.tabifyDockWidget(self.ui.evDockWidget, self.ui.subDockWidget) self.tabifyDockWidget(self.ui.subDockWidget, self.ui.refDockWidget) self.tabifyDockWidget(self.ui.refDockWidget, self.ui.graphDockWidget) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaClient") self.settings = QSettings() self._address_list = self.settings.value("address_list", ["opc.tcp://localhost:4840", "opc.tcp://localhost:53530/OPCUA/SimulationServer/"]) print("ADR", self._address_list) self._address_list_max_count = int(self.settings.value("address_list_max_count", 10)) # init widgets for addr in self._address_list: self.ui.addrComboBox.insertItem(100, addr) self.uaclient = UaClient() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.setup_context_menu_tree() self.ui.treeView.selectionModel().currentChanged.connect(self._update_actions_state) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.datachange_ui = DataChangeUI(self, self.uaclient) self.event_ui = EventUI(self, self.uaclient) self.graph_ui = GraphUI(self, self.uaclient) self.ui.addrComboBox.currentTextChanged.connect(self._uri_changed) self._uri_changed(self.ui.addrComboBox.currentText()) # force update for current value at startup self.ui.treeView.selectionModel().selectionChanged.connect(self.show_refs) self.ui.actionCopyPath.triggered.connect(self.tree_ui.copy_path) self.ui.actionCopyNodeId.triggered.connect(self.tree_ui.copy_nodeid) self.ui.actionCall.triggered.connect(self.call_method) self.ui.treeView.selectionModel().selectionChanged.connect(self.show_attrs) self.ui.attrRefreshButton.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) data = self.settings.value("main_window_state", None) if data: self.restoreState(data) self.ui.connectButton.clicked.connect(self.connect) self.ui.disconnectButton.clicked.connect(self.disconnect) # self.ui.treeView.expanded.connect(self._fit) self.ui.actionConnect.triggered.connect(self.connect) self.ui.actionDisconnect.triggered.connect(self.disconnect) self.ui.connectOptionButton.clicked.connect(self.show_connection_dialog) def _uri_changed(self, uri): self.uaclient.load_security_settings(uri) def show_connection_dialog(self): dia = ConnectionDialog(self, self.ui.addrComboBox.currentText()) dia.security_mode = self.uaclient.security_mode dia.security_policy = self.uaclient.security_policy dia.certificate_path = self.uaclient.certificate_path dia.private_key_path = self.uaclient.private_key_path ret = dia.exec_() if ret: self.uaclient.security_mode = dia.security_mode self.uaclient.security_policy = dia.security_policy self.uaclient.certificate_path = dia.certificate_path self.uaclient.private_key_path = dia.private_key_path @trycatchslot def show_refs(self, selection): if isinstance(selection, QItemSelection): if not selection.indexes(): # no selection return node = self.get_current_node() if node: self.refs_ui.show_refs(node) @trycatchslot def show_attrs(self, selection): if isinstance(selection, QItemSelection): if not selection.indexes(): # no selection return node = self.get_current_node() if node: self.attrs_ui.show_attrs(node) def show_error(self, msg): logger.warning("showing error: %s") self.ui.statusBar.show() self.ui.statusBar.setStyleSheet("QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def get_uaclient(self): return self.uaclient @trycatchslot def connect(self): uri = self.ui.addrComboBox.currentText() try: self.uaclient.connect(uri) except Exception as ex: self.show_error(ex) raise self._update_address_list(uri) self.tree_ui.set_root_node(self.uaclient.client.get_root_node()) self.ui.treeView.setFocus() self.load_current_node() def _update_address_list(self, uri): if uri == self._address_list[0]: return if uri in self._address_list: self._address_list.remove(uri) self._address_list.insert(0, uri) if len(self._address_list) > self._address_list_max_count: self._address_list.pop(-1) def disconnect(self): try: self.uaclient.disconnect() except Exception as ex: self.show_error(ex) raise finally: self.save_current_node() self.tree_ui.clear() self.refs_ui.clear() self.attrs_ui.clear() self.datachange_ui.clear() self.event_ui.clear() def closeEvent(self, event): self.tree_ui.save_state() self.attrs_ui.save_state() self.refs_ui.save_state() self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("address_list", self._address_list) self.disconnect() event.accept() def save_current_node(self): current_node = self.tree_ui.get_current_node() if current_node: mysettings = self.settings.value("current_node", None) if mysettings is None: mysettings = {} uri = self.ui.addrComboBox.currentText() mysettings[uri] = current_node.nodeid.to_string() self.settings.setValue("current_node", mysettings) def load_current_node(self): mysettings = self.settings.value("current_node", None) if mysettings is None: return uri = self.ui.addrComboBox.currentText() if uri in mysettings: nodeid = ua.NodeId.from_string(mysettings[uri]) node = self.uaclient.client.get_node(nodeid) self.tree_ui.expand_to_node(node) def setup_context_menu_tree(self): self.ui.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.treeView.customContextMenuRequested.connect(self._show_context_menu_tree) self._contextMenu = QMenu() self.addAction(self.ui.actionCopyPath) self.addAction(self.ui.actionCopyNodeId) self._contextMenu.addSeparator() self._contextMenu.addAction(self.ui.actionCall) self._contextMenu.addSeparator() def addAction(self, action): self._contextMenu.addAction(action) @trycatchslot def _update_actions_state(self, current, previous): node = self.get_current_node(current) self.ui.actionCall.setEnabled(False) if node: if node.get_node_class() == ua.NodeClass.Method: self.ui.actionCall.setEnabled(True) def _show_context_menu_tree(self, position): node = self.tree_ui.get_current_node() if node: self._contextMenu.exec_(self.ui.treeView.viewport().mapToGlobal(position)) def call_method(self): node = self.get_current_node() dia = CallMethodDialog(self, self.uaclient.client, node) dia.show()