示例#1
0
    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())
示例#3
0
    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)
示例#4
0
    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()
示例#5
0
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)
示例#6
0
    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")
示例#7
0
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()
示例#8
0
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()
示例#9
0
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()
示例#10
0
    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)
示例#11
0
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()
示例#12
0
 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())
示例#13
0
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)
示例#14
0
    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)
示例#15
0
 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 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))
示例#17
0
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()
示例#18
0
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()
示例#19
0
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()
示例#20
0
    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)
示例#21
0
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()