1 // Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/
20 #include "SALOME_PYQT_Module.h"
22 #include "PyInterp_Dispatcher.h"
23 #include "SUIT_ResourceMgr.h"
24 #include "STD_MDIDesktop.h"
25 #include "STD_TabDesktop.h"
26 #include "SalomeApp_Application.h"
27 #include "SalomeApp_Study.h"
29 #include "QtxWorkstack.h"
30 #include "QtxActionMenuMgr.h"
31 #include "QtxActionToolMgr.h"
32 #include <SALOME_LifeCycleCORBA.hxx>
33 #include <Container_init_python.hxx>
37 #include <qworkspace.h>
39 #include <qpopupmenu.h>
41 #include "SALOME_PYQT_SipDefs.h"
42 #if defined(SIP_VERS_v4_old) || defined(SIP_VERS_v4_new)
43 #include "sipAPISalomePyQtGUI.h"
45 #include "sipSalomePyQtGUIDeclSalomePyQtGUI.h"
48 #include <sipqtQWidget.h>
49 #include <sipqtQPopupMenu.h>
56 \var __DEFAULT_NAME__ - Default name of the module, replaced at the moment of module creation
58 const char* __DEFAULT_NAME__ = "SALOME_PYQT_Module";
61 \var __DEFAULT_GROUP__ - Default menu group number
63 const int __DEFAULT_GROUP__ = 40;
65 // If __CALL_OLD_METHODS__ macro is not defined the invoking of obsolete Python
66 // module's methods like setSetting(), definePopup(), etc. is blocked.
67 // This macro is defined by default (in Makefile)
68 #ifdef __CALL_OLD_METHODS__
69 const bool IsCallOldMethods = true;
71 const bool IsCallOldMethods = false;
74 // NB: Python requests.
75 // General rule for Python requests created by SALOME_PYQT_Module:
76 // all requests should be executed SYNCHRONOUSLY within the main GUI thread.
77 // However, it is obligatory that ANY Python call is wrapped with a request object,
78 // so that ALL Python API calls are serialized with PyInterp_Dispatcher.
81 \class SALOME_PYQT_XmlHandler
82 The class for parsing of the XML resource files.
83 Used for backward compatibility with existing Python modules.
85 class SALOME_PYQT_XmlHandler
88 SALOME_PYQT_XmlHandler( SALOME_PYQT_Module* module, const QString& fileName );
91 void createPopup ( QPopupMenu* menu,
92 const QString& context,
93 const QString& parent,
94 const QString& object );
97 void createToolBar ( QDomNode& parentNode );
98 void createMenu ( QDomNode& parentNode,
99 const int parentMenuId = -1,
100 QPopupMenu* parentPopup = 0 );
102 void insertPopupItems( QDomNode& parentNode,
106 SALOME_PYQT_Module* myModule;
108 QStringList myMenuItems;
109 QStringList myCurrentMenu;
113 // SALOME_PYQT_Module class implementation (implements CAM_Module API for
114 // all Python-based SALOME module
116 // While the SalomePyQtGUI library is not imported in Python it's initialization function
117 // should be called manually (and only once) in order to initialize global sip data
118 // and to get C API from sip : sipBuildResult for example
119 #if defined(SIP_VERS_v4_old) || defined(SIP_VERS_v4_new)
120 #define INIT_FUNCTION initSalomePyQtGUI
121 #if defined(SIP_STATIC_MODULE)
122 extern "C" void INIT_FUNCTION();
124 PyMODINIT_FUNC INIT_FUNCTION();
127 #define INIT_FUNCTION initlibSalomePyQtGUIc
128 extern "C" void INIT_FUNCTION();
132 * This function creates an instance of SALOME_PYQT_Module object by request
133 * of and application object when the module is loaded.
136 SALOME_PYQT_EXPORT CAM_Module* createModule() {
137 static bool alreadyInitialized = false;
138 if ( !alreadyInitialized ) {
139 // call only once (see above) !
140 PyEval_RestoreThread( KERNEL_PYTHON::_gtstate );
142 PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate );
143 alreadyInitialized = !alreadyInitialized;
145 return new SALOME_PYQT_Module();
150 * Static variables definition
152 SALOME_PYQT_Module::InterpMap SALOME_PYQT_Module::myInterpMap;
153 SALOME_PYQT_Module* SALOME_PYQT_Module::myInitModule = 0;
156 * Little trick : provide an access to being activated Python module from outside;
157 * needed by the SalomePyQt library :(
159 SALOME_PYQT_Module* SALOME_PYQT_Module::getInitModule()
167 SALOME_PYQT_Module::SALOME_PYQT_Module()
168 : SalomeApp_Module( __DEFAULT_NAME__ ),
177 SALOME_PYQT_Module::~SALOME_PYQT_Module()
184 * Initialization of the module.
185 * Inherited from CAM_Module.
187 * This method is used for creation of the menus, toolbars and other staff.
188 * There are two ways:
189 * - for obsolete modules this method first tries to read <module>_<language>.xml
190 * resource file which contains a menu, toolbars and popup menus description.
191 * - new modules can create menus by by calling the corresponding methods of SalomePyQt
192 * Python API in the Python module's initialize() method which is called from here.
193 * NOTE: if postponed modules loading is not used, the active study might be not defined
194 * yet at this stage, so initialize() method should not perform any study-based initialization.
196 void SALOME_PYQT_Module::initialize( CAM_Application* app )
198 MESSAGE( "SALOME_PYQT_Module::initialize" );
200 SalomeApp_Module::initialize( app );
202 // Try to get XML resource file name
203 SUIT_ResourceMgr* aResMgr = getApp()->resourceMgr();
204 QString aLang = aResMgr->stringValue( "language", "language", QString::null );
205 if ( aLang.isEmpty() ) aLang = QString( "en" );
206 QString aName = name( "" );
207 QString aFileName = aName + "_" + aLang + ".xml";
208 aFileName = aResMgr->path( "resources", aName, aFileName );
210 // create XML handler instance
211 if ( !myXmlHandler && !aFileName.isEmpty() && QFile::exists( aFileName ) )
212 myXmlHandler = new SALOME_PYQT_XmlHandler( this, aFileName );
214 // perform internal initialization and call module's initialize() method
215 // InitializeReq: request class for internal init() operation
216 class InitializeReq : public PyInterp_Request
219 InitializeReq( CAM_Application* _app,
220 SALOME_PYQT_Module* _obj )
221 : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true)
226 virtual void execute()
228 myObj->init( myApp );
232 CAM_Application* myApp;
233 SALOME_PYQT_Module* myObj;
236 // Posting the request
237 PyInterp_Dispatcher::Get()->Exec( new InitializeReq( app, this ) );
241 * Activation of the module.
242 * Inherited from CAM_Module.
244 bool SALOME_PYQT_Module::activateModule( SUIT_Study* theStudy )
246 MESSAGE( "SALOME_PYQT_Module::activateModule" );
248 bool res = SalomeApp_Module::activateModule( theStudy );
253 // ActivateReq: request class for internal activate() operation
254 class ActivateReq : public PyInterp_Request
257 ActivateReq( SUIT_Study* _study,
258 SALOME_PYQT_Module* _obj )
259 : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true)
264 virtual void execute()
266 myObj->activate( myStudy );
271 SALOME_PYQT_Module* myObj;
274 // Posting the request
275 PyInterp_Dispatcher::Get()->Exec( new ActivateReq( theStudy, this ) );
277 // activate menus, toolbars, etc
278 setMenuShown( true );
279 setToolShown( true );
282 connect( menuMgr(), SIGNAL( menuHighlighted( int, int ) ),
283 this, SLOT( onMenuHighlighted( int, int ) ) );
285 // create menus & toolbars from XML file if required
287 myXmlHandler->createActions();
289 // CustomizeReq: request class for internal customize() operation
290 class CustomizeReq : public PyInterp_Request
293 CustomizeReq( SUIT_Study* _study,
294 SALOME_PYQT_Module* _obj )
295 : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true)
300 virtual void execute()
302 myObj->customize( myStudy );
307 SALOME_PYQT_Module* myObj;
310 // Posting the request
311 PyInterp_Dispatcher::Get()->Exec( new CustomizeReq( theStudy, this ) );
317 * Deactivation of the module.
318 * Inherited from CAM_Module.
320 bool SALOME_PYQT_Module::deactivateModule( SUIT_Study* theStudy )
322 MESSAGE( "SALOME_PYQT_Module::deactivateModule" );
325 disconnect( menuMgr(), SIGNAL( menuHighlighted( int, int ) ),
326 this, SLOT( onMenuHighlighted( int, int ) ) );
328 // remove menus & toolbars created from XML file if required
330 myXmlHandler->clearActions();
332 // deactivate menus, toolbars, etc
333 setMenuShown( false );
334 setToolShown( false );
336 // DeactivateReq: request class for internal deactivate() operation
337 class DeactivateReq : public PyInterp_LockRequest
340 DeactivateReq( PyInterp_base* _py_interp,
342 SALOME_PYQT_Module* _obj )
343 : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
348 virtual void execute()
350 myObj->deactivate( myStudy );
355 SALOME_PYQT_Module* myObj;
358 // Posting the request
359 PyInterp_Dispatcher::Get()->Exec( new DeactivateReq( myInterp, theStudy, this ) );
361 return SalomeApp_Module::deactivateModule( theStudy );
365 * Called when study desktop is activated.
366 * Used for notifying about changing of the active study.
368 void SALOME_PYQT_Module::studyActivated()
370 // StudyChangedReq: request class for internal studyChanged() operation
371 class StudyChangedReq : public PyInterp_Request
374 StudyChangedReq( SUIT_Study* _study,
375 SALOME_PYQT_Module* _obj )
376 : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true)
381 virtual void execute()
383 myObj->studyChanged( myStudy );
388 SALOME_PYQT_Module* myObj;
391 // Posting the request
392 PyInterp_Dispatcher::Get()->Exec( new StudyChangedReq( application()->activeStudy(), this ) );
396 * Processes GUI action (from main menu, toolbar or context popup menu)
398 void SALOME_PYQT_Module::onGUIEvent()
401 const QObject* obj = sender();
402 if ( !obj || !obj->inherits( "QAction" ) )
404 QAction* action = (QAction*)obj;
407 int id = actionId( action );
408 MESSAGE( "SALOME_PYQT_Module::onGUIEvent: id = " << id );
410 // perform synchronous request to Python event dispatcher
411 class GUIEvent : public PyInterp_LockRequest
414 GUIEvent( PyInterp_base* _py_interp,
415 SALOME_PYQT_Module* _obj,
417 : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
422 virtual void execute()
424 myObj->guiEvent( myId );
429 SALOME_PYQT_Module* myObj;
432 // Posting the request
433 PyInterp_Dispatcher::Get()->Exec( new GUIEvent( myInterp, this, id ) );
437 * Processes GUI action (from context popup menu, only for XML-based actions!)
439 void SALOME_PYQT_Module::onGUIEvent( int id )
441 // perform synchronous request to Python event dispatcher
442 class GUIEvent : public PyInterp_LockRequest
445 GUIEvent( PyInterp_base* _py_interp,
446 SALOME_PYQT_Module* _obj,
448 : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
453 virtual void execute()
455 myObj->guiEvent( myId );
460 SALOME_PYQT_Module* myObj;
463 // Posting the request
464 PyInterp_Dispatcher::Get()->Exec( new GUIEvent( myInterp, this, id ) );
468 * Menu highlight processing
470 void SALOME_PYQT_Module::onMenuHighlighted( int menu, int submenu )
472 if ( !action( menu ) && registered( menu, submenu ) ) {
473 // perform synchronous request to Python event dispatcher
474 class MenuHighlightEvent : public PyInterp_LockRequest
477 MenuHighlightEvent( PyInterp_base* _py_interp,
478 SALOME_PYQT_Module* _obj,
481 : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
483 mySubMenu( _submenu ),
487 virtual void execute()
489 myObj->menuHighlight( myMenu, mySubMenu );
495 SALOME_PYQT_Module* myObj;
498 // Posting the request
499 PyInterp_Dispatcher::Get()->Exec( new MenuHighlightEvent( myInterp, this, menu, submenu ) );
504 Context popup menu request.
505 Called when user activates popup menu in some window (view, object browser, etc).
507 void SALOME_PYQT_Module::contextMenuPopup( const QString& theContext, QPopupMenu* thePopupMenu, QString& /*title*/ )
509 MESSAGE( "SALOME_PYQT_Module::contextMenuPopup : " << theContext.latin1() );
510 // perform synchronous request to Python event dispatcher
511 class PopupMenuEvent : public PyInterp_LockRequest
514 PopupMenuEvent( PyInterp_base* _py_interp,
515 SALOME_PYQT_Module* _obj,
516 const QString& _context,
518 : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
519 myContext( _context ),
524 virtual void execute()
526 myObj->contextMenu( myContext, myPopup );
530 SALOME_PYQT_Module* myObj;
535 // Posting the request only if dispatcher is not busy!
536 // Executing the request synchronously
537 if ( !PyInterp_Dispatcher::Get()->IsBusy() )
538 PyInterp_Dispatcher::Get()->Exec( new PopupMenuEvent( myInterp, this, theContext, thePopupMenu ) );
542 * Defines the dockable window associated with the module.
543 * To fill the list of windows the correspondind Python module's windows()
544 * method is called from SALOME_PYQT_Module::init() method.
545 * By default, ObjectBrowser, PythonConsole and LogWindow are provided.
547 void SALOME_PYQT_Module::windows( QMap<int, int>& mappa ) const
549 // First clear the output parameters
550 QMap<int, int>::ConstIterator it;
551 for ( it = myWindowsMap.begin(); it != myWindowsMap.end(); ++it ) {
552 mappa[ it.key() ] = it.data();
557 * Defines the compatible views which should be opened on module activation.
558 * To fill the list of views the correspondind Python module's views()
559 * method is called from SALOME_PYQT_Module::init() method.
560 * By default, the list is empty.
562 void SALOME_PYQT_Module::viewManagers( QStringList& listik ) const
564 for ( QStringList::ConstIterator it = myViewMgrList.begin(); it != myViewMgrList.end(); ++it ) {
565 listik.append( *it );
570 * Performs internal initialization
571 * - initializes/gets the Python interpreter (one per study)
572 * - imports the Python module
573 * - passes the workspace widget to the Python module
574 * - calls Python module's initialize() method
575 * - calls Python module's windows() method
576 * - calls Python module's views() method
578 void SALOME_PYQT_Module::init( CAM_Application* app )
580 // reset interpreter to NULL
584 SalomeApp_Application* anApp = dynamic_cast<SalomeApp_Application*>( app );
588 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() );
591 int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0;
593 // initialize Python subinterpreter (on per study) and put it in <myInterp> variable
594 initInterp( aStudyId );
598 // import Python GUI module
605 // then call Python module's initialize() method
606 // ... first get python lock
607 PyLockWrapper aLock = myInterp->GetLockWrapper();
608 // ... (the Python module is already imported)
609 // ... finally call Python module's initialize() method
610 if(PyObject_HasAttrString(myModule , "initialize")){
611 PyObjWrapper res( PyObject_CallMethod( myModule, "initialize", "" ) );
617 // get the windows list from the Python module by calling windows() method
618 // ... first put default values
619 myWindowsMap.insert( SalomeApp_Application::WT_ObjectBrowser, Qt::DockLeft );
620 myWindowsMap.insert( SalomeApp_Application::WT_PyConsole, Qt::DockBottom );
621 // VSR: LogWindow is not yet implemented
622 // myWindowsMap.insert( SalomeApp_Application::WT_LogWindow, Qt::DockBottom );
624 if(PyObject_HasAttrString(myModule , "windows")){
625 PyObjWrapper res1( PyObject_CallMethod( myModule, "windows", "" ) );
630 myWindowsMap.clear();
631 if ( PyDict_Check( res1 ) ) {
635 while ( PyDict_Next( res1, &pos, &key, &value ) ) {
636 // parse the return value
637 // it should be a map: {integer:integer}
639 if( key && PyInt_Check( key ) && value && PyInt_Check( value ) ) {
640 aKey = PyInt_AsLong( key );
641 aValue = PyInt_AsLong( value );
642 myWindowsMap[ aKey ] = aValue;
648 // get the windows list from the Python module by calling views() method
649 if(PyObject_HasAttrString(myModule , "views")){
650 PyObjWrapper res2( PyObject_CallMethod( myModule, "views", "" ) );
655 // parse the return value
656 // result can be one string...
657 if ( PyString_Check( res2 ) ) {
658 myViewMgrList.append( PyString_AsString( res2 ) );
660 // ... or list of strings
661 else if ( PyList_Check( res2 ) ) {
662 int size = PyList_Size( res2 );
663 for ( int i = 0; i < size; i++ ) {
664 PyObject* value = PyList_GetItem( res2, i );
665 if( value && PyString_Check( value ) ) {
666 myViewMgrList.append( PyString_AsString( value ) );
676 * Performs internal activation:
677 * - initializes/gets the Python interpreter (one per study)
678 * - imports the Python GUI module
679 * - calls Python module's activate() method (for new modules)
681 void SALOME_PYQT_Module::activate( SUIT_Study* theStudy )
684 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( theStudy );
685 int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0;
687 // initialize Python subinterpreter (on per study) and put it in <myInterp> variable
688 initInterp( aStudyId );
692 // import Python GUI module
698 PyLockWrapper aLock = myInterp->GetLockWrapper();
700 // call Python module's activate() method (for the new modules)
701 if(PyObject_HasAttrString(myModule , "activate")){
702 PyObjWrapper res1( PyObject_CallMethod( myModule, "activate", "" ) );
710 * Performs additional customization after module is activated:
711 * - gets the Python interpreter (one per study)
712 * - imports the Python GUI module
713 * - calls Python module's setSettings() method (obsolete function, used for compatibility with old code)
715 void SALOME_PYQT_Module::customize ( SUIT_Study* theStudy )
718 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( theStudy );
719 int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0;
721 // initialize Python subinterpreter (on per study) and put it in <myInterp> variable
722 initInterp( aStudyId );
726 // import Python GUI module
731 if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__
732 // call Python module's setWorkspace() method
734 } //__CALL_OLD_METHODS__
737 PyLockWrapper aLock = myInterp->GetLockWrapper();
739 if ( IsCallOldMethods ) { //__CALL_OLD_METHODS__
740 // call Python module's setSettings() method (obsolete)
741 if(PyObject_HasAttrString(myModule , "setSettings")){
742 PyObjWrapper res( PyObject_CallMethod( myModule, "setSettings", "" ) );
747 } //__CALL_OLD_METHODS__
751 * Performs internal deactivation:
752 * - calls Python module's deactivate() method
754 void SALOME_PYQT_Module::deactivate( SUIT_Study* theStudy )
756 // check if the subinterpreter is initialized and Python module is imported
757 if ( !myInterp || !myModule ) {
758 // Error! Python subinterpreter should be initialized and module should be imported first!
761 // then call Python module's deactivate() method
762 if(PyObject_HasAttrString(myModule , "deactivate")){
763 PyObjWrapper res( PyObject_CallMethod( myModule, "deactivate", "" ) );
771 * Called when active the study is actived (user brings its desktop to top)
772 * - initializes/gets the Python interpreter (one per study)
773 * - imports the Python GUI module
774 * - calls Python module's activeStudyChanged() method
776 void SALOME_PYQT_Module::studyChanged( SUIT_Study* theStudy )
779 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( theStudy );
780 int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0;
782 // initialize Python subinterpreter (on per study) and put it in <myInterp> variable
783 initInterp( aStudyId );
787 // import Python GUI module
792 if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__
793 // call Python module's setWorkspace() method
795 } //__CALL_OLD_METHODS__
798 PyLockWrapper aLock = myInterp->GetLockWrapper();
800 // call Python module's activeStudyChanged() method
801 if(PyObject_HasAttrString(myModule , "activeStudyChanged")){
802 PyObjWrapper res( PyObject_CallMethod( myModule, "activeStudyChanged", "i", aStudyId ) );
810 * Get module engine, returns nil var if engine is not found in LifeCycleCORBA
812 Engines::Component_var SALOME_PYQT_Module::getEngine() const
814 Engines::Component_var comp;
815 // temporary solution
817 comp = getApp()->lcc()->FindOrLoad_Component( "FactoryServerPy", name( "" ) );
819 catch (CORBA::Exception&) {
825 * Get module engine IOR, returns empty string if engine is not found in LifeCycleCORBA
827 QString SALOME_PYQT_Module::engineIOR() const
829 if ( !CORBA::is_nil( getEngine() ) )
830 return QString( getApp()->orb()->object_to_string( getEngine() ) );
831 return QString( "" );
835 * Processes context popup menu request
836 * - calls Python module's definePopup(...) method (obsolete function, used for compatibility with old code)
837 * to define the popup menu context
838 * - parses XML resourses file (if exists) and fills the popup menu with the items)
839 * - calls Python module's customPopup(...) method (obsolete function, used for compatibility with old code)
840 * to allow module to customize the popup menu
841 * - for new modules calls createPopupMenu() function to allow the modules to build the popup menu
842 * by using insertItem(...) Qt functions.
844 void SALOME_PYQT_Module::contextMenu( const QString& theContext, QPopupMenu* thePopupMenu )
846 // Python interpreter should be initialized and Python module should be
848 if ( !myInterp || !myModule )
851 QString aContext( theContext ), aObject( "" ), aParent( "" );
853 if ( IsCallOldMethods && PyObject_HasAttrString(myModule , "definePopup") ) { //__CALL_OLD_METHODS__
854 // call definePopup() Python module's function
855 // this is obsolete function, used only for compatibility reasons
856 PyObjWrapper res(PyObject_CallMethod( myModule,
861 aParent.latin1() ) );
866 // parse return value
868 if( PyArg_ParseTuple( res, "sss", &co, &ob, &pa ) ) {
874 } //__CALL_OLD_METHODS__
876 // first try to create menu via XML parser:
877 // we create popup menus without help of QtxPopupMgr
879 myXmlHandler->createPopup( thePopupMenu, aContext, aParent, aObject );
881 PyObjWrapper sipPopup( sipBuildResult( 0, "M", thePopupMenu, sipClass_QPopupMenu ) );
883 // then call Python module's createPopupMenu() method (for new modules)
884 if ( PyObject_HasAttrString(myModule , "createPopupMenu") ) {
885 PyObjWrapper res1( PyObject_CallMethod( myModule,
889 aContext.latin1() ) );
895 if ( IsCallOldMethods && PyObject_HasAttrString(myModule , "customPopup") ) { //__CALL_OLD_METHODS__
896 // call customPopup() Python module's function
897 // this is obsolete function, used only for compatibility reasons
898 PyObjWrapper res2( PyObject_CallMethod( myModule,
904 aParent.latin1() ) );
908 } //__CALL_OLD_METHODS__
912 * Processes GUI event
913 * - calls Python module's OnGUIEvent() method
915 void SALOME_PYQT_Module::guiEvent( const int theId )
917 // Python interpreter should be initialized and Python module should be
919 if ( !myInterp || !myModule )
922 if ( PyObject_HasAttrString(myModule , "OnGUIEvent") ) {
923 PyObjWrapper res( PyObject_CallMethod( myModule, "OnGUIEvent", "i", theId ) );
931 * Menu highlight processing
932 * - calls Python module's menuActivated(int,int) method
934 void SALOME_PYQT_Module::menuHighlight( const int menu, const int submenu )
936 // Python interpreter should be initialized and Python module should be
938 if ( !myInterp || !myModule )
941 if ( PyObject_HasAttrString(myModule , "menuHighlight") ) {
942 PyObjWrapper res( PyObject_CallMethod( myModule, "menuHighlight", "ii", menu, submenu ) );
950 * Initialises python subinterpreter (one per study)
952 void SALOME_PYQT_Module::initInterp( int theStudyId )
956 // Error! Study Id must not be 0!
960 // try to find the subinterpreter
961 if( myInterpMap.find( theStudyId ) != myInterpMap.end() ) {
963 myInterp = myInterpMap[ theStudyId ];
966 // not found - create a new one!
967 ///////////////////////////////////////////////////////////////////
968 // Attention: the creation of Python interpretor must be protected
969 // by a C++ Lock because of C threads
970 ///////////////////////////////////////////////////////////////////
971 myInterp = new SALOME_PYQT_PyInterp();
972 myInterp->initialize();
973 myInterpMap[ theStudyId ] = myInterp;
975 // import 'salome' module and call 'salome_init' method;
976 // do it only once on interpreter creation
977 // ... first get python lock
978 PyLockWrapper aLock = myInterp->GetLockWrapper();
979 // ... then import a module
980 PyObjWrapper aMod = PyImport_ImportModule( "salome" );
986 // ... then call a method
988 PyObjWrapper aRes( PyObject_CallMethod( aMod, "salome_init", "ii", theStudyId, embedded ) );
997 * Imports Python GUI module and remember the reference to the module
998 * !!! initInterp() should be called first!!!
1000 void SALOME_PYQT_Module::importModule()
1002 // check if the subinterpreter is initialized
1004 // Error! Python subinterpreter should be initialized first!
1008 // import Python GUI module and puts it in <myModule> attribute
1009 // ... first get python lock
1010 PyLockWrapper aLock = myInterp->GetLockWrapper();
1011 // ... then import a module
1012 QString aMod = QString( name("") ) + "GUI";
1013 myModule = PyImport_ImportModule( (char*)( aMod.latin1() ) );
1022 * Calls <module>.setWorkSpace() method with PyQt QWidget object to use with
1024 * !!! initInterp() and importModule() should be called first!!!
1026 void SALOME_PYQT_Module::setWorkSpace()
1028 // check if the subinterpreter is initialized and Python module is imported
1029 if ( !myInterp || !myModule ) {
1030 // Error! Python subinterpreter should be initialized and module should be imported first!
1034 // call setWorkspace() method
1035 // ... first get python lock
1036 PyLockWrapper aLock = myInterp->GetLockWrapper();
1038 // ... then try to import SalomePyQt module. If it's not possible don't go on.
1039 PyObjWrapper aQtModule( PyImport_ImportModule( "SalomePyQt" ) );
1046 if ( IsCallOldMethods ) { //__CALL_OLD_METHODS__
1047 // ... then get workspace object
1048 QWidget* aWorkspace = 0;
1049 if ( getApp()->desktop()->inherits( "STD_MDIDesktop" ) ) {
1050 STD_MDIDesktop* aDesktop = dynamic_cast<STD_MDIDesktop*>( getApp()->desktop() );
1052 aWorkspace = aDesktop->workspace();
1054 else if ( getApp()->desktop()->inherits( "STD_TabDesktop" ) ) {
1055 STD_TabDesktop* aDesktop = dynamic_cast<STD_TabDesktop*>( getApp()->desktop() );
1057 aWorkspace = aDesktop->workstack();
1059 PyObjWrapper pyws( sipBuildResult( 0, "M", aWorkspace, sipClass_QWidget ) );
1060 // ... and finally call Python module's setWorkspace() method (obsolete)
1061 if ( PyObject_HasAttrString(myModule , "setWorkSpace") ) {
1062 PyObjWrapper res( PyObject_CallMethod( myModule, "setWorkSpace", "O", pyws.get() ) );
1067 } //__CALL_OLD_METHODS__
1071 * Returns default menu group
1073 int SALOME_PYQT_Module::defaultMenuGroup()
1075 return __DEFAULT_GROUP__;
1079 * The next methods call the parent implementation.
1080 * This is done to open protected methods from CAM_Module class.
1081 * Also these methods are used to register created from outside menus
1082 * in order to enable dynamic menus handling.
1086 /*! Create tool bar with name \a name, if it was't created before.
1087 * \retval -1 - if tool manager was't be created.
1089 int SALOME_PYQT_Module::createTool( const QString& name )
1091 return SalomeApp_Module::createTool( name );
1094 * Insert QAction with id \a id from action map(myActionMap) to tool manager.
1095 *\param id - integer
1096 *\param tBar - integer
1097 *\param idx - integer
1098 *\retval integer id of new action in tool manager.
1099 *\retval Return -1 if something wrong.
1101 int SALOME_PYQT_Module::createTool( const int id, const int tBar, const int idx )
1103 return SalomeApp_Module::createTool( id, tBar, idx );
1106 * Insert QAction with id \a id from action map(myActionMap) to tool manager.
1107 *\param id - integer
1108 *\param tBar - QString&
1109 *\param idx - integer
1110 *\retval integer id of new action in tool manager.
1111 *\retval Return -1 if something wrong.
1113 int SALOME_PYQT_Module::createTool( const int id, const QString& tBar, const int idx )
1115 return SalomeApp_Module::createTool( id, tBar, idx );
1117 /*! Create tool. Register action \a a with id \a id.
1118 * Insert QAction to tool manager.
1120 *\param tBar - integer
1121 *\param id - integer
1122 *\param idx - integer
1123 *\retval integer id of new action in tool manager.
1124 *\retval Return -1 if something wrong.
1126 int SALOME_PYQT_Module::createTool( QAction* a, const int tBar, const int id, const int idx )
1128 return SalomeApp_Module::createTool( a, tBar, id, idx );
1130 /*! Create tool. Register action \a a with id \a id.
1131 * Insert QAction to tool manager.
1133 *\param tBar - QString&
1134 *\param id - integer
1135 *\param idx - integer
1136 *\retval integer id of new action in tool manager.
1137 *\retval Return -1 if something wrong.
1139 int SALOME_PYQT_Module::createTool( QAction* a, const QString& tBar, const int id, const int idx )
1141 return SalomeApp_Module::createTool( a, tBar, id, idx );
1144 int SALOME_PYQT_Module::createMenu( const QString& subMenu, const int menu, const int id, const int group, const int idx, const bool constantMenu )
1146 bool exists = hasMenu( subMenu, menu );
1147 int regId = SalomeApp_Module::createMenu( subMenu, menu, id, group, idx, true );
1149 registerMenu( regId, menu, constantMenu );
1153 int SALOME_PYQT_Module::createMenu( const QString& subMenu, const QString& menu, const int id, const int group, const int idx, const bool constantMenu )
1155 QStringList menus = QStringList::split( "|", menu, false );
1157 for (int i = 0; i < menus.count(); i++ ) {
1158 pid = createMenu( menus[i], pid, -1, -1, -1, constantMenu );
1159 if ( pid == -1 ) break;
1162 pid = createMenu( subMenu, pid, id, group, idx, constantMenu );
1166 int SALOME_PYQT_Module::createMenu( const int id, const int menu, const int group, const int idx, const bool constantMenu )
1168 int regId = SalomeApp_Module::createMenu( id, menu, group, idx );
1170 registerMenu( regId, menu, constantMenu );
1174 int SALOME_PYQT_Module::createMenu( const int id, const QString& menu, const int group, const int idx, const bool constantMenu )
1176 QStringList menus = QStringList::split( "|", menu, false );
1178 for (int i = 0; i < menus.count(); i++ ) {
1179 pid = createMenu( menus[i], pid, -1, -1, -1, constantMenu );
1180 if ( pid == -1 ) break;
1183 pid = createMenu( id, pid, group, idx, constantMenu );
1187 int SALOME_PYQT_Module::createMenu( QAction* a, const int menu, const int id, const int group, const int idx, const bool constantMenu )
1189 int regId = SalomeApp_Module::createMenu( a, menu, id, group, idx );
1191 registerMenu( regId, menu, constantMenu );
1195 int SALOME_PYQT_Module::createMenu( QAction* a, const QString& menu, const int id, const int group, const int idx, const bool constantMenu )
1197 QStringList menus = QStringList::split( "|", menu, false );
1199 for (int i = 0; i < menus.count(); i++ ) {
1200 pid = createMenu( menus[i], pid, -1, -1, -1, constantMenu );
1201 if ( pid == -1 ) break;
1204 pid = createMenu( a, pid, id, group, idx, constantMenu );
1208 QAction* SALOME_PYQT_Module::createSeparator()
1210 return SalomeApp_Module::separator();
1213 QAction* SALOME_PYQT_Module::action( const int id ) const
1215 return SalomeApp_Module::action( id );
1218 int SALOME_PYQT_Module::actionId( const QAction* a ) const
1220 return SalomeApp_Module::actionId( a );
1223 QAction* SALOME_PYQT_Module::createAction( const int id, const QString& text, const QString& icon,
1224 const QString& menu, const QString& tip, const int key,
1227 QIconSet anIcon = loadIcon( icon );
1228 QAction* a = action( id );
1230 if ( a->text().isEmpty() && !text.isEmpty() ) a->setText( text );
1231 if ( a->menuText().isEmpty() && !menu.isEmpty() ) a->setMenuText( menu );
1232 if ( a->iconSet().isNull() && !anIcon.isNull() ) a->setIconSet( anIcon );
1233 if ( a->statusTip().isEmpty() && !tip.isNull() ) a->setStatusTip( tip );
1234 if ( a->accel().isEmpty() && key ) a->setAccel( key );
1235 if ( a->isToggleAction() != toggle ) a->setToggleAction( toggle );
1236 disconnect( a, SIGNAL( activated() ), this, SLOT( onGUIEvent() ) );
1237 connect( a, SIGNAL( activated() ), this, SLOT( onGUIEvent() ) );
1240 a = SalomeApp_Module::createAction( id, text, anIcon, menu, tip, key, getApp()->desktop(), toggle, this, SLOT( onGUIEvent() ) );
1245 * Load icon from resource file
1247 QIconSet SALOME_PYQT_Module::loadIcon( const QString& fileName )
1250 if ( !fileName.isEmpty() ) {
1251 QPixmap pixmap = getApp()->resourceMgr()->loadPixmap( name(""), tr( fileName ) );
1252 if ( !pixmap.isNull() )
1253 anIcon = QIconSet( pixmap );
1259 * Returns TRUE if menu already exists
1261 bool SALOME_PYQT_Module::hasMenu( const QString& subMenu, const int menu )
1263 return menuMgr() && menuMgr()->containsMenu( subMenu, menu );
1269 void SALOME_PYQT_Module::registerMenu( const int id, const int menu, const bool constantMenu )
1271 QAction* a = action( id );
1272 QAction* s = separator();
1275 if ( !registered( id, menu ) )
1276 myMenus[menu].append( MenuId( id, constantMenu ) );
1280 * Unregister the menu
1282 void SALOME_PYQT_Module::unregisterMenu( const int id, const int menu )
1284 if ( myMenus.find( menu ) != myMenus.end() ) {
1285 MenuIdList::iterator lit;
1286 for ( lit = myMenus[menu].begin(); lit != myMenus[menu].end(); ++lit ) {
1287 if ( (*lit).id == id ) {
1288 myMenus[menu].remove( lit );
1296 * Returns TRUE if the menu is registered
1298 bool SALOME_PYQT_Module::registered( const int id, const int menu )
1300 MenuMap::iterator mit;
1301 for ( mit = myMenus.begin(); mit != myMenus.end(); ++mit ) {
1302 MenuIdList::iterator lit;
1303 for ( lit = mit.data().begin(); lit != mit.data().end(); ++lit ) {
1304 if ( (*lit).id == id && ( menu == 0 || mit.key() == menu ) )
1312 * Returns TRUE if the menu is constant (not removed by clearMenu()).
1313 * This concerns the menus which are created from XML files.
1315 bool SALOME_PYQT_Module::isConstantMenu( const int id, const int menu )
1317 if ( myMenus.find( menu ) != myMenus.end() ) {
1318 MenuIdList& l = myMenus[ menu ];
1319 MenuIdList::iterator lit;
1320 for ( lit = l.begin(); lit != l.end(); ++lit ) {
1321 if ( (*lit).id == id && (*lit).constantMenu )
1329 * Displays/hides the module's menus.
1331 void SALOME_PYQT_Module::setMenuShown( const bool show )
1333 QtxActionMenuMgr* mMgr = menuMgr();
1337 bool upd = mMgr->isUpdatesEnabled();
1338 mMgr->setUpdatesEnabled( false );
1340 SalomeApp_Module::setMenuShown( show );
1342 for ( MenuMap::iterator mit = myMenus.begin(); mit != myMenus.end(); ++mit ) {
1343 MenuIdList::iterator lit;
1344 for ( lit = mit.data().begin(); lit != mit.data().end(); ++lit )
1345 if ( !action( (*lit).id ) )
1346 mMgr->setShown( (*lit).id, show );
1349 mMgr->setUpdatesEnabled( upd );
1355 * Displays/hides the module's toolbars.
1357 void SALOME_PYQT_Module::setToolShown( const bool show )
1359 SalomeApp_Module::setToolShown( show );
1363 * Clears the given menu.
1364 * If <id> = 0 : clear all items in the <menu> menu
1365 * If <menu> = 0 : clear all menus recursively starting from top-level.
1366 * If <removeActions> = 0 : also unregister all removed actions (not delete!).
1368 bool SALOME_PYQT_Module::clearMenu( const int id, const int menu, const bool removeActions )
1370 QAction* a = action( id );
1371 QAction* s = separator();
1372 typedef QValueList<int> IntList;
1373 if ( a && a != s ) {
1377 if ( registered( id, menu ) ) menus.append( menu );
1380 MenuMap::iterator mit;
1381 for ( mit = myMenus.begin(); mit != myMenus.end(); ++mit )
1382 if ( registered( id, mit.key() ) ) menus.append( mit.key() );
1384 for ( int i = 0; i < menus.count(); i++ ) {
1385 if ( !isConstantMenu( id, menus[i] ) ) {
1386 menuMgr()->remove( menuMgr()->actionId( a ), menus[ i ] );
1387 unregisterMenu( id, menus[i] );
1390 if ( !registered( id ) && removeActions )
1391 unregisterAction( id );
1397 // clear all menus recursively starting from top-level (main menu)
1398 IntList l = myMenus.keys();
1399 IntList::iterator lit;
1400 for ( lit = l.begin(); lit != l.end(); ++lit )
1401 clearMenu( 0, *lit, removeActions );
1404 if ( myMenus.find( menu ) != myMenus.end() ) {
1405 // remove all items in the parent menu
1407 MenuIdList::iterator lit;
1408 for ( lit = myMenus[menu].begin(); lit != myMenus[menu].end(); ++lit )
1409 l.append( (*lit).id );
1410 for ( int i = 0; i < l.count(); i++ )
1411 clearMenu( l[i], menu, removeActions );
1412 if ( myMenus[menu].empty() )
1413 myMenus.remove( menu );
1418 MenuMap::iterator mit;
1419 for ( mit = myMenus.begin(); mit != myMenus.end(); ++mit ) {
1420 MenuIdList::iterator lit;
1421 for ( lit = mit.data().begin(); lit != mit.data().end(); ++lit ) {
1422 if ( (*lit).id == id && ( menu == 0 || mit.key() == menu ) ) {
1423 clearMenu( 0, id, removeActions ); // first remove all sub-menus
1424 if ( !isConstantMenu( id, mit.key() ) ) {
1425 menuMgr()->remove( id, mit.key() );
1426 mit.data().remove( lit );
1437 // SALOME_PYQT_XmlHandler class implementation
1439 // gets an tag name for the dom element [ static ]
1440 // returns an empty string if the element does not have tag name
1441 static QString tagName( const QDomElement& element ) {
1442 return element.tagName().stripWhiteSpace();
1445 // gets an attribute by it's name for the dom element [ static ]
1446 // returns an empty string if the element does not have such attribute
1447 static QString attribute( const QDomElement& element, const QString& attName ) {
1448 return element.attribute( attName ).stripWhiteSpace();
1451 // checks the given value for the boolean value [ static ]
1452 // returns TRUE if string represents boolean value:
1453 // - "true", "yes" or "1" for true
1454 // - "false", "no" or "0" for false
1455 // second parameter allows to check certain boolean value
1458 // - other value is not taken into account
1459 static bool checkBool( const QString& value, const int check = -1 ) {
1460 QString v = value.lower();
1461 if ( ( v == "true" || v == "yes" || v == "1" ) && ( check != 0 ) )
1463 if ( ( v == "false" || v == "no" || v == "0" ) && ( check != 1 ) )
1468 // checks the given value for the integer value [ static ]
1469 // returns -1 if item is empty or presents and invalid number
1470 static int checkInt( const QString& value, const int def = -1, const int shift = -1 )
1473 int val = value.toInt( &bOk );
1474 if ( !bOk ) val = def;
1475 if ( shift > 0 && bOk && val < 0 )
1483 SALOME_PYQT_XmlHandler::SALOME_PYQT_XmlHandler( SALOME_PYQT_Module* module,
1484 const QString& fileName )
1485 : myModule( module ),
1486 myMenuCreated( false )
1488 if (fileName.isEmpty() )
1490 QFile aFile( fileName );
1491 if ( !aFile.open( IO_ReadOnly ) )
1493 if ( !myDoc.setContent( &aFile ) ) {
1501 * Called by SALOME_PYQT_Module::activate() in order to create actions
1502 * (menus, toolbars, popup menus)
1504 void SALOME_PYQT_XmlHandler::createActions()
1506 // check flag : are menus already created?
1507 if ( myMenuCreated && !IsCallOldMethods )
1510 // get document element
1511 QDomElement aDocElem = myDoc.documentElement();
1513 // create main menu actions
1514 QDomNodeList aMenuList = aDocElem.elementsByTagName( "menu-item" );
1515 for ( int i = 0; i < aMenuList.count(); i++ ) {
1516 QDomNode n = aMenuList.item( i );
1520 // create toolbars actions
1521 QDomNodeList aToolsList = aDocElem.elementsByTagName( "toolbar" );
1522 for ( int i = 0; i < aToolsList.count(); i++ ) {
1523 QDomNode n = aToolsList.item( i );
1526 // set flag : menus are already created
1527 myMenuCreated = true;
1531 * Called by SALOME_PYQT_Module::deactivate() in order to remove actions
1532 * (menus, toolbars, popup menus)
1534 void SALOME_PYQT_XmlHandler::clearActions()
1536 for ( uint i = 0; i < myMenuItems.count(); i++ ) {
1537 QMenuData* md = dynamic_cast<QMenuData*>( myModule->getApp()->desktop()->menuBar() );
1538 QStringList menus = QStringList::split( ":", myMenuItems[ i ] );
1539 for ( uint j = 0; j < menus.count(); j++) {
1540 int id = menus[ j ].toInt();
1542 QMenuItem* mi = md->findItem( id, &smd );
1543 if ( mi && md == smd ) {
1544 if ( j == menus.count()-1 || !mi->popup() ) { // last item or not popup
1545 md->removeItem( id );
1548 else if ( mi->popup() )
1549 md = dynamic_cast<QMenuData*>( mi->popup() );
1555 myMenuItems.clear();
1559 * Creates popup menu
1561 void SALOME_PYQT_XmlHandler::createPopup( QPopupMenu* menu,
1562 const QString& context,
1563 const QString& parent,
1564 const QString& object )
1566 // get document element
1567 QDomElement aDocElem = myDoc.documentElement();
1569 // get popup menus actions
1570 QDomNodeList aPopupList = aDocElem.elementsByTagName( "popupmenu" );
1571 for ( int i = 0; i < aPopupList.count(); i++ ) {
1572 QDomNode n = aPopupList.item( i );
1573 if ( !n.isNull() && n.isElement() ) {
1574 QDomElement e = n.toElement();
1575 QString lab = attribute( e, "label-id" );
1576 QString ctx = attribute( e, "context-id" );
1577 QString prt = attribute( e, "parent-id" );
1578 QString obj = attribute( e, "object-id" );
1579 if ( ctx == context && prt == parent && obj == object ) {
1580 insertPopupItems( n, menu );
1588 Create main menu with child actions
1590 void SALOME_PYQT_XmlHandler::createMenu( QDomNode& parentNode,
1591 const int parentMenuId,
1592 QPopupMenu* parentPopup )
1597 if ( parentNode.isNull() )
1600 QDomElement parentElement = parentNode.toElement();
1601 if ( !parentElement.isNull() ) {
1602 QString plabel = attribute( parentElement, "label-id" );
1603 int pid = checkInt( attribute( parentElement, "item-id" ) );
1604 int ppos = checkInt( attribute( parentElement, "pos-id" ) );
1605 int group = checkInt( attribute( parentElement, "group-id" ),
1606 myModule->defaultMenuGroup() );
1607 if ( !plabel.isEmpty() ) {
1608 QPopupMenu* popup = 0;
1611 if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__
1612 SUIT_Desktop* desktop = myModule->getApp()->desktop();
1613 if ( parentMenuId == -1 ) { // top-level menu
1614 QMenuBar* mb = desktop->menuBar();
1615 QMenuItem* mi = mb->findItem( pid );
1616 if ( mi ) popup = mi->popup();
1618 popup = new QPopupMenu( desktop );
1619 ppos = checkInt( attribute( parentElement, "pos-id" ), -1, mb->count() );
1620 menuId = mb->insertItem( plabel, popup, pid, ppos );
1621 myCurrentMenu.push_back( QString::number( menuId ) );
1622 myMenuItems.append( myCurrentMenu.join( ":" ) );
1626 myCurrentMenu.push_back( QString::number( menuId ) );
1630 // parentPopup should not be 0 here!
1631 QMenuItem* mi = parentPopup->findItem( pid );
1632 if ( mi ) popup = mi->popup();
1634 popup = new QPopupMenu( desktop );
1635 ppos = checkInt( attribute( parentElement, "pos-id" ), -1, popup->count() );
1636 menuId = parentPopup->insertItem( plabel, popup, pid, ppos );
1637 myCurrentMenu.push_back( QString::number( menuId ) );
1638 myMenuItems.append( myCurrentMenu.join( ":" ) );
1642 myCurrentMenu.push_back( QString::number( menuId ) );
1646 else { //!__CALL_OLD_METHODS__
1647 menuId = myModule->createMenu( plabel, // label
1648 parentMenuId, // parent menu ID, should be -1 for main menu
1652 true ); // create constant menu (not removed by clearMenu())
1653 } // __CALL_OLD_METHODS__
1654 QDomNode node = parentNode.firstChild();
1655 while ( !node.isNull() ) {
1656 if ( node.isElement() ) {
1657 QDomElement elem = node.toElement();
1658 QString aTagName = tagName( elem );
1659 if ( aTagName == "popup-item" ) {
1660 int id = checkInt( attribute( elem, "item-id" ) );
1661 int pos = checkInt( attribute( elem, "pos-id" ) );
1662 int group = checkInt( attribute( elem, "group-id" ),
1663 myModule->defaultMenuGroup() );
1664 QString label = attribute( elem, "label-id" );
1665 QString icon = attribute( elem, "icon-id" );
1666 QString tooltip = attribute( elem, "tooltip-id" );
1667 QString accel = attribute( elem, "accel-id" );
1668 bool toggle = checkBool( attribute( elem, "toggle-id" ) );
1669 ////QString execute = attribute( elem, "execute-action" ); // not used
1671 // -1 action ID is not allowed : it means that <item-id> attribute is missed in the XML file!
1672 // also check if the action with given ID is already created
1674 if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__
1675 QIconSet iconSet = myModule->loadIcon( icon );
1676 pos = checkInt( attribute( elem, "pos-id" ), -1, popup->count() );
1677 int aid = iconSet.isNull() ? popup->insertItem( label,
1679 SLOT( onGUIEvent(int) ),
1680 QKeySequence( accel ),
1683 popup->insertItem( iconSet,
1686 SLOT( onGUIEvent(int) ),
1687 QKeySequence( accel ),
1690 myCurrentMenu.push_back( QString::number( aid ) );
1691 myMenuItems.append( myCurrentMenu.join( ":" ) );
1692 myCurrentMenu.pop_back();
1694 popup->setItemChecked( aid, checkBool( attribute( elem, "toggle-id" ), 1 ) );
1696 else { //!__CALL_OLD_METHODS__
1697 // create menu action
1698 QAction* action = myModule->createAction( id, // ID
1702 tooltip, // status-bar text
1703 QKeySequence( accel ), // keyboard accelerator
1704 toggle ); // toogled action
1705 myModule->createMenu( action, // action
1706 menuId, // parent menu ID
1707 id, // ID (same as for createAction())
1710 true ); // create constant menu (not removed by clearMenu())
1711 } // __CALL_OLD_METHODS__
1714 else if ( aTagName == "submenu" ) {
1716 createMenu( node, menuId, popup );
1718 else if ( aTagName == "separator" ) {
1719 // create menu separator
1720 int id = checkInt( attribute( elem, "item-id" ) ); // separator can have ID
1721 int pos = checkInt( attribute( elem, "pos-id" ) );
1722 int group = checkInt( attribute( elem, "group-id" ),
1723 myModule->defaultMenuGroup() );
1724 if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__
1725 pos = checkInt( attribute( elem, "pos-id" ), -1, popup->count() );
1726 int sid = popup->insertSeparator( pos );
1727 myCurrentMenu.push_back( QString::number( sid ) );
1728 myMenuItems.append( myCurrentMenu.join( ":" ) );
1729 myCurrentMenu.pop_back();
1731 else { //!__CALL_OLD_METHODS__
1732 QAction* action = myModule->createSeparator();
1733 myModule->createMenu( action, // separator action
1734 menuId, // parent menu ID
1738 true ); // create constant menu (not removed by clearMenu())
1739 } // __CALL_OLD_METHODS__
1742 node = node.nextSibling();
1744 myCurrentMenu.pop_back();
1750 Create a toolbar with child actions
1752 void SALOME_PYQT_XmlHandler::createToolBar( QDomNode& parentNode )
1757 if ( parentNode.isNull() )
1760 QDomElement parentElement = parentNode.toElement();
1761 if ( !parentElement.isNull() ) {
1762 QString aLabel = attribute( parentElement, "label-id" );
1763 if ( !aLabel.isEmpty() ) {
1765 int tbId = myModule->createTool( aLabel );
1766 QDomNode node = parentNode.firstChild();
1767 while ( !node.isNull() ) {
1768 if ( node.isElement() ) {
1769 QDomElement elem = node.toElement();
1770 QString aTagName = tagName( elem );
1771 if ( aTagName == "toolbutton-item" ) {
1772 int id = checkInt( attribute( elem, "item-id" ) );
1773 int pos = checkInt( attribute( elem, "pos-id" ) );
1774 QString label = attribute( elem, "label-id" );
1775 QString icon = attribute( elem, "icon-id" );
1776 QString tooltip = attribute( elem, "tooltip-id" );
1777 QString accel = attribute( elem, "accel-id" );
1778 bool toggle = checkBool( attribute( elem, "toggle-id" ) );
1779 ////QString execute = attribute( elem, "execute-action" ); // not used
1781 // -1 action ID is not allowed : it means that <item-id> attribute is missed in the XML file!
1782 // also check if the action with given ID is already created
1784 // create toolbar action
1785 QAction* action = myModule->createAction( id, // ID
1789 tooltip, // status-bar text
1790 QKeySequence( accel ), // keyboard accelerator
1791 toggle ); // toogled action
1792 myModule->createTool( action, tbId, -1, pos );
1795 else if ( aTagName == "separatorTB" || aTagName == "separator" ) {
1796 // create toolbar separator
1797 int pos = checkInt( attribute( elem, "pos-id" ) );
1798 QAction* action = myModule->createSeparator();
1799 myModule->createTool( action, tbId, -1, pos );
1802 node = node.nextSibling();
1809 * Fill popup menu with items
1811 void SALOME_PYQT_XmlHandler::insertPopupItems( QDomNode& parentNode, QPopupMenu* menu )
1816 if ( parentNode.isNull() )
1819 // we create popup menus without help of QtxPopupMgr
1820 QDomNode node = parentNode.firstChild();
1821 while ( !node.isNull() ) {
1822 if ( node.isElement() ) {
1823 QDomElement elem = node.toElement();
1824 QString aTagName = tagName( elem );
1825 if ( aTagName == "popup-item" ) {
1826 // insert a command item
1827 int id = checkInt( attribute( elem, "item-id" ) );
1828 int pos = checkInt( attribute( elem, "pos-id" ) );
1829 QString label = attribute( elem, "label-id" );
1830 QString icon = attribute( elem, "icon-id" );
1831 /////QString tooltip = attribute( elem, "tooltip-id" ); // not used
1832 QString accel = attribute( elem, "accel-id" );
1833 /////bool toggle = checkBool( attribute( elem, "toggle-id" ) ); // not used
1834 /////QString execute = attribute( elem, "execute-action" ); // not used
1837 if ( !icon.isEmpty() ) {
1838 QPixmap pixmap = myModule->getApp()->resourceMgr()->loadPixmap( myModule->name(""), icon );
1839 if ( !pixmap.isNull() )
1840 anIcon = QIconSet( pixmap );
1843 // -1 action ID is not allowed : it means that <item-id> attribute is missed in the XML file!
1844 // also check if the action with given ID is already created
1846 menu->insertItem( anIcon, label, myModule, SLOT( onGUIEvent(int) ), QKeySequence( accel ), id, pos );
1849 else if ( aTagName == "submenu" ) {
1851 int id = checkInt( attribute( elem, "item-id" ) );
1852 int pos = checkInt( attribute( elem, "pos-id" ) );
1853 QString label = attribute( elem, "label-id" );
1854 QString icon = attribute( elem, "icon-id" );
1857 if ( !icon.isEmpty() ) {
1858 QPixmap pixmap = myModule->getApp()->resourceMgr()->loadPixmap( myModule->name(""), icon );
1859 if ( !pixmap.isNull() )
1860 anIcon = QIconSet( pixmap );
1863 QPopupMenu* newPopup = new QPopupMenu( menu, label );
1864 menu->insertItem( anIcon, label, newPopup, id, pos );
1865 insertPopupItems( node, newPopup );
1867 else if ( aTagName == "separator" ) {
1868 // create menu separator
1869 int pos = checkInt( attribute( elem, "pos-id" ) );
1870 menu->insertSeparator( pos );
1873 node = node.nextSibling();