def get_plugin_root(self, path): """ This function returns one of the root-Items of the plugin tree. The root-Item is determined by the plugin path. :return: """ parts = path.split('/') part = parts[-3] name = part if part not in self.plugin_roots: cfg_file = str.join("/", parts[0:-2]) + "/" + pc.GUI_PLUGIN_CONFIG if os.path.isfile(cfg_file): config = configparser.ConfigParser() config.read(cfg_file) if 'Config' in config.sections(): if 'name' in config.options('Config'): name = config.get('Config', 'name') self.plugin_roots[part] = PaPIRootItem(name) return self.plugin_roots[part]
def get_plugin_root(self, path): parts = path.split('/') part = parts[-3] name = part if part not in self.plugin_roots: cfg_file = str.join("/", parts[0:-2]) + "/" + pc.GUI_PLUGIN_CONFIG if os.path.isfile(cfg_file): config = configparser.ConfigParser() config.read(cfg_file) if 'Config' in config.sections(): if 'name' in config.options('Config'): name = config.get('Config', 'name') self.plugin_roots[part] = PaPIRootItem(name) return self.plugin_roots[part]
def __init__(self, gui_api, tabmanager, parent=None): """ Constructor of this class. 'gui_api' provides an access to all functions which are needed for the functionality of the GUI. 'tabmanager' manages the tabs of the gui :param gui_api: :param tabmanager: :param parent: :return: """ super(OverviewPluginMenu, self).__init__(parent) self.setupUi(self) self.dgui = gui_api.gui_data self.gui_api = gui_api self.TabManager = tabmanager self.setWindowTitle("OverviewMenu") self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager) # ---------------------------------- # Build structure of plugin tree # ---------------------------------- self.dpluginModel = DPluginTreeModel() self.dpluginModel.setHorizontalHeaderLabels(['Name']) self.pluginProxyModel = PaPITreeProxyModel(self) self.pluginProxyModel.setSourceModel(self.dpluginModel) regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard) self.pluginProxyModel.setFilterRegExp(regex) self.pluginTree.setModel(self.pluginProxyModel) self.pluginTree.setUniformRowHeights(True) self.plugin_roots = {} # ----------------------------------- # Build structure of parameter tree # ----------------------------------- self.dparameterModel = DParameterTreeModel() self.dparameterModel.setHorizontalHeaderLabels(['Name']) self.parameterTree.setModel(self.dparameterModel) self.parameterTree.setUniformRowHeights(True) self.dparameterModel.dataChanged.connect( self.data_changed_parameter_model) # ----------------------------------- # Build structure of block tree # ----------------------------------- self.bModel = DBlockTreeModel(self.showInternalNameCheckBox) self.bModel.setHorizontalHeaderLabels(['Name']) self.bModel.setColumnCount(2) self.blockTree.setModel(self.bModel) self.blockTree.setUniformRowHeights(True) self.bModel.dataChanged.connect(self.data_changed_block_model) self.showInternalNameCheckBox.clicked.connect( self.show_internal_name_callback) # ----------------------------------- # Build structure of connection tree # ----------------------------------- self.connectionModel = PaPITreeModel() self.connectionModel.setHorizontalHeaderLabels(['']) self.connectionTree.setHeaderHidden(True) self.connectionTree.setModel(self.connectionModel) self.connectionTree.setUniformRowHeights(True) self.subscribers_root = PaPIRootItem('Subscribers') self.connectionModel.appendRow(self.subscribers_root) self.subscriptions_root = PaPIRootItem('Subscriptions') self.connectionModel.appendRow(self.subscriptions_root) # ----------------------------------- # signal/slots # ----------------------------------- self.playButton.clicked.connect(self.play_button_callback) self.pauseButton.clicked.connect(self.pause_button_callback) self.stopButton.clicked.connect(self.stop_start_button_callback) self.pluginTree.clicked.connect(self.plugin_item_changed) self.pluginTree.selectionModel().selectionChanged.connect( self.changed_dplugin_tree_selection) self.pluginTree.setStyleSheet(pc.TREE_CSS) # ---------------------------------- # Add context menu # ---------------------------------- self.pluginTree.setContextMenuPolicy(Qt.CustomContextMenu) self.pluginTree.customContextMenuRequested.connect( self.open_context_menu_dplugin_tree) self.blockTree.setContextMenuPolicy(Qt.CustomContextMenu) self.blockTree.customContextMenuRequested.connect( self.open_context_menu_block_tree) self.parameterTree.setContextMenuPolicy(Qt.CustomContextMenu) self.parameterTree.customContextMenuRequested.connect( self.open_context_menu_parameter_tree) self.connectionTree.setContextMenuPolicy(Qt.CustomContextMenu) self.connectionTree.customContextMenuRequested.connect( self.open_context_menu_connection_tree) # ---------------------------------- # Add Actions # ---------------------------------- self.actionRefresh.triggered.connect(self.refresh_action) self.pluginSearchText.textChanged.connect( self.changed_search_plugin_text_field) self.clear() # set focus to the search bar self.pluginSearchText.setFocus(Qt.OtherFocusReason)
class OverviewPluginMenu(QMainWindow, Ui_PluginOverviewMenu): """ This class is used to create an extra window which displays all created plugins. The information are taken by the corresponding DPlugin-Object of a plugin. By this window a user is also able to create and cancel subscriptions. """ def __init__(self, gui_api, tabmanager, parent=None): """ Constructor of this class. 'gui_api' provides an access to all functions which are needed for the functionality of the GUI. 'tabmanager' manages the tabs of the gui :param gui_api: :param tabmanager: :param parent: :return: """ super(OverviewPluginMenu, self).__init__(parent) self.setupUi(self) self.dgui = gui_api.gui_data self.gui_api = gui_api self.TabManager = tabmanager self.setWindowTitle("OverviewMenu") self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager) # ---------------------------------- # Build structure of plugin tree # ---------------------------------- self.dpluginModel = DPluginTreeModel() self.dpluginModel.setHorizontalHeaderLabels(['Name']) self.pluginProxyModel = PaPITreeProxyModel(self) self.pluginProxyModel.setSourceModel(self.dpluginModel) regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard) self.pluginProxyModel.setFilterRegExp(regex) self.pluginTree.setModel(self.pluginProxyModel) self.pluginTree.setUniformRowHeights(True) self.plugin_roots = {} # ----------------------------------- # Build structure of parameter tree # ----------------------------------- self.dparameterModel = DParameterTreeModel() self.dparameterModel.setHorizontalHeaderLabels(['Name']) self.parameterTree.setModel(self.dparameterModel) self.parameterTree.setUniformRowHeights(True) self.dparameterModel.dataChanged.connect( self.data_changed_parameter_model) # ----------------------------------- # Build structure of block tree # ----------------------------------- self.bModel = DBlockTreeModel(self.showInternalNameCheckBox) self.bModel.setHorizontalHeaderLabels(['Name']) self.bModel.setColumnCount(2) self.blockTree.setModel(self.bModel) self.blockTree.setUniformRowHeights(True) self.bModel.dataChanged.connect(self.data_changed_block_model) self.showInternalNameCheckBox.clicked.connect( self.show_internal_name_callback) # ----------------------------------- # Build structure of connection tree # ----------------------------------- self.connectionModel = PaPITreeModel() self.connectionModel.setHorizontalHeaderLabels(['']) self.connectionTree.setHeaderHidden(True) self.connectionTree.setModel(self.connectionModel) self.connectionTree.setUniformRowHeights(True) self.subscribers_root = PaPIRootItem('Subscribers') self.connectionModel.appendRow(self.subscribers_root) self.subscriptions_root = PaPIRootItem('Subscriptions') self.connectionModel.appendRow(self.subscriptions_root) # ----------------------------------- # signal/slots # ----------------------------------- self.playButton.clicked.connect(self.play_button_callback) self.pauseButton.clicked.connect(self.pause_button_callback) self.stopButton.clicked.connect(self.stop_start_button_callback) self.pluginTree.clicked.connect(self.plugin_item_changed) self.pluginTree.selectionModel().selectionChanged.connect( self.changed_dplugin_tree_selection) self.pluginTree.setStyleSheet(pc.TREE_CSS) # ---------------------------------- # Add context menu # ---------------------------------- self.pluginTree.setContextMenuPolicy(Qt.CustomContextMenu) self.pluginTree.customContextMenuRequested.connect( self.open_context_menu_dplugin_tree) self.blockTree.setContextMenuPolicy(Qt.CustomContextMenu) self.blockTree.customContextMenuRequested.connect( self.open_context_menu_block_tree) self.parameterTree.setContextMenuPolicy(Qt.CustomContextMenu) self.parameterTree.customContextMenuRequested.connect( self.open_context_menu_parameter_tree) self.connectionTree.setContextMenuPolicy(Qt.CustomContextMenu) self.connectionTree.customContextMenuRequested.connect( self.open_context_menu_connection_tree) # ---------------------------------- # Add Actions # ---------------------------------- self.actionRefresh.triggered.connect(self.refresh_action) self.pluginSearchText.textChanged.connect( self.changed_search_plugin_text_field) self.clear() # set focus to the search bar self.pluginSearchText.setFocus(Qt.OtherFocusReason) def clear(self): """ This function will clear this window. It is used to reset all elements in this windows. :return: """ self.bModel.clear() self.dparameterModel.clear() self.subscribers_root.setRowCount(0) self.subscriptions_root.setRowCount(0) self.unameEdit.setText('') self.usedpluginEdit.setText('') self.stateEdit.setText('') self.typeEdit.setText('') self.alivestateEdit.setText('') self.bModel.setHorizontalHeaderLabels(['Name']) self.dparameterModel.setHorizontalHeaderLabels(['Name', 'Value']) self.connectionModel.setHorizontalHeaderLabels(['']) def plugin_item_changed(self, index): """ Used to display all known information for a DPlugin which is accessible in the pluginTree by its index. It is called when an user changes the selected plugin in the plugin tree. :param index: Current selected index :return: """ dplugin = self.pluginTree.model().data(index, Qt.UserRole) self.clear() if dplugin is None: self.pluginWidget.setDisabled(True) return self.pluginWidget.setDisabled(False) # ------------------------------------ # Get all needed dplugin information # ------------------------------------ self.unameEdit.setText(dplugin.uname) self.usedpluginEdit.setText(dplugin.plugin_identifier) self.stateEdit.setText(dplugin.state) self.typeEdit.setText(dplugin.type) self.alivestateEdit.setText(dplugin.alive_state) self.pauseButton.setDisabled(False) self.playButton.setDisabled(False) self.stopButton.setDisabled(False) if dplugin.alive_state != PLUGIN_STATE_DEAD: if dplugin.state == PLUGIN_STATE_PAUSE: self.pauseButton.setDisabled(True) if dplugin.state == PLUGIN_STATE_STOPPED: self.pauseButton.setDisabled(True) self.playButton.setDisabled(True) self.stopButton.setText('START') if dplugin.state == PLUGIN_STATE_RESUMED: self.playButton.setDisabled(True) if dplugin.state == PLUGIN_STATE_START_SUCCESFUL: self.playButton.setDisabled(True) self.stopButton.setText('STOP') # --------------------------- # Add DBlocks(Also DEvent) # --------------------------- dblock_ids = dplugin.get_dblocks() for dblock_id in dblock_ids: dblock = dblock_ids[dblock_id] block_item = DBlockTreeItem(dblock) self.bModel.appendRow(block_item) # ------------------------- # Add Signals of this DBlock # ------------------------- for signal in dblock.get_signals(): if signal.uname not in [pc.CORE_TIME_SIGNAL]: signal_item = DSignalTreeItem( signal, self.showInternalNameCheckBox) block_item.appendRow(signal_item) block_item.sortChildren(0) # ---------------------------------- # Add Subscribers of this DBlock # ---------------------------------- subscriber_ids = dblock.get_subscribers() for subscriber_id in subscriber_ids: # Other plugin subscriber = self.dgui.get_dplugin_by_id(subscriber_id) if dplugin.id in subscriber.get_subscribtions(): for dblock_sub_id in subscriber.get_subscribtions()[ dplugin.id]: subscriber_item = DPluginTreeItem(subscriber) # self.subscriberModel.appendRow(subscriber_item) self.subscribers_root.appendRow(subscriber_item) subscription = subscriber.get_subscribtions()[ dplugin.id][dblock_sub_id] block_item = DBlockTreeItem(dblock) subscriber_item.appendRow(block_item) subscription_item = PaPITreeItem( subscription, "Signals") block_item.appendRow(subscription_item) for signal_uname in sorted(subscription.get_signals()): if signal_uname not in [pc.CORE_TIME_SIGNAL]: signal_item = PaPITreeItem( signal_uname, signal_uname) subscription_item.appendRow(signal_item) # ------------------------- # Add all Subscriptions # for this plugin # ------------------------- dplugin_sub_ids = dplugin.get_subscribtions() for dplugin_sub_id in dplugin_sub_ids: dblock_names = dplugin_sub_ids[dplugin_sub_id] dplugin_sub = self.gui_api.gui_data.get_dplugin_by_id( dplugin_sub_id) dplugin_sub_item = DPluginTreeItem(dplugin_sub) #self.subscriptionModel.appendRow(dplugin_sub_item) self.subscriptions_root.appendRow(dplugin_sub_item) for dblock_name in dblock_names: dblock_sub = dplugin_sub.get_dblock_by_name(dblock_name) dblock_sub_item = DBlockTreeItem(dblock_sub) dplugin_sub_item.appendRow(dblock_sub_item) subscription = dblock_names[dblock_name] subscription_item = PaPITreeItem(subscription, "Signals") dblock_sub_item.appendRow(subscription_item) for signal_uname in sorted(subscription.get_signals()): if signal_uname not in [pc.CORE_TIME_SIGNAL]: signal_item = PaPITreeItem(signal_uname, signal_uname) subscription_item.appendRow(signal_item) # -------------------------- # Add DParameters # -------------------------- dparameter_names = dplugin.get_parameters() for dparameter_name in sorted(dparameter_names): dparameter = dparameter_names[dparameter_name] dparameter_item = DParameterTreeItem(dparameter) self.dparameterModel.appendRow(dparameter_item) self.parameterTree.resizeColumnToContents(0) self.parameterTree.resizeColumnToContents(1) self.blockTree.expandAll() self.parameterTree.expandAll() self.connectionTree.expandAll() # http://srinikom.github.io/pyside-docs/PySide/QtGui/QAbstractItemView.html \ # #PySide.QtGui.PySide.QtGui.QAbstractItemView.SelectionMode self.blockTree.setSelectionMode(QAbstractItemView.ExtendedSelection) # Sort Models self.bModel.sort(0) def plugin_item_refresh(self, index): """ This function is called when it's known that the dplugin object, which describes the selected plugin, was changed. :param index: :return: """ self.parameterTree.viewport().update() self.blockTree.viewport().update() self.connectionTree.viewport().update() def open_context_menu_dplugin_tree(self, position): """ This callback function is called to create a context menu for the dplugin tree. It is triggered by use :param position: :return: """ index = self.pluginTree.indexAt(position) if index.parent().isValid() is False: return None if index.isValid() is False: return None if self.pluginTree.isIndexHidden(index): return dplugin = self.pluginTree.model().data(index, Qt.UserRole) menu = QMenu('Menu') submenu = QMenu('Action') menu.addMenu(submenu) action = QAction('Remove plugin', self) submenu.addAction(action) action.triggered.connect( lambda ignore, p=dplugin.id: self.gui_api.do_delete_plugin(p)) action = QAction('Copy plugin', self) submenu.addAction(action) action.triggered.connect( lambda ignore, p=dplugin: self.show_create_plugin_dialog(p)) actionCollapsAll = QAction('Collapse all', self) actionCollapsAll.triggered.connect(self.pluginTree.collapseAll) actionExpandAll = QAction('Expand all', self) actionExpandAll.triggered.connect(self.pluginTree.expandAll) menu.addAction(actionCollapsAll) menu.addAction(actionExpandAll) menu.exec_(self.pluginTree.viewport().mapToGlobal(position)) def open_context_menu_block_tree(self, position): """ This callback function is called to create a context menu for the block tree :param position: :return: """ index = self.blockTree.indexAt(position) if index.isValid() is False: return None if self.blockTree.isIndexHidden(index): return item = self.blockTree.model().data(index, Qt.UserRole) if isinstance(item, DPlugin) or isinstance(item, DBlock): return index_sel = self.pluginTree.currentIndex() dplugin_sel = self.pluginTree.model().data(index_sel, Qt.UserRole) if dplugin_sel is not None: sub_menu = QMenu('Add Subscription') dplugin_ids = self.dgui.get_all_plugins() for dplugin_id in dplugin_ids: dplugin = dplugin_ids[dplugin_id] if dplugin_sel.id != dplugin_id: action = QAction(self.tr(dplugin.uname), self) sub_menu.addAction(action) action.triggered.connect(lambda ignore, p=dplugin.uname: self.add_subscription_action(p)) menu = QMenu() menu.addMenu(sub_menu) menu.exec_(self.blockTree.viewport().mapToGlobal(position)) def open_context_menu_connection_tree(self, position): """ This callback function is called to create a context menu for the subscriper tree :param position: :return: """ index = self.connectionTree.indexAt(position) if index.isValid() is False: return None if self.connectionTree.isIndexHidden(index): return None if index.parent().isValid() is False: return None parIndex = index subscriberPart = False subscriptionPart = False signals = [] isSignal = False while True: object = self.connectionTree.model().data(parIndex, Qt.DisplayRole) if "Subscribers" in object: subscriberPart = True if "Subscriptions" in object: subscriptionPart = True if (subscriptionPart or subscriberPart): break parIndex = parIndex.parent() if parIndex.isValid() is False: return if not (subscriptionPart or subscriberPart): return None if isinstance(self.connectionTree.model().data(index, Qt.UserRole), DSubscription): return if isinstance(self.connectionTree.model().data(index, Qt.UserRole), DPlugin): return # ---------------------------------- # Open no context menu for signals # ---------------------------------- if isinstance(self.connectionTree.model().data(index, Qt.UserRole), str): isSignal = True else: isSignal = False # ---------------------------------- # Get necessary objects for this subscription/subscriber # ---------------------------------- if isSignal: dblock = self.connectionTree.model().data(index.parent().parent(), Qt.UserRole) dplugin = self.connectionTree.model().data( index.parent().parent().parent(), Qt.UserRole) signal_uname = self.connectionTree.model().data(index, Qt.UserRole) signals.append(signal_uname) else: dblock = self.connectionTree.model().data(index, Qt.UserRole) dplugin = self.connectionTree.model().data(index.parent(), Qt.UserRole) if subscriberPart: action = QAction('Remove Subscriber', self) action.triggered.connect(lambda ignore, p=dblock, m=dplugin: self. remove_subscriber_action(m, p)) if subscriptionPart: action = QAction('Remove Subscription', self) action.triggered.connect( lambda ignore, p=dblock, m=dplugin, s=signals: self. cancel_subscription_action(m, p, s)) actionCollapsAll = QAction('Collapse all', self) actionCollapsAll.triggered.connect(self.connectionTree.collapseAll) actionExpandAll = QAction('Expand all', self) actionExpandAll.triggered.connect(self.connectionTree.expandAll) menu = QMenu('Remove') menu.addAction(action) menu.addAction(actionCollapsAll) menu.addAction(actionExpandAll) menu.exec_(self.connectionTree.viewport().mapToGlobal(position)) def open_context_menu_parameter_tree(self, position): """ This callback function is called to create a context menu for the parameter tree :param position: :return: """ index = self.parameterTree.indexAt(position) if index.isValid() is False: return None if self.parameterTree.isIndexHidden(index): return index_sibling = index.sibling(index.row(), index.column() - 1) if index_sibling.isValid(): index = index_sibling dparameter = self.parameterTree.model().data(index, Qt.UserRole) dplugin = self.pluginTree.model().data(self.pluginTree.currentIndex(), Qt.UserRole) sub_menu = QMenu('Control by') dplugin_ids = self.dgui.get_all_plugins() for dplugin_id in dplugin_ids: dplugin_pcp = dplugin_ids[dplugin_id] if len(dplugin_pcp.get_devent()) > 0: # action = QAction(self.tr(dplugin.uname), self) # sub_menu.addAction(action) pcp_menu = QMenu(self.tr(dplugin_pcp.uname), sub_menu) sub_menu.addMenu(pcp_menu) dblock_pcp_ids = dplugin_pcp.get_dblocks() for dblock_pcp_id in dblock_pcp_ids: dblock_pcp = dblock_pcp_ids[dblock_pcp_id] count = len(dblock_pcp.get_subscribers()) action = QAction( self.tr(dblock_pcp.name) + ' (' + str(count) + ')', pcp_menu) pcp_menu.addAction(action) action.triggered.connect( lambda ignore, p1=dplugin, p2=dparameter, p3= dplugin_pcp, p4=dblock_pcp: self. add_pcp_subscription_action(p1, p2, p3, p4)) menu = QMenu() menu.addMenu(sub_menu) menu.exec_(self.parameterTree.viewport().mapToGlobal(position)) def add_pcp_subscription_action(self, dplugin: DPlugin, dparameter: DParameter, dplugin_pcp: DPlugin, dblock_pcp: DBlock): """ This function is used to create a subscription for a process control plugin. :param dplugin: Subscriber of a pcp plugin :param dparameter: Parameter of the subscriber which should be controlled by the pcp plugin. :param dplugin_pcp: The pcp plugin :param dblock_pcp: Block of the pcp plugin which is used to control the subscriber's parameter. :return: """ self.gui_api.do_subscribe(dplugin.id, dplugin_pcp.id, dblock_pcp.name, [], dparameter.name) def add_subscription_action(self, dplugin_uname): """ Used to add subscription for a specific dplugin :param dplugin_uname: Add Subscription for this DPlugin :return: """ signals = [] dplugin = self.gui_api.gui_data.get_dplugin_by_uname(dplugin_uname) indexes = self.blockTree.selectedIndexes() for index in indexes: if index.isValid(): signal = self.blockTree.model().data(index, Qt.UserRole) signals.append(signal.uname) index_dblock = index.parent() dblock = self.blockTree.model().data(index_dblock, Qt.UserRole) index = self.pluginTree.currentIndex() dplugin_source = self.pluginTree.model().data(index, Qt.UserRole) self.gui_api.do_subscribe(dplugin.id, dplugin_source.id, dblock.name, signals) #self.blockTree.scrollTo(indexes[-1]) def remove_subscriber_action(self, subscriber: DPlugin, dblock: DBlock): """ Used to remove a subscriber of the dplugin selected in the DPlugin tree. :param subscriber: Subscriber which is effected :param dblock: DBlock which should be unsubscribed by Subscriber :return: """ index = self.pluginTree.currentIndex() source = self.pluginTree.model().data(index, Qt.UserRole) self.gui_api.do_unsubscribe_uname(subscriber.uname, source.uname, dblock.name, []) def refresh_action(self, new_dplugin: DPlugin = None): """ Used to refresh the overview menu view. :param new_dplugin: New dplugin which should be added in self.dpluginTreev. :return: """ # ----------------------------------------- # case: no DPlugin was added or removed # e.g. parameter was changed # ----------------------------------------- index = self.pluginTree.currentIndex() dplugin = self.pluginTree.model().data(index, Qt.UserRole) if dplugin is not None: if dplugin.state == PLUGIN_STATE_DELETE: self.pluginWidget.setDisabled(True) self.clear() else: self.pluginWidget.setEnabled(True) self.plugin_item_refresh(index) # ----------------------------------------- # case: remove already deleted plugins # ----------------------------------------- key_copy = self.plugin_roots.copy().keys() for root in key_copy: self.plugin_roots[root].clean() if not self.plugin_roots[root].rowCount(): self.dpluginModel.remove_item(self.plugin_roots[root]) del self.plugin_roots[root] self.subscribers_root.clean() self.subscriptions_root.clean() # self.subscribersTree # ----------------------------------------- # case: a DPlugin was added # ----------------------------------------- if new_dplugin is not None: plugin_item = DPluginTreeItem(new_dplugin) plugin_root = self.get_plugin_root(new_dplugin.path) if not plugin_root.hasItem(new_dplugin): plugin_root.appendRow(plugin_item) if plugin_root not in self.dpluginModel.findItems( "", Qt.MatchContains): self.dpluginModel.appendRow(plugin_root) def cancel_subscription_action(self, source: DPlugin, dblock: DBlock, signals: []): """ Action called to cancel a subscription of the current selected dplugin. :param source: :param dblock: :return: """ index = self.pluginTree.currentIndex() subscriber = self.pluginTree.model().data(index, Qt.UserRole) self.gui_api.do_unsubscribe_uname(subscriber.uname, source.uname, dblock.name, signals) def showEvent(self, *args, **kwargs): """ ShowEvent of this class. :param args: :param kwargs: :return: """ dplugin_ids = self.dgui.get_all_plugins() for dplugin_id in dplugin_ids: dplugin = dplugin_ids[dplugin_id] # ------------------------------ # Sort DPluginItem in TreeWidget # ------------------------------ plugin_item = DPluginTreeItem(dplugin) plugin_root = self.get_plugin_root(dplugin.path) plugin_root.appendRow(plugin_item) for root in sorted(self.plugin_roots.keys()): self.pluginTree.model().sourceModel().appendRow( self.plugin_roots[root]) self.plugin_roots[root].sortChildren(0) self.pluginTree.expandAll() def play_button_callback(self): """ Callback function for the play button. :return: """ index = self.pluginTree.currentIndex() item = self.pluginTree.model().data(index, Qt.UserRole) if item is not None: self.gui_api.do_resume_plugin_by_id(item.id) self.playButton.setDisabled(True) self.pauseButton.setDisabled(False) self.stopButton.setDisabled(False) def pause_button_callback(self): """ Function pause_button_callback :return: """ index = self.pluginTree.currentIndex() item = self.pluginTree.model().data(index, Qt.UserRole) if item is not None: self.pauseButton.setDisabled(True) self.playButton.setDisabled(False) self.gui_api.do_pause_plugin_by_id(item.id) def stop_start_button_callback(self): """ Function stop_start_button_callback :return: """ index = self.pluginTree.currentIndex() item = self.pluginTree.model().data(index, Qt.UserRole) if item is not None: if self.stopButton.text() == 'STOP': self.gui_api.do_stopReset_pluign(item.id) self.stopButton.setText('START') self.pauseButton.setDisabled(True) self.playButton.setDisabled(True) self.stopButton.setDisabled(False) else: self.gui_api.do_start_plugin(item.id) self.stopButton.setText('STOP') self.pauseButton.setDisabled(False) self.playButton.setDisabled(False) self.stopButton.setDisabled(False) def show_internal_name_callback(self): """ Callback function for 'showInternalNameCheckBox' :return: """ self.plugin_item_changed(self.pluginTree.currentIndex()) def data_changed_parameter_model(self, index, n): """ This function is called when a dparameter value is changed by editing the 'value'-column. :param index: Index of current changed dparameter :param n: None :return: """ dparameter = self.parameterTree.model().data(index, Qt.UserRole) index = self.pluginTree.currentIndex() dplugin = self.pluginTree.model().data(index, Qt.UserRole) self.gui_api.do_set_parameter(dplugin.id, dparameter.name, dparameter.value) def data_changed_block_model(self, index, n): """ This function is called when a dblock child, a disgnal, is changed. :param index: Index of current changed dsignal object :param n: None :return: """ dsignal = self.blockTree.model().data(index, Qt.UserRole) dblock = self.blockTree.model().data(index.parent(), Qt.UserRole) dplugin = self.pluginTree.model().data(self.pluginTree.currentIndex(), Qt.UserRole) self.gui_api.do_edit_plugin_uname(dplugin.uname, dblock, {"edit": dsignal}) def get_plugin_root(self, path): parts = path.split('/') part = parts[-3] name = part if part not in self.plugin_roots: cfg_file = str.join("/", parts[0:-2]) + "/" + pc.GUI_PLUGIN_CONFIG if os.path.isfile(cfg_file): config = configparser.ConfigParser() config.read(cfg_file) if 'Config' in config.sections(): if 'name' in config.options('Config'): name = config.get('Config', 'name') self.plugin_roots[part] = PaPIRootItem(name) return self.plugin_roots[part] def changed_search_plugin_text_field(self, value): if not len(value): value = "*" self.pluginTree.collapseAll() else: value = "*" + value + "*" self.pluginTree.expandAll() self.pluginProxyModel.sourceModel().mark_visibility_by_name(value) # Used to trigger filter action regex = QRegExp(value, Qt.CaseInsensitive, QRegExp.Wildcard) self.pluginProxyModel.setFilterRegExp(regex) def show_create_plugin_dialog(self, dplugin): if dplugin.type == PLUGIN_VIP_IDENTIFIER: dplugin.startup_config = dplugin.plugin.pl_get_current_config() self.plugin_create_dialog.set_dplugin( dplugin, dplugin.plugin._get_startup_configuration(), dplugin.type) self.plugin_create_dialog.show() def keyPressEvent(self, event): """ Used to handle key events for this gui element. :param event: KeyEvent :return: """ if event.key() == Qt.Key_Escape: self.close() if self.pluginTree.hasFocus() and \ event.key() in [Qt.Key_Return, Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right]: self.plugin_item_changed(self.pluginTree.currentIndex()) # if search bar has focus and user pressed enter/return,arrow up/down, change focus to the plugin tree if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter or event.key() == Qt.Key_Down \ or event.key() == Qt.Key_Up) and self.pluginSearchText.hasFocus(): self.pluginTree.setFocus(Qt.OtherFocusReason) def changed_dplugin_tree_selection(self, new_selection, old_selection): pass
def __init__(self, gui_api, tabmanager, parent=None): """ Constructor of this class. 'gui_api' provides an access to all functions which are needed for the functionality of the GUI. 'tabmanager' manages the tabs of the gui :param gui_api: :param tabmanager: :param parent: :return: """ super(OverviewPluginMenu, self).__init__(parent) self.setupUi(self) self.dgui = gui_api.gui_data self.gui_api = gui_api self.TabManager = tabmanager; self.setWindowTitle("OverviewMenu") self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager) # ---------------------------------- # Build structure of plugin tree # ---------------------------------- self.dpluginModel = DPluginTreeModel() self.dpluginModel.setHorizontalHeaderLabels(['Name']) self.pluginProxyModel = PaPITreeProxyModel(self) self.pluginProxyModel.setSourceModel(self.dpluginModel) regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard) self.pluginProxyModel.setFilterRegExp(regex) self.pluginTree.setModel(self.pluginProxyModel) self.pluginTree.setUniformRowHeights(True) self.plugin_roots = {} # ----------------------------------- # Build structure of parameter tree # ----------------------------------- self.dparameterModel = DParameterTreeModel() self.dparameterModel.setHorizontalHeaderLabels(['Name']) self.parameterTree.setModel(self.dparameterModel) self.parameterTree.setUniformRowHeights(True) self.dparameterModel.dataChanged.connect(self.data_changed_parameter_model) # ----------------------------------- # Build structure of block tree # ----------------------------------- self.bModel = DBlockTreeModel(self.showInternalNameCheckBox) self.bModel.setHorizontalHeaderLabels(['Name']) self.bModel.setColumnCount(2) self.blockTree.setModel(self.bModel) self.blockTree.setUniformRowHeights(True) self.bModel.dataChanged.connect(self.data_changed_block_model) self.showInternalNameCheckBox.clicked.connect(self.show_internal_name_callback) # ----------------------------------- # Build structure of connection tree # ----------------------------------- self.connectionModel = PaPITreeModel() self.connectionModel.setHorizontalHeaderLabels(['']) self.connectionTree.setHeaderHidden(True) self.connectionTree.setModel(self.connectionModel) self.connectionTree.setUniformRowHeights(True) self.subscribers_root = PaPIRootItem('Subscribers') self.connectionModel.appendRow(self.subscribers_root) self.subscriptions_root = PaPIRootItem('Subscriptions') self.connectionModel.appendRow(self.subscriptions_root) # ----------------------------------- # signal/slots # ----------------------------------- self.playButton.clicked.connect(self.play_button_callback) self.pauseButton.clicked.connect(self.pause_button_callback) self.stopButton.clicked.connect(self.stop_start_button_callback) self.pluginTree.clicked.connect(self.plugin_item_changed) self.pluginTree.selectionModel().selectionChanged.connect(self.changed_dplugin_tree_selection) self.pluginTree.setStyleSheet(pc.TREE_CSS) # ---------------------------------- # Add context menu # ---------------------------------- self.pluginTree.setContextMenuPolicy(Qt.CustomContextMenu) self.pluginTree.customContextMenuRequested.connect(self.open_context_menu_dplugin_tree) self.blockTree.setContextMenuPolicy(Qt.CustomContextMenu) self.blockTree.customContextMenuRequested.connect(self.open_context_menu_block_tree) self.parameterTree.setContextMenuPolicy(Qt.CustomContextMenu) self.parameterTree.customContextMenuRequested.connect(self.open_context_menu_parameter_tree) self.connectionTree.setContextMenuPolicy(Qt.CustomContextMenu) self.connectionTree.customContextMenuRequested.connect(self.open_context_menu_connection_tree) # ---------------------------------- # Add Actions # ---------------------------------- self.actionRefresh.triggered.connect(self.refresh_action) self.pluginSearchText.textChanged.connect(self.changed_search_plugin_text_field) self.clear() # set focus to the search bar self.pluginSearchText.setFocus(Qt.OtherFocusReason)
class OverviewPluginMenu(QMainWindow, Ui_PluginOverviewMenu): """ This class is used to create an extra window which displays all created plugins. The information are taken by the corresponding DPlugin-Object of a plugin. By this window a user is also able to create and cancel subscriptions. """ def __init__(self, gui_api, tabmanager, parent=None): """ Constructor of this class. 'gui_api' provides an access to all functions which are needed for the functionality of the GUI. 'tabmanager' manages the tabs of the gui :param gui_api: :param tabmanager: :param parent: :return: """ super(OverviewPluginMenu, self).__init__(parent) self.setupUi(self) self.dgui = gui_api.gui_data self.gui_api = gui_api self.TabManager = tabmanager; self.setWindowTitle("OverviewMenu") self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager) # ---------------------------------- # Build structure of plugin tree # ---------------------------------- self.dpluginModel = DPluginTreeModel() self.dpluginModel.setHorizontalHeaderLabels(['Name']) self.pluginProxyModel = PaPITreeProxyModel(self) self.pluginProxyModel.setSourceModel(self.dpluginModel) regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard) self.pluginProxyModel.setFilterRegExp(regex) self.pluginTree.setModel(self.pluginProxyModel) self.pluginTree.setUniformRowHeights(True) self.plugin_roots = {} # ----------------------------------- # Build structure of parameter tree # ----------------------------------- self.dparameterModel = DParameterTreeModel() self.dparameterModel.setHorizontalHeaderLabels(['Name']) self.parameterTree.setModel(self.dparameterModel) self.parameterTree.setUniformRowHeights(True) self.dparameterModel.dataChanged.connect(self.data_changed_parameter_model) # ----------------------------------- # Build structure of block tree # ----------------------------------- self.bModel = DBlockTreeModel(self.showInternalNameCheckBox) self.bModel.setHorizontalHeaderLabels(['Name']) self.bModel.setColumnCount(2) self.blockTree.setModel(self.bModel) self.blockTree.setUniformRowHeights(True) self.bModel.dataChanged.connect(self.data_changed_block_model) self.showInternalNameCheckBox.clicked.connect(self.show_internal_name_callback) # ----------------------------------- # Build structure of connection tree # ----------------------------------- self.connectionModel = PaPITreeModel() self.connectionModel.setHorizontalHeaderLabels(['']) self.connectionTree.setHeaderHidden(True) self.connectionTree.setModel(self.connectionModel) self.connectionTree.setUniformRowHeights(True) self.subscribers_root = PaPIRootItem('Subscribers') self.connectionModel.appendRow(self.subscribers_root) self.subscriptions_root = PaPIRootItem('Subscriptions') self.connectionModel.appendRow(self.subscriptions_root) # ----------------------------------- # signal/slots # ----------------------------------- self.playButton.clicked.connect(self.play_button_callback) self.pauseButton.clicked.connect(self.pause_button_callback) self.stopButton.clicked.connect(self.stop_start_button_callback) self.pluginTree.clicked.connect(self.plugin_item_changed) self.pluginTree.selectionModel().selectionChanged.connect(self.changed_dplugin_tree_selection) self.pluginTree.setStyleSheet(pc.TREE_CSS) # ---------------------------------- # Add context menu # ---------------------------------- self.pluginTree.setContextMenuPolicy(Qt.CustomContextMenu) self.pluginTree.customContextMenuRequested.connect(self.open_context_menu_dplugin_tree) self.blockTree.setContextMenuPolicy(Qt.CustomContextMenu) self.blockTree.customContextMenuRequested.connect(self.open_context_menu_block_tree) self.parameterTree.setContextMenuPolicy(Qt.CustomContextMenu) self.parameterTree.customContextMenuRequested.connect(self.open_context_menu_parameter_tree) self.connectionTree.setContextMenuPolicy(Qt.CustomContextMenu) self.connectionTree.customContextMenuRequested.connect(self.open_context_menu_connection_tree) # ---------------------------------- # Add Actions # ---------------------------------- self.actionRefresh.triggered.connect(self.refresh_action) self.pluginSearchText.textChanged.connect(self.changed_search_plugin_text_field) self.clear() # set focus to the search bar self.pluginSearchText.setFocus(Qt.OtherFocusReason) def clear(self): """ This function will clear this window. It is used to reset all elements in this windows. :return: """ self.bModel.clear() self.dparameterModel.clear() self.subscribers_root.setRowCount(0) self.subscriptions_root.setRowCount(0) self.unameEdit.setText('') self.usedpluginEdit.setText('') self.stateEdit.setText('') self.typeEdit.setText('') self.alivestateEdit.setText('') self.bModel.setHorizontalHeaderLabels(['Name']) self.dparameterModel.setHorizontalHeaderLabels(['Name', 'Value']) self.connectionModel.setHorizontalHeaderLabels(['']) def plugin_item_changed(self, index): """ Used to display all known information for a DPlugin which is accessible in the pluginTree by its index. It is called when an user changes the selected plugin in the plugin tree. :param index: Current selected index :return: """ dplugin = self.pluginTree.model().data(index, Qt.UserRole) self.clear() if dplugin is None: self.pluginWidget.setDisabled(True) return self.pluginWidget.setDisabled(False) # ------------------------------------ # Get all needed dplugin information # ------------------------------------ self.unameEdit.setText(dplugin.uname) self.usedpluginEdit.setText(dplugin.plugin_identifier) self.stateEdit.setText(dplugin.state) self.typeEdit.setText(dplugin.type) self.alivestateEdit.setText(dplugin.alive_state) self.pauseButton.setDisabled(False) self.playButton.setDisabled(False) self.stopButton.setDisabled(False) if dplugin.alive_state != PLUGIN_STATE_DEAD: if dplugin.state == PLUGIN_STATE_PAUSE: self.pauseButton.setDisabled(True) if dplugin.state == PLUGIN_STATE_STOPPED: self.pauseButton.setDisabled(True) self.playButton.setDisabled(True) self.stopButton.setText('START') if dplugin.state == PLUGIN_STATE_RESUMED: self.playButton.setDisabled(True) if dplugin.state == PLUGIN_STATE_START_SUCCESFUL: self.playButton.setDisabled(True) self.stopButton.setText('STOP') # --------------------------- # Add DBlocks(Also DEvent) # --------------------------- dblock_ids = dplugin.get_dblocks() for dblock_id in dblock_ids: dblock = dblock_ids[dblock_id] block_item = DBlockTreeItem(dblock) self.bModel.appendRow(block_item) # ------------------------- # Add Signals of this DBlock # ------------------------- for signal in dblock.get_signals(): if signal.uname not in [pc.CORE_TIME_SIGNAL]: signal_item = DSignalTreeItem(signal, self.showInternalNameCheckBox) block_item.appendRow(signal_item) block_item.sortChildren(0) # ---------------------------------- # Add Subscribers of this DBlock # ---------------------------------- subscriber_ids = dblock.get_subscribers() for subscriber_id in subscriber_ids: # Other plugin subscriber = self.dgui.get_dplugin_by_id(subscriber_id) if dplugin.id in subscriber.get_subscribtions(): for dblock_sub_id in subscriber.get_subscribtions()[dplugin.id]: subscriber_item = DPluginTreeItem(subscriber) # self.subscriberModel.appendRow(subscriber_item) self.subscribers_root.appendRow(subscriber_item) subscription = subscriber.get_subscribtions()[dplugin.id][dblock_sub_id] block_item = DBlockTreeItem(dblock) subscriber_item.appendRow(block_item) subscription_item = PaPITreeItem(subscription, "Signals") block_item.appendRow(subscription_item) for signal_uname in sorted(subscription.get_signals()): if signal_uname not in [pc.CORE_TIME_SIGNAL]: signal_item = PaPITreeItem(signal_uname, signal_uname) subscription_item.appendRow(signal_item) # ------------------------- # Add all Subscriptions # for this plugin # ------------------------- dplugin_sub_ids = dplugin.get_subscribtions() for dplugin_sub_id in dplugin_sub_ids: dblock_names = dplugin_sub_ids[dplugin_sub_id] dplugin_sub = self.gui_api.gui_data.get_dplugin_by_id(dplugin_sub_id) dplugin_sub_item = DPluginTreeItem(dplugin_sub) #self.subscriptionModel.appendRow(dplugin_sub_item) self.subscriptions_root.appendRow(dplugin_sub_item) for dblock_name in dblock_names: dblock_sub = dplugin_sub.get_dblock_by_name(dblock_name) dblock_sub_item = DBlockTreeItem(dblock_sub) dplugin_sub_item.appendRow(dblock_sub_item) subscription = dblock_names[dblock_name] subscription_item = PaPITreeItem(subscription, "Signals") dblock_sub_item.appendRow(subscription_item) for signal_uname in sorted(subscription.get_signals()): if signal_uname not in [pc.CORE_TIME_SIGNAL]: signal_item = PaPITreeItem(signal_uname, signal_uname) subscription_item.appendRow(signal_item) # -------------------------- # Add DParameters # -------------------------- dparameter_names = dplugin.get_parameters() for dparameter_name in sorted(dparameter_names): dparameter = dparameter_names[dparameter_name] dparameter_item = DParameterTreeItem(dparameter) self.dparameterModel.appendRow(dparameter_item) self.parameterTree.resizeColumnToContents(0) self.parameterTree.resizeColumnToContents(1) self.blockTree.expandAll() self.parameterTree.expandAll() self.connectionTree.expandAll() # http://srinikom.github.io/pyside-docs/PySide/QtGui/QAbstractItemView.html \ # #PySide.QtGui.PySide.QtGui.QAbstractItemView.SelectionMode self.blockTree.setSelectionMode(QAbstractItemView.ExtendedSelection) # Sort Models self.bModel.sort(0) def plugin_item_refresh(self, index): """ This function is called when it's known that the dplugin object, which describes the selected plugin, was changed. :param index: :return: """ self.parameterTree.viewport().update() self.blockTree.viewport().update() self.connectionTree.viewport().update() def open_context_menu_dplugin_tree(self, position): """ This callback function is called to create a context menu for the dplugin tree. It is triggered by use :param position: :return: """ index = self.pluginTree.indexAt(position) if index.parent().isValid() is False: return None if index.isValid() is False: return None if self.pluginTree.isIndexHidden(index): return dplugin = self.pluginTree.model().data(index, Qt.UserRole) menu = QMenu('Menu') submenu = QMenu('Action') menu.addMenu(submenu) action = QAction('Remove plugin', self) submenu.addAction(action) action.triggered.connect(lambda ignore, p=dplugin.id: self.gui_api.do_delete_plugin(p)) action = QAction('Copy plugin', self) submenu.addAction(action) action.triggered.connect(lambda ignore, p=dplugin: self.show_create_plugin_dialog(p)) actionCollapsAll = QAction('Collapse all',self) actionCollapsAll.triggered.connect(self.pluginTree.collapseAll) actionExpandAll = QAction('Expand all',self) actionExpandAll.triggered.connect(self.pluginTree.expandAll) menu.addAction(actionCollapsAll) menu.addAction(actionExpandAll) menu.exec_(self.pluginTree.viewport().mapToGlobal(position)) def open_context_menu_block_tree(self, position): """ This callback function is called to create a context menu for the block tree :param position: :return: """ index = self.blockTree.indexAt(position) if index.isValid() is False: return None if self.blockTree.isIndexHidden(index): return item = self.blockTree.model().data(index, Qt.UserRole) if isinstance(item, DPlugin) or isinstance(item, DBlock): return index_sel = self.pluginTree.currentIndex() dplugin_sel = self.pluginTree.model().data(index_sel, Qt.UserRole) if dplugin_sel is not None: sub_menu = QMenu('Add Subscription') dplugin_ids = self.dgui.get_all_plugins() for dplugin_id in dplugin_ids: dplugin = dplugin_ids[dplugin_id] if dplugin_sel.id != dplugin_id: action = QAction(self.tr(dplugin.uname), self) sub_menu.addAction(action) action.triggered.connect(lambda ignore, p=dplugin.uname: self.add_subscription_action(p)) menu = QMenu() menu.addMenu(sub_menu) menu.exec_(self.blockTree.viewport().mapToGlobal(position)) def open_context_menu_connection_tree(self, position): """ This callback function is called to create a context menu for the subscriper tree :param position: :return: """ index = self.connectionTree.indexAt(position) if index.isValid() is False: return None if self.connectionTree.isIndexHidden(index): return None if index.parent().isValid() is False: return None parIndex = index subscriberPart = False subscriptionPart = False signals = [] isSignal = False while True: object = self.connectionTree.model().data(parIndex, Qt.DisplayRole) if "Subscribers" in object: subscriberPart = True if "Subscriptions" in object: subscriptionPart = True if ( subscriptionPart or subscriberPart ): break parIndex = parIndex.parent() if parIndex.isValid() is False: return if not (subscriptionPart or subscriberPart): return None if isinstance(self.connectionTree.model().data(index, Qt.UserRole), DSubscription): return if isinstance(self.connectionTree.model().data(index, Qt.UserRole), DPlugin): return # ---------------------------------- # Open no context menu for signals # ---------------------------------- if isinstance(self.connectionTree.model().data(index, Qt.UserRole), str): isSignal = True else: isSignal = False # ---------------------------------- # Get necessary objects for this subscription/subscriber # ---------------------------------- if isSignal: dblock = self.connectionTree.model().data(index.parent().parent(), Qt.UserRole) dplugin = self.connectionTree.model().data(index.parent().parent().parent(), Qt.UserRole) signal_uname = self.connectionTree.model().data(index, Qt.UserRole) signals.append(signal_uname) else: dblock = self.connectionTree.model().data(index, Qt.UserRole) dplugin = self.connectionTree.model().data(index.parent(), Qt.UserRole) if subscriberPart: action = QAction('Remove Subscriber', self) action.triggered.connect(lambda ignore, p=dblock, m=dplugin: self.remove_subscriber_action(m, p)) if subscriptionPart: action = QAction('Remove Subscription', self) action.triggered.connect(lambda ignore, p=dblock, m=dplugin, s=signals: self.cancel_subscription_action(m, p, s)) actionCollapsAll = QAction('Collapse all',self) actionCollapsAll.triggered.connect(self.connectionTree.collapseAll) actionExpandAll = QAction('Expand all',self) actionExpandAll.triggered.connect(self.connectionTree.expandAll) menu = QMenu('Remove') menu.addAction(action) menu.addAction(actionCollapsAll) menu.addAction(actionExpandAll) menu.exec_(self.connectionTree.viewport().mapToGlobal(position)) def open_context_menu_parameter_tree(self, position): """ This callback function is called to create a context menu for the parameter tree :param position: :return: """ index = self.parameterTree.indexAt(position) if index.isValid() is False: return None if self.parameterTree.isIndexHidden(index): return index_sibling = index.sibling(index.row(), index.column()-1) if index_sibling.isValid(): index = index_sibling dparameter = self.parameterTree.model().data(index, Qt.UserRole) dplugin = self.pluginTree.model().data(self.pluginTree.currentIndex(), Qt.UserRole) sub_menu = QMenu('Control by') dplugin_ids = self.dgui.get_all_plugins() for dplugin_id in dplugin_ids: dplugin_pcp = dplugin_ids[dplugin_id] if len(dplugin_pcp.get_devent()) > 0: # action = QAction(self.tr(dplugin.uname), self) # sub_menu.addAction(action) pcp_menu = QMenu(self.tr(dplugin_pcp.uname), sub_menu) sub_menu.addMenu(pcp_menu) dblock_pcp_ids = dplugin_pcp.get_dblocks() for dblock_pcp_id in dblock_pcp_ids: dblock_pcp = dblock_pcp_ids[dblock_pcp_id] count = len(dblock_pcp.get_subscribers()) action = QAction(self.tr(dblock_pcp.name)+' ('+str(count)+')', pcp_menu) pcp_menu.addAction(action) action.triggered.connect(lambda ignore, p1=dplugin, p2=dparameter, p3=dplugin_pcp, p4=dblock_pcp: self.add_pcp_subscription_action(p1, p2, p3, p4)) menu = QMenu() menu.addMenu(sub_menu) menu.exec_(self.parameterTree.viewport().mapToGlobal(position)) def add_pcp_subscription_action(self, dplugin: DPlugin, dparameter: DParameter, dplugin_pcp: DPlugin, dblock_pcp: DBlock): """ This function is used to create a subscription for a process control plugin. :param dplugin: Subscriber of a pcp plugin :param dparameter: Parameter of the subscriber which should be controlled by the pcp plugin. :param dplugin_pcp: The pcp plugin :param dblock_pcp: Block of the pcp plugin which is used to control the subscriber's parameter. :return: """ self.gui_api.do_subscribe(dplugin.id, dplugin_pcp.id, dblock_pcp.name, [], dparameter.name) def add_subscription_action(self, dplugin_uname): """ Used to add subscription for a specific dplugin :param dplugin_uname: Add Subscription for this DPlugin :return: """ signals = [] dplugin = self.gui_api.gui_data.get_dplugin_by_uname(dplugin_uname) indexes = self.blockTree.selectedIndexes() for index in indexes: if index.isValid(): signal = self.blockTree.model().data(index, Qt.UserRole) signals.append(signal.uname) index_dblock = index.parent() dblock = self.blockTree.model().data(index_dblock, Qt.UserRole) index = self.pluginTree.currentIndex() dplugin_source = self.pluginTree.model().data(index, Qt.UserRole) self.gui_api.do_subscribe(dplugin.id, dplugin_source.id, dblock.name, signals) #self.blockTree.scrollTo(indexes[-1]) def remove_subscriber_action(self, subscriber: DPlugin, dblock: DBlock): """ Used to remove a subscriber of the dplugin selected in the DPlugin tree. :param subscriber: Subscriber which is effected :param dblock: DBlock which should be unsubscribed by Subscriber :return: """ index = self.pluginTree.currentIndex() source = self.pluginTree.model().data(index, Qt.UserRole) self.gui_api.do_unsubscribe_uname(subscriber.uname, source.uname, dblock.name, []) def refresh_action(self, new_dplugin: DPlugin=None): """ Used to refresh the overview menu view. :param new_dplugin: New dplugin which should be added in self.dpluginTreev. :return: """ # ----------------------------------------- # case: no DPlugin was added or removed # e.g. parameter was changed # ----------------------------------------- index = self.pluginTree.currentIndex() dplugin = self.pluginTree.model().data(index, Qt.UserRole) if dplugin is not None: if dplugin.state == PLUGIN_STATE_DELETE: self.pluginWidget.setDisabled(True) self.clear() else: self.pluginWidget.setEnabled(True) self.plugin_item_refresh(index) # ----------------------------------------- # case: remove already deleted plugins # ----------------------------------------- key_copy = self.plugin_roots.copy().keys() for root in key_copy: self.plugin_roots[root].clean() if not self.plugin_roots[root].rowCount(): self.dpluginModel.remove_item(self.plugin_roots[root]) del self.plugin_roots[root] self.subscribers_root.clean() self.subscriptions_root.clean() # self.subscribersTree # ----------------------------------------- # case: a DPlugin was added # ----------------------------------------- if new_dplugin is not None: plugin_item = DPluginTreeItem(new_dplugin) plugin_root = self.get_plugin_root(new_dplugin.path) if not plugin_root.hasItem(new_dplugin): plugin_root.appendRow(plugin_item) if plugin_root not in self.dpluginModel.findItems("", Qt.MatchContains): self.dpluginModel.appendRow(plugin_root) def cancel_subscription_action(self, source: DPlugin, dblock: DBlock, signals: []): """ Action called to cancel a subscription of the current selected dplugin. :param source: :param dblock: :return: """ index = self.pluginTree.currentIndex() subscriber = self.pluginTree.model().data(index, Qt.UserRole) self.gui_api.do_unsubscribe_uname(subscriber.uname, source.uname, dblock.name, signals) def showEvent(self, *args, **kwargs): """ ShowEvent of this class. :param args: :param kwargs: :return: """ dplugin_ids = self.dgui.get_all_plugins() for dplugin_id in dplugin_ids: dplugin = dplugin_ids[dplugin_id] # ------------------------------ # Sort DPluginItem in TreeWidget # ------------------------------ plugin_item = DPluginTreeItem(dplugin) plugin_root = self.get_plugin_root(dplugin.path) plugin_root.appendRow(plugin_item) for root in sorted(self.plugin_roots.keys()): self.pluginTree.model().sourceModel().appendRow(self.plugin_roots[root]) self.plugin_roots[root].sortChildren(0) self.pluginTree.expandAll() def play_button_callback(self): """ Callback function for the play button. :return: """ index = self.pluginTree.currentIndex() item = self.pluginTree.model().data(index, Qt.UserRole) if item is not None: self.gui_api.do_resume_plugin_by_id(item.id) self.playButton.setDisabled(True) self.pauseButton.setDisabled(False) self.stopButton.setDisabled(False) def pause_button_callback(self): """ Function pause_button_callback :return: """ index = self.pluginTree.currentIndex() item = self.pluginTree.model().data(index, Qt.UserRole) if item is not None: self.pauseButton.setDisabled(True) self.playButton.setDisabled(False) self.gui_api.do_pause_plugin_by_id(item.id) def stop_start_button_callback(self): """ Function stop_start_button_callback :return: """ index = self.pluginTree.currentIndex() item = self.pluginTree.model().data(index, Qt.UserRole) if item is not None: if self.stopButton.text() == 'STOP': self.gui_api.do_stopReset_pluign(item.id) self.stopButton.setText('START') self.pauseButton.setDisabled(True) self.playButton.setDisabled(True) self.stopButton.setDisabled(False) else: self.gui_api.do_start_plugin(item.id) self.stopButton.setText('STOP') self.pauseButton.setDisabled(False) self.playButton.setDisabled(False) self.stopButton.setDisabled(False) def show_internal_name_callback(self): """ Callback function for 'showInternalNameCheckBox' :return: """ self.plugin_item_changed(self.pluginTree.currentIndex()) def data_changed_parameter_model(self, index, n): """ This function is called when a dparameter value is changed by editing the 'value'-column. :param index: Index of current changed dparameter :param n: None :return: """ dparameter = self.parameterTree.model().data(index, Qt.UserRole) index = self.pluginTree.currentIndex() dplugin = self.pluginTree.model().data(index, Qt.UserRole) self.gui_api.do_set_parameter(dplugin.id, dparameter.name, dparameter.value) def data_changed_block_model(self, index, n): """ This function is called when a dblock child, a disgnal, is changed. :param index: Index of current changed dsignal object :param n: None :return: """ dsignal = self.blockTree.model().data(index, Qt.UserRole) dblock = self.blockTree.model().data(index.parent(), Qt.UserRole) dplugin = self.pluginTree.model().data(self.pluginTree.currentIndex(), Qt.UserRole) self.gui_api.do_edit_plugin_uname(dplugin.uname, dblock, {"edit" : dsignal}) def get_plugin_root(self,path): parts = path.split('/'); part = parts[-3] name = part if part not in self.plugin_roots: cfg_file = str.join("/", parts[0:-2]) + "/" + pc.GUI_PLUGIN_CONFIG if os.path.isfile(cfg_file): config = configparser.ConfigParser() config.read(cfg_file) if 'Config' in config.sections(): if 'name' in config.options('Config'): name = config.get('Config', 'name') self.plugin_roots[part] = PaPIRootItem(name) return self.plugin_roots[part] def changed_search_plugin_text_field(self, value): if not len(value): value = "*" self.pluginTree.collapseAll() else: value = "*" + value + "*" self.pluginTree.expandAll() self.pluginProxyModel.sourceModel().mark_visibility_by_name(value) # Used to trigger filter action regex = QRegExp(value, Qt.CaseInsensitive, QRegExp.Wildcard) self.pluginProxyModel.setFilterRegExp(regex) def show_create_plugin_dialog(self, dplugin): if dplugin.type == PLUGIN_VIP_IDENTIFIER: dplugin.startup_config = dplugin.plugin.pl_get_current_config() self.plugin_create_dialog.set_dplugin(dplugin, dplugin.plugin._get_startup_configuration(), dplugin.type) self.plugin_create_dialog.show() def keyPressEvent(self, event): """ Used to handle key events for this gui element. :param event: KeyEvent :return: """ if event.key() == Qt.Key_Escape: self.close() if self.pluginTree.hasFocus() and \ event.key() in [Qt.Key_Return, Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right]: self.plugin_item_changed(self.pluginTree.currentIndex()) # if search bar has focus and user pressed enter/return,arrow up/down, change focus to the plugin tree if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter or event.key() == Qt.Key_Down \ or event.key() == Qt.Key_Up) and self.pluginSearchText.hasFocus(): self.pluginTree.setFocus(Qt.OtherFocusReason) def changed_dplugin_tree_selection(self, new_selection, old_selection): pass