#include <qfile.h>
#include <qdom.h>
#include <qworkspace.h>
+#include <qmenubar.h>
#include <qpopupmenu.h>
#include "SALOME_PYQT_SipDefs.h"
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 );
private:
SALOME_PYQT_Module* myModule;
QDomDocument myDoc;
+ QStringList myMenuItems;
+ QStringList myCurrentMenu;
+ bool myMenuCreated;
};
//=============================================================================
/*!
* 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 )
{
}
*/
void SALOME_PYQT_Module::initialize( CAM_Application* app )
{
+ MESSAGE( "SALOME_PYQT_Module::initialize" );
+
SalomeApp_Module::initialize( app );
// Try to get XML resource file 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() ) {
+ // 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
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;
}
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 );
// 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 ) );
}
/*!
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();
* 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 )
{
// 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<SalomeApp_Study*>( theStudy );
+ int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0;
+
+ // initialize Python subinterpreter (on per study) and put it in <myInterp> 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")){
}
}
} //__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();
- }
- }
}
/*!
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();
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)
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 );
}
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
}
// 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 ]
/*!
* 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 );
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<QMenuData*>( 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<QMenuData*>( mi->popup() );
+ }
+ else
+ break;
+ }
+ }
+ myMenuItems.clear();
}
/*!
/*!
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;
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() ) {
// -1 action ID is not allowed : it means that <item-id> 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
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();
}
}
}
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();
}
}
+/*!
+ * Fill popup menu with items
+ */
void SALOME_PYQT_XmlHandler::insertPopupItems( QDomNode& parentNode, QPopupMenu* menu )
{
if ( !myModule )