From 5111ac84916632b45c102e4f684355bf7e508808 Mon Sep 17 00:00:00 2001 From: Gilles DAVID Date: Thu, 27 Oct 2016 17:48:21 +0200 Subject: [PATCH] GDD: Add a GUI for the Python Plugins Manager --- src/SalomeApp/CMakeLists.txt | 9 + src/SalomeApp/pluginsdemo/salome_plugins.py | 12 + src/SalomeApp/pluginsdemo/smesh_plugins.py | 2 +- src/SalomeApp/salome_pluginsmanager.py | 70 +++-- src/SalomeApp/salome_pluginsmanager_dialog.py | 138 ++++++++++ src/SalomeApp/salome_pluginsmanager_dialog.ui | 244 ++++++++++++++++++ 6 files changed, 449 insertions(+), 26 deletions(-) create mode 100644 src/SalomeApp/salome_pluginsmanager_dialog.py create mode 100644 src/SalomeApp/salome_pluginsmanager_dialog.ui diff --git a/src/SalomeApp/CMakeLists.txt b/src/SalomeApp/CMakeLists.txt index d65ba0b38..b85c112a3 100755 --- a/src/SalomeApp/CMakeLists.txt +++ b/src/SalomeApp/CMakeLists.txt @@ -226,6 +226,14 @@ SET(_bin_SCRIPTS # scripts / python SET(_py_SCRIPTS salome_pluginsmanager.py + salome_pluginsmanager_dialog.py +) + +# scripts / Qt designer ui files +# Dynamically loaded by a python script +# => Not processed by pyuic ! +SET(_ui_FILES + salome_pluginsmanager_dialog.ui ) # --- rules --- @@ -240,4 +248,5 @@ QT_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${SALOME_GUI_INSTALL_RES_DATA}") INSTALL(FILES ${_other_RESOURCES} DESTINATION ${SALOME_GUI_INSTALL_RES_DATA}) SALOME_INSTALL_SCRIPTS("${_py_SCRIPTS}" ${SALOME_INSTALL_PYTHON}) +SALOME_INSTALL_SCRIPTS("${_ui_FILES}" ${SALOME_INSTALL_PYTHON}) SALOME_INSTALL_SCRIPTS("${_bin_SCRIPTS}" ${SALOME_INSTALL_SCRIPT_PYTHON}) diff --git a/src/SalomeApp/pluginsdemo/salome_plugins.py b/src/SalomeApp/pluginsdemo/salome_plugins.py index c532de866..b7ec66e96 100755 --- a/src/SalomeApp/pluginsdemo/salome_plugins.py +++ b/src/SalomeApp/pluginsdemo/salome_plugins.py @@ -289,3 +289,15 @@ def runSalomeShellSession(context): salome_pluginsmanager.AddFunction('SALOME shell session', 'Execute a SALOME shell session in an external xterm', runSalomeShellSession) + +# ------------------------------------------------------------------------- +# Example 4: SALOME Python Plugins scripts manager GUI +# Allow to enable/disable a plugin +def manage_plugins(context): + import salome_pluginsmanager_dialog + dialog = salome_pluginsmanager_dialog.getDialog('salome', context) + dialog.show() + +salome_pluginsmanager.AddFunction('Python Plugins Manager', + 'Manage your SALOME Python plugins', + manage_plugins) diff --git a/src/SalomeApp/pluginsdemo/smesh_plugins.py b/src/SalomeApp/pluginsdemo/smesh_plugins.py index 2252fff75..c2b4ec216 100644 --- a/src/SalomeApp/pluginsdemo/smesh_plugins.py +++ b/src/SalomeApp/pluginsdemo/smesh_plugins.py @@ -24,7 +24,7 @@ import salome_pluginsmanager DEMO_IS_ACTIVATED = True -from minmax_plugin import * +from minmax_plugin import minmax # register the function in the plugin manager if DEMO_IS_ACTIVATED: diff --git a/src/SalomeApp/salome_pluginsmanager.py b/src/SalomeApp/salome_pluginsmanager.py index 2eb1ef319..7b4b88681 100644 --- a/src/SalomeApp/salome_pluginsmanager.py +++ b/src/SalomeApp/salome_pluginsmanager.py @@ -102,18 +102,23 @@ sg = libSALOME_Swig.SALOMEGUI_Swig() plugins={} current_plugins_manager=None + def initialize(module,name,basemenuname,menuname): - if not plugins.has_key(name): + if not plugins.has_key(name): + if module: + plugins[name] = {} + else: + plugins[name] = [] + if module: + d = sgPyQt.getDesktop() + if d in plugins[name]: + return if module: - plugins[name]={} + plugins[name][d] = PluginsManager(module, name, basemenuname, menuname) else: - plugins[name]=[] - if module: - d=sgPyQt.getDesktop() - if plugins[name].has_key(d):return - plugins[name][d]=PluginsManager(module,name,basemenuname,menuname) - else: - plugins[name].append(PluginsManager(module,name,basemenuname,menuname)) + plugins[name].append(PluginsManager(module, name, basemenuname, + menuname)) + class Context: def __init__(self,sgpyqt): @@ -121,21 +126,24 @@ class Context: self.studyId=salome.sg.getActiveStudyId() self.study= salome.myStudyManager.GetStudyByID(self.studyId) + def find_menu(smenu): - lmenus=smenu.split("|") - # Take first element from the list - main=lmenus.pop(0).strip() - menu=sgPyQt.getPopupMenu(main) - return findMenu(lmenus,menu) + lmenus = smenu.split("|") + # Take first element from the list + main = lmenus.pop(0).strip() + menu = sgPyQt.getPopupMenu(main) + return findMenu(lmenus, menu) + def findMenu(lmenu,menu): - if not lmenu:return menu - # Take first element from the list - m=lmenu.pop(0).strip() - for a in menu.actions(): - if a.menu(): - if a.text() == m: - return findMenu(lmenu,a.menu()) + if not lmenu: + return menu + # Take first element from the list + m = lmenu.pop(0).strip() + for a in menu.actions(): + if a.menu(): + if a.text() == m: + return findMenu(lmenu, a.menu()) PLUGIN_PATH_PATTERN="share/salome/plugins" MATCH_ENDING_PATTERN="_plugins.py" @@ -146,13 +154,15 @@ logger=Logger("PluginsManager") #,color=GREEN) # VSR 21/11/2011 : do not show infos in the debug mode #logger.showDebug() -class PluginsManager: + +class PluginsManager(): def __init__(self,module,name,basemenuname,menuname): self.name=name self.basemenuname=unicode(basemenuname, "utf-8") self.menuname=unicode(menuname, "utf-8") self.module=module self.registry={} + self.desactivated=[] self.handlers={} self.entries=[] self.lasttime=0 @@ -199,15 +209,23 @@ class PluginsManager: self.basemenu = find_menu(self.basemenuname) if self.module: - self.menu=QMenu(self.menuname) + self.menu = QMenu(self.menuname) mid=sgPyQt.createMenu(self.menu.menuAction(),self.basemenuname) else: - self.menu=QMenu(self.menuname,self.basemenu) + self.menu = QMenu(self.menuname, self.basemenu) self.basemenu.addMenu(self.menu) self.menu.menuAction().setVisible(False) self.basemenu.aboutToShow.connect(self.importPlugins) + self.importPlugins() + + def toggleStatus(self, name): + if name in self.desactivated: + self.desactivated.remove(name) + else: + self.desactivated.append(name) + self.importPlugins() def analyseFile(self,filename): """ @@ -225,7 +243,8 @@ class PluginsManager: def AddFunction(self,name,description,script): """ Add a plugin function """ - self.registry[name]=script,description + + self.registry[name]=script,description,name not in self.desactivated self.entries.append(name) def handler(obj=self,script=script): @@ -316,6 +335,7 @@ class PluginsManager: name=names.pop(0) act=parentMenu.addAction(name,self.handlers[entry]) act.setStatusTip(self.registry[entry][1]) + act.setEnabled(name not in self.desactivated) self.menu.menuAction().setVisible(True) diff --git a/src/SalomeApp/salome_pluginsmanager_dialog.py b/src/SalomeApp/salome_pluginsmanager_dialog.py new file mode 100644 index 000000000..47fb57ecd --- /dev/null +++ b/src/SalomeApp/salome_pluginsmanager_dialog.py @@ -0,0 +1,138 @@ +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2010-2016 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +# Author : Gilles DAVID (EDF) + +try: + from PyQt4 import uic +except ImportError: + from PyQt5 import uic + +try: + from qtsalome import Qt, QDialog, QTableWidgetItem, QMessageBox +except ImportError: + from PyQt4.Qt import QDialog, QTableWidgetItem, QMessageBox + from PyQt4.QtCore import Qt + +import os +import salome_pluginsmanager # @UnresolvedImport + + +__dialog = None + + +class SalomePluginManagerDialog(QDialog): + ''' + GUI to manage the python plugins from all the modules. + The list of plugins must be updated when a module is loaded for the + first time. + A double click on a row enables or disables the selected plugin. + ''' + + def __init__(self, name, context): + QDialog.__init__(self) + self.setWindowFlags(Qt.WindowStaysOnTopHint) + self.name = name + self.context = context + self.directory = os.path.dirname(os.path.abspath(__file__)) + uic.loadUi(os.path.join(self.directory, + "salome_pluginsmanager_dialog.ui"), + self) + self.updatePluginsList() + + def getPluginsManager(self, module=None): + if module is not None: + pluginslist = salome_pluginsmanager.plugins[module] + if isinstance(pluginslist, list): + return pluginslist[0] + elif isinstance(pluginslist, dict): + return pluginslist.values()[0] + return salome_pluginsmanager.current_plugins_manager + + def updatePluginsList(self, row=None): + self.plugins_list.clear() + self.plugins_list.setRowCount(0) + self.plugins_list.setHorizontalHeaderLabels(['Module', 'Plugin', + 'Activated', 'Description']) + current_plugins_manager = self.getPluginsManager(self.name) + if current_plugins_manager is None: + QMessageBox.warning(None, "Exception occured", + 'current_plugins_manager is None') + return + + for modulename in sorted(salome_pluginsmanager.plugins): + value = salome_pluginsmanager.plugins[modulename] + if isinstance(value, list): + # Not a module plugin: pure salome one + self.addrows(modulename, value) + elif isinstance(value, dict): + # Module plugin + print(value.values()) + self.addrows(modulename, value.values()) + if row is not None: + self.plugins_list.setCurrentIndex(self.plugins_list.model() + .index(row, 0)) + + def addrows(self, module, pluginmanagerlist): + for pluginmanager in pluginmanagerlist: + for pluginname, pluginval in pluginmanager.registry.items(): + if pluginname == "Python Plugins Manager": + continue + _, description, isActivated = pluginval + module_item = QTableWidgetItem(module) + plugin_item = QTableWidgetItem(pluginname) + activated_item = QTableWidgetItem(str(isActivated)) + description_item = QTableWidgetItem(description) + row = self.plugins_list.rowCount() + self.plugins_list.insertRow(self.plugins_list.rowCount()) + self.plugins_list.setItem(row, 0, module_item) + self.plugins_list.setItem(row, 1, plugin_item) + self.plugins_list.setItem(row, 2, activated_item) + self.plugins_list.setItem(row, 3, description_item) + + def createPlugin(self): + pass + + def importPlugin(self): + pass + + def togglePluginStatus(self): + currentRow = self.plugins_list.currentRow() + if currentRow < 0: + return + currentModule = str(self.plugins_list.item(currentRow, 0).text()) + currentPlugin = str(self.plugins_list.item(currentRow, 1).text()) + current_plugins_manager = self.getPluginsManager(currentModule) + current_plugins_manager.toggleStatus(currentPlugin) + self.updatePluginsList(currentRow) + + +def getDialog(name, context): + """ + This function returns a singleton instance of the plugin dialog. + It is mandatory in order to call show without a parent ... + """ + global __dialog + if __dialog is None: + __dialog = SalomePluginManagerDialog(name, context) + else: + __dialog.name = name + __dialog.context = context + __dialog.updatePluginsList() + return __dialog diff --git a/src/SalomeApp/salome_pluginsmanager_dialog.ui b/src/SalomeApp/salome_pluginsmanager_dialog.ui new file mode 100644 index 000000000..50294566a --- /dev/null +++ b/src/SalomeApp/salome_pluginsmanager_dialog.ui @@ -0,0 +1,244 @@ + + + Dialog + + + + 0 + 0 + 530 + 421 + + + + + 530 + 420 + + + + SALOME Python Plugins Manager + + + + + + <html><head/><body><p><span style=" font-size:14pt; font-weight:600;">SALOME Python Plugins Manager</span></p></body></html> + + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SelectRows + + + true + + + true + + + false + + + + Module + + + + + Plugin + + + + + Activated + + + + + Description + + + + + + + + Update List + + + + + + + Activate/Deactivate plugin + + + + + + + false + + + Create plugin + + + + + + + false + + + Import plugin + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + pb_update + pb_remove_plugin + pb_create_plugin + pb_import_plugin + plugins_list + buttonBox + + + + + buttonBox + accepted() + Dialog + accept() + + + 227 + 392 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 295 + 398 + + + 286 + 274 + + + + + pb_create_plugin + clicked() + Dialog + createPlugin() + + + 502 + 260 + + + 526 + 254 + + + + + pb_import_plugin + clicked() + Dialog + importPlugin() + + + 519 + 297 + + + 524 + 313 + + + + + pb_remove_plugin + clicked() + Dialog + togglePluginStatus() + + + 210 + 334 + + + 5 + 344 + + + + + plugins_list + doubleClicked(QModelIndex) + Dialog + togglePluginStatus() + + + 81 + 176 + + + 4 + 185 + + + + + pb_update + clicked() + Dialog + updatePluginsList() + + + 387 + 350 + + + 390 + 416 + + + + + + importPlugin() + createPlugin() + togglePluginStatus() + updatePluginsList() + + -- 2.39.2