From 0a7fcd0b0f56f9635f74502a2e82c4fa0179a161 Mon Sep 17 00:00:00 2001 From: vsr Date: Fri, 14 Apr 2006 14:09:18 +0000 Subject: [PATCH] Implement support of direct menus creation by insertItem() methods (not via menu manager) --- .../SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx | 405 +++++++++++++----- .../SALOME_PYQT_GUI/SALOME_PYQT_Module.h | 4 + 2 files changed, 306 insertions(+), 103 deletions(-) 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 0593d7784..49a2459cf 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx @@ -43,6 +43,7 @@ #include #include #include +#include #include #include "SALOME_PYQT_SipDefs.h" @@ -94,15 +95,17 @@ class SALOME_PYQT_XmlHandler public: SALOME_PYQT_XmlHandler( SALOME_PYQT_Module* module, const QString& fileName ); void createActions(); + void clearActions(); 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 createToolBar ( QDomNode& parentNode ); + void createMenu ( QDomNode& parentNode, + const int parentMenuId = -1, + QPopupMenu* parentPopup = 0 ); void insertPopupItems( QDomNode& parentNode, QPopupMenu* menu ); @@ -110,6 +113,9 @@ protected: private: SALOME_PYQT_Module* myModule; QDomDocument myDoc; + QStringList myMenuItems; + QStringList myCurrentMenu; + bool myMenuCreated; }; //============================================================================= @@ -168,8 +174,10 @@ SALOME_PYQT_Module* SALOME_PYQT_Module::getInitModule() /*! * Constructor */ -SALOME_PYQT_Module::SALOME_PYQT_Module() : - SalomeApp_Module( __DEFAULT_NAME__ ), myModule( 0 ), myXmlHandler ( 0 ) +SALOME_PYQT_Module::SALOME_PYQT_Module() + : SalomeApp_Module( __DEFAULT_NAME__ ), + myModule( 0 ), + myXmlHandler ( 0 ) { } @@ -197,6 +205,8 @@ SALOME_PYQT_Module::~SALOME_PYQT_Module() */ void SALOME_PYQT_Module::initialize( CAM_Application* app ) { + MESSAGE( "SALOME_PYQT_Module::initialize" ); + SalomeApp_Module::initialize( app ); // Try to get XML resource file name @@ -207,11 +217,9 @@ void SALOME_PYQT_Module::initialize( CAM_Application* app ) 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() ) { + // create XML handler instance + if ( !myXmlHandler && !aFileName.isEmpty() && QFile::exists( aFileName ) ) 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 @@ -284,6 +292,34 @@ bool SALOME_PYQT_Module::activateModule( SUIT_Study* theStudy ) connect( menuMgr(), SIGNAL( menuHighlighted( int, int ) ), this, SLOT( onMenuHighlighted( int, int ) ) ); + // create menus & toolbars from XML file if required + if ( myXmlHandler ) + myXmlHandler->createActions(); + + // CustomizeReq: request class for internal customize() operation + class CustomizeReq : public PyInterp_Request + { + public: + CustomizeReq( 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->customize( myStudy ); + } + + private: + SUIT_Study* myStudy; + SALOME_PYQT_Module* myObj; + }; + + // Posting the request + PyInterp_Dispatcher::Get()->Exec( new CustomizeReq( theStudy, this ) ); + return true; } @@ -299,7 +335,9 @@ bool SALOME_PYQT_Module::deactivateModule( SUIT_Study* theStudy ) disconnect( menuMgr(), SIGNAL( menuHighlighted( int, int ) ), this, SLOT( onMenuHighlighted( int, int ) ) ); - bool res = SalomeApp_Module::deactivateModule( theStudy ); + // remove menus & toolbars created from XML file if required + if ( myXmlHandler ) + myXmlHandler->clearActions(); // deactivate menus, toolbars, etc setMenuShown( false ); @@ -330,7 +368,38 @@ bool SALOME_PYQT_Module::deactivateModule( SUIT_Study* theStudy ) // Posting the request PyInterp_Dispatcher::Get()->Exec( new DeactivateReq( myInterp, theStudy, this ) ); - return res; + return SalomeApp_Module::deactivateModule( theStudy ); +} + +/*! + * Called when study desktop is activated. + * Used for notifying about changing of the active study. + */ +void SALOME_PYQT_Module::studyActivated() +{ + // 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 ) {} + + 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 ) ); } /*! @@ -543,11 +612,6 @@ void SALOME_PYQT_Module::init( CAM_Application* app ) 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(); @@ -622,8 +686,7 @@ void SALOME_PYQT_Module::init( CAM_Application* app ) * 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) + * - calls Python module's activate() method (for new modules) */ void SALOME_PYQT_Module::activate( SUIT_Study* theStudy ) { @@ -644,6 +707,45 @@ void SALOME_PYQT_Module::activate( SUIT_Study* theStudy ) // get python lock PyLockWrapper aLock = myInterp->GetLockWrapper(); + // call Python module's activate() method (for the new modules) + if(PyObject_HasAttrString(myModule , "activate")){ + PyObjWrapper res1( PyObject_CallMethod( myModule, "activate", "" ) ); + if( !res1 ) { + PyErr_Print(); + } + } +} + +/*! + * Performs additional customization after module is activated: + * - 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) + */ +void SALOME_PYQT_Module::customize ( 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 + + if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__ + // call Python module's setWorkspace() method + setWorkSpace(); + } //__CALL_OLD_METHODS__ + + // get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + if ( IsCallOldMethods ) { //__CALL_OLD_METHODS__ // call Python module's setSettings() method (obsolete) if(PyObject_HasAttrString(myModule , "setSettings")){ @@ -653,14 +755,6 @@ void SALOME_PYQT_Module::activate( SUIT_Study* theStudy ) } } } //__CALL_OLD_METHODS__ - - // call Python module's activate() method (for the new modules) - if(PyObject_HasAttrString(myModule , "activate")){ - PyObjWrapper res1( PyObject_CallMethod( myModule, "activate", "" ) ); - if( !res1 ) { - PyErr_Print(); - } - } } /*! @@ -705,6 +799,11 @@ void SALOME_PYQT_Module::studyChanged( SUIT_Study* theStudy ) if ( !myModule ) return; // Error + if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__ + // call Python module's setWorkspace() method + setWorkSpace(); + } //__CALL_OLD_METHODS__ + // get python lock PyLockWrapper aLock = myInterp->GetLockWrapper(); @@ -742,37 +841,6 @@ QString SALOME_PYQT_Module::engineIOR() const return QString( "" ); } -/*! - * Called when study desktop is activated. - * Used for notifying about changing of the active study. - */ -void SALOME_PYQT_Module::studyActivated() -{ - // 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 ) {} - - 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) @@ -1116,12 +1184,7 @@ QAction* SALOME_PYQT_Module::createAction( const int id, const QString& text, co 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 ); - } + QIconSet anIcon = loadIcon( icon ); QAction* a = action( id ); if ( a ) { if ( a->text().isEmpty() && !text.isEmpty() ) a->setText( text ); @@ -1138,6 +1201,19 @@ QAction* SALOME_PYQT_Module::createAction( const int id, const QString& text, co } return a; } +/*! + * Load icon from resource file + */ +QIconSet SALOME_PYQT_Module::loadIcon( const QString& fileName ) +{ + QIconSet anIcon; + if ( !fileName.isEmpty() ) { + QPixmap pixmap = getApp()->resourceMgr()->loadPixmap( name(""), tr( fileName ) ); + if ( !pixmap.isNull() ) + anIcon = QIconSet( pixmap ); + } + return anIcon; +} /*! * Returns TRUE if menu already exists @@ -1335,9 +1411,20 @@ static QString attribute( const QDomElement& element, const QString& attName ) { } // 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" ); +// returns TRUE if string represents boolean value: +// - "true", "yes" or "1" for true +// - "false", "no" or "0" for false +// second parameter allows to check certain boolean value +// - 1: true +// - 0: false +// - other value is not taken into account +static bool checkBool( const QString& value, const int check = -1 ) { + QString v = value.lower(); + if ( ( v == "true" || v == "yes" || v == "1" ) && ( check != 0 ) ) + return true; + if ( ( v == "false" || v == "no" || v == "0" ) && ( check != 1 ) ) + return true; + return false; } // checks the given value for the integer value [ static ] @@ -1350,29 +1437,37 @@ static int checkInt( const QString& value, const int def = -1 ) /*! * Constructor */ -SALOME_PYQT_XmlHandler::SALOME_PYQT_XmlHandler( SALOME_PYQT_Module* module, const QString& fileName ) - : myModule( module ) +SALOME_PYQT_XmlHandler::SALOME_PYQT_XmlHandler( SALOME_PYQT_Module* module, + const QString& fileName ) + : myModule( module ), + myMenuCreated( false ) { + if (fileName.isEmpty() ) + return; QFile aFile( fileName ); if ( !aFile.open( IO_ReadOnly ) ) return; if ( !myDoc.setContent( &aFile ) ) { - aFile.close(); - return; + aFile.close(); + return; } aFile.close(); } /*! - Called by SALOME_PYQT_Module::initialize() in order to create actions - (menus, toolbars, popup menus) + * Called by SALOME_PYQT_Module::activate() in order to create actions + * (menus, toolbars, popup menus) */ void SALOME_PYQT_XmlHandler::createActions() { + // check flag : are menus already created? + if ( myMenuCreated && !IsCallOldMethods ) + return; + // get document element QDomElement aDocElem = myDoc.documentElement(); - // get main menu actions + // create main menu actions QDomNodeList aMenuList = aDocElem.elementsByTagName( "menu-item" ); for ( int i = 0; i < aMenuList.count(); i++ ) { QDomNode n = aMenuList.item( i ); @@ -1385,6 +1480,36 @@ void SALOME_PYQT_XmlHandler::createActions() QDomNode n = aToolsList.item( i ); createToolBar( n ); } + // set flag : menus are already created + myMenuCreated = true; +} + +/*! + * Called by SALOME_PYQT_Module::deactivate() in order to remove actions + * (menus, toolbars, popup menus) + */ +void SALOME_PYQT_XmlHandler::clearActions() +{ + for ( uint i = 0; i < myMenuItems.count(); i++ ) { + QMenuData* md = dynamic_cast( myModule->getApp()->desktop()->menuBar() ); + QStringList menus = QStringList::split( ":", myMenuItems[ i ] ); + for ( uint j = 0; j < menus.count(); j++) { + int id = menus[ j ].toInt(); + QMenuData* smd; + QMenuItem* mi = md->findItem( id, &smd ); + if ( mi && md == smd ) { + if ( j == menus.count()-1 || !mi->popup() ) { // last item or not popup + md->removeItem( id ); + break; + } + else if ( mi->popup() ) + md = dynamic_cast( mi->popup() ); + } + else + break; + } + } + myMenuItems.clear(); } /*! @@ -1419,7 +1544,9 @@ void SALOME_PYQT_XmlHandler::createPopup( QPopupMenu* menu, /*! Create main menu with child actions */ -void SALOME_PYQT_XmlHandler::createMenu( QDomNode& parentNode, const int parentMenuId ) +void SALOME_PYQT_XmlHandler::createMenu( QDomNode& parentNode, + const int parentMenuId, + QPopupMenu* parentPopup ) { if ( !myModule ) return; @@ -1435,13 +1562,50 @@ void SALOME_PYQT_XmlHandler::createMenu( QDomNode& parentNode, const int parentM int group = checkInt( attribute( parentElement, "group-id" ), myModule->defaultMenuGroup() ); if ( !plabel.isEmpty() ) { + QPopupMenu* popup = 0; + int menuId = -1; // create menu - int menuId = myModule->createMenu( plabel, // label - parentMenuId, // parent menu ID, should be -1 for main menu - pid, // ID - group, // group ID - ppos, // position - true ); // create constant menu (not removed by clearMenu()) + if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__ + SUIT_Desktop* desktop = myModule->getApp()->desktop(); + if ( parentMenuId == -1 ) { // top-level menu + QMenuBar* mb = desktop->menuBar(); + QMenuItem* mi = mb->findItem( pid ); + if ( mi ) popup = mi->popup(); + if ( !popup ) { + popup = new QPopupMenu( desktop ); + menuId = mb->insertItem( plabel, popup, pid, ppos ); + myCurrentMenu.push_back( QString::number( menuId ) ); + myMenuItems.append( myCurrentMenu.join( ":" ) ); + } + else { + menuId = pid; + myCurrentMenu.push_back( QString::number( menuId ) ); + } + } + else { + // parentPopup should not be 0 here! + QMenuItem* mi = parentPopup->findItem( pid ); + if ( mi ) popup = mi->popup(); + if ( !popup ) { + popup = new QPopupMenu( desktop ); + menuId = parentPopup->insertItem( plabel, popup, pid, ppos ); + myCurrentMenu.push_back( QString::number( menuId ) ); + myMenuItems.append( myCurrentMenu.join( ":" ) ); + } + else { + menuId = pid; + myCurrentMenu.push_back( QString::number( menuId ) ); + } + } + } + else { //!__CALL_OLD_METHODS__ + menuId = myModule->createMenu( plabel, // label + parentMenuId, // parent menu ID, should be -1 for main menu + pid, // ID + group, // group ID + ppos, // position + true ); // create constant menu (not removed by clearMenu()) + } // __CALL_OLD_METHODS__ QDomNode node = parentNode.firstChild(); while ( !node.isNull() ) { if ( node.isElement() ) { @@ -1462,25 +1626,48 @@ void SALOME_PYQT_XmlHandler::createMenu( QDomNode& parentNode, const int parentM // -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 ) { - // 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->createMenu( action, // action - menuId, // parent menu ID - id, // ID (same as for createAction()) - group, // group ID - pos, // position - true ); // create constant menu (not removed by clearMenu()) + if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__ + QIconSet iconSet = myModule->loadIcon( icon ); + int aid = iconSet.isNull() ? popup->insertItem( label, + myModule, + SLOT( onGUIEvent(int) ), + QKeySequence( accel ), + id, + pos ) : + popup->insertItem( iconSet, + label, + myModule, + SLOT( onGUIEvent(int) ), + QKeySequence( accel ), + id, + pos ); + myCurrentMenu.push_back( QString::number( aid ) ); + myMenuItems.append( myCurrentMenu.join( ":" ) ); + myCurrentMenu.pop_back(); + if ( toggle ) + popup->setItemChecked( aid, checkBool( attribute( elem, "toggle-id" ), 1 ) ); + } + else { //!__CALL_OLD_METHODS__ + // 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->createMenu( action, // action + menuId, // parent menu ID + id, // ID (same as for createAction()) + group, // group ID + pos, // position + true ); // create constant menu (not removed by clearMenu()) + } // __CALL_OLD_METHODS__ } } else if ( aTagName == "submenu" ) { // create sub-menu - createMenu( node, menuId ); + createMenu( node, menuId, popup ); } else if ( aTagName == "separator" ) { // create menu separator @@ -1488,17 +1675,26 @@ void SALOME_PYQT_XmlHandler::createMenu( QDomNode& parentNode, const int parentM int pos = checkInt( attribute( elem, "pos-id" ) ); int group = checkInt( attribute( elem, "group-id" ), myModule->defaultMenuGroup() ); - QAction* action = myModule->createSeparator(); - myModule->createMenu( action, // separator action - menuId, // parent menu ID - id, // ID - group, // group ID - pos, // position - true ); // create constant menu (not removed by clearMenu()) + if ( IsCallOldMethods ) { // __CALL_OLD_METHODS__ + int sid = popup->insertSeparator( pos ); + myCurrentMenu.push_back( QString::number( sid ) ); + myMenuItems.append( myCurrentMenu.join( ":" ) ); + myCurrentMenu.pop_back(); + } + else { //!__CALL_OLD_METHODS__ + QAction* action = myModule->createSeparator(); + myModule->createMenu( action, // separator action + menuId, // parent menu ID + id, // ID + group, // group ID + pos, // position + true ); // create constant menu (not removed by clearMenu()) + } // __CALL_OLD_METHODS__ } } node = node.nextSibling(); } + myCurrentMenu.pop_back(); } } } @@ -1549,7 +1745,7 @@ void SALOME_PYQT_XmlHandler::createToolBar( QDomNode& parentNode ) myModule->createTool( action, tbId, -1, pos ); } } - else if ( aTagName == "separatorTB" ) { + else if ( aTagName == "separatorTB" || aTagName == "separator" ) { // create toolbar separator int pos = checkInt( attribute( elem, "pos-id" ) ); QAction* action = myModule->createSeparator(); @@ -1562,6 +1758,9 @@ void SALOME_PYQT_XmlHandler::createToolBar( QDomNode& parentNode ) } } +/*! + * Fill popup menu with items + */ void SALOME_PYQT_XmlHandler::insertPopupItems( QDomNode& parentNode, QPopupMenu* menu ) { if ( !myModule ) diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h index 57fa50cce..b22f8524d 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h @@ -152,6 +152,8 @@ public: int actionId( const QAction* ) const; QAction* createAction( const int, const QString&, const QString&, const QString&, const QString&, const int, const bool = false ); + /* load icon from resource file */ + QIconSet loadIcon( const QString& fileName ); /* Show/hide menus/toolbars */ void setMenuShown( const bool ); @@ -190,6 +192,8 @@ private: void activate ( SUIT_Study* ); /* internal deactivation */ void deactivate ( SUIT_Study* ); + /* customization */ + void customize ( SUIT_Study* ); /* study activation */ void studyChanged( SUIT_Study* ); /* context popup menu processing */ -- 2.39.2