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()
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()