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()
class UaModeler(QMainWindow): """ Main class of modeler. Should be as simple as possible, try to push things to other classes or even better python-opcua """ def __init__(self): QMainWindow.__init__(self) self.ui = Ui_UaModeler() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # we only show statusbar in case of errors self.ui.statusBar.hide() # setup QSettings for application and get a settings object QCoreApplication.setOrganizationName("FreeOpcUa") QCoreApplication.setApplicationName("OpcUaModeler") self.settings = QSettings() self._restore_ui_geometri() self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.refs_ui.reference_changed.connect(self.tree_ui.reload_current) # FIXME: shoudl reload a specific node self.attrs_ui = AttrsWidget(self.ui.attrView, show_timestamps=False) self.attrs_ui.error.connect(self.show_error) self.idx_ui = NamespaceWidget(self.ui.namespaceView) self.nodesets_ui = RefNodeSetsWidget(self.ui.refNodeSetsView) self.nodesets_ui.error.connect(self.show_error) self.nodesets_ui.nodeset_added.connect(self.nodesets_change) self.nodesets_ui.nodeset_removed.connect(self.nodesets_change) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.model_mgr = ModelManagerUI(self) self.model_mgr.error.connect(self.show_error) self.model_mgr.titleChanged.connect(self.update_title) self.actions = ActionsManager(self, self.ui, self.model_mgr) self.setup_context_menu_tree() delegate = BoldDelegate(self, self.tree_ui.model, self.model_mgr.get_new_nodes()) self.ui.treeView.setItemDelegate(delegate) self.ui.treeView.selectionModel().currentChanged.connect(self._update_actions_state) self._recent_files = self.settings.value("recent_files", []) self._recent_files_max_count = int(self.settings.value("recent_files_max_count", 10)) self._recent_files_acts = [QAction(self, visible=False, triggered=self.open_recent_files) for _ in range(self._recent_files_max_count)] for act in self._recent_files_acts: self.ui.menuRecentFiles.addAction(act) self._update_recent_files_ui() def open_recent_files(self): if not self.model_mgr.try_close_model(): return action = self.sender() if action: path = action.data() self.model_mgr.open_file(path) self.update_recent_files(path) def update_recent_files(self, path): if self._recent_files and path == self._recent_files[0]: return if self._recent_files is not None: if path in self._recent_files: self._recent_files.remove(path) self._recent_files.insert(0, path) self._recent_files = self._recent_files[:self._recent_files_max_count] self._update_recent_files_ui() def _update_recent_files_ui(self): if self._recent_files is not None: for idx, path in enumerate(self._recent_files): self._recent_files_acts[idx].setText(path) self._recent_files_acts[idx].setData(path) self._recent_files_acts[idx].setVisible(True) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def get_current_server(self): """ Used by tests """ return self.model_mgr.get_current_server() def clear_all_widgets(self): self.tree_ui.clear() self.refs_ui.clear() self.attrs_ui.clear() self.idx_ui.clear() self.nodesets_ui.clear() @trycatchslot def _update_actions_state(self, current, previous): node = self.get_current_node(current) self.actions.update_actions_states(node) def setup_context_menu_tree(self): self.ui.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.treeView.customContextMenuRequested.connect(self._show_context_menu_tree) self._contextMenu = QMenu() # tree view menu self._contextMenu.addAction(self.ui.actionCopy) self._contextMenu.addAction(self.ui.actionPaste) self._contextMenu.addAction(self.ui.actionDelete) self._contextMenu.addSeparator() self._contextMenu.addAction(self.tree_ui.actionReload) self._contextMenu.addSeparator() self._contextMenu.addAction(self.ui.actionAddFolder) self._contextMenu.addAction(self.ui.actionAddObject) self._contextMenu.addAction(self.ui.actionAddVariable) self._contextMenu.addAction(self.ui.actionAddProperty) self._contextMenu.addAction(self.ui.actionAddMethod) self._contextMenu.addAction(self.ui.actionAddObjectType) self._contextMenu.addAction(self.ui.actionAddVariableType) self._contextMenu.addAction(self.ui.actionAddDataType) def _show_context_menu_tree(self, position): node = self.tree_ui.get_current_node() if node: self._contextMenu.exec_(self.ui.treeView.viewport().mapToGlobal(position)) def _restore_ui_geometri(self): self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) #self.restoreState(self.settings.value("main_window_state", b"", type="QByteArray")) self.restoreState(self.settings.value("main_window_state", bytearray())) self.ui.splitterLeft.restoreState(self.settings.value("splitter_left", bytearray())) self.ui.splitterRight.restoreState(self.settings.value("splitter_right", bytearray())) self.ui.splitterCenter.restoreState(self.settings.value("splitter_center", bytearray())) def update_title(self, path): self.setWindowTitle("FreeOpcUa Modeler " + str(path)) def show_error(self, msg): self.ui.statusBar.show() self.ui.statusBar.setStyleSheet("QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(2500, self.ui.statusBar.hide) def show_msg(self, msg): self.ui.statusBar.show() self.ui.statusBar.setStyleSheet("QStatusBar { background-color : green; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) @trycatchslot def show_refs(self, idx=None): node = self.get_current_node(idx) if node: self.refs_ui.show_refs(node) @trycatchslot def show_attrs(self, idx=None): if not isinstance(idx, QModelIndex): idx = None node = self.get_current_node(idx) if node: self.attrs_ui.show_attrs(node) def nodesets_change(self, data): self.idx_ui.reload() self.tree_ui.reload() self.refs_ui.clear() self.attrs_ui.clear() self.model_mgr.setModified(True) def closeEvent(self, event): if not self.model_mgr.try_close_model(): event.ignore() return self.attrs_ui.save_state() self.refs_ui.save_state() self.tree_ui.save_state() self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("splitter_left", self.ui.splitterLeft.saveState()) self.settings.setValue("splitter_right", self.ui.splitterRight.saveState()) self.settings.setValue("splitter_center", self.ui.splitterCenter.saveState()) self.settings.setValue("recent_files", self._recent_files) event.accept()
class UaModeler(QMainWindow): 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()