def __init__(self, gui_api, TabManger, plugin_manager, parent=None): super(CreatePluginMenu, self).__init__(parent) self.setupUi(self) self.dgui = gui_api.gui_data self.TabManager = TabManger self.gui_api = gui_api self.subscriberID = None self.targetID = None self.blockName = None self.plugin_manager = plugin_manager self.pluginTree.setDragEnabled(True) self.pluginTree.setDropIndicatorShown(True) self.setWindowTitle('Available Plugins') model = PaPITreeModel() model.setHorizontalHeaderLabels(['Name']) self.pluginProxyModel = PaPITreeProxyModel(self) self.pluginProxyModel.setSourceModel(model) regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard) self.pluginProxyModel.setFilterRegExp(regex) self.pluginTree.setModel(self.pluginProxyModel) self.pluginTree.setUniformRowHeights(True) self.pluginTree.setSortingEnabled(True) self.pluginTree.setStyleSheet(pc.TREE_CSS) self.plugin_roots = {} self.configuration_inputs = {} self.pluginTree.clicked.connect(self.pluginItemChanged) self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager) self.createButton.clicked.connect(self.show_create_plugin_dialog) self.helpButton.clicked.connect(self.help_button_triggered) self.finder = ModuleFinder() self.pluginSearchText.textChanged.connect( self.changed_search_plugin_text_field) self.pluginSearchText.setFocus(Qt.OtherFocusReason) self.helpButton.setText('') self.helpButton.setIcon(get16Icon('help.png')) self.helpButton.setToolTip( 'Opens the documentation for the currently selected plugin.')
def __init__(self, gui_api, TabManger, plugin_manager, parent=None): super(CreatePluginMenu, self).__init__(parent) self.setupUi(self) self.dgui = gui_api.gui_data self.TabManager = TabManger self.gui_api = gui_api self.subscriberID = None self.targetID = None self.blockName = None self.plugin_manager = plugin_manager self.pluginTree.setDragEnabled(True) self.pluginTree.setDropIndicatorShown(True) self.setWindowTitle('Available Plugins') model = PaPITreeModel() model.setHorizontalHeaderLabels(['Name']) self.pluginProxyModel = PaPITreeProxyModel(self) self.pluginProxyModel.setSourceModel(model) regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard) self.pluginProxyModel.setFilterRegExp(regex) self.pluginTree.setModel(self.pluginProxyModel) self.pluginTree.setUniformRowHeights(True) self.pluginTree.setSortingEnabled(True) self.pluginTree.setStyleSheet(pc.TREE_CSS) self.plugin_roots = {} self.configuration_inputs = {} self.pluginTree.clicked.connect(self.pluginItemChanged) self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager) self.createButton.clicked.connect(self.show_create_plugin_dialog) self.helpButton.clicked.connect(self.help_button_triggered) self.finder = ModuleFinder() self.pluginSearchText.textChanged.connect(self.changed_search_plugin_text_field) self.pluginSearchText.setFocus(Qt.OtherFocusReason) self.helpButton.setText('') self.helpButton.setIcon(get16Icon('help.png')) self.helpButton.setToolTip('Opens the documentation for the currently selected plugin.')
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, TabManger, plugin_manager, parent=None): """ Constructor of this class. 'gui_api' is used to access the GUI data storage 'DGUI' and for creating the plugin. 'TabManager' access to the tab manager is needed because it provides the information about all used tabs. 'plugin_manager' provides access to the yapsy manager which is used to parse the plugin information. :param gui_api: :param TabManger: :param plugin_manager: :param parent: :return: """ super(CreatePluginMenu, self).__init__(parent) self.setupUi(self) self.dgui = gui_api.gui_data self.TabManager = TabManger self.gui_api = gui_api self.subscriberID = None self.targetID = None self.blockName = None self.plugin_manager = plugin_manager self.pluginTree.setDragEnabled(True) self.pluginTree.setDropIndicatorShown(True) self.setWindowTitle('Available Plugins') model = PaPITreeModel() model.setHorizontalHeaderLabels(['Name']) self.pluginProxyModel = PaPITreeProxyModel(self) self.pluginProxyModel.setSourceModel(model) regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard) self.pluginProxyModel.setFilterRegExp(regex) self.pluginTree.setModel(self.pluginProxyModel) self.pluginTree.setUniformRowHeights(True) self.pluginTree.setSortingEnabled(True) self.pluginTree.setStyleSheet(pc.TREE_CSS) self.plugin_roots = {} self.configuration_inputs = {} self.pluginTree.clicked.connect(self.plugin_item_changed) self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager) self.createButton.clicked.connect(self.show_create_plugin_dialog) self.helpButton.clicked.connect(self.help_button_triggered) self.finder = ModuleFinder() self.pluginSearchText.textChanged.connect(self.changed_search_plugin_text_field) self.pluginSearchText.setFocus(Qt.OtherFocusReason) self.helpButton.setText('') self.helpButton.setIcon(get16Icon('help.png')) self.helpButton.setToolTip('Opens the documentation for the currently selected plugin.')
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