X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSALOME_PYQT%2FSALOME_PYQT_GUI%2FSALOME_PYQT_Module.cxx;h=4b73279a700c3c34c38c8323852d078342d20d0c;hb=6516e549128fb08e3cc3ae16bddea0345e083d24;hp=8267e67a1de2ad222a68c5e2ff226c8f32a4622e;hpb=27969666653f17d6aee219d54a3bcca7c9c6d2fd;p=modules%2Fgui.git diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx index 8267e67a1..4b73279a7 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx @@ -1,1326 +1,287 @@ -//============================================================================= -// File : SALOME_PYQT_Module.cxx -// Created : 25/04/05 -// Author : Vadim SANDLER -// Project : SALOME -// Copyright : 2003-2005 CEA/DEN, EDF R&D -// $Header : $ -//============================================================================= +// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// 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 +// +// File : SALOME_PYQT_Module.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) #include "SALOME_PYQT_Module.h" - -#include "PyInterp_Dispatcher.h" -#include "SUIT_ResourceMgr.h" -#include "STD_MDIDesktop.h" -#include "STD_TabDesktop.h" +#include "SALOME_PYQT_PyModule.h" #include "SalomeApp_Application.h" -#include "SalomeApp_Study.h" -#include "QtxWorkstack.h" #include #include -#include -#include -#include -#include - -#include "SALOME_PYQT_SipDefs.h" -#if defined(SIP_VERS_v4_old) || defined(SIP_VERS_v4_new) -#include "sipAPISalomePyQtGUI.h" -#else -#include "sipSalomePyQtGUIDeclSalomePyQtGUI.h" -#endif - -#include -#include +#include -#include - -using namespace std; - -/////////////////////////////////////////////////////////////////////////////// -// Default name of the module, replaced at the moment of module creation -#define __DEFAULT_NAME__ "SALOME_PYQT_Module" - -/////////////////////////////////////////////////////////////////////////////// -// If __CALL_OLD_METHODS__ macro is not defined the invoking of obsolete Python -// module's methods like setSetting(), definePopup(), etc. is blocked. -// This macro is defined by default (in Makefile) -#ifdef __CALL_OLD_METHODS__ -const bool IsCallOldMethods = true; -#else -const bool IsCallOldMethods = false; -#endif - -/////////////////////////////////////////////////////////////////////////////// +// // NB: Python requests. -// General rule for Python requests created by SALOME_PYQT_Module: +// General rule for Python requests created by Python-based GUI modules +// (SALOME_PYQT_Module and other ones): // all requests should be executed SYNCHRONOUSLY within the main GUI thread. // However, it is obligatory that ANY Python call is wrapped with a request object, // so that ALL Python API calls are serialized with PyInterp_Dispatcher. -/////////////////////////////////////////////////////////////////////////////// - -//============================================================================= -// The class for parsing of the XML resource files. -// Used for backward compatibility with existing Python modules. -//============================================================================= -class SALOME_PYQT_XmlHandler -{ -public: - SALOME_PYQT_XmlHandler( SALOME_PYQT_Module* module, const QString& fileName ); - void createActions(); - void createPopup ( QPopupMenu* menu, - const QString& context, - const QString& parent, - const QString& object ); - -protected: - void createToolBar ( QDomNode& parentNode ); - void createMenu ( QDomNode& parentNode, - const int parentMenuId = -1 ); - - void insertPopupItems( QDomNode& parentNode, - QPopupMenu* menu ); - -private: - SALOME_PYQT_Module* myModule; - QDomDocument myDoc; -}; - -//============================================================================= -// SALOME_PYQT_Module class implementation (implements CAM_Module API for -// all Python-based SALOME module -//============================================================================= - -// While the SalomePyQtGUI library is not imported in Python it's initialization function +// +// NB: Library initialization +// Since the SalomePyQtGUI library is not imported in Python it's initialization function // should be called manually (and only once) in order to initialize global sip data // and to get C API from sip : sipBuildResult for example +// + +#define INIT_FUNCTION initSalomePyQtGUILight #if defined(SIP_STATIC_MODULE) -extern "C" void initSalomePyQtGUI(); +extern "C" void INIT_FUNCTION(); #else -PyMODINIT_FUNC initSalomePyQtGUI(); +PyMODINIT_FUNC INIT_FUNCTION(); #endif /*! - * This function creates an instance of SALOME_PYQT_Module object by request - * of and application object when the module is loaded. - */ + \fn CAM_Module* createModule() + \brief Module factory function. + \internal + + Creates an instance of SALOME_PYQT_Module object by request + of an application when the module is loaded and initialized. + + \return new module object +*/ + extern "C" { - SALOME_PYQT_EXPORT CAM_Module* createModule() { - static bool alreadyInitialized = false; + SALOME_PYQT_EXPORT CAM_Module* createModule() + { + QCoreApplication* app = QCoreApplication::instance(); + bool alreadyInitialized = app && app->property( "salome_pyqt_gui_light_initialized" ).toBool(); + if ( !alreadyInitialized ) { - // call only once (see above) ! - PyEval_RestoreThread( KERNEL_PYTHON::_gtstate ); - initSalomePyQtGUI(); - PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate ); - alreadyInitialized = !alreadyInitialized; + PyLockWrapper lck; // GIL acquisition + INIT_FUNCTION(); + if ( app ) app->setProperty( "salome_pyqt_gui_light_initialized", true ); } + return new SALOME_PYQT_Module(); } } -/*! - * Static variables definition - */ -SALOME_PYQT_Module::InterpMap SALOME_PYQT_Module::myInterpMap; -SALOME_PYQT_Module* SALOME_PYQT_Module::myInitModule = 0; - /*! - * Little trick : provide an access to being activated Python module from outside; - * needed by the SalomePyQt library :( + \class SALOME_PYQT_Module + \brief This class implements GUI module for CORBA engine-based Python SALOME modules. */ -SALOME_PYQT_Module* SALOME_PYQT_Module::getInitModule() -{ - return myInitModule; -} /*! - * Constructor - */ -SALOME_PYQT_Module::SALOME_PYQT_Module() : - SalomeApp_Module( __DEFAULT_NAME__ ), myModule( 0 ), myXmlHandler ( 0 ) + \brief Constructor +*/ +SALOME_PYQT_Module::SALOME_PYQT_Module() + : SalomeApp_Module( "noname" ) // name is set explicitly at the module initialization { - myMenuActionList.setAutoDelete( false ); - myPopupActionList.setAutoDelete( false ); - myToolbarActionList.setAutoDelete( false ); + // initialize helper + myHelper = new PyModuleHelper( this ); } /*! - * Destructor - */ + \brief Destructor +*/ SALOME_PYQT_Module::~SALOME_PYQT_Module() { - myMenuActionList.clear(); - myPopupActionList.clear(); - myToolbarActionList.clear(); - if ( myXmlHandler ) - delete myXmlHandler; + // as myHelper is a QObject, it should be deleted automatically } /*! - * Initialization of the module. - * Inherited from CAM_Module. - * - * This method is used for creation of the menus, toolbars and other staff. - * There are two ways: - * - for obsolete modules this method first tries to read _.xml - * resource file which contains a menu, toolbars and popup menus description. - * - new modules can create menus by by calling the corresponding methods of SalomePyQt - * Python API in the Python module's initialize() method which is called from here. - * NOTE: if postponed modules loading is not used, the active study might be not defined - * yet at this stage, so initialize() method should not perform any study-based initialization. - */ -void SALOME_PYQT_Module::initialize( CAM_Application* app ) -{ - SalomeApp_Module::initialize( app ); - - // Try to get XML resource file name - SUIT_ResourceMgr* aResMgr = getApp()->resourceMgr(); - QString aLang = aResMgr->stringValue( "language", "language", QString::null ); - if ( aLang.isEmpty() ) aLang = QString( "en" ); - QString aName = name( "" ); - QString aFileName = aName + "_" + aLang + ".xml"; - aFileName = aResMgr->path( "resources", aName, aFileName ); - - // parse XML file if it is found and create actions - if ( !myXmlHandler && !aFileName.isEmpty() ) { - myXmlHandler = new SALOME_PYQT_XmlHandler( this, aFileName ); - myXmlHandler->createActions(); - } - - // perform internal initialization and call module's initialize() method - // InitializeReq: request class for internal init() operation - class InitializeReq : public PyInterp_Request - { - public: - InitializeReq( CAM_Application* _app, - SALOME_PYQT_Module* _obj ) - : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) - myApp( _app ), - myObj( _obj ) {} - - protected: - virtual void execute() - { - myObj->init( myApp ); - } - - private: - CAM_Application* myApp; - SALOME_PYQT_Module* myObj; - }; - - // Posting the request - PyInterp_Dispatcher::Get()->Exec( new InitializeReq( app, this ) ); -} - -/*! - * Activation of the module. - * Inherited from CAM_Module. - */ -bool SALOME_PYQT_Module::activateModule( SUIT_Study* theStudy ) -{ - MESSAGE( "SALOME_PYQT_Module::activateModule" ); - - bool res = SalomeApp_Module::activateModule( theStudy ); + \brief Get module engine IOR - if ( !res ) - return res; - - // ActivateReq: request class for internal activate() operation - class ActivateReq : public PyInterp_Request - { - public: - ActivateReq( SUIT_Study* _study, - SALOME_PYQT_Module* _obj ) - : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) - myStudy ( _study ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->activate( myStudy ); - } - - private: - SUIT_Study* myStudy; - SALOME_PYQT_Module* myObj; - }; - - // Posting the request - PyInterp_Dispatcher::Get()->Exec( new ActivateReq( theStudy, this ) ); - - // activate menus, toolbars, etc - setMenuShown( true ); - setToolShown( true ); - - return true; -} - -/*! - * Deactivation of the module. - * Inherited from CAM_Module. - */ -bool SALOME_PYQT_Module::deactivateModule( SUIT_Study* theStudy ) -{ - MESSAGE( "SALOME_PYQT_Module::deactivateModule" ); - - bool res = SalomeApp_Module::deactivateModule( theStudy ); - - // deactivate menus, toolbars, etc - setMenuShown( false ); - setToolShown( false ); - - // DeactivateReq: request class for internal deactivate() operation - class DeactivateReq : public PyInterp_LockRequest - { - public: - DeactivateReq( PyInterp_base* _py_interp, - SUIT_Study* _study, - SALOME_PYQT_Module* _obj ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myStudy ( _study ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->deactivate( myStudy ); - } - - private: - SUIT_Study* myStudy; - SALOME_PYQT_Module* myObj; - }; - - // Posting the request - PyInterp_Dispatcher::Get()->Exec( new DeactivateReq( myInterp, theStudy, this ) ); - - return res; -} - -/*! - * Processes GUI action (from main menu, toolbar or context popup menu) - */ -void SALOME_PYQT_Module::onGUIEvent() -{ - // get sender action - const QObject* obj = sender(); - if ( !obj || !obj->inherits( "QAction" ) ) - return; - QAction* action = (QAction*)obj; - - // get action ID - int id = actionId( action ); - if ( myMenuActionList.contains( action ) ) - id -= PYQT_ACTION_MENU; - if ( myToolbarActionList.contains( action ) ) - id -= PYQT_ACTION_TOOLBAL; - if ( myPopupActionList.contains( action ) ) - id -= PYQT_ACTION_POPUP; - MESSAGE( "SALOME_PYQT_Module::onGUIEvent: id = " << id ); - - // perform synchronous request to Python event dispatcher - class GUIEvent : public PyInterp_LockRequest - { - public: - GUIEvent( PyInterp_base* _py_interp, - SALOME_PYQT_Module* _obj, - int _id ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myId ( _id ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->guiEvent( myId ); - } - - private: - int myId; - SALOME_PYQT_Module* myObj; - }; - - // Posting the request - PyInterp_Dispatcher::Get()->Exec( new GUIEvent( myInterp, this, id ) ); -} - -/*! - * Processes GUI action (from context popup menu, only for XML-based actions!) - */ -void SALOME_PYQT_Module::onGUIEvent( int id ) -{ - // perform synchronous request to Python event dispatcher - class GUIEvent : public PyInterp_LockRequest - { - public: - GUIEvent( PyInterp_base* _py_interp, - SALOME_PYQT_Module* _obj, - int _id ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myId ( _id ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->guiEvent( myId ); - } - - private: - int myId; - SALOME_PYQT_Module* myObj; - }; - - // Posting the request - PyInterp_Dispatcher::Get()->Exec( new GUIEvent( myInterp, this, id ) ); -} - -/*! - Context popup menu request. - Called when user activates popup menu in some window (view, object browser, etc). - */ -void SALOME_PYQT_Module::contextMenuPopup( const QString& theContext, QPopupMenu* thePopupMenu, QString& /*title*/ ) -{ - MESSAGE( "SALOME_PYQT_Module::contextMenuPopup : " << theContext.latin1() ); - // perform synchronous request to Python event dispatcher - class PopupMenuEvent : public PyInterp_LockRequest - { - public: - PopupMenuEvent( PyInterp_base* _py_interp, - SALOME_PYQT_Module* _obj, - const QString& _context, - QPopupMenu* _popup ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myContext( _context ), - myPopup ( _popup ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->contextMenu( myContext, myPopup ); - } - - private: - SALOME_PYQT_Module* myObj; - QString myContext; - QPopupMenu* myPopup; - }; - - // Posting the request only if dispatcher is not busy! - // Executing the request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new PopupMenuEvent( myInterp, this, theContext, thePopupMenu ) ); -} - -/*! - * Defines the dockable window associated with the module. - * To fill the list of windows the correspondind Python module's windows() - * method is called from SALOME_PYQT_Module::init() method. - * By default, ObjectBrowser, PythonConsole and LogWindow are provided. - */ -void SALOME_PYQT_Module::windows( QMap& mappa ) const -{ - // First clear the output parameters - QMap::ConstIterator it; - for ( it = myWindowsMap.begin(); it != myWindowsMap.end(); ++it ) { - mappa[ it.key() ] = it.data(); - } -} - -/*! - * Defines the compatible views which should be opened on module activation. - * To fill the list of views the correspondind Python module's views() - * method is called from SALOME_PYQT_Module::init() method. - * By default, the list is empty. - */ -void SALOME_PYQT_Module::viewManagers( QStringList& listik ) const -{ - for ( QStringList::ConstIterator it = myViewMgrList.begin(); it != myViewMgrList.end(); ++it ) { - listik.append( *it ); - } -} - -/*! - * Performs internal initialization - * - initializes/gets the Python interpreter (one per study) - * - imports the Python module - * - passes the workspace widget to the Python module - * - calls Python module's initialize() method - * - calls Python module's windows() method - * - calls Python module's views() method - */ -void SALOME_PYQT_Module::init( CAM_Application* app ) + This function tries to get engine IOR from the Python module using engineIOR() function. + That function can load module engine using appropriate container if required. + If this function is not available in Python module, the default implementation + is used which loads engine to the default FactoryServer container. +*/ +QString SALOME_PYQT_Module::engineIOR() const { - // reset interpreter to NULL - myInterp = NULL; - - // get study Id - SalomeApp_Application* anApp = dynamic_cast( app ); - if ( !anApp ) - return; + // call helper to get IOR from Python module + static QString ior; - SalomeApp_Study* aStudy = dynamic_cast( app->activeStudy() ); - if ( !aStudy ) - return; - int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0; - - // initialize Python subinterpreter (on per study) and put it in variable - initInterp( aStudyId ); - if ( !myInterp ) - return; // Error - - // import Python GUI module - importModule(); - if ( !myModule ) - return; // Error - - myInitModule = this; - - if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__ - // call Python module's setWorkspace() method - setWorkSpace(); - } //__CALL_OLD_METHODS__ - - // then call Python module's initialize() method - // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - // ... (the Python module is already imported) - // ... finally call Python module's initialize() method - PyObjWrapper res( PyObject_CallMethod( myModule, "initialize", "" ) ); - if( !res ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); + if ( ior.isEmpty() ) { + // first call helper to get IOR from Python module + ior = myHelper->engineIOR(); } - - // get the windows list from the Python module by calling windows() method - // ... first put default values - myWindowsMap.insert( SalomeApp_Application::WT_ObjectBrowser, Qt::DockLeft ); - myWindowsMap.insert( SalomeApp_Application::WT_PyConsole, Qt::DockBottom ); - // VSR: LogWindow is not yet implemented - // myWindowsMap.insert( SalomeApp_Application::WT_LogWindow, Qt::DockBottom ); - - PyObjWrapper res1( PyObject_CallMethod( myModule, "windows", "" ) ); - if( !res1 ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); - } - else { - myWindowsMap.clear(); - if ( PyDict_Check( res1 ) ) { - PyObject* key; - PyObject* value; - int pos = 0; - while ( PyDict_Next( res1, &pos, &key, &value ) ) { - // parse the return value - // it should be a map: {integer:integer} - int aKey, aValue; - if( key && PyInt_Check( key ) && value && PyInt_Check( value ) ) { - aKey = PyInt_AsLong( key ); - aValue = PyInt_AsLong( value ); - myWindowsMap[ aKey ] = aValue; - } - } + if ( ior.isEmpty() ) { + // if IOR is still not specified, try default implementation + // which loads engine to the default FactoryServer container. + Engines::EngineComponent_var comp; + // temporary solution + try { + comp = getApp()->lcc()->FindOrLoad_Component( "FactoryServer", name().toLatin1() ); } - } - // get the windows list from the Python module by calling views() method - PyObjWrapper res2( PyObject_CallMethod( myModule, "views", "" ) ); - if( !res2 ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); - } - else { - // parse the return value - // result can be one string... - if ( PyString_Check( res2 ) ) { - myViewMgrList.append( PyString_AsString( res2 ) ); - } - // ... or list of strings - else if ( PyList_Check( res2 ) ) { - int size = PyList_Size( res2 ); - for ( int i = 0; i < size; i++ ) { - PyObject* value = PyList_GetItem( res2, i ); - if( value && PyString_Check( value ) ) { - myViewMgrList.append( PyString_AsString( value ) ); - } - } - } - } - myInitModule = 0; -} - -/*! - * Performs internal activation: - * - initializes/gets the Python interpreter (one per study) - * - imports the Python GUI module - * - calls Python module's setSettings() method (obsolete function, used for compatibility with old code) - * or activate() method (for new modules) - */ -void SALOME_PYQT_Module::activate( SUIT_Study* theStudy ) -{ - // get study Id - SalomeApp_Study* aStudy = dynamic_cast( theStudy ); - int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0; - - // initialize Python subinterpreter (on per study) and put it in variable - initInterp( aStudyId ); - if ( !myInterp ) - return; // Error - - // import Python GUI module - importModule(); - if ( !myModule ) - return; // Error - - // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - - if ( IsCallOldMethods ) { //__CALL_OLD_METHODS__ - // call Python module's setSettings() method (obsolete) - PyObjWrapper res( PyObject_CallMethod( myModule, "setSettings", "" ) ); - if( !res ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); + catch (CORBA::Exception&) { } - } //__CALL_OLD_METHODS__ - - // call Python module's activate() method (for the new modules) - PyObjWrapper res1( PyObject_CallMethod( myModule, "activate", "" ) ); - if( !res1 ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); + if ( !CORBA::is_nil( comp ) ) + ior = QString( getApp()->orb()->object_to_string( comp.in() ) ); } -} -/*! - * Performs internal deactivation: - * - calls Python module's deactivate() method - */ -void SALOME_PYQT_Module::deactivate( SUIT_Study* theStudy ) -{ - // check if the subinterpreter is initialized and Python module is imported - if ( !myInterp || !myModule ) { - // Error! Python subinterpreter should be initialized and module should be imported first! - return; - } - // then call Python module's deactivate() method - PyObjWrapper res( PyObject_CallMethod( myModule, "deactivate", "" ) ); - if( !res ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); - } + return ior; } /*! - * Called when active the study is actived (user brings its desktop to top) - * - initializes/gets the Python interpreter (one per study) - * - imports the Python GUI module - * - calls Python module's activeStudyChanged() method - */ -void SALOME_PYQT_Module::studyChanged( SUIT_Study* theStudy ) + \brief Initialization of the module. + \param app parent application object + \sa PyModuleHelper::initialize() +*/ +void SALOME_PYQT_Module::initialize( CAM_Application* app ) { - // get study Id - SalomeApp_Study* aStudy = dynamic_cast( theStudy ); - int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0; - - // initialize Python subinterpreter (on per study) and put it in variable - initInterp( aStudyId ); - if ( !myInterp ) - return; // Error - - // import Python GUI module - importModule(); - if ( !myModule ) - return; // Error - - // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); + // call base implementation + SalomeApp_Module::initialize( app ); - // call Python module's activeStudyChanged() method - PyObjWrapper res( PyObject_CallMethod( myModule, "activeStudyChanged", "i", aStudyId ) ); - if( !res ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); - } + // ... then call helper + myHelper->initialize( app ); } /*! - * Get module engine, returns nil var if engine is not found in LifeCycleCORBA - */ -Engines::Component_var SALOME_PYQT_Module::getEngine() const + \brief Activation of the module. + \param study parent study + \return \c true if activation is successful and \c false otherwise + \sa PyModuleHelper::activate() +*/ +bool SALOME_PYQT_Module::activateModule( SUIT_Study* study ) { - Engines::Component_var comp; - // temporary solution - try { - comp = getApp()->lcc()->FindOrLoad_Component( "FactoryServerPy", name( "" ) ); - } - catch (CORBA::Exception&) { - } - return comp; + // call base implementation and then helper + return SalomeApp_Module::activateModule( study ) && myHelper->activate( study ); } /*! - * Get module engine IOR, returns empty string if engine is not found in LifeCycleCORBA - */ -QString SALOME_PYQT_Module::engineIOR() const -{ - if ( !CORBA::is_nil( getEngine() ) ) - return QString( getApp()->orb()->object_to_string( getEngine() ) ); - return QString( "" ); -} - -/*! - * Called when study desktop is activated. - * Used for notifying about changing of the active study. - */ -void SALOME_PYQT_Module::studyActivated() + \brief Deactivation of the module. + \param study parent study + \return \c true if deactivation is successful and \c false otherwise + \sa PyModuleHelper::deactivate() +*/ +bool SALOME_PYQT_Module::deactivateModule( SUIT_Study* study ) { - // StudyChangedReq: request class for internal studyChanged() operation - class StudyChangedReq : public PyInterp_Request - { - public: - StudyChangedReq( SUIT_Study* _study, - SALOME_PYQT_Module* _obj ) - : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) - myStudy ( _study ), - myObj ( _obj ) {} + // call helper + bool res = myHelper->deactivate( study ); - protected: - virtual void execute() - { - myObj->studyChanged( myStudy ); - } - - private: - SUIT_Study* myStudy; - SALOME_PYQT_Module* myObj; - }; - - // Posting the request - PyInterp_Dispatcher::Get()->Exec( new StudyChangedReq( application()->activeStudy(), this ) ); -} - -/*! - * Processes context popup menu request - * - calls Python module's definePopup(...) method (obsolete function, used for compatibility with old code) - * to define the popup menu context - * - parses XML resourses file (if exists) and fills the popup menu with the items) - * - calls Python module's customPopup(...) method (obsolete function, used for compatibility with old code) - * to allow module to customize the popup menu - * - for new modules calls createPopupMenu() function to allow the modules to build the popup menu - * by using insertItem(...) Qt functions. - */ -void SALOME_PYQT_Module::contextMenu( const QString& theContext, QPopupMenu* thePopupMenu ) -{ - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - QString aContext( theContext ), aObject( "" ), aParent( "" ); - - if ( IsCallOldMethods ) { //__CALL_OLD_METHODS__ - // call definePopup() Python module's function - // this is obsolete function, used only for compatibility reasons - PyObjWrapper res(PyObject_CallMethod( myModule, - "definePopup", - "sss", - aContext.latin1(), - aObject.latin1(), - aParent.latin1() ) ); - if( !res ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); - } - else { - // parse return value - char *co, *ob, *pa; - if( PyArg_ParseTuple( res, "sss", &co, &ob, &pa ) ) { - aContext = co; - aObject = ob; - aParent = pa; - } - } - } //__CALL_OLD_METHODS__ - - // first try to create menu via XML parser: - // we create popup menus without help of QtxPopupMgr - if ( myXmlHandler ) - myXmlHandler->createPopup( thePopupMenu, aContext, aParent, aObject ); - - PyObjWrapper sipPopup( sipBuildResult( 0, "M", thePopupMenu, sipClass_QPopupMenu ) ); - - // then call Python module's createPopupMenu() method (for new modules) - PyObjWrapper res1( PyObject_CallMethod( myModule, - "createPopupMenu", - "Os", - sipPopup.get(), - aContext.latin1() ) ); - if( !res1 ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); - } - - if ( IsCallOldMethods ) { //__CALL_OLD_METHODS__ - // call customPopup() Python module's function - // this is obsolete function, used only for compatibility reasons - PyObjWrapper res2( PyObject_CallMethod( myModule, - "customPopup", - "Osss", - sipPopup.get(), - aContext.latin1(), - aObject.latin1(), - aParent.latin1() ) ); - if( !res2 ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); - } - } //__CALL_OLD_METHODS__ + // ... then call base implementation + return SalomeApp_Module::deactivateModule( study ) && res; } /*! - * Processes GUI event - * - calls Python module's OnGUIEvent() method - */ -void SALOME_PYQT_Module::guiEvent( const int theId ) -{ - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - PyObjWrapper res( PyObject_CallMethod( myModule, "OnGUIEvent", "i", theId ) ); - if( !res ) { - // Error! - PyErr_Print(); - } -} - -/*! - * Initialises python subinterpreter (one per study) - */ -void SALOME_PYQT_Module::initInterp( int theStudyId ) -{ - // check study Id - if ( !theStudyId ) { - // Error! Study Id must not be 0! - myInterp = NULL; - return; - } - // try to find the subinterpreter - if( myInterpMap.find( theStudyId ) != myInterpMap.end() ) { - // found! - myInterp = myInterpMap[ theStudyId ]; - return; - } - // not found - create a new one! - /////////////////////////////////////////////////////////////////// - // Attention: the creation of Python interpretor must be protected - // by a C++ Lock because of C threads - /////////////////////////////////////////////////////////////////// - myInterp = new SALOME_PYQT_PyInterp(); - myInterp->initialize(); - myInterpMap[ theStudyId ] = myInterp; - - // import 'salome' module and call 'salome_init' method; - // do it only once on interpreter creation - // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - // ... then import a module - PyObjWrapper aMod = PyImport_ImportModule( "salome" ); - if( !aMod ) { - // Error! - PyErr_Print(); - return; - } - // ... then call a method - PyObjWrapper aRes( PyObject_CallMethod( aMod, "salome_init", "" ) ); - if( !aRes ) { - // Error! - PyErr_Print(); - return; - } -} - -/*! - * Imports Python GUI module and remember the reference to the module - * !!! initInterp() should be called first!!! - */ -void SALOME_PYQT_Module::importModule() + \brief Get the dockable windows associated with the module. + \param winMap output map of dockable windows in form { : } + \sa PyModuleHelper::windows() +*/ +void SALOME_PYQT_Module::windows( QMap& winMap ) const { - // check if the subinterpreter is initialized - if ( !myInterp ) { - // Error! Python subinterpreter should be initialized first! - myModule = 0; - return; - } - // import Python GUI module and puts it in attribute - // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - // ... then import a module - QString aMod = QString( name("") ) + "GUI"; - myModule = PyImport_ImportModule( (char*)( aMod.latin1() ) ); - if( !myModule ) { - // Error! - PyErr_Print(); - return; - } + // get list of dockable windows from helper + winMap = myHelper->windows(); } /*! - * Calls .setWorkSpace() method with PyQt QWidget object to use with - * interpreter. - * !!! initInterp() and importModule() should be called first!!! - */ -void SALOME_PYQT_Module::setWorkSpace() + \brief Define the compatible view windows associated with the module. + \param viewList output list of view windows types + \sa PyModuleHelper::viewManagers() +*/ +void SALOME_PYQT_Module::viewManagers( QStringList& viewList ) const { - // check if the subinterpreter is initialized and Python module is imported - if ( !myInterp || !myModule ) { - // Error! Python subinterpreter should be initialized and module should be imported first! - return; - } - - // call setWorkspace() method - // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - - // ... then try to import SalomePyQt module. If it's not possible don't go on. - PyObjWrapper aQtModule( PyImport_ImportModule( "SalomePyQt" ) ); - if( !aQtModule ) { - // Error! - PyErr_Print(); - return; - } - - if ( IsCallOldMethods ) { //__CALL_OLD_METHODS__ - // ... then get workspace object - QWidget* aWorkspace = 0; - if ( getApp()->desktop()->inherits( "STD_MDIDesktop" ) ) { - STD_MDIDesktop* aDesktop = dynamic_cast( getApp()->desktop() ); - if ( aDesktop ) - aWorkspace = aDesktop->workspace(); - } - else if ( getApp()->desktop()->inherits( "STD_TabDesktop" ) ) { - STD_TabDesktop* aDesktop = dynamic_cast( getApp()->desktop() ); - if ( aDesktop ) - aWorkspace = aDesktop->workstack(); - } - PyObjWrapper pyws( sipBuildResult( 0, "M", aWorkspace, sipClass_QWidget ) ); - // ... and finally call Python module's setWorkspace() method (obsolete) - PyObjWrapper res( PyObject_CallMethod( myModule, "setWorkSpace", "O", pyws.get() ) ); - if( !res ) { - // VSR: this method may not be implemented in Python module - // PyErr_Print(); - return; - } - } //__CALL_OLD_METHODS__ + // get list of view types from helper + viewList = myHelper->viewManagers(); } /*! - * Adds an action into private action list [internal usage] - */ -void SALOME_PYQT_Module::addAction( const PyQtGUIAction type, QAction* action ) + \brief Process study activation. + \sa PyModuleHelper::studyActivated() +*/ +void SALOME_PYQT_Module::studyActivated() { - switch ( type ) { - case PYQT_ACTION_MENU: - myMenuActionList.append( action ); - break; - case PYQT_ACTION_TOOLBAL: - myToolbarActionList.append( action ); - break; - case PYQT_ACTION_POPUP: - myPopupActionList.append( action ); - break; - } + // call helper + myHelper->studyActivated( application()->activeStudy() ); } - /*! - * The next methods just call the parent implementation. - * This is done to open protected methods from CAM_Module class. + \brief Process context popup menu request. + \param context popup menu context (e.g. "ObjectBrowser") + \param menu popup menu + \param title popup menu title (not used) + \sa PyModuleHelper::contextMenu() */ -int SALOME_PYQT_Module::createTool( const QString& name ) -{ - return SalomeApp_Module::createTool( name ); -} -int SALOME_PYQT_Module::createTool( const int id, const int tBar, const int idx ) -{ - return SalomeApp_Module::createTool( id, tBar, idx ); -} -int SALOME_PYQT_Module::createTool( const int id, const QString& tBar, const int idx ) +void SALOME_PYQT_Module::contextMenuPopup( const QString& context, + QMenu* menu, + QString& /*title*/ ) { - return SalomeApp_Module::createTool( id, tBar, idx ); -} -int SALOME_PYQT_Module::createTool( QAction* a, const int tBar, const int id, const int idx ) -{ - return SalomeApp_Module::createTool( a, tBar, id, idx ); -} -int SALOME_PYQT_Module::createTool( QAction* a, const QString& tBar, const int id, const int idx ) -{ - return SalomeApp_Module::createTool( a, tBar, id, idx ); -} -int SALOME_PYQT_Module::createMenu( const QString& subMenu, const int menu, const int id, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( subMenu, menu, id, group, idx ); -} -int SALOME_PYQT_Module::createMenu( const QString& subMenu, const QString& menu, const int id, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( subMenu, menu, id, group, idx ); -} -int SALOME_PYQT_Module::createMenu( const int id, const int menu, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( id, menu, group, idx ); -} -int SALOME_PYQT_Module::createMenu( const int id, const QString& menu, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( id, menu, group, idx ); -} -int SALOME_PYQT_Module::createMenu( QAction* a, const int menu, const int id, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( a, menu, id, group, idx ); -} -int SALOME_PYQT_Module::createMenu( QAction* a, const QString& menu, const int id, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( a, menu, id, group, idx ); -} -QAction* SALOME_PYQT_Module::createSeparator() -{ - return SalomeApp_Module::separator(); -} -QAction* SALOME_PYQT_Module::action( const int id ) const -{ - QAction* a = SalomeApp_Module::action( id ); - if ( !a ) // try own action map for menu items - a = SalomeApp_Module::action( id + PYQT_ACTION_MENU ); - if ( !a ) // try own action map for toolbar items - a = SalomeApp_Module::action( id + PYQT_ACTION_TOOLBAL ); - if ( !a ) // try own action map for popup items - a = SalomeApp_Module::action( id + PYQT_ACTION_POPUP ); - return a; -} -int SALOME_PYQT_Module::actionId( const QAction* a ) const -{ - int id = SalomeApp_Module::actionId( a ); - if ( myMenuActionList.contains( a ) ) // check own action map for menu items - id -= PYQT_ACTION_MENU; - if ( myToolbarActionList.contains( a ) ) // check own action map for toolbar items - id -= PYQT_ACTION_TOOLBAL; - if ( myPopupActionList.contains( a ) ) // check own action map for popup items - id -= PYQT_ACTION_POPUP; - return id; -} -QAction* SALOME_PYQT_Module::createAction( const int id, const QString& text, const QString& icon, - const QString& menu, const QString& tip, const int key, - const bool toggle ) -{ - QIconSet anIcon; - if ( !icon.isEmpty() ) { - QPixmap pixmap = getApp()->resourceMgr()->loadPixmap( name(""), tr( icon ) ); - if ( !pixmap.isNull() ) - anIcon = QIconSet( pixmap ); - } - return SalomeApp_Module::createAction( id, text, anIcon, menu, tip, key, getApp()->desktop(), toggle, this, SLOT( onGUIEvent() ) ); -} - - -//============================================================================= -// SALOME_PYQT_XmlHandler class implementation -//============================================================================= - -// gets an tag name for the dom element [ static ] -// returns an empty string if the element does not have tag name -static QString tagName( const QDomElement& element ) { - return element.tagName().stripWhiteSpace(); -} - -// gets an attribute by it's name for the dom element [ static ] -// returns an empty string if the element does not have such attribute -static QString attribute( const QDomElement& element, const QString& attName ) { - return element.attribute( attName ).stripWhiteSpace(); -} - -// checks the given value for the boolean value [ static ] -// returns TRUE if string is "true", "yes" or "1" -static bool checkBool( const QString& value ) { - return ( value == "true" || value == "yes" || value == "1" ); -} - -// checks the given value for the integer value [ static ] -// returns -1 if item is empty or presents and invalid number -static int checkInt( const QString& value ) -{ - return value.isEmpty() ? -1 : value.toInt(); + // call helper + myHelper->contextMenu( context, menu ); } /*! - * Constructor - */ -SALOME_PYQT_XmlHandler::SALOME_PYQT_XmlHandler( SALOME_PYQT_Module* module, const QString& fileName ) - : myModule( module ) + \brief Export preferences for the Python module. + \sa PyModuleHelper::createPreferences() +*/ +void SALOME_PYQT_Module::createPreferences() { - QFile aFile( fileName ); - if ( !aFile.open( IO_ReadOnly ) ) - return; - if ( !myDoc.setContent( &aFile ) ) { - aFile.close(); - return; - } - aFile.close(); + // call helper + myHelper->createPreferences(); } /*! - Called by SALOME_PYQT_Module::initialize() in order to create actions - (menus, toolbars, popup menus) - */ -void SALOME_PYQT_XmlHandler::createActions() + \brief Process module's preferences changing. + \param section preference resources section + \param parameter preference resources parameter name + \sa PyModuleHelper::preferencesChanged() +*/ +void SALOME_PYQT_Module::preferencesChanged( const QString& section, const QString& parameter ) { - // get document element - QDomElement aDocElem = myDoc.documentElement(); - - // get main menu actions - QDomNodeList aMenuList = aDocElem.elementsByTagName( "menu-item" ); - for ( int i = 0; i < aMenuList.count(); i++ ) { - QDomNode n = aMenuList.item( i ); - createMenu( n ); - } - - // create toolbars actions - QDomNodeList aToolsList = aDocElem.elementsByTagName( "toolbar" ); - for ( int i = 0; i < aToolsList.count(); i++ ) { - QDomNode n = aToolsList.item( i ); - createToolBar( n ); - } + // call helper + myHelper->preferencesChanged( section, parameter ); } /*! - * Creates popup menu - */ -void SALOME_PYQT_XmlHandler::createPopup( QPopupMenu* menu, - const QString& context, - const QString& parent, - const QString& object ) + \brief Test if object \a what can be dragged by the user. + \param what data object being tested + \return \c true if object can be dragged or \c false otherwise + \sa PyModuleHelper::isDraggable() +*/ +bool SALOME_PYQT_Module::isDraggable( const SUIT_DataObject* what ) const { - // get document element - QDomElement aDocElem = myDoc.documentElement(); - - // get popup menus actions - QDomNodeList aPopupList = aDocElem.elementsByTagName( "popupmenu" ); - for ( int i = 0; i < aPopupList.count(); i++ ) { - QDomNode n = aPopupList.item( i ); - if ( !n.isNull() && n.isElement() ) { - QDomElement e = n.toElement(); - QString lab = attribute( e, "label-id" ); - QString ctx = attribute( e, "context-id" ); - QString prt = attribute( e, "parent-id" ); - QString obj = attribute( e, "object-id" ); - if ( ctx == context && prt == parent && obj == object ) { - insertPopupItems( n, menu ); - break; - } - } - } + // call helper + return myHelper->isDraggable( what ); } /*! - Create main menu with child actions - */ -void SALOME_PYQT_XmlHandler::createMenu( QDomNode& parentNode, const int parentMenuId ) + \brief Test if drop operation can be done on the \a where object. + \param where data object being tested + \return \c true if if drop operation is supported by object or \c false otherwise + \sa PyModuleHelper::isDropAccepted() +*/ +bool SALOME_PYQT_Module::isDropAccepted( const SUIT_DataObject* where ) const { - if ( !myModule ) - return; - - if ( parentNode.isNull() ) - return; - - QDomElement parentElement = parentNode.toElement(); - if ( !parentElement.isNull() ) { - QString plabel = attribute( parentElement, "label-id" ); - int pid = checkInt( attribute( parentElement, "item-id" ) ); - int ppos = checkInt( attribute( parentElement, "pos-id" ) ); - if ( !plabel.isEmpty() ) { - // create menu - int menuId = myModule->createMenu( plabel, // label - parentMenuId, // parent menu ID, should be -1 for main menu - pid, // ID - 80, // group ID - ppos ); // position - QDomNode node = parentNode.firstChild(); - while ( !node.isNull() ) { - if ( node.isElement() ) { - QDomElement elem = node.toElement(); - QString aTagName = tagName( elem ); - if ( aTagName == "popup-item" ) { - int id = checkInt( attribute( elem, "item-id" ) ); - int pos = checkInt( attribute( elem, "pos-id" ) ); - QString label = attribute( elem, "label-id" ); - QString icon = attribute( elem, "icon-id" ); - QString tooltip = attribute( elem, "tooltip-id" ); - QString accel = attribute( elem, "accel-id" ); - bool toggle = checkBool( attribute( elem, "toggle-id" ) ); - ////QString execute = attribute( elem, "execute-action" ); // not used - - // -1 action ID is not allowed : it means that attribute is missed in the XML file! - // also check if the action with given ID is already created - if ( id != -1 && !myModule->action( SALOME_PYQT_Module::PYQT_ACTION_MENU + id ) ) { - // little trick to have several actions with same ID for menus and toolbars - id = SALOME_PYQT_Module::PYQT_ACTION_MENU + id; - // create menu action - QAction* action = myModule->createAction( id, // ID - tooltip, // tooltip - icon, // icon - label, // menu text - tooltip, // status-bar text - QKeySequence( accel ), // keyboard accelerator - toggle ); // toogled action - myModule->addAction( SALOME_PYQT_Module::PYQT_ACTION_MENU, action ); - myModule->createMenu( action, menuId, -1, 80, pos ); - } - } - else if ( aTagName == "submenu" ) { - // create sub-menu - createMenu( node, menuId ); - } - else if ( aTagName == "separator" ) { - // create menu separator - int pos = checkInt( attribute( elem, "pos-id" ) ); - QAction* action = myModule->createSeparator(); - myModule->createMenu( action, menuId, -1, 80, pos ); - } - } - node = node.nextSibling(); - } - } - } + // call helper + return myHelper->isDropAccepted( where ); } /*! - Create a toolbar with child actions - */ -void SALOME_PYQT_XmlHandler::createToolBar( QDomNode& parentNode ) + \brief Perform drop operation + \param what list of data objects being dropped + \param where target data object for drop operation + \param row line (child item index) where drop operation is performed to + \param action current drop action (copy or move) + \sa PyModuleHelper::dropObjects() +*/ +void SALOME_PYQT_Module::dropObjects( const DataObjectList& what, SUIT_DataObject* where, + const int row, Qt::DropAction action ) { - if ( !myModule ) - return; - - if ( parentNode.isNull() ) - return; - - QDomElement parentElement = parentNode.toElement(); - if ( !parentElement.isNull() ) { - QString aLabel = attribute( parentElement, "label-id" ); - if ( !aLabel.isEmpty() ) { - // create toolbar - int tbId = myModule->createTool( aLabel ); - QDomNode node = parentNode.firstChild(); - while ( !node.isNull() ) { - if ( node.isElement() ) { - QDomElement elem = node.toElement(); - QString aTagName = tagName( elem ); - if ( aTagName == "toolbutton-item" ) { - int id = checkInt( attribute( elem, "item-id" ) ); - int pos = checkInt( attribute( elem, "pos-id" ) ); - QString label = attribute( elem, "label-id" ); - QString icon = attribute( elem, "icon-id" ); - QString tooltip = attribute( elem, "tooltip-id" ); - QString accel = attribute( elem, "accel-id" ); - bool toggle = checkBool( attribute( elem, "toggle-id" ) ); - ////QString execute = attribute( elem, "execute-action" ); // not used - - // -1 action ID is not allowed : it means that attribute is missed in the XML file! - // also check if the action with given ID is already created - if ( id != -1 && !myModule->action( SALOME_PYQT_Module::PYQT_ACTION_TOOLBAL + id ) ) { - // little trick to have several actions with same ID for menus and toolbars - id = SALOME_PYQT_Module::PYQT_ACTION_TOOLBAL + id; - // create toolbar action - QAction* action = myModule->createAction( id, // ID - tooltip, // tooltip - icon, // icon - label, // menu text - tooltip, // status-bar text - QKeySequence( accel ), // keyboard accelerator - toggle ); // toogled action - myModule->addAction( SALOME_PYQT_Module::PYQT_ACTION_TOOLBAL, action ); - myModule->createTool( action, tbId, -1, pos ); - } - } - else if ( aTagName == "separatorTB" ) { - // create toolbar separator - int pos = checkInt( attribute( elem, "pos-id" ) ); - QAction* action = myModule->createSeparator(); - myModule->createTool( action, tbId, -1, pos ); - } - } - node = node.nextSibling(); - } - } - } + // call helper + myHelper->dropObjects( what, where, row, action ); } -void SALOME_PYQT_XmlHandler::insertPopupItems( QDomNode& parentNode, QPopupMenu* menu ) -{ - if ( !myModule ) - return; - - if ( parentNode.isNull() ) - return; - - // we create popup menus without help of QtxPopupMgr - QDomNode node = parentNode.firstChild(); - while ( !node.isNull() ) { - if ( node.isElement() ) { - QDomElement elem = node.toElement(); - QString aTagName = tagName( elem ); - if ( aTagName == "popup-item" ) { - // insert a command item - int id = checkInt( attribute( elem, "item-id" ) ); - int pos = checkInt( attribute( elem, "pos-id" ) ); - QString label = attribute( elem, "label-id" ); - QString icon = attribute( elem, "icon-id" ); - /////QString tooltip = attribute( elem, "tooltip-id" ); // not used - QString accel = attribute( elem, "accel-id" ); - /////bool toggle = checkBool( attribute( elem, "toggle-id" ) ); // not used - /////QString execute = attribute( elem, "execute-action" ); // not used - - QIconSet anIcon; - if ( !icon.isEmpty() ) { - QPixmap pixmap = myModule->getApp()->resourceMgr()->loadPixmap( myModule->name(""), icon ); - if ( !pixmap.isNull() ) - anIcon = QIconSet( pixmap ); - } - - // -1 action ID is not allowed : it means that attribute is missed in the XML file! - // also check if the action with given ID is already created - if ( id != -1 ) { - menu->insertItem( anIcon, label, myModule, SLOT( onGUIEvent(int) ), QKeySequence( accel ), id, pos ); - } - } - else if ( aTagName == "submenu" ) { - // create sub-menu - int id = checkInt( attribute( elem, "item-id" ) ); - int pos = checkInt( attribute( elem, "pos-id" ) ); - QString label = attribute( elem, "label-id" ); - QString icon = attribute( elem, "icon-id" ); - - QIconSet anIcon; - if ( !icon.isEmpty() ) { - QPixmap pixmap = myModule->getApp()->resourceMgr()->loadPixmap( myModule->name(""), icon ); - if ( !pixmap.isNull() ) - anIcon = QIconSet( pixmap ); - } - - QPopupMenu* newPopup = new QPopupMenu( menu, label ); - menu->insertItem( anIcon, label, newPopup, id, pos ); - insertPopupItems( node, newPopup ); - } - else if ( aTagName == "separator" ) { - // create menu separator - int pos = checkInt( attribute( elem, "pos-id" ) ); - menu->insertSeparator( pos ); - } - } - node = node.nextSibling(); - } -}