From ee3854640b0f7bac306fa7f3d333e4ca41e0ef14 Mon Sep 17 00:00:00 2001 From: caremoli Date: Mon, 12 Apr 2010 07:05:56 +0000 Subject: [PATCH] CCAR: add python plugins manager to SALOME application and modules see salome_pluginsmanager.py header for details python plugins manager for SALOME application is initialized in SalomeApp_Application.cxx --- src/LightApp/LightApp_Module.cxx | 26 +++ src/LightApp/LightApp_Module.h | 7 + src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx | 11 +- src/SalomeApp/Makefile.am | 3 + src/SalomeApp/SalomeApp_Application.cxx | 11 ++ src/SalomeApp/salome_pluginsmanager.py | 198 ++++++++++++++++++++++ 6 files changed, 252 insertions(+), 4 deletions(-) create mode 100644 src/SalomeApp/salome_pluginsmanager.py diff --git a/src/LightApp/LightApp_Module.cxx b/src/LightApp/LightApp_Module.cxx index 46d4b48da..db606ec57 100644 --- a/src/LightApp/LightApp_Module.cxx +++ b/src/LightApp/LightApp_Module.cxx @@ -683,3 +683,29 @@ void LightApp_Module::copy() void LightApp_Module::paste() { } + + +int LightApp_Module::createMenu( const QString& subMenu, const int menu, const int id, const int group, const int idx ) +{ + return CAM_Module::createMenu( subMenu, menu, id, group, idx ); +} +int LightApp_Module::createMenu( const QString& subMenu, const QString& menu, const int id, const int group, const int idx ) +{ + return CAM_Module::createMenu( subMenu, menu, id, group, idx ); +} +int LightApp_Module::createMenu( const int id, const int menu, const int group, const int idx ) +{ + return CAM_Module::createMenu( id, menu, group, idx ); +} +int LightApp_Module::createMenu( const int id, const QString& menu, const int group, const int idx ) +{ + return CAM_Module::createMenu( id, menu, group, idx ); +} +int LightApp_Module::createMenu( QAction* a, const int menu, const int id, const int group, const int idx ) +{ + return CAM_Module::createMenu( a, menu, id, group, idx ); +} +int LightApp_Module::createMenu( QAction* a, const QString& menu, const int id, const int group, const int idx ) +{ + return CAM_Module::createMenu( a, menu, id, group, idx ); +} diff --git a/src/LightApp/LightApp_Module.h b/src/LightApp/LightApp_Module.h index 971586ad2..56b0d3356 100644 --- a/src/LightApp/LightApp_Module.h +++ b/src/LightApp/LightApp_Module.h @@ -97,6 +97,13 @@ public: virtual void copy(); virtual void paste(); + int createMenu( const QString&, const int, const int = -1, const int = -1, const int = -1 ); + int createMenu( const QString&, const QString&, const int = -1, const int = -1, const int = -1 ); + int createMenu( const int, const int, const int = -1, const int = -1 ); + int createMenu( const int, const QString&, const int = -1, const int = -1 ); + int createMenu( QAction*, const int, const int = -1, const int = -1, const int = -1 ); + int createMenu( QAction*, const QString&, const int = -1, const int = -1, const int = -1 ); + public slots: virtual bool activateModule( SUIT_Study* ); virtual bool deactivateModule( SUIT_Study* ); diff --git a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx index b7efe52de..8c6c60537 100644 --- a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx +++ b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx @@ -1521,7 +1521,7 @@ public: CrMenu( QAction* action, const QString& menu, const int id, const int group, const int idx ) : myCase( 5 ), myAction( action ), myMenuName( menu ), myId( id ), myGroup( group ), myIndex( idx ) {} - int execute( SALOME_PYQT_ModuleLight* module ) const + int execute( LightApp_Module* module ) const { if ( module ) { switch ( myCase ) { @@ -1562,9 +1562,12 @@ public: : myResult( -1 ), myCrMenu( crMenu ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = myCrMenu.execute( module ); + if ( LightApp_Application* anApp = getApplication() ) + { + LightApp_Module* module = dynamic_cast( anApp->activeModule() ); + if ( module ) + myResult = myCrMenu.execute( module ); + } } }; diff --git a/src/SalomeApp/Makefile.am b/src/SalomeApp/Makefile.am index 614de706b..594450bdf 100755 --- a/src/SalomeApp/Makefile.am +++ b/src/SalomeApp/Makefile.am @@ -94,6 +94,9 @@ MOC_FILES = \ nodist_libSalomeApp_la_SOURCES = $(MOC_FILES) +# python modules +salomepython_PYTHON = salome_pluginsmanager.py + dist_salomeres_DATA = \ resources/SalomeApp.ini \ resources/SalomeApp.xml diff --git a/src/SalomeApp/SalomeApp_Application.cxx b/src/SalomeApp/SalomeApp_Application.cxx index 753f3a113..e840e43b5 100644 --- a/src/SalomeApp/SalomeApp_Application.cxx +++ b/src/SalomeApp/SalomeApp_Application.cxx @@ -305,6 +305,17 @@ void SalomeApp_Application::createActions() createMenu( separator(), toolsMenu, -1, 15, -1 ); createExtraActions(); + + // import Python module that manages SALOME plugins + PyGILState_STATE gstate = PyGILState_Ensure(); + PyObject* pluginsmanager=PyImport_ImportModule((char*)"salome_pluginsmanager"); + PyObject* res=PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome","Tools","Plugins"); + if(res==NULL) + PyErr_Print(); + Py_XDECREF(res); + PyGILState_Release(gstate); + // end of SALOME plugins loading + } /*! diff --git a/src/SalomeApp/salome_pluginsmanager.py b/src/SalomeApp/salome_pluginsmanager.py new file mode 100644 index 000000000..3e1526e66 --- /dev/null +++ b/src/SalomeApp/salome_pluginsmanager.py @@ -0,0 +1,198 @@ +""" +This module is imported from C++ SalomeApp_Application +and initialized (call to initialize function with 4 parameters) +module : 0 if it's plugins manager at the application level 1 if it is at the module level +name : the name of the plugins manager. This name is used to build the name of the plugins files +basemenuname : the name of the menu into we want to add the menu of the plugins ("Tools" for example) +menuname : the name of plugins menu + +A plugins manager is created at when calling initialize. + +The plugins manager creates a submenu in the menu. + +The plugins manager searches in $HOME/.salome/Plugins, $HOME/$APPLI/Plugins, $SALOME_PLUGINS_PATH directories +files named _plugins.py and executes them. + +These files should contain python code that register functions into the plugins manager. + +Example of a plugins manager with name salome. It searches files with name salome_plugins.py (example follows):: + + import salome_pluginsmanager + + def about(context): + from PyQt4.QtGui import QMessageBox + QMessageBox.about(None, "About SALOME pluginmanager", "SALOME plugins manager in SALOME virtual application ") + + salome_pluginsmanager.AddFunction('About plugins','About SALOME pluginmanager',about) + +First you need to import the python module salome_pluginsmanager +Second write a function with one argument context (it's an object with 3 attributes) +Third register the function with a call to AddFunction (entry in menu plugins, tooltip, function) + +context attributes: +- sg : the SALOME Swig interface +- studyId : the SALOME studyId that must be used to execute the plugin +- study : the SALOME study object that must be used to execute the plugin + +""" + +import os,sys,traceback +from PyQt4 import QtGui +from PyQt4 import QtCore + +import salome + +SEP=":" +if sys.platform == "win32": + SEP = ";" + +# Get SALOME PyQt interface +import SalomePyQt +sgPyQt = SalomePyQt.SalomePyQt() + +# Get SALOME Swig interface +import libSALOME_Swig +sg = libSALOME_Swig.SALOMEGUI_Swig() + +plugins={} +current_plugins_manager=None + +def initialize(module,name,basemenuname,menuname): + if plugins.has_key(name):return + plugins[name]=PluginsManager(module,name,basemenuname,menuname) + +class Context: + def __init__(self,sg): + self.sg=sg + self.studyId=salome.sg.getActiveStudyId() + self.study= salome.myStudyManager.GetStudyByID(self.studyId) + +def find_menu(smenu): + lmenus=smenu.split("|") + main=lmenus.pop(0).strip() + menu=sgPyQt.getPopupMenu(main) + return findMenu(lmenus,menu) + +def findMenu(lmenu,menu): + if not lmenu:return menu + m=lmenu.pop(0).strip() + for a in menu.actions(): + if a.menu(): + if a.text() == m: + return findMenu(lmenu,a.menu()) + +class PluginsManager: + def __init__(self,module,name,basemenuname,menuname): + self.name=name + self.basemenuname=basemenuname + self.menuname=menuname + self.module=module + self.registry={} + self.handlers={} + self.lasttime=0 + self.plugindirs=[] + self.plugins_files=[] + + # USER plugins directory + user_dir = os.path.expanduser("~/.salome/Plugins") + self.plugindirs.append(user_dir) + + # APPLI plugins directory + appli=os.getenv("APPLI") + if appli: + appli_dir=os.path.join(os.path.expanduser("~"),appli,"Plugins") + self.plugindirs.append(appli_dir) + + #SALOME_PLUGINS_PATH environment variable (list of directories separated by ":") + pluginspath=os.getenv("SALOME_PLUGINS_PATH") + if pluginspath: + for directory in pluginspath.split(SEP): + self.plugindirs.append(directory) + + self.basemenu = find_menu(self.basemenuname) + + if self.module: + self.menu=QtGui.QMenu(self.menuname) + mid=sgPyQt.createMenu(self.menu.menuAction(),self.basemenuname) + else: + self.menu=QtGui.QMenu(self.menuname,self.basemenu) + self.basemenu.addMenu(self.menu) + + self.menu.menuAction().setVisible(False) + + self.basemenu.connect(self.basemenu, QtCore.SIGNAL("aboutToShow()"), self.importPlugins) + + def AddFunction(self,name,description,script): + """ Add a plugin function + """ + self.registry[name]=script,description + + def handler(obj=self,script=script): + try: + script(Context(sgPyQt)) + except: + s=traceback.format_exc() + QtGui.QMessageBox.warning(None,"Exception occured",s) + + self.handlers[name]=handler + + def importPlugins(self): + """Execute the salome_plugins file that contains plugins definition """ + studyId=sg.getActiveStudyId() + if studyId == 0: + self.menu.clear() + self.menu.menuAction().setVisible(False) + return + elif self.lasttime ==0: + salome.salome_init(embedded=1) + + lasttime=0 + + plugins_files=[] + plugins_file_name=self.name+"_plugins.py" + for directory in self.plugindirs: + plugins_file = os.path.join(directory,plugins_file_name) + if os.path.isfile(plugins_file): + plugins_files.append((directory,plugins_file)) + lasttime=max(lasttime,os.path.getmtime(plugins_file)) + + plugins_files.sort() + + if not plugins_files: + self.registry.clear() + self.handlers.clear() + self.lasttime=0 + self.menu.clear() + self.menu.menuAction().setVisible(False) + return + + if self.plugins_files != plugins_files or lasttime > self.lasttime: + global current_plugins_manager + current_plugins_manager=self + self.registry.clear() + self.handlers.clear() + self.lasttime=lasttime + for directory,plugins_file in plugins_files: + if directory not in sys.path: + sys.path.insert(0,directory) + try: + execfile(plugins_file,globals(),{}) + except: + print "Error while loading plugins from file:",plugins_file + traceback.print_exc() + + self.updateMenu() + + def updateMenu(self): + """Update the Plugins menu""" + self.menu.clear() + for name,handler in self.handlers.items(): + act=self.menu.addAction(name,handler) + act.setStatusTip(self.registry[name][1]) + self.menu.menuAction().setVisible(True) + +def AddFunction(name,description,script): + """ Add a plugin function + Called by a user to register a function (script) + """ + return current_plugins_manager.AddFunction(name,description,script) -- 2.39.2