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 _ctrlMenu_copy(self): """ Callback function for context menu for copying plugins :return: """ dplugin = self.control_api.get_dplugin_by_uname(self._dplugin_info.uname) dplugin.startup_config = self.pl_get_current_config() plugin_create_dialog = CreatePluginDialog(self.control_api, self.TabManager, parent=self._widget) plugin_create_dialog.set_dplugin(dplugin, self._get_startup_configuration(), self._get_type()) print() plugin_create_dialog.show()
class CreatePluginMenu(QMainWindow, Ui_PluginCreateMenu): 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 keyPressEvent(self, event): if event.key() in [Qt.Key_Right, Qt.Key_Space]: index = self.pluginTree.currentIndex() self.pluginItemChanged(index) if event.key() == Qt.Key_Escape: self.close() # Use enter/return to bring up the dialog for a selected plugin if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter) and self.pluginTree.hasFocus(): self.show_create_plugin_dialog() # 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 pluginItemChanged(self, index): plugin_info = self.pluginTree.model().data(index, Qt.UserRole) self.clear() self.scrollArea.setDisabled(True) if plugin_info is None: return self.scrollArea.setDisabled(False) self.nameEdit.setText(plugin_info.name) self.authorEdit.setText(plugin_info.author) self.descriptionText.setText(plugin_info.description) self.pathEdit.setText(plugin_info.path) self.createButton.setEnabled(plugin_info.loadable) lines = None with open(plugin_info.path + '.py') as f: lines = f.readlines() found_imports = [] for line in lines: if line.startswith('import'): m = re.search('(import)\s+([\w.]*)(\s+as){0,1}',str.strip(line)) if m is not None: if len(m.groups()) > 2: found_imports.append(m.group(2)) if line.startswith('from'): m = re.search('(from)\s+([\w.]*)(\s+import)',str.strip(line)) if m is not None: if len(m.groups()) > 2: found_imports.append(m.group(2)) found_imports.sort() for imp in found_imports: item = QListWidgetItem(imp) spam_loader = importlib.find_loader(imp) found = spam_loader is not None if not found: self.modulesList.addItem(item) item.setBackground(QColor(255,0,0,50)) if not plugin_info.loadable: self.modulesList.setEnabled(True) self.modulesLabel.setEnabled(True) def show_create_plugin_dialog(self): index = self.pluginTree.currentIndex() plugin_info = self.pluginTree.model().data(index, Qt.UserRole) if plugin_info is not None: if plugin_info.loadable: self.plugin_create_dialog.set_plugin(plugin_info) self.plugin_create_dialog.show() def showEvent(self, *args, **kwargs): self.plugin_manager.locatePlugins() candidates = self.plugin_manager.getPluginCandidates() all_pluginfo = {c[2].path:c[2] for c in candidates} loadable_pluginfo = {p.path:p for p in self.plugin_manager.getAllPlugins()} for pluginfo in all_pluginfo.values(): if pluginfo.path in loadable_pluginfo.keys(): pluginfo = loadable_pluginfo[pluginfo.path] pluginfo.loadable = True else: pluginfo.loadable = False plugin_item = PluginTreeItem(pluginfo) plugin_root = self.get_plugin_root(pluginfo.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) def help_button_triggered(self): index = self.pluginTree.currentIndex() plugin_info = self.pluginTree.model().data(index, Qt.UserRole) if plugin_info is not None: path = plugin_info.path plugin_type = path.split('/')[-3] suffix = "." + '.'.join(path.split('/')[-2:]) target_url = pc.PAPI_DOC_URL + pc.PAPI_DOC_PREFIX_PLUGIN + "." + plugin_type.lower() + suffix + ".html" QDesktopServices.openUrl(QUrl(target_url, QUrl.TolerantMode)) 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 clear(self): self.nameEdit.setText('') self.authorEdit.setText('') self.descriptionText.setText('') self.pathEdit.setText('') self.modulesList.clear() self.modulesList.setEnabled(False) self.modulesLabel.setEnabled(False) def closeEvent(self, *args, **kwargs): self.plugin_create_dialog.close()
def __init__(self, gui_api, tabmanager, parent=None): 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 is used to display all created plugins. The information are taken by the corresponding DPlugin-Object of a plugin. By this window a user is able to create and cancel subscriptions. """ def __init__(self, gui_api, tabmanager, parent=None): 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. :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. :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() # 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): self.parameterTree.viewport().update() self.blockTree.viewport().update() self.connectionTree.viewport().update() # noinspection PyUnresolvedReferences def open_context_menu_dplugin_tree(self, position): """ This callback function is called to create a context menu for the dplugin tree :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)) 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)) menu = QMenu('Remove') menu.addAction(action) 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) 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 gui_graphic_init(self): self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE) # set GUI size self.setGeometry(self.geometry().x(),self.geometry().y(), pc.GUI_DEFAULT_WIDTH, pc.GUI_DEFAULT_HEIGHT) self.count = 0 self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL, pc.GUI_PROCESS_CONSOLE_IDENTIFIER) self.log.printText(1,pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: '+str(os.getpid())) self.last_config = pc.PAPI_LAST_CFG_PATH self.in_run_mode = False # ------------------------------------- # Create placeholder # ------------------------------------- self.overview_menu = None self.create_plugin_menu = None self.plugin_create_dialog = None # ------------------------------------- # Create menues # ------------------------------------- self.plugin_create_dialog = CreatePluginDialog(self.gui_management.gui_api, self.TabManager) # ------------------------------------- # Create callback functions for buttons # ------------------------------------- #self.loadButton.clicked.connect(self.load_triggered) #self.saveButton.clicked.connect(self.save_triggered) # ------------------------------------- # Create actions # ------------------------------------- _translate = QtCore.QCoreApplication.translate self.actionLoad.triggered.connect(self.triggered_load) self.actionLoad.setShortcut(_translate("DefaultMain","Ctrl+L")) self.actionSave.triggered.connect(self.triggered_save) self.actionSave.setShortcut(_translate("DefaultMain","Ctrl+S")) self.actionOverview.triggered.connect(self.triggered_show_overview_menu) self.actionOverview.setShortcut(_translate("DefaultMain","Ctrl+O")) self.actionCreate.triggered.connect(self.triggered_show_create_plugin_menu) self.actionCreate.setShortcut(_translate("DefaultMain","Ctrl+N")) self.actionResetPaPI.triggered.connect(self.triggered_reset_papi) self.actionReloadConfig.triggered.connect(self.triggered_reload_config) self.actionRunMode.triggered.connect(self.toggle_run_mode) self.actionReload_Plugin_DB.triggered.connect(self.triggered_reload_plugin_db) self.actionPaPI_Wiki.triggered.connect(self.triggered_papi_wiki) self.actionPaPI_Doc.triggered.connect(self.triggered_papi_doc) self.actionPaPI_Doc.setShortcut(_translate("DefaultMain","Ctrl+H")) self.actionAbout.triggered.connect(self.triggered_papi_about) self.actionAbout_Qt.triggered.connect(self.triggered_papi_about_qt) self.actionToolbar.triggered.connect(self.triggered_show_toolbar) #self.toolBar.dragEnterEvent = self.toolbarDragEnterEvent #self.toolBar.dropEvent = self.toolbarDropEvent self.toolBar.clickedFavouritePlugin.connect(self.toolbarAddFavPlugin) self.toolBar.removedFavouritePlugin.connect(self.favPluginWasRemoved) self.set_icons()
class GUI(QMainWindow, Ui_DefaultMain): """ Used to create the qt based PaPI gui. """ def __init__(self, core_queue = None, gui_queue= None, gui_id = None, gui_data = None, is_parent = False, parent=None): """ Init function :param core_queue: Queue used to send papi events to Core :param gui_queue: GUI queue which contains papi events for the gui :param gui_id: Unique ID for this gui :param gui_data: Contains all data for the current session :param parent: parent element :return: """ super(GUI, self).__init__(parent) self.is_parent = is_parent self.setupUi(self) # Create a data structure for gui if it is missing # -------------------------------------------------- # if not isinstance(gui_data, DGui): self.gui_data = DGui() else: self.gui_data = gui_data # check if gui should be the parent process or core is the parent # start core if gui is parent # -------------------------------------------------- # self.core_process = None if is_parent: core_queue_ref = Queue() gui_queue_ref = Queue() gui_id_ref = 1 self.core_process = Process(target = run_core_in_own_process, args=(gui_queue_ref,core_queue_ref, gui_id_ref )) self.core_process.start() else: if core_queue is None: raise Exception('Gui started with wrong arguments') if gui_queue is None: raise Exception('Gui started with wrong arguments') if not isinstance(gui_id, str): raise Exception('Gui started with wrong arguments') core_queue_ref = core_queue gui_queue_ref = gui_queue gui_id_ref = gui_id # Create the Tab Manager and the gui management unit # # connect some signals of management to gui # # -------------------------------------------------- # self.TabManager = PapiTabManger(tabWigdet=self.widgetTabs, centralWidget=self.centralwidget) self.gui_management = GuiManagement(core_queue_ref, gui_queue_ref, gui_id_ref, self.TabManager, self.get_gui_config, self.set_gui_config) self.TabManager.gui_api = self.gui_management.gui_api self.TabManager.dGui = self.gui_management.gui_data self.gui_management.gui_event_processing.added_dplugin.connect(self.add_dplugin) self.gui_management.gui_event_processing.removed_dplugin.connect(self.remove_dplugin) self.gui_management.gui_event_processing.dgui_changed.connect(self.changed_dgui) self.gui_management.gui_event_processing.plugin_died.connect(self.plugin_died) self.gui_management.gui_api.error_occured.connect(self.error_occured) # initialize the graphic of the gui # -------------------------------------------------- # self.gui_graphic_init() signal.signal(signal.SIGINT, lambda a,b: self.signal_handler(a,b)) # List for keys that are active self.keysActiveList = []; def signal_handler(self,signal, frame): """ This handler will be called, when CTRL+C is used in the console It will react to SIGINT Signal As an reaction it will close the gui by first telling the core to close and then closing the gui :return: """ self.gui_management.gui_api.do_close_program() sys.exit(0) def gui_graphic_init(self): self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE) # set GUI size self.setGeometry(self.geometry().x(),self.geometry().y(), pc.GUI_DEFAULT_WIDTH, pc.GUI_DEFAULT_HEIGHT) self.count = 0 self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL, pc.GUI_PROCESS_CONSOLE_IDENTIFIER) self.log.printText(1,pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: '+str(os.getpid())) self.last_config = pc.PAPI_LAST_CFG_PATH self.in_run_mode = False # ------------------------------------- # Create placeholder # ------------------------------------- self.overview_menu = None self.create_plugin_menu = None self.plugin_create_dialog = None # ------------------------------------- # Create menues # ------------------------------------- self.plugin_create_dialog = CreatePluginDialog(self.gui_management.gui_api, self.TabManager) # ------------------------------------- # Create callback functions for buttons # ------------------------------------- #self.loadButton.clicked.connect(self.load_triggered) #self.saveButton.clicked.connect(self.save_triggered) # ------------------------------------- # Create actions # ------------------------------------- _translate = QtCore.QCoreApplication.translate self.actionLoad.triggered.connect(self.triggered_load) self.actionLoad.setShortcut(_translate("DefaultMain","Ctrl+L")) self.actionSave.triggered.connect(self.triggered_save) self.actionSave.setShortcut(_translate("DefaultMain","Ctrl+S")) self.actionOverview.triggered.connect(self.triggered_show_overview_menu) self.actionOverview.setShortcut(_translate("DefaultMain","Ctrl+O")) self.actionCreate.triggered.connect(self.triggered_show_create_plugin_menu) self.actionCreate.setShortcut(_translate("DefaultMain","Ctrl+N")) self.actionResetPaPI.triggered.connect(self.triggered_reset_papi) self.actionReloadConfig.triggered.connect(self.triggered_reload_config) self.actionRunMode.triggered.connect(self.toggle_run_mode) self.actionReload_Plugin_DB.triggered.connect(self.triggered_reload_plugin_db) self.actionPaPI_Wiki.triggered.connect(self.triggered_papi_wiki) self.actionPaPI_Doc.triggered.connect(self.triggered_papi_doc) self.actionPaPI_Doc.setShortcut(_translate("DefaultMain","Ctrl+H")) self.actionAbout.triggered.connect(self.triggered_papi_about) self.actionAbout_Qt.triggered.connect(self.triggered_papi_about_qt) self.actionToolbar.triggered.connect(self.triggered_show_toolbar) #self.toolBar.dragEnterEvent = self.toolbarDragEnterEvent #self.toolBar.dropEvent = self.toolbarDropEvent self.toolBar.clickedFavouritePlugin.connect(self.toolbarAddFavPlugin) self.toolBar.removedFavouritePlugin.connect(self.favPluginWasRemoved) self.set_icons() def addFavPlugin(self, fav_plugin): plugin_manager = self.gui_management.plugin_manager; plugin_manager.locatePlugins() candidates = plugin_manager.getPluginCandidates() all_pluginfo = {c[2].path:c[2] for c in candidates} loadable_pluginfo = {p.path:p for p in plugin_manager.getAllPlugins()} for plugin_info in all_pluginfo.values(): if plugin_info.name == fav_plugin: if plugin_info.path in loadable_pluginfo.keys(): plugin_info = loadable_pluginfo[plugin_info.path] plugin_info.loadable = True else: plugin_info.loadable = False self.toolbarAddFavPlugin(plugin_info) def favPluginWasRemoved(self): self.gui_management.gui_api.do_save_xml_config_reloaded( pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True) def set_icons(self): # ------------------------------------- # Create Icons for buttons # ------------------------------------- load_icon = get32Icon('folder') save_icon = get32Icon('file_save_as') # ------------------------------------- # Set Icons for buttons # ------------------------------------- #self.loadButton.setIconSize(QSize(32, 32)) #self.loadButton.setIcon(load_icon) #self.saveButton.setIconSize(QSize(32, 32)) #self.saveButton.setIcon(save_icon) # ------------------------------------- # Create Icons for actions # ------------------------------------- load_icon = get16Icon('folder') save_icon = get16Icon('file_save_as') exit_icon = get16Icon('cancel') overview_icon = get16Icon('tree_list') create_icon = get16Icon('application_add') reload_icon = get16Icon('arrow_rotate_clockwise') help_icon = get16Icon('help') info_icon = get16Icon('information') refresh_icon = get16Icon('arrow_refresh') delete_icon = get16Icon('delete') view_icon = get16Icon('reviewing_pane') # ------------------------------------- # Set Icons for actions # ------------------------------------- self.actionLoad.setIcon(load_icon) self.actionSave.setIcon(save_icon) self.actionExit.setIcon(exit_icon) self.actionOverview.setIcon(overview_icon) self.actionCreate.setIcon(create_icon) self.actionReload_Plugin_DB.setIcon(reload_icon) self.actionReloadConfig.setIcon(reload_icon) self.actionPaPI_Wiki.setIcon(help_icon) self.actionPaPI_Doc.setIcon(help_icon) self.actionAbout.setIcon(info_icon) self.actionAbout_Qt.setIcon(info_icon) self.actionAbout_PySide.setIcon(info_icon) self.actionResetPaPI.setIcon(delete_icon) self.actionRunMode.setIcon(view_icon) # ------------------------------------- # Set Icons visible in menu # ------------------------------------- self.actionLoad.setIconVisibleInMenu(True) self.actionSave.setIconVisibleInMenu(True) self.actionExit.setIconVisibleInMenu(True) self.actionOverview.setIconVisibleInMenu(True) self.actionCreate.setIconVisibleInMenu(True) self.actionReload_Plugin_DB.setIconVisibleInMenu(True) self.actionReloadConfig.setIconVisibleInMenu(True) self.actionPaPI_Wiki.setIconVisibleInMenu(True) self.actionPaPI_Doc.setIconVisibleInMenu(True) self.actionAbout.setIconVisibleInMenu(True) self.actionAbout_Qt.setIconVisibleInMenu(True) self.actionAbout_PySide.setIconVisibleInMenu(True) self.actionResetPaPI.setIconVisibleInMenu(True) self.actionRunMode.setIconVisibleInMenu(True) def get_gui_config(self, saveUserSettings=False): actTab = {} actTab['Active'] = str(self.TabManager.get_currently_active_tab()) tabs = {} tab_dict = self.TabManager.get_tabs_by_uname() for tab in tab_dict: tabOb = tab_dict[tab] tabs[tab]= {} tabs[tab]['Background'] = tabOb.background tabs[tab]['Position'] = str(self.TabManager.getTabPosition_by_name(tab)) size = {} size['X']= str(self.size().width()) size['Y']= str(self.size().height()) cfg = {} cfg['ActiveTab'] = actTab cfg['Tabs'] = tabs cfg['Size'] = size # ---------------------- # Set favourite plugins # ---------------------- if saveUserSettings: favourites = {} actions = self.toolBar.actions() for i in range(len(actions)): action = actions[i] if isinstance(action, PaPIFavAction): favourites[action.text()] = {} favourites[action.text()]['position'] = str(i) cfg['Favourites'] = favourites return cfg def set_gui_config(self, cfg): #print(cfg) # ################# # # Cfgs for Tabs # # ################# # if 'tabs' in cfg: # tabList = {} # for tab in cfg['tabs']: # # Tab Name # name = tab # # # Tab details # tabDetails = cfg['tabs'][tab] # # # check for background # if 'background' in tabDetails: # bg = tabDetails['background'] # if bg != 'default': # self.TabManager.set_background_for_tab_with_name(name,bg) # else: # bg = None # # # check for position # if 'position' in tabDetails: # pos = int(tabDetails['position']) # else: # if len(list(tabList.keys())) > 1: # pos = max(list(tabList.keys()))+1 # else: # pos = 0 # # tabList[pos] = [name, bg] # # # sort tabs acoriding to positions # keys = list(tabList.keys()) # keys.sort() # for position in keys: # name = tabList[position][0] # bg = tabList[position][1] # tabOb = self.TabManager.add_tab(name) # self.TabManager.set_background_for_tab_with_name(name,bg) # # if 'activeTab' in cfg: # if 'value' in cfg['activeTab']['active']: # self.TabManager.set_tab_active_by_index(int( cfg['activeTab']['active']['value'] )) # ################# # windows size: # ################# if 'Size' in cfg: w = int(cfg['Size']['X']) h = int(cfg['Size']['Y']) self.resize_gui_window(w,h) # ------------------------ # Restore favourite icons # ------------------------ if 'Favourites' in cfg: sorted_positions = {} for plugin in cfg['Favourites']: sorted_positions[int(cfg['Favourites'][plugin]['position'])] = plugin for position in sorted(sorted_positions.keys()): plugin = sorted_positions[position] self.addFavPlugin(plugin) # ----------------------- # Restore Tabs # ----------------------- if 'Tabs' in cfg: for tabName in cfg['Tabs']: tab = cfg['Tabs'][tabName] self.TabManager.add_tab(tabName) if 'Background' in tab: self.TabManager.set_background_for_tab_with_name(tabName, tab['Background']) def triggered_reload_plugin_db(self): """ This Callback function will reload the plugin list of the plugin manager :return: """ self.gui_management.plugin_manager.collectPlugins() def run(self): """ :return: """ # create a timer and set interval for processing events with working loop #QtCore.QTimer.singleShot(GUI_WOKRING_INTERVAL, lambda: self.gui_event_processing.gui_working(self.closeEvent)) self.workingTimer = QtCore.QTimer(self) self.workingTimer.timeout.connect(lambda: self.gui_management.gui_event_processing.gui_working(self.closeEvent, self.workingTimer)) self.workingTimer.start(pc.GUI_WOKRING_INTERVAL) def triggered_show_create_plugin_menu(self): """ :return: """ self.create_plugin_menu = CreatePluginMenu(self.gui_management.gui_api, self.TabManager, self.gui_management.plugin_manager ) self.create_plugin_menu.show() def triggered_show_overview_menu(self): """ Used to show the overview menu. :return: """ self.overview_menu = OverviewPluginMenu(self.gui_management.gui_api, self.gui_management.tab_manager) self.overview_menu.show() def triggered_show_toolbar(self): """ Used to hide and unhide the toolbar :return: """ self.toolBar.setHidden(not self.toolBar.isHidden()) self.actionToolbar.setChecked(not self.toolBar.isHidden()) def triggered_load(self): """ Used to start the 'load config' dialog. :return: """ fileNames = '' dialog = QFileDialog(self) dialog.setFileMode(QFileDialog.ExistingFile) dialog.setNameFilter( self.tr("PaPI-Cfg (*.xml)")) dialog.setDirectory(pc.CONFIG_DEFAULT_DIRECTORY) dialog.setWindowTitle("Load Configuration") if dialog.exec_(): fileNames = dialog.selectedFiles() if len(fileNames): if fileNames[0] != '': self.last_config = fileNames[0] self.load_config(fileNames[0]) def load_config(self, file_name): self.gui_management.gui_api.do_load_xml(file_name) def triggered_save(self): """ Used to start the 'save config' dialog. :return: """ fileNames = '' dialog = PaPIConfigSaveDialog(self, self.gui_management.gui_api) dialog.fill_with() if dialog.exec_(): fileNames = dialog.selectedFiles() plugin_list, subscription_list = dialog.get_create_lists() if len(fileNames): if fileNames[0] != '': if "json" in dialog.selectedNameFilter(): self.gui_management.gui_api.do_save_json_config_reloaded(fileNames[0], plToSave=plugin_list, sToSave=subscription_list) if "xml" in dialog.selectedNameFilter(): self.gui_management.gui_api.do_save_xml_config_reloaded(fileNames[0], plToSave=plugin_list, sToSave=subscription_list) def closeEvent(self, *args, **kwargs): """ Handle close event. Saves current session as 'papi/last_active_papi.xml' Closes all opened windows. :param args: :param kwargs: :return: """ try: self.gui_management.gui_api.do_save_xml_config('papi/last_active_papi.xml') except Exception as E: tb = traceback.format_exc() self.gui_management.gui_api.do_close_program() if self.create_plugin_menu is not None: self.create_plugin_menu.close() if self.overview_menu is not None: self.overview_menu.close() self.close() def add_dplugin(self, dplugin): """ Callback function called by 'DPlugin added signal' Used to add a DPlugin SubWindow on the GUI if possible. :param dplugin: :return: """ if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER: # sub_window_ori = dplugin.plugin.get_sub_window() # # dplugin.plugin.set_window_for_internal_usage(PaPIMDISubWindow()) # dplugin.plugin.pl_set_widget_for_internal_usage(sub_window_ori.widget()) sub_window = dplugin.plugin._get_sub_window() config = dplugin.startup_config tab_name = config['tab']['value'] if tab_name in self.TabManager.get_tabs_by_uname(): area = self.TabManager.get_tabs_by_uname()[tab_name] else: self.log.printText(1,'add dplugin: no tab with tab_id of dplugin') area = self.TabManager.add_tab(tab_name) area.addSubWindow(sub_window) isMaximized = config['maximized']['value'] == '1' size_re = re.compile(r'([0-9]+)') pos = config['position']['value'] window_pos = size_re.findall(pos) sub_window.move(int(window_pos[0]), int(window_pos[1])) if not isMaximized: sub_window.show() else: sub_window.showMaximized() # see http://qt-project.org/doc/qt-4.8/qt.html#WindowType-enum sub_window.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinMaxButtonsHint | Qt.WindowTitleHint ) if self.overview_menu is not None: self.overview_menu.refresh_action(dplugin) def remove_dplugin(self, dplugin): """ Callback function called by 'DPlugin removed signal' Used to removed a DPlugin SubWindow from the GUI if possible. :param dplugin: :return: """ if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER: config = dplugin.plugin.pl_get_current_config() tab_name = config['tab']['value'] if tab_name in self.TabManager.get_tabs_by_uname(): tabOb = self.TabManager.get_tabs_by_uname()[tab_name] tabOb.removeSubWindow(dplugin.plugin._get_sub_window()) if tabOb.closeIfempty is True: if len(tabOb.subWindowList()) == 0: if isinstance(tabOb, TabObject): self.TabManager.closeTab_by_name(tabOb.name) else: self.TabManager.remove_window(tabOb) def changed_dgui(self): if self.overview_menu is not None: self.overview_menu.refresh_action() def plugin_died(self, dplugin, e, msg): dplugin.state = pc.PLUGIN_STATE_STOPPED self.gui_management.gui_api.do_stopReset_plugin_uname(dplugin.uname) errMsg = QtGui.QMessageBox(self) errMsg.setFixedWidth(650) # layout = errMsg.layout(); # spacer = QtGui.QSpacerItem(1000, 0, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) # layout.addItem(spacer, layout.rowCount(), 0,1, layout.columnCount()) errMsg.setIcon(QtGui.QMessageBox.Critical) errMsg.setSizeGripEnabled(True) errMsg.setWindowTitle("Plugin: " + dplugin.uname + " // " + str(e)) errMsg.setText("Error in plugin" + dplugin.uname + " // " + str(e)) errMsg.setDetailedText(str(msg)) errMsg.setWindowModality(Qt.NonModal) errMsg.show() def error_occured(self, title, msg, detailed_msg): errMsg = QtGui.QMessageBox(self) errMsg.setFixedWidth(650) errMsg.setWindowTitle(title) errMsg.setText(str(msg)) errMsg.setDetailedText(str(detailed_msg)) errMsg.setWindowModality(Qt.NonModal) errMsg.show() def toggle_run_mode(self): if self.in_run_mode is False: # hide toolbar self.toolBar.setHidden(True) self.actionToolbar.setChecked(False) # disable context menu of tabmanger self.TabManager.disableContextMenus() # lock subwindows in tabs for tabName in self.TabManager.tab_dict_uname: tabObject = self.TabManager.tab_dict_uname[tabName] for subWindow in tabObject.subWindowList(): subWindow.disableInteraction() self.in_run_mode = True else: # show toolbar self.toolBar.setHidden(False) self.actionToolbar.setChecked(True) # disable context menu of tabmanger self.TabManager.enableContextMenus() # unlock subwindows in tabs for tabName in self.TabManager.tab_dict_uname: tabObject = self.TabManager.tab_dict_uname[tabName] for subWindow in tabObject.subWindowList(): subWindow.enableInteraction() self.in_run_mode = False def toogle_lock(self): raise Exception("PLEASE REPORT THIS BUG!!") if self.in_run_mode: for tab_name in self.TabManager.get_tabs_by_uname(): area = self.TabManager.get_tabs_by_uname()[tab_name] windowsList = area.subWindowList() for window in windowsList: #window.setAttribute(Qt.WA_NoBackground) #window.setAttribute(Qt.WA_NoSystemBackground) #window.setAttribute(Qt.WA_TranslucentBackground) #window.set_movable(False) window.setMouseTracking(False) window.setWindowFlags(~Qt.WindowMinMaxButtonsHint & (Qt.CustomizeWindowHint | Qt.WindowTitleHint)) if not self.in_run_mode: for tab_name in self.TabManager.get_tabs_by_uname(): area = self.TabManager.get_tabs_by_uname()[tab_name] windowsList = area.subWindowList() for window in windowsList: #window.set_movable(True) window.setMouseTracking(True) window.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinMaxButtonsHint | Qt.WindowTitleHint ) def keyPressEvent(self, event): if event.key() not in self.keysActiveList: self.keysActiveList.append(event.key()) if QtCore.Qt.Key_Escape in self.keysActiveList: if self.in_run_mode: self.toggle_run_mode() if QtCore.Qt.Key_D in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList: self.gui_management.tab_manager.select_next_tab() self.keysActiveList.remove(QtCore.Qt.Key_D) #self.keysActiveList.remove(QtCore.Qt.Key_Control) if QtCore.Qt.Key_A in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList: self.gui_management.tab_manager.select_prev_tab() self.keysActiveList.remove(QtCore.Qt.Key_A) #self.keysActiveList.remove(QtCore.Qt.Key_Control) def keyReleaseEvent(self, event): if event.key() in self.keysActiveList: self.keysActiveList.remove(event.key()) def resize_gui_window(self, w, h): self.setGeometry(self.geometry().x(),self.geometry().y(),w,h) def triggered_reload_config(self): """ This function is used to reset PaPI and to reload the last loaded configuration file. :return: """ if self.last_config is not None: self.triggered_reset_papi() QtCore.QTimer.singleShot(pc.GUI_WAIT_TILL_RELOAD, lambda: self.gui_management.gui_api.do_load_xml(self.last_config)) def triggered_reset_papi(self): """ This function is called to reset PaPI. That means all subscriptions were canceled and all plugins were removed. :return: """ h = pc.GUI_DEFAULT_HEIGHT w = pc.GUI_DEFAULT_WIDTH self.setGeometry(self.geometry().x(),self.geometry().y(),w,h) self.TabManager.set_all_tabs_to_close_when_empty(True) self.TabManager.close_all_empty_tabs() self.gui_management.gui_api.do_reset_papi() def triggered_papi_wiki(self): QDesktopServices.openUrl(QUrl(pc.PAPI_WIKI_URL, QUrl.TolerantMode)) def triggered_papi_doc(self): QDesktopServices.openUrl(QUrl(pc.PAPI_DOC_URL, QUrl.TolerantMode)) def triggered_papi_about(self): QMessageBox.about(self, pc.PAPI_ABOUT_TITLE, pc.PAPI_ABOUT_TEXT) def triggered_papi_about_qt(self): QMessageBox.aboutQt(self) def toolbarAddFavPlugin(self, plugin_info): l = len(plugin_info.name) path = plugin_info.path[:-l] path += 'box.png' px = QPixmap(path) icon = QIcon(px) for action in self.toolBar.actions(): if action.text() == plugin_info.name: return plugin_action = PaPIFavAction(icon, plugin_info.name, self) plugin_action.triggered.connect(lambda ignore, p1=plugin_info : self.show_create_plugin_dialog(p1)) self.toolBar.addAction(plugin_action) self.gui_management.gui_api.do_save_xml_config_reloaded( pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True) def show_create_plugin_dialog(self, plugin_info): if plugin_info is not None: if plugin_info.loadable: self.plugin_create_dialog.set_plugin(plugin_info) self.plugin_create_dialog.show() def dropEvent(self, event:QDropEvent): source = event.source()
def __init__(self, gui_api, tabmanager, parent=None): 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 is used to display all created plugins. The information are taken by the corresponding DPlugin-Object of a plugin. By this window a user is able to create and cancel subscriptions. """ def __init__(self, gui_api, tabmanager, parent=None): 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. :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. :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() # 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): self.parameterTree.viewport().update() self.blockTree.viewport().update() self.connectionTree.viewport().update() # noinspection PyUnresolvedReferences def open_context_menu_dplugin_tree(self, position): """ This callback function is called to create a context menu for the dplugin tree :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)) 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)) menu = QMenu('Remove') menu.addAction(action) 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) 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 gui_graphic_init(self): self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE) # set GUI size self.setGeometry(self.geometry().x(), self.geometry().y(), pc.GUI_DEFAULT_WIDTH, pc.GUI_DEFAULT_HEIGHT) self.count = 0 self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL, pc.GUI_PROCESS_CONSOLE_IDENTIFIER) self.log.printText( 1, pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: ' + str(os.getpid())) self.last_config = pc.PAPI_LAST_CFG_PATH self.in_run_mode = False # ------------------------------------- # Create placeholder # ------------------------------------- self.overview_menu = None self.create_plugin_menu = None self.plugin_create_dialog = None # ------------------------------------- # Create menues # ------------------------------------- self.plugin_create_dialog = CreatePluginDialog( self.gui_management.gui_api, self.TabManager) # ------------------------------------- # Create callback functions for buttons # ------------------------------------- #self.loadButton.clicked.connect(self.load_triggered) #self.saveButton.clicked.connect(self.save_triggered) # ------------------------------------- # Create actions # ------------------------------------- _translate = QtCore.QCoreApplication.translate self.actionLoad.triggered.connect(self.triggered_load) self.actionLoad.setShortcut(_translate("DefaultMain", "Ctrl+L")) self.actionSave.triggered.connect(self.triggered_save) self.actionSave.setShortcut(_translate("DefaultMain", "Ctrl+S")) self.actionOverview.triggered.connect( self.triggered_show_overview_menu) self.actionOverview.setShortcut(_translate("DefaultMain", "Ctrl+O")) self.actionCreate.triggered.connect( self.triggered_show_create_plugin_menu) self.actionCreate.setShortcut(_translate("DefaultMain", "Ctrl+N")) self.actionResetPaPI.triggered.connect(self.triggered_reset_papi) self.actionReloadConfig.triggered.connect(self.triggered_reload_config) self.actionRunMode.triggered.connect(self.toggle_run_mode) self.actionReload_Plugin_DB.triggered.connect( self.triggered_reload_plugin_db) self.actionPaPI_Wiki.triggered.connect(self.triggered_papi_wiki) self.actionPaPI_Doc.triggered.connect(self.triggered_papi_doc) self.actionPaPI_Doc.setShortcut(_translate("DefaultMain", "Ctrl+H")) self.actionAbout.triggered.connect(self.triggered_papi_about) self.actionAbout_Qt.triggered.connect(self.triggered_papi_about_qt) self.actionToolbar.triggered.connect(self.triggered_show_toolbar) #self.toolBar.dragEnterEvent = self.toolbarDragEnterEvent #self.toolBar.dropEvent = self.toolbarDropEvent self.toolBar.clickedFavouritePlugin.connect(self.toolbarAddFavPlugin) self.toolBar.removedFavouritePlugin.connect(self.favPluginWasRemoved) self.set_icons()
class GUI(QMainWindow, Ui_DefaultMain): """ Used to create the qt based PaPI gui. """ def __init__(self, core_queue=None, gui_queue=None, gui_id=None, gui_data=None, is_parent=False, parent=None): """ Init function :param core_queue: Queue used to send papi events to Core :param gui_queue: GUI queue which contains papi events for the gui :param gui_id: Unique ID for this gui :param gui_data: Contains all data for the current session :param parent: parent element :return: """ super(GUI, self).__init__(parent) self.is_parent = is_parent self.setupUi(self) # Create a data structure for gui if it is missing # -------------------------------------------------- # if not isinstance(gui_data, DGui): self.gui_data = DGui() else: self.gui_data = gui_data # check if gui should be the parent process or core is the parent # start core if gui is parent # -------------------------------------------------- # self.core_process = None if is_parent: core_queue_ref = Queue() gui_queue_ref = Queue() gui_id_ref = 1 self.core_process = Process(target=run_core_in_own_process, args=(gui_queue_ref, core_queue_ref, gui_id_ref)) self.core_process.start() else: if core_queue is None: raise Exception('Gui started with wrong arguments') if gui_queue is None: raise Exception('Gui started with wrong arguments') if not isinstance(gui_id, str): raise Exception('Gui started with wrong arguments') core_queue_ref = core_queue gui_queue_ref = gui_queue gui_id_ref = gui_id # Create the Tab Manager and the gui management unit # # connect some signals of management to gui # # -------------------------------------------------- # self.TabManager = PapiTabManger(tabWigdet=self.widgetTabs, centralWidget=self.centralwidget) self.gui_management = GuiManagement(core_queue_ref, gui_queue_ref, gui_id_ref, self.TabManager, self.get_gui_config, self.set_gui_config) self.TabManager.gui_api = self.gui_management.gui_api self.TabManager.dGui = self.gui_management.gui_data self.gui_management.gui_event_processing.added_dplugin.connect( self.add_dplugin) self.gui_management.gui_event_processing.removed_dplugin.connect( self.remove_dplugin) self.gui_management.gui_event_processing.dgui_changed.connect( self.changed_dgui) self.gui_management.gui_event_processing.plugin_died.connect( self.plugin_died) self.gui_management.gui_api.error_occured.connect(self.error_occured) # initialize the graphic of the gui # -------------------------------------------------- # self.gui_graphic_init() signal.signal(signal.SIGINT, lambda a, b: self.signal_handler(a, b)) # List for keys that are active self.keysActiveList = [] def signal_handler(self, signal, frame): """ This handler will be called, when CTRL+C is used in the console It will react to SIGINT Signal As an reaction it will close the gui by first telling the core to close and then closing the gui :return: """ self.gui_management.gui_api.do_close_program() sys.exit(0) def gui_graphic_init(self): self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE) # set GUI size self.setGeometry(self.geometry().x(), self.geometry().y(), pc.GUI_DEFAULT_WIDTH, pc.GUI_DEFAULT_HEIGHT) self.count = 0 self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL, pc.GUI_PROCESS_CONSOLE_IDENTIFIER) self.log.printText( 1, pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: ' + str(os.getpid())) self.last_config = pc.PAPI_LAST_CFG_PATH self.in_run_mode = False # ------------------------------------- # Create placeholder # ------------------------------------- self.overview_menu = None self.create_plugin_menu = None self.plugin_create_dialog = None # ------------------------------------- # Create menues # ------------------------------------- self.plugin_create_dialog = CreatePluginDialog( self.gui_management.gui_api, self.TabManager) # ------------------------------------- # Create callback functions for buttons # ------------------------------------- #self.loadButton.clicked.connect(self.load_triggered) #self.saveButton.clicked.connect(self.save_triggered) # ------------------------------------- # Create actions # ------------------------------------- _translate = QtCore.QCoreApplication.translate self.actionLoad.triggered.connect(self.triggered_load) self.actionLoad.setShortcut(_translate("DefaultMain", "Ctrl+L")) self.actionSave.triggered.connect(self.triggered_save) self.actionSave.setShortcut(_translate("DefaultMain", "Ctrl+S")) self.actionOverview.triggered.connect( self.triggered_show_overview_menu) self.actionOverview.setShortcut(_translate("DefaultMain", "Ctrl+O")) self.actionCreate.triggered.connect( self.triggered_show_create_plugin_menu) self.actionCreate.setShortcut(_translate("DefaultMain", "Ctrl+N")) self.actionResetPaPI.triggered.connect(self.triggered_reset_papi) self.actionReloadConfig.triggered.connect(self.triggered_reload_config) self.actionRunMode.triggered.connect(self.toggle_run_mode) self.actionReload_Plugin_DB.triggered.connect( self.triggered_reload_plugin_db) self.actionPaPI_Wiki.triggered.connect(self.triggered_papi_wiki) self.actionPaPI_Doc.triggered.connect(self.triggered_papi_doc) self.actionPaPI_Doc.setShortcut(_translate("DefaultMain", "Ctrl+H")) self.actionAbout.triggered.connect(self.triggered_papi_about) self.actionAbout_Qt.triggered.connect(self.triggered_papi_about_qt) self.actionToolbar.triggered.connect(self.triggered_show_toolbar) #self.toolBar.dragEnterEvent = self.toolbarDragEnterEvent #self.toolBar.dropEvent = self.toolbarDropEvent self.toolBar.clickedFavouritePlugin.connect(self.toolbarAddFavPlugin) self.toolBar.removedFavouritePlugin.connect(self.favPluginWasRemoved) self.set_icons() def addFavPlugin(self, fav_plugin): plugin_manager = self.gui_management.plugin_manager plugin_manager.locatePlugins() candidates = plugin_manager.getPluginCandidates() all_pluginfo = {c[2].path: c[2] for c in candidates} loadable_pluginfo = {p.path: p for p in plugin_manager.getAllPlugins()} for plugin_info in all_pluginfo.values(): if plugin_info.name == fav_plugin: if plugin_info.path in loadable_pluginfo.keys(): plugin_info = loadable_pluginfo[plugin_info.path] plugin_info.loadable = True else: plugin_info.loadable = False self.toolbarAddFavPlugin(plugin_info) def favPluginWasRemoved(self): self.gui_management.gui_api.do_save_xml_config_reloaded( pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True) def set_icons(self): # ------------------------------------- # Create Icons for buttons # ------------------------------------- load_icon = get32Icon('folder') save_icon = get32Icon('file_save_as') # ------------------------------------- # Set Icons for buttons # ------------------------------------- #self.loadButton.setIconSize(QSize(32, 32)) #self.loadButton.setIcon(load_icon) #self.saveButton.setIconSize(QSize(32, 32)) #self.saveButton.setIcon(save_icon) # ------------------------------------- # Create Icons for actions # ------------------------------------- load_icon = get16Icon('folder') save_icon = get16Icon('file_save_as') exit_icon = get16Icon('cancel') overview_icon = get16Icon('tree_list') create_icon = get16Icon('application_add') reload_icon = get16Icon('arrow_rotate_clockwise') help_icon = get16Icon('help') info_icon = get16Icon('information') refresh_icon = get16Icon('arrow_refresh') delete_icon = get16Icon('delete') view_icon = get16Icon('reviewing_pane') # ------------------------------------- # Set Icons for actions # ------------------------------------- self.actionLoad.setIcon(load_icon) self.actionSave.setIcon(save_icon) self.actionExit.setIcon(exit_icon) self.actionOverview.setIcon(overview_icon) self.actionCreate.setIcon(create_icon) self.actionReload_Plugin_DB.setIcon(reload_icon) self.actionReloadConfig.setIcon(reload_icon) self.actionPaPI_Wiki.setIcon(help_icon) self.actionPaPI_Doc.setIcon(help_icon) self.actionAbout.setIcon(info_icon) self.actionAbout_Qt.setIcon(info_icon) self.actionAbout_PySide.setIcon(info_icon) self.actionResetPaPI.setIcon(delete_icon) self.actionRunMode.setIcon(view_icon) # ------------------------------------- # Set Icons visible in menu # ------------------------------------- self.actionLoad.setIconVisibleInMenu(True) self.actionSave.setIconVisibleInMenu(True) self.actionExit.setIconVisibleInMenu(True) self.actionOverview.setIconVisibleInMenu(True) self.actionCreate.setIconVisibleInMenu(True) self.actionReload_Plugin_DB.setIconVisibleInMenu(True) self.actionReloadConfig.setIconVisibleInMenu(True) self.actionPaPI_Wiki.setIconVisibleInMenu(True) self.actionPaPI_Doc.setIconVisibleInMenu(True) self.actionAbout.setIconVisibleInMenu(True) self.actionAbout_Qt.setIconVisibleInMenu(True) self.actionAbout_PySide.setIconVisibleInMenu(True) self.actionResetPaPI.setIconVisibleInMenu(True) self.actionRunMode.setIconVisibleInMenu(True) def get_gui_config(self, saveUserSettings=False): actTab = {} actTab['Active'] = str(self.TabManager.get_currently_active_tab()) tabs = {} tab_dict = self.TabManager.get_tabs_by_uname() for tab in tab_dict: tabOb = tab_dict[tab] tabs[tab] = {} tabs[tab]['Background'] = tabOb.background tabs[tab]['Position'] = str( self.TabManager.getTabPosition_by_name(tab)) size = {} size['X'] = str(self.size().width()) size['Y'] = str(self.size().height()) cfg = {} cfg['ActiveTab'] = actTab cfg['Tabs'] = tabs cfg['Size'] = size # ---------------------- # Set favourite plugins # ---------------------- if saveUserSettings: favourites = {} actions = self.toolBar.actions() for i in range(len(actions)): action = actions[i] if isinstance(action, PaPIFavAction): favourites[action.text()] = {} favourites[action.text()]['position'] = str(i) cfg['Favourites'] = favourites return cfg def set_gui_config(self, cfg): #print(cfg) # ################# # # Cfgs for Tabs # # ################# # if 'tabs' in cfg: # tabList = {} # for tab in cfg['tabs']: # # Tab Name # name = tab # # # Tab details # tabDetails = cfg['tabs'][tab] # # # check for background # if 'background' in tabDetails: # bg = tabDetails['background'] # if bg != 'default': # self.TabManager.set_background_for_tab_with_name(name,bg) # else: # bg = None # # # check for position # if 'position' in tabDetails: # pos = int(tabDetails['position']) # else: # if len(list(tabList.keys())) > 1: # pos = max(list(tabList.keys()))+1 # else: # pos = 0 # # tabList[pos] = [name, bg] # # # sort tabs acoriding to positions # keys = list(tabList.keys()) # keys.sort() # for position in keys: # name = tabList[position][0] # bg = tabList[position][1] # tabOb = self.TabManager.add_tab(name) # self.TabManager.set_background_for_tab_with_name(name,bg) # # if 'activeTab' in cfg: # if 'value' in cfg['activeTab']['active']: # self.TabManager.set_tab_active_by_index(int( cfg['activeTab']['active']['value'] )) # ################# # windows size: # ################# if 'Size' in cfg: w = int(cfg['Size']['X']) h = int(cfg['Size']['Y']) self.resize_gui_window(w, h) # ------------------------ # Restore favourite icons # ------------------------ if 'Favourites' in cfg: sorted_positions = {} for plugin in cfg['Favourites']: sorted_positions[int( cfg['Favourites'][plugin]['position'])] = plugin for position in sorted(sorted_positions.keys()): plugin = sorted_positions[position] self.addFavPlugin(plugin) # ----------------------- # Restore Tabs # ----------------------- if 'Tabs' in cfg: for tabName in cfg['Tabs']: tab = cfg['Tabs'][tabName] self.TabManager.add_tab(tabName) if 'Background' in tab: self.TabManager.set_background_for_tab_with_name( tabName, tab['Background']) def triggered_reload_plugin_db(self): """ This Callback function will reload the plugin list of the plugin manager :return: """ self.gui_management.plugin_manager.collectPlugins() def run(self): """ :return: """ # create a timer and set interval for processing events with working loop #QtCore.QTimer.singleShot(GUI_WOKRING_INTERVAL, lambda: self.gui_event_processing.gui_working(self.closeEvent)) self.workingTimer = QtCore.QTimer(self) self.workingTimer.timeout.connect( lambda: self.gui_management.gui_event_processing.gui_working( self.closeEvent, self.workingTimer)) self.workingTimer.start(pc.GUI_WOKRING_INTERVAL) def triggered_show_create_plugin_menu(self): """ :return: """ self.create_plugin_menu = CreatePluginMenu( self.gui_management.gui_api, self.TabManager, self.gui_management.plugin_manager) self.create_plugin_menu.show() def triggered_show_overview_menu(self): """ Used to show the overview menu. :return: """ self.overview_menu = OverviewPluginMenu( self.gui_management.gui_api, self.gui_management.tab_manager) self.overview_menu.show() def triggered_show_toolbar(self): """ Used to hide and unhide the toolbar :return: """ self.toolBar.setHidden(not self.toolBar.isHidden()) self.actionToolbar.setChecked(not self.toolBar.isHidden()) def triggered_load(self): """ Used to start the 'load config' dialog. :return: """ fileNames = '' dialog = QFileDialog(self) dialog.setFileMode(QFileDialog.ExistingFile) dialog.setNameFilter(self.tr("PaPI-Cfg (*.xml)")) dialog.setDirectory(pc.CONFIG_DEFAULT_DIRECTORY) dialog.setWindowTitle("Load Configuration") if dialog.exec_(): fileNames = dialog.selectedFiles() if len(fileNames): if fileNames[0] != '': self.last_config = fileNames[0] self.load_config(fileNames[0]) def load_config(self, file_name): self.gui_management.gui_api.do_load_xml(file_name) def triggered_save(self): """ Used to start the 'save config' dialog. :return: """ fileNames = '' dialog = PaPIConfigSaveDialog(self, self.gui_management.gui_api) dialog.fill_with() if dialog.exec_(): fileNames = dialog.selectedFiles() plugin_list, subscription_list = dialog.get_create_lists() if len(fileNames): if fileNames[0] != '': if "json" in dialog.selectedNameFilter(): self.gui_management.gui_api.do_save_json_config_reloaded( fileNames[0], plToSave=plugin_list, sToSave=subscription_list) if "xml" in dialog.selectedNameFilter(): self.gui_management.gui_api.do_save_xml_config_reloaded( fileNames[0], plToSave=plugin_list, sToSave=subscription_list) def closeEvent(self, *args, **kwargs): """ Handle close event. Saves current session as 'papi/last_active_papi.xml' Closes all opened windows. :param args: :param kwargs: :return: """ try: self.gui_management.gui_api.do_save_xml_config( 'papi/last_active_papi.xml') except Exception as E: tb = traceback.format_exc() self.gui_management.gui_api.do_close_program() if self.create_plugin_menu is not None: self.create_plugin_menu.close() if self.overview_menu is not None: self.overview_menu.close() self.close() def add_dplugin(self, dplugin): """ Callback function called by 'DPlugin added signal' Used to add a DPlugin SubWindow on the GUI if possible. :param dplugin: :return: """ if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER: # sub_window_ori = dplugin.plugin.get_sub_window() # # dplugin.plugin.set_window_for_internal_usage(PaPIMDISubWindow()) # dplugin.plugin.pl_set_widget_for_internal_usage(sub_window_ori.widget()) sub_window = dplugin.plugin._get_sub_window() config = dplugin.startup_config tab_name = config['tab']['value'] if tab_name in self.TabManager.get_tabs_by_uname(): area = self.TabManager.get_tabs_by_uname()[tab_name] else: self.log.printText( 1, 'add dplugin: no tab with tab_id of dplugin') area = self.TabManager.add_tab(tab_name) area.addSubWindow(sub_window) isMaximized = config['maximized']['value'] == '1' size_re = re.compile(r'([0-9]+)') pos = config['position']['value'] window_pos = size_re.findall(pos) sub_window.move(int(window_pos[0]), int(window_pos[1])) if not isMaximized: sub_window.show() else: sub_window.showMaximized() # see http://qt-project.org/doc/qt-4.8/qt.html#WindowType-enum sub_window.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinMaxButtonsHint | Qt.WindowTitleHint) if self.overview_menu is not None: self.overview_menu.refresh_action(dplugin) def remove_dplugin(self, dplugin): """ Callback function called by 'DPlugin removed signal' Used to removed a DPlugin SubWindow from the GUI if possible. :param dplugin: :return: """ if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER: config = dplugin.plugin.pl_get_current_config() tab_name = config['tab']['value'] if tab_name in self.TabManager.get_tabs_by_uname(): tabOb = self.TabManager.get_tabs_by_uname()[tab_name] tabOb.removeSubWindow(dplugin.plugin._get_sub_window()) if tabOb.closeIfempty is True: if len(tabOb.subWindowList()) == 0: if isinstance(tabOb, TabObject): self.TabManager.closeTab_by_name(tabOb.name) else: self.TabManager.remove_window(tabOb) def changed_dgui(self): if self.overview_menu is not None: self.overview_menu.refresh_action() def plugin_died(self, dplugin, e, msg): dplugin.state = pc.PLUGIN_STATE_STOPPED self.gui_management.gui_api.do_stopReset_plugin_uname(dplugin.uname) errMsg = QtGui.QMessageBox(self) errMsg.setFixedWidth(650) # layout = errMsg.layout(); # spacer = QtGui.QSpacerItem(1000, 0, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) # layout.addItem(spacer, layout.rowCount(), 0,1, layout.columnCount()) errMsg.setIcon(QtGui.QMessageBox.Critical) errMsg.setSizeGripEnabled(True) errMsg.setWindowTitle("Plugin: " + dplugin.uname + " // " + str(e)) errMsg.setText("Error in plugin" + dplugin.uname + " // " + str(e)) errMsg.setDetailedText(str(msg)) errMsg.setWindowModality(Qt.NonModal) errMsg.show() def error_occured(self, title, msg, detailed_msg): errMsg = QtGui.QMessageBox(self) errMsg.setFixedWidth(650) errMsg.setWindowTitle(title) errMsg.setText(str(msg)) errMsg.setDetailedText(str(detailed_msg)) errMsg.setWindowModality(Qt.NonModal) errMsg.show() def toggle_run_mode(self): if self.in_run_mode is False: # hide toolbar self.toolBar.setHidden(True) self.actionToolbar.setChecked(False) # disable context menu of tabmanger self.TabManager.disableContextMenus() # lock subwindows in tabs for tabName in self.TabManager.tab_dict_uname: tabObject = self.TabManager.tab_dict_uname[tabName] for subWindow in tabObject.subWindowList(): subWindow.disableInteraction() self.in_run_mode = True else: # show toolbar self.toolBar.setHidden(False) self.actionToolbar.setChecked(True) # disable context menu of tabmanger self.TabManager.enableContextMenus() # unlock subwindows in tabs for tabName in self.TabManager.tab_dict_uname: tabObject = self.TabManager.tab_dict_uname[tabName] for subWindow in tabObject.subWindowList(): subWindow.enableInteraction() self.in_run_mode = False def toogle_lock(self): raise Exception("PLEASE REPORT THIS BUG!!") if self.in_run_mode: for tab_name in self.TabManager.get_tabs_by_uname(): area = self.TabManager.get_tabs_by_uname()[tab_name] windowsList = area.subWindowList() for window in windowsList: #window.setAttribute(Qt.WA_NoBackground) #window.setAttribute(Qt.WA_NoSystemBackground) #window.setAttribute(Qt.WA_TranslucentBackground) #window.set_movable(False) window.setMouseTracking(False) window.setWindowFlags(~Qt.WindowMinMaxButtonsHint & (Qt.CustomizeWindowHint | Qt.WindowTitleHint)) if not self.in_run_mode: for tab_name in self.TabManager.get_tabs_by_uname(): area = self.TabManager.get_tabs_by_uname()[tab_name] windowsList = area.subWindowList() for window in windowsList: #window.set_movable(True) window.setMouseTracking(True) window.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinMaxButtonsHint | Qt.WindowTitleHint) def keyPressEvent(self, event): if event.key() not in self.keysActiveList: self.keysActiveList.append(event.key()) if QtCore.Qt.Key_Escape in self.keysActiveList: if self.in_run_mode: self.toggle_run_mode() if QtCore.Qt.Key_D in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList: self.gui_management.tab_manager.select_next_tab() self.keysActiveList.remove(QtCore.Qt.Key_D) #self.keysActiveList.remove(QtCore.Qt.Key_Control) if QtCore.Qt.Key_A in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList: self.gui_management.tab_manager.select_prev_tab() self.keysActiveList.remove(QtCore.Qt.Key_A) #self.keysActiveList.remove(QtCore.Qt.Key_Control) def keyReleaseEvent(self, event): if event.key() in self.keysActiveList: self.keysActiveList.remove(event.key()) def resize_gui_window(self, w, h): self.setGeometry(self.geometry().x(), self.geometry().y(), w, h) def triggered_reload_config(self): """ This function is used to reset PaPI and to reload the last loaded configuration file. :return: """ if self.last_config is not None: self.triggered_reset_papi() QtCore.QTimer.singleShot( pc.GUI_WAIT_TILL_RELOAD, lambda: self.gui_management.gui_api. do_load_xml(self.last_config)) def triggered_reset_papi(self): """ This function is called to reset PaPI. That means all subscriptions were canceled and all plugins were removed. :return: """ h = pc.GUI_DEFAULT_HEIGHT w = pc.GUI_DEFAULT_WIDTH self.setGeometry(self.geometry().x(), self.geometry().y(), w, h) self.TabManager.set_all_tabs_to_close_when_empty(True) self.TabManager.close_all_empty_tabs() self.gui_management.gui_api.do_reset_papi() def triggered_papi_wiki(self): QDesktopServices.openUrl(QUrl(pc.PAPI_WIKI_URL, QUrl.TolerantMode)) def triggered_papi_doc(self): QDesktopServices.openUrl(QUrl(pc.PAPI_DOC_URL, QUrl.TolerantMode)) def triggered_papi_about(self): QMessageBox.about(self, pc.PAPI_ABOUT_TITLE, pc.PAPI_ABOUT_TEXT) def triggered_papi_about_qt(self): QMessageBox.aboutQt(self) def toolbarAddFavPlugin(self, plugin_info): l = len(plugin_info.name) path = plugin_info.path[:-l] path += 'box.png' px = QPixmap(path) icon = QIcon(px) for action in self.toolBar.actions(): if action.text() == plugin_info.name: return plugin_action = PaPIFavAction(icon, plugin_info.name, self) plugin_action.triggered.connect( lambda ignore, p1=plugin_info: self.show_create_plugin_dialog(p1)) self.toolBar.addAction(plugin_action) self.gui_management.gui_api.do_save_xml_config_reloaded( pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True) def show_create_plugin_dialog(self, plugin_info): if plugin_info is not None: if plugin_info.loadable: self.plugin_create_dialog.set_plugin(plugin_info) self.plugin_create_dialog.show() def dropEvent(self, event: QDropEvent): source = event.source()
class CreatePluginMenu(QMainWindow, Ui_PluginCreateMenu): 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 keyPressEvent(self, event): if event.key() in [Qt.Key_Right, Qt.Key_Space]: index = self.pluginTree.currentIndex() self.pluginItemChanged(index) if event.key() == Qt.Key_Escape: self.close() # Use enter/return to bring up the dialog for a selected plugin if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter) and self.pluginTree.hasFocus(): self.show_create_plugin_dialog() # 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 pluginItemChanged(self, index): plugin_info = self.pluginTree.model().data(index, Qt.UserRole) self.clear() self.scrollArea.setDisabled(True) if plugin_info is None: return self.scrollArea.setDisabled(False) self.nameEdit.setText(plugin_info.name) self.authorEdit.setText(plugin_info.author) self.descriptionText.setText(plugin_info.description) self.pathEdit.setText(plugin_info.path) self.createButton.setEnabled(plugin_info.loadable) lines = None with open(plugin_info.path + '.py') as f: lines = f.readlines() found_imports = [] for line in lines: if line.startswith('import'): m = re.search('(import)\s+([\w.]*)(\s+as){0,1}', str.strip(line)) if m is not None: if len(m.groups()) > 2: found_imports.append(m.group(2)) if line.startswith('from'): m = re.search('(from)\s+([\w.]*)(\s+import)', str.strip(line)) if m is not None: if len(m.groups()) > 2: found_imports.append(m.group(2)) found_imports.sort() for imp in found_imports: item = QListWidgetItem(imp) spam_loader = importlib.find_loader(imp) found = spam_loader is not None if not found: self.modulesList.addItem(item) item.setBackground(QColor(255, 0, 0, 50)) if not plugin_info.loadable: self.modulesList.setEnabled(True) self.modulesLabel.setEnabled(True) def show_create_plugin_dialog(self): index = self.pluginTree.currentIndex() plugin_info = self.pluginTree.model().data(index, Qt.UserRole) if plugin_info is not None: if plugin_info.loadable: self.plugin_create_dialog.set_plugin(plugin_info) self.plugin_create_dialog.show() def showEvent(self, *args, **kwargs): self.plugin_manager.locatePlugins() candidates = self.plugin_manager.getPluginCandidates() all_pluginfo = {c[2].path: c[2] for c in candidates} loadable_pluginfo = { p.path: p for p in self.plugin_manager.getAllPlugins() } for pluginfo in all_pluginfo.values(): if pluginfo.path in loadable_pluginfo.keys(): pluginfo = loadable_pluginfo[pluginfo.path] pluginfo.loadable = True else: pluginfo.loadable = False plugin_item = PluginTreeItem(pluginfo) plugin_root = self.get_plugin_root(pluginfo.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) def help_button_triggered(self): index = self.pluginTree.currentIndex() plugin_info = self.pluginTree.model().data(index, Qt.UserRole) if plugin_info is not None: path = plugin_info.path plugin_type = path.split('/')[-3] suffix = "." + '.'.join(path.split('/')[-2:]) target_url = pc.PAPI_DOC_URL + pc.PAPI_DOC_PREFIX_PLUGIN + "." + plugin_type.lower( ) + suffix + ".html" QDesktopServices.openUrl(QUrl(target_url, QUrl.TolerantMode)) 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 clear(self): self.nameEdit.setText('') self.authorEdit.setText('') self.descriptionText.setText('') self.pathEdit.setText('') self.modulesList.clear() self.modulesList.setEnabled(False) self.modulesLabel.setEnabled(False) def closeEvent(self, *args, **kwargs): self.plugin_create_dialog.close()