From b2bc30bc10479c9919ce4612c97e3fb29e76f2c7 Mon Sep 17 00:00:00 2001 From: vsr Date: Fri, 14 Dec 2012 10:11:30 +0000 Subject: [PATCH] Merge from BR_Qt48_porting (compatibility with Qt4.8) 14/12/2012 --- adm_local/unix/config_files/check_sip.m4 | 1 + src/CAM/CAM_Module.cxx | 24 + src/CAM/CAM_Module.h | 52 +- src/GuiHelpers/StandardApp_Module.cxx | 3 +- src/LightApp/LightApp_Module.cxx | 27 - src/LightApp/LightApp_Module.h | 7 - src/OCCViewer/OCCViewer_ViewFrame.cxx | 3 + .../SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx | 278 +- .../SALOME_PYQT_GUI/SALOME_PYQT_Module.h | 51 +- .../SALOME_PYQT_GUILight/CMakeLists.txt | 3 +- .../SALOME_PYQT_GUILight/Makefile.am | 10 +- .../SALOME_PYQT_DataModelLight.cxx | 2 +- .../SALOME_PYQT_DataModelLight.h | 4 - .../SALOME_PYQT_ModuleLight.cxx | 3163 ++--------------- .../SALOME_PYQT_ModuleLight.h | 239 +- .../SALOME_PYQT_PyModule.cxx | 2625 ++++++++++++++ .../SALOME_PYQT_PyModule.h | 138 + src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx | 870 +++-- src/SALOME_PYQT/SalomePyQt/SalomePyQt.h | 59 +- src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip | 1 + src/SalomeApp/SalomeApp_Module.h | 2 +- src/TreeData/Test/Makefile.am | 2 +- 22 files changed, 3942 insertions(+), 3622 deletions(-) create mode 100644 src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx create mode 100644 src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h diff --git a/adm_local/unix/config_files/check_sip.m4 b/adm_local/unix/config_files/check_sip.m4 index f7c60477e..cb50cce22 100644 --- a/adm_local/unix/config_files/check_sip.m4 +++ b/adm_local/unix/config_files/check_sip.m4 @@ -72,6 +72,7 @@ if test "x$sip_ok" = "xyes" ; then fi TEST_INC_DIRS="${TEST_INC_DIRS} /usr/include /usr/include/python${PYTHON_VERSION}" TEST_LIB_DIRS="${TEST_LIB_DIRS} /usr/lib${LIB_LOCATION_SUFFIX} /usr/lib${LIB_LOCATION_SUFFIX}/python${PYTHON_VERSION}/site-packages" + TEST_LIB_DIRS="${TEST_LIB_DIRS} /usr/lib${LIB_LOCATION_SUFFIX}/python${PYTHON_VERSION}/dist-packages" TEST_LIB_DIRS="${TEST_LIB_DIRS} /usr/lib${LIB_LOCATION_SUFFIX}/python${PYTHON_VERSION}/dist-packages/PyQt4" TEST_LIB_DIRS="${TEST_LIB_DIRS} /usr/lib${LIB_LOCATION_SUFFIX}/pymodules/python${PYTHON_VERSION}" if test "${build_cpu::6}" = "x86_64" ; then diff --git a/src/CAM/CAM_Module.cxx b/src/CAM/CAM_Module.cxx index 9983c43d2..4901a9a42 100755 --- a/src/CAM/CAM_Module.cxx +++ b/src/CAM/CAM_Module.cxx @@ -27,6 +27,7 @@ #include "CAM_Study.h" #include +#include #include #include @@ -34,6 +35,8 @@ #include #include +#include + /*! \class CAM_Module \brief Base implementation of the module in the CAM application architecture. @@ -874,6 +877,10 @@ QAction* CAM_Module::action( const int id ) const QAction* a = 0; if ( myActionMap.contains( id ) ) a = myActionMap[id]; + else if ( menuMgr() ) { + QMenu* m = menuMgr()->findMenu( id ); + if ( m ) a = m->menuAction(); + } return a; } @@ -928,6 +935,23 @@ QAction* CAM_Module::createAction( const int id, const QString& text, const QIco return a; } +/*! + \brief Create new action group. + \param id action group ID + \param exclusive \c true for exclusive action group + \return created action group +*/ +QtxActionGroup* CAM_Module::createActionGroup( const int id, const bool exclusive ) +{ + QtxActionGroup* a = qobject_cast( action( id ) ); + if ( !a ) { + a = new QtxActionGroup( this ); + registerAction( id, a ); + } + a->setExclusive( exclusive ); + return a; +} + /*! \brief Register action in the internal action map. diff --git a/src/CAM/CAM_Module.h b/src/CAM/CAM_Module.h index c469049b9..1ac64e24c 100755 --- a/src/CAM/CAM_Module.h +++ b/src/CAM/CAM_Module.h @@ -34,6 +34,7 @@ class QAction; class QMenu; class QIcon; +class QtxActionGroup; class QtxActionMenuMgr; class QtxActionToolMgr; class SUIT_Study; @@ -82,6 +83,33 @@ public: virtual void updateModuleVisibilityState(); + // actions/menu/toolbars management + + QtxActionMenuMgr* menuMgr() const; + QtxActionToolMgr* toolMgr() const; + + virtual QAction* action( const int ) const; + virtual int actionId( const QAction* ) const; + virtual QAction* createAction( const int, const QString&, const QIcon&, const QString&, + const QString&, const int, QObject* = 0, + const bool = false, QObject* = 0, const char* = 0, const QString& = QString() ); + QtxActionGroup* createActionGroup( const int, const bool = true ); + + int createTool( const QString& ); + int createTool( const int, const int, const int = -1 ); + int createTool( const int, const QString&, const int = -1 ); + int createTool( QAction*, const int, const int = -1, const int = -1 ); + int createTool( QAction*, const QString&, const int = -1, const int = -1 ); + + int createMenu( const QString&, const int, const int = -1, const int = -1, const int = -1 ); + int createMenu( const QString&, const QString&, const int = -1, const int = -1, const int = -1 ); + int createMenu( const int, const int, const int = -1, const int = -1 ); + int createMenu( const int, const QString&, const int = -1, const int = -1 ); + int createMenu( QAction*, const int, const int = -1, const int = -1, const int = -1 ); + int createMenu( QAction*, const QString&, const int = -1, const int = -1, const int = -1 ); + + static QAction* separator(); + public slots: virtual bool activateModule( SUIT_Study* ); virtual bool deactivateModule( SUIT_Study* ); @@ -104,33 +132,9 @@ protected: void setName( const QString& ); virtual void setModuleName( const QString& ); - QtxActionMenuMgr* menuMgr() const; - QtxActionToolMgr* toolMgr() const; - - int createTool( const QString& ); - int createTool( const int, const int, const int = -1 ); - int createTool( const int, const QString&, const int = -1 ); - int createTool( QAction*, const int, const int = -1, const int = -1 ); - int createTool( QAction*, const QString&, const int = -1, const int = -1 ); - - int createMenu( const QString&, const int, const int = -1, const int = -1, const int = -1 ); - int createMenu( const QString&, const QString&, const int = -1, const int = -1, const int = -1 ); - int createMenu( const int, const int, const int = -1, const int = -1 ); - int createMenu( const int, const QString&, const int = -1, const int = -1 ); - int createMenu( QAction*, const int, const int = -1, const int = -1, const int = -1 ); - int createMenu( QAction*, const QString&, const int = -1, const int = -1, const int = -1 ); - - static QAction* separator(); - - QAction* action( const int ) const; - int actionId( const QAction* ) const; - int registerAction( const int, QAction* ); bool unregisterAction( const int ); bool unregisterAction( QAction* ); - QAction* createAction( const int, const QString&, const QIcon&, const QString&, - const QString&, const int, QObject* = 0, - const bool = false, QObject* = 0, const char* = 0, const QString& = QString() ); private: CAM_Application* myApp; //!< parent application object diff --git a/src/GuiHelpers/StandardApp_Module.cxx b/src/GuiHelpers/StandardApp_Module.cxx index 6ace49427..258223378 100644 --- a/src/GuiHelpers/StandardApp_Module.cxx +++ b/src/GuiHelpers/StandardApp_Module.cxx @@ -38,8 +38,7 @@ // Constructor StandardApp_Module::StandardApp_Module() : - SalomeApp_Module( "" ), - LightApp_Module( "" ) + SalomeApp_Module( "" ) { // Note that it's no use to specify here the moduleName because it's // automatically determined by the name of the GUI library diff --git a/src/LightApp/LightApp_Module.cxx b/src/LightApp/LightApp_Module.cxx index 5aa863e6a..745b17168 100644 --- a/src/LightApp/LightApp_Module.cxx +++ b/src/LightApp/LightApp_Module.cxx @@ -755,30 +755,3 @@ bool LightApp_Module::renameObject( const QString& /*entry*/, const QString& /*n { return false; } - - - -int LightApp_Module::createMenu( const QString& subMenu, const int menu, const int id, const int group, const int idx ) -{ - return CAM_Module::createMenu( subMenu, menu, id, group, idx ); -} -int LightApp_Module::createMenu( const QString& subMenu, const QString& menu, const int id, const int group, const int idx ) -{ - return CAM_Module::createMenu( subMenu, menu, id, group, idx ); -} -int LightApp_Module::createMenu( const int id, const int menu, const int group, const int idx ) -{ - return CAM_Module::createMenu( id, menu, group, idx ); -} -int LightApp_Module::createMenu( const int id, const QString& menu, const int group, const int idx ) -{ - return CAM_Module::createMenu( id, menu, group, idx ); -} -int LightApp_Module::createMenu( QAction* a, const int menu, const int id, const int group, const int idx ) -{ - return CAM_Module::createMenu( a, menu, id, group, idx ); -} -int LightApp_Module::createMenu( QAction* a, const QString& menu, const int id, const int group, const int idx ) -{ - return CAM_Module::createMenu( a, menu, id, group, idx ); -} diff --git a/src/LightApp/LightApp_Module.h b/src/LightApp/LightApp_Module.h index e52dd7d17..9348b075d 100644 --- a/src/LightApp/LightApp_Module.h +++ b/src/LightApp/LightApp_Module.h @@ -106,13 +106,6 @@ public: virtual bool renameAllowed( const QString& ) const; virtual bool renameObject( const QString&, const QString& ); - int createMenu( const QString&, const int, const int = -1, const int = -1, const int = -1 ); - int createMenu( const QString&, const QString&, const int = -1, const int = -1, const int = -1 ); - int createMenu( const int, const int, const int = -1, const int = -1 ); - int createMenu( const int, const QString&, const int = -1, const int = -1 ); - int createMenu( QAction*, const int, const int = -1, const int = -1, const int = -1 ); - int createMenu( QAction*, const QString&, const int = -1, const int = -1, const int = -1 ); - public slots: virtual bool activateModule( SUIT_Study* ); virtual bool deactivateModule( SUIT_Study* ); diff --git a/src/OCCViewer/OCCViewer_ViewFrame.cxx b/src/OCCViewer/OCCViewer_ViewFrame.cxx index ada4a63a8..e28d5e823 100644 --- a/src/OCCViewer/OCCViewer_ViewFrame.cxx +++ b/src/OCCViewer/OCCViewer_ViewFrame.cxx @@ -213,6 +213,9 @@ void OCCViewer_ViewFrame::connectViewSignals(OCCViewer_ViewWindow* theView) connect( theView, SIGNAL( contextMenuRequested(QContextMenuEvent*) ), this, SIGNAL( contextMenuRequested(QContextMenuEvent*) ) ); + + connect( theView, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), + this, SIGNAL( viewCloned( SUIT_ViewWindow* ) ) ); } // obsolete 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 8213a19ce..45f827b50 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx @@ -22,20 +22,23 @@ // File : SALOME_PYQT_Module.cxx // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) -#include - #include "SALOME_PYQT_Module.h" +#include "SALOME_PYQT_PyModule.h" #include "SalomeApp_Application.h" -#include "SALOME_PYQT_ModuleLight.h" #include #include -#include - +// +// NB: Python requests. +// 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. // // NB: Library initialization -// Since the SalomePyQtGUILight library is not imported in Python it's initialization function +// 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 // @@ -59,198 +62,225 @@ PyMODINIT_FUNC INIT_FUNCTION(); */ extern "C" { - SALOME_PYQT_EXPORT CAM_Module* createModule() { - + SALOME_PYQT_EXPORT CAM_Module* createModule() + { static bool alreadyInitialized = false; + if ( !alreadyInitialized ) { // call only once (see comment above) ! - PyEval_RestoreThread( KERNEL_PYTHON::_gtstate); INIT_FUNCTION(); PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate); alreadyInitialized = !alreadyInitialized; } + return new SALOME_PYQT_Module(); } } - /*! - \var __DEFAULT_NAME__ - Default name of the module, replaced at the moment of module creation + \class SALOME_PYQT_Module + \brief This class implements GUI module for CORBA engine-based Python SALOME modules. */ -const char* __DEFAULT_NAME__ = "SALOME_PYQT_Module"; /*! - * Constructor - */ + \brief Constructor +*/ SALOME_PYQT_Module::SALOME_PYQT_Module() - : SalomeApp_Module(__DEFAULT_NAME__), - LightApp_Module(__DEFAULT_NAME__), - SALOME_PYQT_ModuleLight() + : SalomeApp_Module( "noname" ) // name is set explicitly at the module initialization { + // initialize helper + myHelper = new PyModuleHelper( this ); } /*! - * Destructor - */ + \brief Destructor +*/ SALOME_PYQT_Module::~SALOME_PYQT_Module() { + // as myHelper is a QObject, it should be deleted automatically } /*! - * Get module engine, returns nil var if engine is not found in LifeCycleCORBA - */ -Engines::EngineComponent_var SALOME_PYQT_Module::getEngine() const -{ - Engines::EngineComponent_var comp; - // temporary solution - try { - comp = getApp()->lcc()->FindOrLoad_Component( "FactoryServerPy", name().toLatin1() ); - } - catch (CORBA::Exception&) { - } - return comp; -} - -/*! - * Get module engine IOR, returns empty string if engine is not found in LifeCycleCORBA - */ + \brief Get module engine IOR + + 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 FactoryServerPy container. +*/ QString SALOME_PYQT_Module::engineIOR() const { - class EngineIORReq : public PyInterp_LockRequest - { - public: - EngineIORReq( PyInterp_Interp* _py_interp, - SALOME_PYQT_Module* _obj ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj( _obj ) {} + // call helper to get IOR from Python module + static QString ior; - protected: - virtual void execute() - { - myObj->getEngineIOR(); + if ( ior.isEmpty() ) { + // first call helper to get IOR from Python module + ior = myHelper->engineIOR(); + } + if ( ior.isEmpty() ) { + // if IOR is still not specified, try default implementation + // which loads engine to the default FactoryServerPy container. + Engines::EngineComponent_var comp; + // temporary solution + try { + comp = getApp()->lcc()->FindOrLoad_Component( "FactoryServerPy", name().toLatin1() ); } + catch (CORBA::Exception&) { + } + if ( !CORBA::is_nil( comp ) ) + ior = QString( getApp()->orb()->object_to_string( comp.in() ) ); + } - private: - SALOME_PYQT_Module* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new EngineIORReq( myInterp, const_cast( this ) ) ); - - return myIOR; + return ior; } - /*! - * Redefined to invokec correct version - */ -bool SALOME_PYQT_Module::activateModule( SUIT_Study* theStudy ) + \brief Initialization of the module. + \param app parent application object + \sa PyModuleHelper::initialize() +*/ +void SALOME_PYQT_Module::initialize( CAM_Application* app ) { // call base implementation - bool res = SalomeApp_Module::activateModule( theStudy ); - - if ( !res ) - return res; + SalomeApp_Module::initialize( app ); - // internal activation - return activateModuleInternal( theStudy ); + // ... then call helper + myHelper->initialize( app ); } /*! - * 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 FactoryServerPy container. - */ -void SALOME_PYQT_Module::getEngineIOR() + \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 ) { - myIOR = ""; - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; + // call base implementation and then helper + return SalomeApp_Module::activateModule( study ) && myHelper->activate( study ); +} - if ( PyObject_HasAttrString( myModule , "engineIOR" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"engineIOR", (char*)"" ) ); - if ( !res ) { - PyErr_Print(); - } - else { - // parse the return value, result chould be string - if ( PyString_Check( res ) ) { - myIOR = PyString_AsString( res ); - } - } - } - else if ( !CORBA::is_nil( getEngine() ) ) - myIOR = QString( getApp()->orb()->object_to_string( getEngine() ) ); +/*! + \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 ) +{ + // call helper + bool res = myHelper->deactivate( study ); + + // ... then call base implementation + return SalomeApp_Module::deactivateModule( study ) && res; } -CAM_DataModel* SALOME_PYQT_Module::createDataModel() +/*! + \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 { - MESSAGE( "SALOME_PYQT_Module::createDataModel()" ); - CAM_DataModel * dm = SalomeApp_Module::createDataModel(); - return dm; + // get list of dockable windows from helper + winMap = myHelper->windows(); } /*! - \brief Process GUI action (from main menu, toolbar or - context popup menu action). + \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::onGUIEvent(){ - SALOME_PYQT_ModuleLight::onGUIEvent(); +void SALOME_PYQT_Module::viewManagers( QStringList& viewList ) const +{ + // get list of view types from helper + viewList = myHelper->viewManagers(); } /*! - \brief Signal handler closing(SUIT_ViewWindow*) of a view - \param pview view being closed + \brief Process study activation. + \sa PyModuleHelper::studyActivated() */ -void SALOME_PYQT_Module::onViewClosed( SUIT_ViewWindow* pview ) +void SALOME_PYQT_Module::studyActivated() { - SALOME_PYQT_ModuleLight::onViewClosed( pview ); + // call helper + myHelper->studyActivated( application()->activeStudy() ); } /*! - \brief Signal handler tryClose(SUIT_ViewWindow*) of a view - \param pview view user tries to close + \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() */ -void SALOME_PYQT_Module::onViewTryClose( SUIT_ViewWindow* pview ) +void SALOME_PYQT_Module::contextMenuPopup( const QString& context, + QMenu* menu, + QString& /*title*/ ) { - SALOME_PYQT_ModuleLight::onViewTryClose( pview ); + // call helper + myHelper->contextMenu( context, menu ); } /*! - \breif Process application preferences changing. + \brief Export preferences for the Python module. + \sa PyModuleHelper::createPreferences() +*/ +void SALOME_PYQT_Module::createPreferences() +{ + // call helper + myHelper->createPreferences(); +} - Called when any application setting is changed. +/*! + \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 ) +{ + // call helper + myHelper->preferencesChanged( section, parameter ); +} - \param module preference module - \param section preference resource file section - \param setting preference resource name +/*! + \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() */ -void SALOME_PYQT_Module::preferenceChanged( const QString& module, - const QString& section, - const QString& setting ) +bool SALOME_PYQT_Module::isDraggable( const SUIT_DataObject* what ) const { - SALOME_PYQT_ModuleLight::preferenceChanged(module,section,setting); + // call helper + return myHelper->isDraggable( what ); } /*! - \brief Signal handler windowActivated(SUIT_ViewWindow*) of SUIT_Desktop - \param pview view being activated + \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() */ -void SALOME_PYQT_Module::onActiveViewChanged( SUIT_ViewWindow* pview ) +bool SALOME_PYQT_Module::isDropAccepted( const SUIT_DataObject* where ) const { - SALOME_PYQT_ModuleLight::onActiveViewChanged(pview); + // call helper + return myHelper->isDropAccepted( where ); } /*! - \brief Signal handler cloneView() of OCCViewer_ViewWindow - \param pview view being cloned + \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::onViewCloned( SUIT_ViewWindow* pview ) +void SALOME_PYQT_Module::dropObjects( const DataObjectList& what, SUIT_DataObject* where, + const int row, Qt::DropAction action ) { - SALOME_PYQT_ModuleLight::onViewCloned(pview); + // call helper + myHelper->dropObjects( what, where, row, action ); } + 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 f888a9dbc..3b6e89ea3 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h @@ -26,16 +26,13 @@ #define SALOME_PYQT_MODULE_H #include "SALOME_PYQT_GUI.h" -#include "SALOME_PYQT_PyInterp.h" // this include must be first (see PyInterp_base.h)!*/ -#include "SALOME_PYQT_ModuleLight.h" -#include "SalomeApp_Module.h" -#include -#include CORBA_CLIENT_HEADER(SALOME_Component) +#include "PyInterp_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! +#include "SalomeApp_Module.h" +class PyModuleHelper; -class SALOME_PYQT_EXPORT SALOME_PYQT_Module: public SalomeApp_Module, - public SALOME_PYQT_ModuleLight +class SALOME_PYQT_EXPORT SALOME_PYQT_Module: public SalomeApp_Module { Q_OBJECT; @@ -43,31 +40,27 @@ public: SALOME_PYQT_Module(); ~SALOME_PYQT_Module(); - /* get module engine IOR */ - virtual QString engineIOR() const; - -public slots: - virtual bool activateModule( SUIT_Study* ); - void preferenceChanged( const QString&, - const QString&, - const QString& ); - void onGUIEvent(); - void onActiveViewChanged( SUIT_ViewWindow* ); - void onViewClosed( SUIT_ViewWindow* ); - void onViewTryClose( SUIT_ViewWindow* ); - void onViewCloned( SUIT_ViewWindow* ); + // engine management + QString engineIOR() const; -protected: - /* create data model */ - virtual CAM_DataModel* createDataModel(); - - Engines::EngineComponent_var getEngine() const; - -private: - void getEngineIOR(); + // module activation, preferences, menus + void initialize( CAM_Application* ); + bool activateModule( SUIT_Study* ); + bool deactivateModule( SUIT_Study* ); + void windows( QMap& ) const; + void viewManagers( QStringList& ) const; + void studyActivated(); + void contextMenuPopup( const QString&, QMenu*, QString& ); + void createPreferences(); + void preferencesChanged( const QString&, const QString& ); + // drag-n-drop support + bool isDraggable( const SUIT_DataObject* ) const; + bool isDropAccepted( const SUIT_DataObject* ) const; + void dropObjects( const DataObjectList&, SUIT_DataObject*, + const int, Qt::DropAction ); private: - QString myIOR; + PyModuleHelper* myHelper; }; #endif // SALOME_PYQT_MODULE_H diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/CMakeLists.txt b/src/SALOME_PYQT/SALOME_PYQT_GUILight/CMakeLists.txt index b8e534ac4..b486ac979 100755 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/CMakeLists.txt +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/CMakeLists.txt @@ -54,7 +54,7 @@ ELSE(GUI_ENABLE_CORBA) SET(COMMON_FLAGS "${COMMON_FLAGS} -DGUI_DISABLE_CORBA") ENDIF(GUI_ENABLE_CORBA) -SET(GUI_HEADERS SALOME_PYQT_ModuleLight.h SALOME_PYQT_DataModelLight.h) +SET(GUI_HEADERS SALOME_PYQT_PyModule.h SALOME_PYQT_ModuleLight.h SALOME_PYQT_DataModelLight.h) QT4_WRAP_CPP(GUI_HEADERS_MOC ${GUI_HEADERS}) # extra source files (generated by sip) @@ -81,6 +81,7 @@ ENDFOREACH(input ${SIP_FILES}) SET(SalomePyQtGUI_SOURCES + SALOME_PYQT_PyModule.cxx SALOME_PYQT_ModuleLight.cxx SALOME_PYQT_DataObjectLight.cxx SALOME_PYQT_DataModelLight.cxx diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile.am b/src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile.am index 525818cac..c2d15f38d 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile.am +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile.am @@ -42,9 +42,9 @@ CLEANFILES = $(SIP_SRC) # moc files (generated my moc) MOC_FILES = \ + SALOME_PYQT_PyModule_moc.cxx \ SALOME_PYQT_ModuleLight_moc.cxx \ - SALOME_PYQT_DataModelLight_moc.cxx - + SALOME_PYQT_DataModelLight_moc.cxx # exported header files salomeinclude_HEADERS = \ @@ -56,6 +56,8 @@ salomeinclude_HEADERS = \ # library sources dist_libSalomePyQtGUILight_la_SOURCES = \ + SALOME_PYQT_PyModule.h \ + SALOME_PYQT_PyModule.cxx \ SALOME_PYQT_ModuleLight.cxx \ SALOME_PYQT_DataObjectLight.cxx \ SALOME_PYQT_DataModelLight.cxx \ @@ -78,7 +80,7 @@ if GUI_ENABLE_CORBA libSalomePyQtGUILight_la_CPPFLAGS += -I$(srcdir)/../../SalomeApp \ @CORBA_CXXFLAGS@ @CORBA_INCLUDES@ endif - + if !GUI_ENABLE_CORBA libSalomePyQtGUILight_la_CPPFLAGS += -DGUI_DISABLE_CORBA @@ -91,7 +93,7 @@ libSalomePyQtGUILight_la_LIBADD = $(PYTHON_LIBS) $(SIP_LIBS) $(PYQT_LIBS) $(VTK_ if GUI_ENABLE_CORBA libSalomePyQtGUILight_la_LIBADD +=../../SalomeApp/libSalomeApp.la $(KERNEL_LDFLAGS) -lSalomeContainer endif - + # Custom build step: generate C++ wrapping according to $(SIP_FILES) diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx index 70222af53..b3526e8c4 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx @@ -70,7 +70,7 @@ bool SALOME_PYQT_DataModelLight::open( const QString& theURL, CAM_Study* study, setModified( false ); - return aModule->open(theListOfFiles); + return aModule->load(theListOfFiles); } diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h index 35ca6d19f..47b02c898 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h @@ -29,10 +29,6 @@ #include #include "SALOME_PYQT_DataObjectLight.h" -class SALOME_PYQT_RootObjectLight; - - - class SALOME_PYQT_LIGHT_EXPORT SALOME_PYQT_DataModelLight : public LightApp_DataModel { Q_OBJECT diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx index b9a6aa3d2..f00641efa 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx @@ -17,93 +17,26 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File : SALOME_PYQT_Module.cxx +// File : SALOME_PYQT_ModuleLight.cxx // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) -// -#include "SALOME_PYQT_PyInterp.h" -#include -#include -#include -#include -#include -#include "SALOME_PYQT_ModuleLight.h" #include "SALOME_PYQT_DataModelLight.h" +#include "SALOME_PYQT_ModuleLight.h" +#include "SALOME_PYQT_PyModule.h" -#ifndef GUI_DISABLE_CORBA -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include +#include "CAM_Application.h" +#include "SUITApp_init_python.hxx" +#include "SUIT_DataObjectIterator.h" #include "sipAPISalomePyQtGUILight.h" -#include -#if SIP_VERSION < 0x040700 -#include "sipQtGuiQWidget.h" -#include "sipQtGuiQMenu.h" -#endif - -#include - -/*! - \brief Default name of the module, replaced at the moment - of module creation. - \internal -*/ -const char* DEFAULT_NAME = "SALOME_PYQT_ModuleLight"; - -/*! - \brief Default menu group number. - \internal -*/ -const int DEFAULT_GROUP = 40; - -/*! - \var IsCallOldMethods - \brief Allow calling obsolete callback methods. - \internal - - If the macro CALL_OLD_METHODS is not defined, the invoking - of obsolete Python module's methods like setSetting(), definePopup(), - etc. is blocked. - - CALL_OLD_METHODS macro can be defined for example by adding - -DCALL_OLD_METHODS compilation option to the Makefile. -*/ -#ifdef CALL_OLD_METHODS -const bool IsCallOldMethods = true; -#else -const bool IsCallOldMethods = false; +#ifndef GUI_DISABLE_CORBA +#include #endif -/* Py_ssize_t for old Pythons */ -/* This code is as recommended by: */ -/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ +// Py_ssize_t for old Pythons +// This code is as recommended by" +// http://www.python.org/dev/peps/pep-0353/#conversion-guidelines #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) typedef int Py_ssize_t; # define PY_SSIZE_T_MAX INT_MAX @@ -112,48 +45,11 @@ typedef int Py_ssize_t; // // 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_ModuleLight 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. -// - -/*! - \class SALOME_PYQT_Module::XmlHandler - \brief XML resource files parser. - \internal - - This class is used to provide backward compatibility with - existing Python modules in which obsolete menu definition system - (via XML files) is used. -*/ - -class SALOME_PYQT_ModuleLight::XmlHandler -{ -public: - XmlHandler( SALOME_PYQT_ModuleLight* module, const QString& fileName ); - void createActions(); - void createPopup ( QMenu* menu, - const QString& context, - const QString& parent, - const QString& object ); - void activateMenus( bool ); - -protected: - void createToolBar ( QDomNode& parentNode ); - void createMenu ( QDomNode& parentNode, - const int parentMenuId = -1, - QMenu* parentPopup = 0 ); - - void insertPopupItems( QDomNode& parentNode, - QMenu* menu ); - -private: - SALOME_PYQT_ModuleLight* myModule; - QDomDocument myDoc; - QList myMenuItems; -}; - // // NB: Library initialization // Since the SalomePyQtGUILight library is not imported in Python it's initialization function @@ -179,15 +75,17 @@ PyMODINIT_FUNC INIT_FUNCTION(); \return new module object */ -extern "C" { - SALOME_PYQT_LIGHT_EXPORT CAM_Module* createModule() { - +extern "C" +{ + SALOME_PYQT_LIGHT_EXPORT CAM_Module* createModule() + { static bool alreadyInitialized = false; + + // make initialization only once (see comment above) ! if ( !alreadyInitialized ) { - // call only once (see comment above) ! - static PyThreadState *gtstate = 0; + static PyThreadState* gtstate = 0; #ifndef GUI_DISABLE_CORBA - if(SUIT_PYTHON::initialized) + if ( SUIT_PYTHON::initialized ) gtstate = SUIT_PYTHON::_gtstate; else gtstate = KERNEL_PYTHON::_gtstate; @@ -195,81 +93,32 @@ extern "C" { gtstate = SUIT_PYTHON::_gtstate; #endif PyEval_RestoreThread( gtstate ); + INIT_FUNCTION(); + PyEval_ReleaseThread( gtstate ); + alreadyInitialized = !alreadyInitialized; } + return new SALOME_PYQT_ModuleLight(); } } -/*! - \class FuncMsg - \brief Function call in/out tracer. - \internal -*/ - -class FuncMsg -{ -public: - FuncMsg( const QString& funcName ) - { - myName = funcName; - MESSAGE( myName.toLatin1().constData() << " [ begin ]" ); - } - ~FuncMsg() - { - MESSAGE( myName.toLatin1().constData() << " [ end ]" ); - } - void message( const QString& msg ) - { - MESSAGE( myName.toLatin1().constData() << " : " << msg.toLatin1().constData() ); - } -private: - QString myName; -}; - /*! \class SALOME_PYQT_ModuleLight - \brief This class implements module API for all the Python-based - SALOME modules. -*/ - -// -// Static variables definition -// -SALOME_PYQT_ModuleLight::InterpMap SALOME_PYQT_ModuleLight::myInterpMap; -SALOME_PYQT_ModuleLight* SALOME_PYQT_ModuleLight::myInitModule = 0; - -/*! - \brief Get the module being initialized. - - This is a little trick :) needed to provide an access from Python - (SalomePyQt) to the module being currently activated. The problem - that during the process of module initialization (initialize() - function) it is not yet available via application->activeModule() - call. - - This method returns valid pointer only if called in scope of - initialize() function. - - \return the module being currently initialized + \brief This class implements GUI module for "light-weight" (no-CORBA-engine) + Python-based SALOME modules. */ -SALOME_PYQT_ModuleLight* SALOME_PYQT_ModuleLight::getInitModule() -{ - return myInitModule; -} /*! \brief Constructor */ SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight() -: LightApp_Module( DEFAULT_NAME ), - myInterp( 0 ), - myModule( 0 ), - myXmlHandler ( 0 ), - myLastActivateStatus( true ) + : LightApp_Module( "noname" ) // name is set explicitly at the module initialization { + // initialize helper + myHelper = new PyModuleHelper( this ); } /*! @@ -277,2852 +126,448 @@ SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight() */ SALOME_PYQT_ModuleLight::~SALOME_PYQT_ModuleLight() { - if ( myXmlHandler ) - delete myXmlHandler; - if ( myInterp && myModule ) { - PyLockWrapper aLock = myInterp->GetLockWrapper(); - Py_XDECREF(myModule); - } + // as myHelper is a QObject, it should be deleted automatically } /*! \brief Initialization of the module. - - This method can be used for creation of the menus, toolbars and - other such staff. - - There are two ways to do this: - - 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 direct calling of the - corresponding methods of SalomePyQt Python API in the Python - module's initialize() method which is called from here. - - NOTE: SALOME supports two modes of modules loading: - - immediate (all the modules are created and initialized - immediately when the application object is created; - - postponed modules loading (used currently); in this mode - the module is loaded only be request. - If postponed modules loading is not used, the active - study might be not yet defined at this stage, so initialize() - method should not perform any study-based initialization. - \param app parent application object + \sa PyModuleHelper::initialize() */ void SALOME_PYQT_ModuleLight::initialize( CAM_Application* app ) { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::initialize()" ); - // call base implementation LightApp_Module::initialize( app ); - // try to get XML resource file name - SUIT_ResourceMgr* aResMgr = getApp()->resourceMgr(); - if ( !myXmlHandler && aResMgr ) { - // get current language - QString aLang = aResMgr->stringValue( "language", "language", QString() ); - if ( aLang.isEmpty() ) - aLang = "en"; - // define resource file name - QString aFileName = name() + "_" + aLang + ".xml"; - aFileName = aResMgr->path( "resources", name(), aFileName ); - // create XML handler instance - if ( !aFileName.isEmpty() && QFile::exists( aFileName ) ) - myXmlHandler = new SALOME_PYQT_ModuleLight::XmlHandler( this, aFileName ); - // create menus & toolbars from XML file if required - if ( myXmlHandler ) - myXmlHandler->createActions(); - } - - // perform internal initialization and call module's initialize() funtion - // InitializeReq: request class for internal init() operation - class InitializeReq : public PyInterp_Request - { - public: - InitializeReq( CAM_Application* _app, - SALOME_PYQT_ModuleLight* _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_ModuleLight* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new InitializeReq( app, this ) ); + // ... then call helper + myHelper->initialize( app ); } /*! \brief Activation of the module. - - This function is usually used in order to show the module's - specific menus and toolbars, update actions state and perform - other such actions required when the module is activated. - - Note, that returning \c false in this function prevents the - module activation. - - \param theStudy parent study + \param study parent study \return \c true if activation is successful and \c false otherwise + \sa PyModuleHelper::activate() */ -bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* theStudy ) -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::activateModule()" ); - - // call base implementation - bool res = LightApp_Module::activateModule( theStudy ); - - if ( !res ) - return res; - - // internal activation - return activateModuleInternal( theStudy ); -} - -/*! - \brief Perform internal activation of the module. - - The only goal of this function is to extract common functionality - for LightApp_Module and SalomeApp_module classes requried by the - specific architecture aspects of "light" / "full" SALOME modes. - - \sa activateModule() -*/ -bool SALOME_PYQT_ModuleLight::activateModuleInternal( SUIT_Study* theStudy ) +bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* study ) { - // reset the activation status to the default value - myLastActivateStatus = true; - - // perform internal activation - // ActivateReq: request class for internal activate() operation - class ActivateReq : public PyInterp_Request - { - public: - ActivateReq( SUIT_Study* _study, - SALOME_PYQT_ModuleLight* _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_ModuleLight* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new ActivateReq( theStudy, this ) ); - - // check activation status (set by activate()) - if ( !lastActivationStatus() ) - return false; - - // activate menus, toolbars, etc - if ( myXmlHandler ) myXmlHandler->activateMenus( true ); - setMenuShown( true ); - setToolShown( true ); - - // connect preferences changing signal - connect( getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ), - this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); - - // perform custom activation actions - // CustomizeReq: request class for internal customize() operation - class CustomizeReq : public PyInterp_Request - { - public: - CustomizeReq( SUIT_Study* _study, - SALOME_PYQT_ModuleLight* _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_ModuleLight* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new CustomizeReq( theStudy, this ) ); - - return true; + // call base implementation and then helper + return LightApp_Module::activateModule( study ) && myHelper->activate( study ); } /*! \brief Deactivation of the module. - - This function is usually used in order to hide the module's - specific menus and toolbars and perform other such actions - required when the module is deactivated. - - \param theStudy parent study + \param study parent study \return \c true if deactivation is successful and \c false otherwise + \sa PyModuleHelper::deactivate() */ -bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* theStudy ) +bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* study ) { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::deactivateModule()" ); - - // disconnect preferences changing signal - disconnect( getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ), - this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); - - // perform internal deactivation - // DeactivateReq: request class for internal deactivate() operation - class DeactivateReq : public PyInterp_LockRequest - { - public: - DeactivateReq( PyInterp_Interp* _py_interp, - SUIT_Study* _study, - SALOME_PYQT_ModuleLight* _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_ModuleLight* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new DeactivateReq( myInterp, theStudy, this ) ); - - // deactivate menus, toolbars, etc - if ( myXmlHandler ) myXmlHandler->activateMenus( false ); - setMenuShown( false ); - setToolShown( false ); - - // call base implementation - return LightApp_Module::deactivateModule( theStudy ); + // call helper + bool res = myHelper->deactivate( study ); + + // ... then call base implementation + return LightApp_Module::deactivateModule( study ) && res; } /*! - \brief Get last activation status. - \return status of last module activation operation - \sa activateModule() + \brief Get the dockable windows associated with the module. + \param winMap output map of dockable windows in form { : } + \sa PyModuleHelper::windows() */ -bool SALOME_PYQT_ModuleLight::lastActivationStatus() const +void SALOME_PYQT_ModuleLight::windows( QMap& winMap ) const { - return myLastActivateStatus; + // get list of dockable windows from helper + winMap = myHelper->windows(); } /*! - \breif Process application preferences changing. - - Called when any application setting is changed. - - \param module preference module - \param section preference resource file section - \param setting preference resource name + \brief Define the compatible view windows associated with the module. + \param viewList output list of view windows types + \sa PyModuleHelper::viewManagers() */ -void SALOME_PYQT_ModuleLight::preferenceChanged( const QString& module, - const QString& section, - const QString& setting ) +void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::preferenceChanged()" ); - - // perform synchronous request to Python event dispatcher - class Event : public PyInterp_LockRequest - { - public: - Event( PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj, - const QString& _section, - const QString& _setting ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj ( _obj ), - mySection( _section ), - mySetting( _setting ) {} - - protected: - virtual void execute() - { - myObj->prefChanged( mySection, mySetting ); - } - - private: - SALOME_PYQT_ModuleLight* myObj; - QString mySection, mySetting; - }; - - if ( module != moduleName() ) { - // module's own preferences are processed by preferencesChanged() method - // ... - // post the request only if dispatcher is not busy! - // execute request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new Event( myInterp, this, section, setting ) ); - } + // get list of view types from helper + viewList = myHelper->viewManagers(); } /*! \brief Process study activation. - - Called when study desktop is activated. Used for notifying the Python - module about changing of the active study. + \sa PyModuleHelper::studyActivated() */ void SALOME_PYQT_ModuleLight::studyActivated() { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::studyActivated()" ); - - // StudyChangedReq: request class for internal studyChanged() operation - class StudyChangedReq : public PyInterp_Request - { - public: - StudyChangedReq( SUIT_Study* _study, - SALOME_PYQT_ModuleLight* _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_ModuleLight* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new StudyChangedReq( application()->activeStudy(), this ) ); -} - -/*! - \brief Process GUI action (from main menu, toolbar or - context popup menu action). -*/ -void SALOME_PYQT_ModuleLight::onGUIEvent() -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::onGUIEvent()" ); - - // get sender action - QAction* action = qobject_cast( sender() ); - if ( !action ) - return; - - // get action ID - int id = actionId( action ); - fmsg.message( QString( "action id = %1" ).arg( id ) ); - - // perform synchronous request to Python event dispatcher - class GUIEvent : public PyInterp_LockRequest - { - public: - GUIEvent( PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _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_ModuleLight* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new GUIEvent( myInterp, this, id ) ); + // call helper + myHelper->studyActivated( application()->activeStudy() ); } /*! \brief Process context popup menu request. - - Called when user activates popup menu in some window - (view, object browser, etc). - - \param theContext popup menu context (e.g. "ObjectBrowser") - \param thePopupMenu popup menu + \param context popup menu context (e.g. "ObjectBrowser") + \param menu popup menu \param title popup menu title (not used) + \sa PyModuleHelper::contextMenu() */ -void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& theContext, - QMenu* thePopupMenu, - QString& /*title*/ ) +void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context, + QMenu* menu, + QString& /*title*/ ) { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::contextMenuPopup()" ); - fmsg.message( QString( "context: %1" ).arg( theContext ) ); - - // perform synchronous request to Python event dispatcher - class PopupMenuEvent : public PyInterp_LockRequest - { - public: - PopupMenuEvent( PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj, - const QString& _context, - QMenu* _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_ModuleLight* myObj; - QString myContext; - QMenu* myPopup; - }; - - // post request only if dispatcher is not busy! - // execute request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new PopupMenuEvent( myInterp, this, theContext, thePopupMenu ) ); + // call helper + myHelper->contextMenu( context, menu ); } /*! \brief Export preferences for the Python module. - - Called only once when the first instance of the module is created. + \sa PyModuleHelper::createPreferences() */ void SALOME_PYQT_ModuleLight::createPreferences() { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::createPreferences()" ); - - // perform synchronous request to Python event dispatcher - class Event : public PyInterp_LockRequest - { - public: - Event( PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->initPreferences(); - } - - private: - SALOME_PYQT_ModuleLight* myObj; - }; - - // post request only if dispatcher is not busy! - // execute request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new Event( myInterp, this ) ); + // call helper + myHelper->createPreferences(); } /*! - \brief Define the dockable windows associated with the module. - - To fill the list of windows the correspondind Python module's windows() - method is called from SALOME_PYQT_ModuleLight::init() method. - - By default, ObjectBrowser, PythonConsole and LogWindow windows are - associated to the module. - - Allowed dockable windows: - - LightApp_Application::WT_ObjectBrowser : object browser - - LightApp_Application::WT_PyConsole : python console - - LightApp_Application::WT_LogWindow : log messages output window - - Dock area is defined by Qt::DockWidgetArea enumeration: - - Qt::TopDockWidgetArea : top dock area - - Qt::BottomDockWidgetArea : bottom dock area - - Qt::LeftDockWidgetArea : left dock area - - Qt::RightDockWidgetArea : right dock area - - \param mappa map of dockable windows: { : } + \brief Process module's preferences changing. + \param section preference resources section + \param parameter preference resources parameter name + \sa PyModuleHelper::preferencesChanged() */ -void SALOME_PYQT_ModuleLight::windows( QMap& mappa ) const +void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter ) { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::windows()" ); - - mappa = myWindowsMap; + // call helper + myHelper->preferencesChanged( section, parameter ); } /*! - \brief Define the compatible view windows associated with the module. - - The associated view windows are opened automatically when the module - is activated. - - To fill the list of views the correspondind Python module's views() - method is called from SALOME_PYQT_ModuleLight::init() method. - By default, the list is empty. - - \param listik list of view windows types + \brief Save module data. Called when user saves study. + \param files output list of files where module stores data + \sa PyModuleHelper::save() */ -void SALOME_PYQT_ModuleLight::viewManagers( QStringList& lst ) const +void SALOME_PYQT_ModuleLight::save( QStringList& files ) { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::viewManagers()" ); + // call helper + myHelper->save( files ); +} - lst = myViewMgrList; +/* + \brief Load module data. Called when user opens study + and activates module. + \param files list of files where module data is stored + \sa PyModuleHelper::load() +*/ +bool SALOME_PYQT_ModuleLight::load( const QStringList& files ) +{ + // call helper + return myHelper->load( files ); } /*! - \brief Process module's preferences changing. - - Called when the module's preferences are changed. - - \param section setting section - \param setting setting name + \brief Dump module data to the Python script. + Called when user activates dump study operation. + \param files output list of files where module stores python script + \sa PyModuleHelper::dumpPython() */ -void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& setting ) +void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files ) { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::preferencesChanged()" ); - - // perform synchronous request to Python event dispatcher - class Event : public PyInterp_LockRequest - { - public: - Event( PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj, - const QString& _section, - const QString& _setting ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj ( _obj ), - mySection( _section ), - mySetting( _setting ) {} - - protected: - virtual void execute() - { - myObj->prefChanged( mySection, mySetting ); - } - - private: - SALOME_PYQT_ModuleLight* myObj; - QString mySection, mySetting; - }; - - // post request only if dispatcher is not busy! - // execut request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new Event( myInterp, this, section, setting ) ); + // call helper + myHelper->dumpPython( files ); } /*! - \brief Internal module initialization: - - Performs the following actions: - - initialize or get the Python interpreter (one per study) - - import the Python module - - pass the workspace widget to the Python module - - call Python module's initialize() method - - call Python module's windows() method - - call Python module's views() method - - \param app parent application 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() */ -void SALOME_PYQT_ModuleLight::init( CAM_Application* app ) +bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::init()" ); - - // reset interpreter to NULL - myInterp = NULL; - - // get study Id - LightApp_Application* anApp = dynamic_cast( app ); - if ( !anApp ) - return; - LightApp_Study* aStudy = dynamic_cast( app->activeStudy() ); - if ( !aStudy ) - return; - int aStudyId = aStudy ? aStudy->id() : 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 - - // this module is being activated now! - myInitModule = this; - - // 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 - if ( PyObject_HasAttrString( myModule, (char*)"initialize" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"initialize", (char*)"" ) ); - if ( !res ) { - PyErr_Print(); - } - } - - // get required dockable windows list from the Python module - // by calling windows() method - // ... first put default values - myWindowsMap.insert( LightApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea ); - myWindowsMap.insert( LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea ); - myWindowsMap.insert( LightApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea ); - - if ( PyObject_HasAttrString( myModule , (char*)"windows" ) ) { - PyObjWrapper res1( PyObject_CallMethod( myModule, (char*)"windows", (char*)"" ) ); - if ( !res1 ) { - PyErr_Print(); - } - else { - myWindowsMap.clear(); - if ( PyDict_Check( res1 ) ) { - PyObject* key; - PyObject* value; - Py_ssize_t 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; - } - } - } - } - } - - // get compatible view windows types from the Python module - // by calling views() method - if ( PyObject_HasAttrString( myModule , (char*)"views" ) ) { - PyObjWrapper res2( PyObject_CallMethod( myModule, (char*)"views", (char*)"" ) ); - if ( !res2 ) { - 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 ) ); - } - } - } - } - } - // module is already activated! - myInitModule = 0; + // call helper + return myHelper->isDraggable( what ); } /*! - \brief Internal activation: - - Performs the following actions: - - initialize or get the Python interpreter (one per study) - - import the Python GUI module - - call Python module's activate() method - - \param theStudy parent study object + \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() */ -void SALOME_PYQT_ModuleLight::activate( SUIT_Study* theStudy ) +bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::activate()" ); - - // get study Id - LightApp_Study* aStudy = dynamic_cast( theStudy ); - int aStudyId = aStudy ? aStudy->id() : 0; - - // initialize Python subinterpreter (on per study) and put it in variable - initInterp( aStudyId ); - if ( !myInterp ) { - myLastActivateStatus = false; - return; // Error - } - - // import Python GUI module - importModule(); - if ( !myModule ) { - myLastActivateStatus = false; - return; // Error - } - - // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - - // call Python module's activate() method (for the new modules) - if ( PyObject_HasAttrString( myModule , (char*)"activate" ) ) { - PyObject* res1 = PyObject_CallMethod( myModule, (char*)"activate", (char*)"" ); - if ( !res1 || !PyBool_Check( res1 ) ) { - PyErr_Print(); - // always true for old modules (no return value) - myLastActivateStatus = true; - } - else { - // detect return status - myLastActivateStatus = PyObject_IsTrue( res1 ); - } - } - - // Connect the SUIT_Desktop signal windowActivated() to this->onActiveViewChanged() - SUIT_Desktop* aDesk = theStudy->application()->desktop(); - if ( aDesk ) - { - connect( aDesk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), - this, SLOT( onActiveViewChanged( SUIT_ViewWindow* ) ) ); - // If a active window exists send activeViewChanged - // If a getActiveView() in SalomePyQt available we no longer need this - SUIT_ViewWindow* aView = aDesk->activeWindow(); - if ( aView ) - activeViewChanged( aView ); - - // get all view currently opened in the study and connect their signals to - // the corresponding slots of the class. - QList wndList = aDesk->windows(); - SUIT_ViewWindow* wnd; - foreach ( wnd, wndList ) - connectView( wnd ); - } + // call helper + return myHelper->isDropAccepted( where ); } /*! - \brief Additional customization after module is activated: - - Performs the following actions: - - get the Python interpreter (one per study) - - import the Python GUI module - - call Python module's setSettings() method (obsolete function, - used for compatibility with old code) - - \param theStudy parent study object + \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_ModuleLight::customize( SUIT_Study* theStudy ) +void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where, + const int row, Qt::DropAction action ) { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::customize()" ); - - // get study Id - LightApp_Study* aStudy = dynamic_cast( theStudy ); - int aStudyId = aStudy ? aStudy->id() : 0; - - // initialize Python subinterpreter (on per study) and put it in variable - initInterp( aStudyId ); - if ( !myInterp ) - return; // Error + // call helper + myHelper->dropObjects( what, where, row, action ); +} - // import Python GUI module - importModule(); - if ( !myModule ) - return; // Error +/*! + \brief Create new empty data object + \param parent entry of parent data object + \return entry of created data object +*/ +QString SALOME_PYQT_ModuleLight::createObject( const QString& parent ) +{ + QString entry; + SALOME_PYQT_DataObjectLight* obj = 0; - if ( IsCallOldMethods ) { - // call Python module's setWorkspace() method - setWorkSpace(); + if ( !parent.isEmpty() ) { + SALOME_PYQT_DataObjectLight* parentObj = findObject( parent ); + if ( parentObj ) + obj = new SALOME_PYQT_DataObjectLight( parentObj ); } + else { + SALOME_PYQT_DataModelLight* dm = + dynamic_cast( dataModel() ); + if ( dm ) + obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() ); + } + if ( obj ) + entry = obj->entry(); + return entry; +} - // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - - if ( IsCallOldMethods ) { - // call Python module's setSettings() method (obsolete) - if ( PyObject_HasAttrString( myModule , (char*)"setSettings" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"setSettings", (char*)"" ) ); - if( !res ) { - PyErr_Print(); - } - } +/*! + \brief Create new data object with specified name, icon and tooltip + \param name data object name + \param icon data object icon + \param toolTip data object tooltip + \param parent entry of parent data object + \return entry of created data object +*/ +QString SALOME_PYQT_ModuleLight::createObject( const QString& name, + const QString& icon, + const QString& toolTip, + const QString& parent ) +{ + QString entry = createObject( parent ); + SALOME_PYQT_DataObjectLight* obj = findObject( entry ); + if ( obj ) { + obj->setName( name); + obj->setToolTip( toolTip ); + obj->setIcon( icon ); } + return entry; } /*! - \brief Internal deactivation: - - Performs the following actions: - - call Python module's deactivate() method - - \param theStudy parent study object + \brief Set data object name + \param entry data object entry + \param name data object name */ -void SALOME_PYQT_ModuleLight::deactivate( SUIT_Study* theStudy ) +void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name ) { - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::deactivate()" ); - - // 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 - if ( PyObject_HasAttrString( myModule , (char*)"deactivate" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"deactivate", (char*)"" ) ); - if( !res ) { - PyErr_Print(); - } - } - - // Disconnect the SUIT_Desktop signal windowActivated() - SUIT_Desktop* aDesk = theStudy->application()->desktop(); - if ( aDesk ) - { - disconnect( aDesk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), - this, SLOT( onActiveViewChanged( SUIT_ViewWindow* ) ) ); - } -} - -/*! - \brief Perform internal actions when active study is changed. - - Called when active the study is actived (user brings its - desktop to top): - - initialize or get the Python interpreter (one per study) - - import the Python GUI module - - call Python module's activeStudyChanged() method - - \param theStudy study being activated -*/ -void SALOME_PYQT_ModuleLight::studyChanged( SUIT_Study* theStudy ) -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::studyChanged()" ); - - // get study Id - LightApp_Study* aStudy = dynamic_cast( theStudy ); - int aStudyId = aStudy ? aStudy->id() : 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 Python module's setWorkspace() method - setWorkSpace(); - } - - // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - - // call Python module's activeStudyChanged() method - if ( PyObject_HasAttrString( myModule, (char*)"activeStudyChanged" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"activeStudyChanged", (char*)"i", aStudyId ) ); - if( !res ) { - PyErr_Print(); - } - } -} - -/*! - \brief Process (internally) context popup menu request. - - Performs the following actions: - - 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. - - \param theContext popup menu context - \param thePopupMenu popup menu -*/ -void SALOME_PYQT_ModuleLight::contextMenu( const QString& theContext, QMenu* thePopupMenu ) -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::contextMenu()" ); - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - QString aContext( "" ), aObject( "" ), aParent( theContext ); - - if ( IsCallOldMethods && PyObject_HasAttrString( myModule, (char*)"definePopup" ) ) { - // call definePopup() Python module's function - // this is obsolete function, used only for compatibility reasons - PyObjWrapper res( PyObject_CallMethod( myModule, - (char*)"definePopup", - (char*)"sss", - theContext.toLatin1().constData(), - aObject.toLatin1().constData(), - aParent.toLatin1().constData() ) ); - if( !res ) { - PyErr_Print(); - } - else { - // parse return value - char *co, *ob, *pa; - if( PyArg_ParseTuple( res, "sss", &co, &ob, &pa ) ) { - aContext = co; - aObject = ob; - aParent = pa; - } - } - } // if ( IsCallOldMethods ... ) - - // first try to create menu via XML parser: - // we create popup menus without help of QtxPopupMgr - if ( myXmlHandler ) - myXmlHandler->createPopup( thePopupMenu, aContext, aParent, aObject ); - -#if SIP_VERSION < 0x040800 - PyObjWrapper sipPopup( sipBuildResult( 0, "M", thePopupMenu, sipClass_QMenu) ); -#else - PyObjWrapper sipPopup( sipBuildResult( 0, "D", thePopupMenu, sipType_QMenu, NULL) ); -#endif - - // then call Python module's createPopupMenu() method (for new modules) - if ( PyObject_HasAttrString( myModule, (char*)"createPopupMenu" ) ) { - PyObjWrapper res1( PyObject_CallMethod( myModule, - (char*)"createPopupMenu", - (char*)"Os", - sipPopup.get(), - theContext.toLatin1().constData() ) ); - if( !res1 ) { - PyErr_Print(); - } - } - - if ( IsCallOldMethods && PyObject_HasAttrString( myModule, (char*)"customPopup" ) ) { - // call customPopup() Python module's function - // this is obsolete function, used only for compatibility reasons - PyObjWrapper res2( PyObject_CallMethod( myModule, - (char*)"customPopup", - (char*)"Osss", - sipPopup.get(), - aContext.toLatin1().constData(), - aObject.toLatin1().constData(), - aParent.toLatin1().constData() ) ); - if( !res2 ) { - PyErr_Print(); - } - } -} - -/*! - \brief Internal GUI event handling. - - Performs the following actions: - - calls Python module's OnGUIEvent() method - - \param theId GUI action ID -*/ -void SALOME_PYQT_ModuleLight::guiEvent( const int theId ) -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::guiEvent()" ); - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - if ( PyObject_HasAttrString( myModule, (char*)"OnGUIEvent" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"OnGUIEvent", (char*)"i", theId ) ); - if( !res ) { - PyErr_Print(); - } - } -} - -/*! - \brief Initialize (internally) preferences for the module. - - Performs the following actions: - - calls Python module's createPreferences() method -*/ -void SALOME_PYQT_ModuleLight::initPreferences() -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::initPreferences()" ); - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - // temporary set myInitModule because createPreferences() method - // might be called during the module intialization process - myInitModule = this; - - if ( PyObject_HasAttrString( myModule, (char*)"createPreferences" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"createPreferences", (char*)"" ) ); - if( !res ) { - PyErr_Print(); - } - } - - myInitModule = 0; -} - -/*! - \brief Initialize python subinterpreter (one per study). - \param theStudyId study ID -*/ -void SALOME_PYQT_ModuleLight::initInterp( int theStudyId ) -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::initInterp()" ); - - // check study Id - if ( !theStudyId ) { - // Error! Study Id must not be 0! - myInterp = NULL; - return; - } - // try to find the subinterpreter - if( myInterpMap.contains( theStudyId ) ) { - // found! - myInterp = myInterpMap[ theStudyId ]; - return; - } - - myInterp = new SALOME_PYQT_PyInterp(); - if(!myInterp) - return; - - myInterp->initialize(); - myInterpMap[ theStudyId ] = myInterp; - -#ifndef GUI_DISABLE_CORBA - if(!SUIT_PYTHON::initialized) { - // 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 - int embedded = 1; - PyObjWrapper aRes( PyObject_CallMethod( aMod, (char*)"salome_init", (char*)"ii", theStudyId, embedded ) ); - if( !aRes ) { - // Error! - PyErr_Print(); - return; - } - } -#endif -} - -/*! - \brief Import Python GUI module and remember the reference to the module. - - Attention! initInterp() should be called first!!! -*/ -void SALOME_PYQT_ModuleLight::importModule() -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::importModule()" ); - - // 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 = name() + "GUI"; - try { - myModule = PyImport_ImportModule( aMod.toLatin1().data() ); - } - catch (...) { - } - if( !myModule ) { - // Error! - PyErr_Print(); - return; - } -} - -/*! - \brief Set study workspace to the Python module. - - Calls setWorkSpace() method of the Pythohn module with - PyQt QWidget object to use with interpreter. - - Attention! initInterp() and importModule() should be called first!!! -*/ -void SALOME_PYQT_ModuleLight::setWorkSpace() -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::setWorkSpace()" ); - - // 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 ) { - // ... 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(); - } -#if SIP_VERSION < 0x040800 - PyObjWrapper pyws( sipBuildResult( 0, "M", aWorkspace, sipClass_QWidget) ); -#else - PyObjWrapper pyws( sipBuildResult( 0, "D", aWorkspace, sipType_QWidget , NULL) ); -#endif - // ... and finally call Python module's setWorkspace() method (obsolete) - if ( PyObject_HasAttrString( myModule, (char*)"setWorkSpace" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"setWorkSpace", (char*)"O", pyws.get() ) ); - if( !res ) { - PyErr_Print(); - } - } - } -} - -/*! - \brief Preference changing callback function (internal). - - Performs the following actions: - - call Python module's preferenceChanged() method - - \param section setting section name - \param setting setting name -*/ -void SALOME_PYQT_ModuleLight::prefChanged( const QString& section, const QString& setting ) -{ - FuncMsg fmsg( "SALOME_PYQT_ModuleLight::prefChanged()" ); - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - if ( PyObject_HasAttrString( myModule, (char*)"preferenceChanged" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, - (char*)"preferenceChanged", - (char*)"ss", - section.toLatin1().constData(), - setting.toLatin1().constData() ) ); - if( !res ) { - PyErr_Print(); - } - } -} - -/*! - \brief Get default menu group identifier - \return menu group ID (40 by default) -*/ -int SALOME_PYQT_ModuleLight::defaultMenuGroup() -{ - return DEFAULT_GROUP; -} - -// -// The next methods call the parent implementation. -// This is done to open protected methods from CAM_Module class. -// - -/*! - \brief Create toolbar with specified \a name. - \param name toolbar name - \return toolbar ID or -1 if toolbar creation is failed -*/ -int SALOME_PYQT_ModuleLight::createTool( const QString& name ) -{ - return LightApp_Module::createTool( name ); -} - -/*! - \brief Insert action with specified \a id to the toolbar. - \param id action ID - \param tBar toolbar ID - \param idx required index in the toolbar - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_ModuleLight::createTool( const int id, const int tBar, const int idx ) -{ - return LightApp_Module::createTool( id, tBar, idx ); -} - -/*! - \brief Insert action with specified \a id to the toolbar. - \param id action ID - \param tBar toolbar name - \param idx required index in the toolbar - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_ModuleLight::createTool( const int id, const QString& tBar, const int idx ) -{ - return LightApp_Module::createTool( id, tBar, idx ); -} - -/*! - \brief Insert action to the toolbar. - \param a action - \param tBar toolbar ID - \param id required action ID - \param idx required index in the toolbar - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_ModuleLight::createTool( QAction* a, const int tBar, const int id, const int idx ) -{ - return LightApp_Module::createTool( a, tBar, id, idx ); -} - -/*! - \brief Insert action to the toolbar. - \param a action - \param tBar toolbar name - \param id required action ID - \param idx required index in the toolbar - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_ModuleLight::createTool( QAction* a, const QString& tBar, const int id, const int idx ) -{ - return LightApp_Module::createTool( a, tBar, id, idx ); + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj ) + dataObj->setName( name ); } /*! - \brief Create main menu. - \param subMenu menu name - \param menu parent menu ID - \param id required menu ID - \param group menu group ID - \param idx required index in the menu - \return menu ID or -1 if menu could not be added + \brief Get data object name + \param entry data object entry + \return data object name */ -int SALOME_PYQT_ModuleLight::createMenu( const QString& subMenu, const int menu, const int id, const int group, const int idx ) +QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const { - return LightApp_Module::createMenu( subMenu, menu, id, group, idx ); + QString name; + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj ) + name = dataObj->name(); + return name; } /*! - \brief Create main menu. - \param subMenu menu name - \param menu parent menu name (list of menu names separated by "|") - \param id required menu ID - \param group menu group ID - \param idx required index in the menu - \return menu ID or -1 if menu could not be added + \brief Set data object icon + \param entry data object entry + \param icon data object icon file name (icon is loaded from module resources) */ -int SALOME_PYQT_ModuleLight::createMenu( const QString& subMenu, const QString& menu, const int id, const int group, const int idx ) +void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon ) { - return LightApp_Module::createMenu( subMenu, menu, id, group, idx ); + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj ) + dataObj->setIcon( icon ); } /*! - \brief Insert action to the main menu. - \param id action ID - \param menu parent menu ID - \param group menu group ID - \param idx required index in the menu - \return action ID or -1 if action could not be added + \brief Set data object tooltip + \param entry data object entry + \param toolTip data object tooltip */ -int SALOME_PYQT_ModuleLight::createMenu( const int id, const int menu, const int group, const int idx ) +void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip ) { - return LightApp_Module::createMenu( id, menu, group, idx ); + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj ) + dataObj->setToolTip( toolTip ); } /*! - \brief Insert action to the main menu. - \param id action ID - \param menu parent menu name (list of menu names separated by "|") - \param group menu group ID - \param idx required index in the menu - \return action ID or -1 if action could not be added + \brief Get data object tooltip + \param entry data object entry + \return data object tooltip */ -int SALOME_PYQT_ModuleLight::createMenu( const int id, const QString& menu, const int group, const int idx ) +QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const { - return LightApp_Module::createMenu( id, menu, group, idx ); + QString toolTip; + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj ) + toolTip = dataObj->toolTip(); + return toolTip; } /*! - \brief Insert action to the main menu. - \param a action - \param menu parent menu ID - \param group menu group ID - \param idx required index in the menu - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_ModuleLight::createMenu( QAction* a, const int menu, const int id, const int group, const int idx ) + \brief Set data object color + \param entry data object entry + \param color data object color + */ +void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color ) { - return LightApp_Module::createMenu( a, menu, id, group, idx ); + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj ) + dataObj->setColor( color ); } /*! - \brief Insert action to the main menu. - \param a action - \param menu parent menu name (list of menu names separated by "|") - \param group menu group ID - \param idx required index in the menu - \return action ID or -1 if action could not be added + \brief Get data object color + \param entry data object entry + \return data object color */ -int SALOME_PYQT_ModuleLight::createMenu( QAction* a, const QString& menu, const int id, const int group, const int idx ) +QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const { - return LightApp_Module::createMenu( a, menu, id, group, idx ); + QColor color; + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj ) + color = dataObj->color( SUIT_DataObject::Foreground ); + return color; } /*! - \brief Create separator action which can be used in the menu or toolbar. - \return new separator action + \brief Set reference to another data object + \param entry data object entry + \param refEntry referenced data object entry */ -QAction* SALOME_PYQT_ModuleLight::separator() +void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry ) { - return LightApp_Module::separator(); + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj ) + dataObj->setRefEntry( refEntry ); } -/*! - \brief Get action by specified \a id. - \return action or 0 if it is not found +/* + \brief Get entry of the referenced object (if there's any) + \param entry data object entry + \return referenced data object entry */ -QAction* SALOME_PYQT_ModuleLight::action( const int id ) const +QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const { - QAction* a = LightApp_Module::action( id ); - if ( !a ) { - // try menu - QMenu* m = menuMgr()->findMenu( id ); - if ( m ) a = m->menuAction(); - } - return a; + QString refEntry; + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj ) + refEntry = dataObj->refEntry(); + return refEntry; } /*! - \brief Get action identifier. - \return action ID or -1 if action is not registered + \brief Remove object by entry + \param entry data object entry */ -int SALOME_PYQT_ModuleLight::actionId( const QAction* a ) const +void SALOME_PYQT_ModuleLight::removeObject( const QString& entry ) { - return LightApp_Module::actionId( a ); + SALOME_PYQT_DataObjectLight* dataObj = findObject( entry ); + if ( dataObj && dataObj->parent() ) + dataObj->parent()->removeChild( dataObj ); } /*! - \brief Create new action. - - If the action with specified identifier already registered - it is not created, but its attributes are only modified. - - \param id action ID - \param text tooltip text - \param icon icon - \param menu menu text - \param tip status tip - \param key keyboard shortcut - \param toggle \c true for checkable action - \return created action + \brief Remove all child data objects from specified data object + \param entry data object entry */ -QAction* SALOME_PYQT_ModuleLight::createAction( const int id, const QString& text, const QString& icon, - const QString& menu, const QString& tip, const int key, - const bool toggle, QObject* parent ) +void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry ) { - QIcon anIcon = loadIcon( icon ); - QAction* a = action( id ); - if ( a ) { - if ( a->toolTip().isEmpty() && !text.isEmpty() ) a->setToolTip( text ); - if ( a->text().isEmpty() && !menu.isEmpty() ) a->setText( menu ); - if ( a->icon().isNull() && !anIcon.isNull() ) a->setIcon( anIcon ); - if ( a->statusTip().isEmpty() && !tip.isEmpty() ) a->setStatusTip( tip ); - if ( a->shortcut().isEmpty() && key ) a->setShortcut( key ); - if ( a->isCheckable() != toggle ) a->setCheckable( toggle ); - disconnect( a, SIGNAL( triggered( bool ) ), this, SLOT( onGUIEvent() ) ); - connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onGUIEvent() ) ); + SUIT_DataObject* dataObj = 0; + if ( !entry.isEmpty() ) { + dataObj = findObject( entry ); } else { - a = LightApp_Module::createAction( id, - text, - anIcon, - menu, - tip, - key, - parent ? parent : this, - toggle, - this, - SLOT( onGUIEvent() ) ); - } - return a; -} - -/*! - \brief Create new action group. - - If the action with specified identifier already registered - it is not created, but its attributes are only modified. - - \param id action ID - \param text tooltip text - \param icon icon - \param menu menu text - \param tip status tip - \param key keyboard shortcut - \param toggle \c true for checkable action - \return created action -*/ -QtxActionGroup* SALOME_PYQT_ModuleLight::createActionGroup(const int id, const bool exclusive) -{ - QtxActionGroup* a = qobject_cast( action( id ) ); - if ( !a ) { - a = new QtxActionGroup( this ); - LightApp_Module::registerAction( id, a ); - } - a->setExclusive( exclusive ); - return a; -} - -/*! - \brief Load icon from resource file. - \param fileName icon file name - \return icon (null icon if loading failed) -*/ -QIcon SALOME_PYQT_ModuleLight::loadIcon( const QString& fileName ) -{ - QIcon anIcon; - if ( !fileName.isEmpty() ) { - QPixmap pixmap = getApp()->resourceMgr()->loadPixmap( name(), tr( fileName.toLatin1() ) ); - if ( !pixmap.isNull() ) - anIcon = QIcon( pixmap ); + SALOME_PYQT_DataModelLight* dm = + dynamic_cast( dataModel() ); + if ( dm ) dataObj = dm->getRoot(); } - return anIcon; -} - -/*! - \brief Add global application preference (for example, - application specific section). - \param label preference name - \return preference ID -*/ -int SALOME_PYQT_ModuleLight::addGlobalPreference( const QString& label ) -{ - LightApp_Preferences* pref = preferences(); - if ( !pref ) - return -1; - - return pref->addPreference( label, -1 ); -} - -/*! - \brief Add preference. - \param label preference name - \return preference ID -*/ -int SALOME_PYQT_ModuleLight::addPreference( const QString& label ) -{ - return LightApp_Module::addPreference( label ); -} - -/*! - \brief Add preference. - \param label preference name - \param pId parent preference ID - \param type preference type - \param section resource file section name - \param param resource file setting name - \return preference ID -*/ -int SALOME_PYQT_ModuleLight::addPreference( const QString& label, - const int pId, const int type, - const QString& section, - const QString& param ) -{ - return LightApp_Module::addPreference( label, pId, type, section, param ); -} - -/*! - \brief Get the preference property. - \param id preference ID - \param prop property name - \return property value (invalid QVariant() if property is not found) -*/ -QVariant SALOME_PYQT_ModuleLight::preferenceProperty( const int id, - const QString& prop ) const -{ - QVariant v = LightApp_Module::preferenceProperty( id, prop ); - return v; -} - -/*! - \brief Set the preference property. - \param id preference ID - \param prop property name - \param var property value -*/ -void SALOME_PYQT_ModuleLight::setPreferenceProperty( const int id, - const QString& prop, - const QVariant& var ) -{ - LightApp_Module::setPreferenceProperty( id, prop, var ); -} - - -/*! - \brief Signal handler windowActivated(SUIT_ViewWindow*) of SUIT_Desktop - \param pview view being activated -*/ -void SALOME_PYQT_ModuleLight::onActiveViewChanged( SUIT_ViewWindow* pview ) -{ - class ActiveViewChange : public PyInterp_LockRequest - { - public: - ActiveViewChange( PyInterp_Interp* _py_interp, SALOME_PYQT_ModuleLight* _obj, const SUIT_ViewWindow* _pview ) - : PyInterp_LockRequest( _py_interp, 0, true ), - myObj(_obj),myView(_pview) {} - - protected: - virtual void execute() - { - myObj->activeViewChanged( myView ); + if ( dataObj ) { + DataObjectList children; + dataObj->children( children ); + QListIterator it( children ); + while ( it.hasNext() ) { + dataObj->removeChild( it.next() ); } - - private: - SALOME_PYQT_ModuleLight* myObj; - const SUIT_ViewWindow * myView; - }; - - PyInterp_Dispatcher::Get()->Exec( new ActiveViewChange( myInterp, this, pview ) ); -} - -/*! - \brief Processes the view changing, calls Python module's activeViewChanged() method - \param pview view being activated -*/ -void SALOME_PYQT_ModuleLight::activeViewChanged( const SUIT_ViewWindow* pview ) -{ - if ( !myInterp || !myModule ) - return; - - // Do not use SUIT_ViewWindow::closing() signal here. View manager reacts on - // this signal and deletes view. So our slot does not works if it is connected - // on this signal. SUIT_ViewManager::deleteView(SUIT_ViewWindow*) is used here - - connectView( pview ); - - if ( PyObject_HasAttrString( myModule, (char*)"activeViewChanged" ) ) - { - if ( !pview ) - return; - - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"activeViewChanged", (char*)"i" , pview->getId() ) ); - if( !res ) - PyErr_Print(); } } /*! - \brief Signal handler cloneView() of OCCViewer_ViewWindow - \param pview view being cloned + \brief Get entries of all child data objects of specified data object + \param entry data object entry + \param recursive \c true for recursive processing */ -void SALOME_PYQT_ModuleLight::onViewCloned( SUIT_ViewWindow* pview ) +QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const { - class ViewClone : public PyInterp_LockRequest - { - public: - ViewClone( PyInterp_Interp* _py_interp, SALOME_PYQT_ModuleLight* _obj, const SUIT_ViewWindow* _pview ) - : PyInterp_LockRequest( _py_interp, 0, true ), - myObj(_obj), myView(_pview) {} - - protected: - virtual void execute() - { - myObj->viewCloned( myView ); + QStringList entryList; + SUIT_DataObject* dataObj = 0; + if ( !entry.isEmpty() ) { + dataObj = findObject( entry ); + } + else { + SALOME_PYQT_DataModelLight* dm = + dynamic_cast( dataModel() ); + if ( dm ) dataObj = dm->getRoot(); + } + if ( dataObj ) { + DataObjectList lst; + dataObj->children( lst, recursive ); + QListIterator it( lst ); + while ( it.hasNext() ) { + SALOME_PYQT_DataObjectLight* sobj = dynamic_cast( it.next() ); + entryList.append( sobj->entry() ); } - - private: - SALOME_PYQT_ModuleLight* myObj; - const SUIT_ViewWindow* myView; - }; - - PyInterp_Dispatcher::Get()->Exec( new ViewClone( myInterp, this, pview ) ); -} - -/*! - \brief Processes the view cloning, calls Python module's activeViewCloned() method - \param pview view being cloned -*/ -void SALOME_PYQT_ModuleLight::viewCloned( const SUIT_ViewWindow* pview ) -{ - if ( !myInterp || !myModule || !pview ) - return; - - if ( PyObject_HasAttrString( myModule, (char*)"viewCloned" ) ) - { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"viewCloned", (char*)"i", pview->getId() ) ); - if( !res ) - PyErr_Print(); } + return entryList; } /*! - \brief Signal handler tryClose(SUIT_ViewWindow*) of a view - \param pview view being closed + \brief Create new instance of data model and return it. */ -void SALOME_PYQT_ModuleLight::onViewTryClose( SUIT_ViewWindow* pview ) +CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel() { - class ViewTryClose : public PyInterp_LockRequest - { - public: - ViewTryClose( PyInterp_Interp* _py_interp, SALOME_PYQT_ModuleLight* _obj, const SUIT_ViewWindow* _pview ) - : PyInterp_LockRequest( _py_interp, 0, true ), - myObj(_obj),myView(_pview) {} - - protected: - virtual void execute() - { - myObj->viewTryClose( myView ); - } - - private: - SALOME_PYQT_ModuleLight* myObj; - const SUIT_ViewWindow * myView; - }; - - PyInterp_Dispatcher::Get()->Exec( new ViewTryClose( myInterp, this, pview ) ); + return new SALOME_PYQT_DataModelLight( this ); } /*! - \brief Processes the view closing attempt, calls Python module's viewTryClose() method - \param pview view user tries to close + \brief Find data object by its entry + \param entry data object entry + \return data object with given entry or 0 if object isn't found */ -void SALOME_PYQT_ModuleLight::viewTryClose( const SUIT_ViewWindow* pview ) +SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const { - if ( !myInterp || !myModule ) - return; - - if ( PyObject_HasAttrString( myModule, (char*)"viewTryClose" ) ) - { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"viewTryClose", (char*)"i", pview->getId() ) ); - if ( !res ) - { - PyErr_Print(); - } - } -} - -/*! - \brief Signal handler closing(SUIT_ViewWindow*) of a view - \param pview view being closed -*/ -void SALOME_PYQT_ModuleLight::onViewClosed( SUIT_ViewWindow* pview ) -{ - class ViewClose : public PyInterp_LockRequest - { - public: - ViewClose( PyInterp_Interp* _py_interp, SALOME_PYQT_ModuleLight* _obj, const SUIT_ViewWindow* _pview ) - : PyInterp_LockRequest( _py_interp, 0, true ), - myObj(_obj),myView(_pview) {} - - protected: - virtual void execute() - { - myObj->viewClosed( myView ); - } - - private: - SALOME_PYQT_ModuleLight* myObj; - const SUIT_ViewWindow * myView; - }; - - PyInterp_Dispatcher::Get()->Exec( new ViewClose( myInterp, this, pview ) ); -} - -/*! - \brief Processes the view closing, calls Python module's viewClosed() method - \param pview view being closed -*/ -void SALOME_PYQT_ModuleLight::viewClosed( const SUIT_ViewWindow* pview ) -{ - if ( !myInterp || !myModule ) - return; - - if ( PyObject_HasAttrString( myModule, (char*)"viewClosed" ) ) - { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"viewClosed", (char*)"i", pview->getId() ) ); - if ( !res ) - { - PyErr_Print(); - } - } -} - -/*! - \brief Connects or disconnects signals about activating and cloning view on the module slots - \param pview view which is connected/disconnected -*/ -void SALOME_PYQT_ModuleLight::connectView( const SUIT_ViewWindow* pview ) -{ - SUIT_ViewManager* viewMgr = pview->getViewManager(); - SUIT_ViewModel* viewModel = viewMgr ? viewMgr->getViewModel() : 0; - - if ( viewMgr ) - { - disconnect( viewMgr, SIGNAL( tryCloseView( SUIT_ViewWindow* ) ), - this, SLOT( onViewTryClose( SUIT_ViewWindow* ) ) ); - disconnect( viewMgr, SIGNAL( deleteView( SUIT_ViewWindow* ) ), - this, SLOT( onViewClosed( SUIT_ViewWindow* ) ) ); - - connect( viewMgr, SIGNAL( tryCloseView( SUIT_ViewWindow* ) ), - this, SLOT( onViewTryClose( SUIT_ViewWindow* ) ) ); - connect( viewMgr, SIGNAL( deleteView( SUIT_ViewWindow* ) ), - this, SLOT( onViewClosed( SUIT_ViewWindow* ) ) ); - } - - // Connect cloneView() signal of an OCC View - if ( pview->inherits( "OCCViewer_ViewWindow" ) ) - { - disconnect( pview, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), - this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); - connect( pview, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), - this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); - } - // Connect cloneView() signal of Plot2d View manager - else if ( viewModel && viewModel->inherits( "Plot2d_Viewer" ) ) - { - disconnect( viewModel, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), - this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); - connect( viewModel, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), - this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); - } -} - -/*! - \brief Get tag name for the DOM element. - \param element DOM element - \return empty string if the element does not have tag name - \internal -*/ -static QString tagName( const QDomElement& element ) -{ - return element.tagName().trimmed(); -} - -/*! - \brief Get DOM element's attribute by its name. - \param element DOM element - \param attName attribute name - \return empty string if the element does not have such attribute - \internal -*/ -static QString attribute( const QDomElement& element, const QString& attName ) -{ - return element.attribute( attName ).trimmed(); -} - -/*! - \brief Inspect specified string for the boolean value. - - This function returns \c true if string represents boolean value: - - "true", "yes" or "1" for \c true - - "false", "no" or "0" for \c false - Second parameter allows to specify what boolean value is expected: - - 1: \c true - - 0: \c false - - other value is not taken into account (return represented value) - - \param value inspected string - \param check expected boolean value - \return boolean value represented by the string (\a check is not 1 or 0) - or \c true if value correspond to the specified \a check -*/ -static bool checkBool( const QString& value, const int check = -1 ) -{ - QString v = value.toLower(); - if ( ( v == "true" || v == "yes" || v == "1" ) && ( check != 0 ) ) - return true; - if ( ( v == "false" || v == "no" || v == "0" ) && ( check == 0 ) ) - return true; - return false; -} - -/*! - \brief Inspect specified string for the integer value. - - This function returns returns -1 if item is empty or represents - an invalid number. - \param value inspected string - \param def default value - \param shift shift value (it is added to the integer value to produce shifted result) -*/ -static int checkInt( const QString& value, const int def = -1, const int shift = -1 ) -{ - bool bOk; - int val = value.toInt( &bOk ); - if ( !bOk ) val = def; - if ( shift > 0 && bOk && val < 0 ) - val += shift; - return val; -} - -/*! - \brief Constructor - \internal - \param module parent module pointer - \param fileName XML file path -*/ -SALOME_PYQT_ModuleLight::XmlHandler::XmlHandler( SALOME_PYQT_ModuleLight* module, - const QString& fileName ) -: myModule( module ) -{ - if ( fileName.isEmpty() ) - return; - QFile aFile( fileName ); - if ( !aFile.open( QIODevice::ReadOnly ) ) - return; - myDoc.setContent( &aFile ); - aFile.close(); -} - -/*! - \brief Parse XML file and create actions. - \internal - - Called by SALOME_PYQT_ModuleLight::activate() in order to create actions - (menus, toolbars). -*/ -void SALOME_PYQT_ModuleLight::XmlHandler::createActions() -{ - // get document element - QDomElement aDocElem = myDoc.documentElement(); - - // create 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 ); - } -} - -/*! - \brief Create popup menu. - \internal - \param menu popup menu - \param context popup menu context - \param context popup menu parent object name - \param context popup menu object name -*/ -void SALOME_PYQT_ModuleLight::XmlHandler::createPopup( QMenu* menu, - const QString& context, - const QString& parent, - const QString& object ) -{ - // 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" ); // not used // - 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; - } - } - } -} - -/*! - \brief Activate menus - \internal - \param enable if \c true menus are activated, otherwise menus are deactivated -*/ -void SALOME_PYQT_ModuleLight::XmlHandler::activateMenus( bool enable ) -{ - if ( !myModule ) - return; - - QtxActionMenuMgr* mgr = myModule->menuMgr(); - int id; - foreach( id, myMenuItems ) mgr->setEmptyEnabled( id, enable ); -} - -/*! - \brief Create main menu item and insert actions to it. - \internal - \param parentNode XML node with menu description - \param parentMenuId parent menu ID (-1 for top-level menu) - \param parentPopup parent popup menu (0 for top-level menu) -*/ -void SALOME_PYQT_ModuleLight::XmlHandler::createMenu( QDomNode& parentNode, - const int parentMenuId, - QMenu* parentPopup ) -{ - if ( !myModule || 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" ) ); - int group = checkInt( attribute( parentElement, "group-id" ), - myModule->defaultMenuGroup() ); - if ( !plabel.isEmpty() ) { - QMenu* popup = 0; - int menuId = -1; - // create menu - menuId = myModule->createMenu( plabel, // label - parentMenuId, // parent menu ID, -1 for top-level menu - pid, // ID - group, // group ID - ppos ); // position - myMenuItems.append( menuId ); - 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" ) ); - int group = checkInt( attribute( elem, "group-id" ), - myModule->defaultMenuGroup() ); - 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" ) ); - - // -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 - } - } - else if ( aTagName == "submenu" ) { - // create sub-menu - createMenu( node, menuId, popup ); - } - else if ( aTagName == "separator" ) { - // create menu separator - int id = checkInt( attribute( elem, "item-id" ) ); // separator can have ID - int pos = checkInt( attribute( elem, "pos-id" ) ); - int group = checkInt( attribute( elem, "group-id" ), - myModule->defaultMenuGroup() ); - QAction* action = myModule->separator(); - myModule->createMenu( action, // separator action - menuId, // parent menu ID - id, // ID - group, // group ID - pos ); // position - } - } - node = node.nextSibling(); - } - } - } -} - -/*! - \brief Create a toolbar and insert actions to it. - \param parentNode XML node with toolbar description -*/ -void SALOME_PYQT_ModuleLight::XmlHandler::createToolBar( QDomNode& parentNode ) -{ - if ( !myModule || 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" ) ); - - // -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 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->createTool( action, tbId, -1, pos ); - } - } - else if ( aTagName == "separatorTB" || aTagName == "separator" ) { - // create toolbar separator - int pos = checkInt( attribute( elem, "pos-id" ) ); - QAction* action = myModule->separator(); - myModule->createTool( action, tbId, -1, pos ); - } - } - node = node.nextSibling(); - } - } - } -} - -/*! - \brief Fill popup menu with the items. - \param parentNode XML node with popup menu description - \param menu popup menu -*/ -void SALOME_PYQT_ModuleLight::XmlHandler::insertPopupItems( QDomNode& parentNode, QMenu* menu ) -{ - if ( !myModule && 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 ); - QList actions = menu->actions(); - 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" ); - QString accel = attribute( elem, "accel-id" ); - bool toggle = checkBool( attribute( elem, "toggle-id" ) ); - - // -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 ) { - QAction* action = myModule->createAction( id, // ID - tooltip, // tooltip - icon, // icon - label, // menu text - tooltip, // status-bar text - QKeySequence( accel ), // keyboard accelerator - toggle ); // toogled action - QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; - menu->insertAction( before, action ); - } - } - else if ( aTagName == "submenu" ) { - // create sub-menu - ////int id = checkInt( attribute( elem, "item-id" ) ); // not used // - int pos = checkInt( attribute( elem, "pos-id" ) ); - QString label = attribute( elem, "label-id" ); - QString icon = attribute( elem, "icon-id" ); - - QIcon anIcon; - if ( !icon.isEmpty() ) { - QPixmap pixmap = myModule->getApp()->resourceMgr()->loadPixmap( myModule->name(), icon ); - if ( !pixmap.isNull() ) - anIcon = QIcon( pixmap ); - } - - QMenu* newPopup = menu->addMenu( anIcon, label ); - QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; - menu->insertMenu( before, newPopup ); - insertPopupItems( node, newPopup ); - } - else if ( aTagName == "separator" ) { - // create menu separator - int pos = checkInt( attribute( elem, "pos-id" ) ); - QAction* action = myModule->separator(); - QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; - menu->insertAction( before, action ); - } - } - node = node.nextSibling(); - } -} - -/* - * Save study request. - * Called when user save study. - */ -void SALOME_PYQT_ModuleLight::save(QStringList& theListOfFiles) -{ - MESSAGE("SALOME_PYQT_ModuleLight::save()") - // perform synchronous request to Python event dispatcher - class SaveEvent: public PyInterp_LockRequest - { - public: - SaveEvent(PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj, - QStringList& _files_list) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj( _obj ) , - myFilesList(_files_list) {} - protected: - virtual void execute() - { - myObj->saveEvent(myFilesList); - } - private: - SALOME_PYQT_ModuleLight* myObj; - QStringList& myFilesList; - }; - - // Posting the request only if dispatcher is not busy! - // Executing the request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new SaveEvent( myInterp, this, theListOfFiles ) ); -} - -void SALOME_PYQT_ModuleLight::saveEvent(QStringList& theListOfFiles) -{ - MESSAGE("SALOME_PYQT_ModuleLight::saveEvent()"); - QStringList::Iterator it = theListOfFiles.begin(); - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule || (it == theListOfFiles.end())) - return; - - if ( PyObject_HasAttrString(myModule, (char*)"saveFiles") ) { - // temporary set myInitModule because saveEvent() method - // might be called by the framework when this module is inactive, - // but still it should be possible to access this module's data - // from Python - myInitModule = this; - - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"saveFiles", - (char*)"s", (*it).toLatin1().constData())); - - myInitModule = 0; - - if( !res ) { - PyErr_Print(); - } - else{ - // parse the return value - // result can be one string... - if ( PyString_Check( res ) ) { - QString astr = PyString_AsString( res ); - //SCRUTE(astr); - theListOfFiles.append(astr); - } - //also result can be a list... - else if ( PyList_Check( res ) ) { - int size = PyList_Size( res ); - for ( int i = 0; i < size; i++ ) { - PyObject* value = PyList_GetItem( res, i ); - if( value && PyString_Check( value ) ) { - theListOfFiles.append( PyString_AsString( value ) ); - } - } - } - } - } -} - -/* - * Python dump request. - * Called when user activates dump study operation. - */ -void SALOME_PYQT_ModuleLight::dumpPython(QStringList& theListOfFiles) -{ - MESSAGE("SALOME_PYQT_ModuleLight::dumpPython()") - // perform synchronous request to Python event dispatcher - class DumpEvent: public PyInterp_LockRequest - { - public: - DumpEvent(PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj, - QStringList& _files_list) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj( _obj ) , - myFilesList(_files_list) {} - protected: - virtual void execute() - { - myObj->dumpEvent(myFilesList); - } - private: - SALOME_PYQT_ModuleLight* myObj; - QStringList& myFilesList; - }; - - // Posting the request only if dispatcher is not busy! - // Executing the request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new DumpEvent( myInterp, this, theListOfFiles ) ); -} - -void SALOME_PYQT_ModuleLight::dumpEvent(QStringList& theListOfFiles) -{ - MESSAGE("SALOME_PYQT_ModuleLight::dumpEvent()"); - QStringList::Iterator it = theListOfFiles.begin(); - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule || (it == theListOfFiles.end())) - return; - - if ( PyObject_HasAttrString(myModule, (char*)"dumpStudy") ) { - // temporary set myInitModule because dumpEvent() method - // might be called by the framework when this module is inactive, - // but still it should be possible to access this module's data - // from Python - myInitModule = this; - - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"dumpStudy", - (char*)"s", (*it).toLatin1().constData())); - - myInitModule = 0; - - if( !res ) { - PyErr_Print(); - } - else{ - // parse the return value - // result can be one string... - if ( PyString_Check( res ) ) { - QString astr = PyString_AsString( res ); - //SCRUTE(astr); - theListOfFiles.append(astr); - } - //also result can be a list... - else if ( PyList_Check( res ) ) { - int size = PyList_Size( res ); - for ( int i = 0; i < size; i++ ) { - PyObject* value = PyList_GetItem( res, i ); - if( value && PyString_Check( value ) ) { - theListOfFiles.append( PyString_AsString( value ) ); - } - } - } - } - } -} - -/* - * Open study request. - * Called when user open study. - */ -bool SALOME_PYQT_ModuleLight::open(QStringList theListOfFiles) -{ - MESSAGE("SALOME_PYQT_ModuleLight::open()"); - // perform synchronous request to Python event dispatcher - bool opened = false; - class OpenEvent: public PyInterp_LockRequest - { - public: - OpenEvent(PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj, - QStringList _files_list, - bool& _opened) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj( _obj ) , - myFilesList(_files_list), - myOpened(_opened) {} - protected: - virtual void execute() - { - myObj->openEvent(myFilesList,myOpened); - } - - private: - SALOME_PYQT_ModuleLight* myObj; - QStringList myFilesList; - bool& myOpened; - }; - - // Posting the request only if dispatcher is not busy! - // Executing the request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new OpenEvent( myInterp, this, theListOfFiles, opened) ); - return opened; -} - - -void SALOME_PYQT_ModuleLight::openEvent(QStringList theListOfFiles, bool &opened) -{ - MESSAGE("SALOME_PYQT_ModuleLight::openEvent()"); - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule || theListOfFiles.isEmpty()) - return; - QStringList* theList = new QStringList(theListOfFiles); - -#if SIP_VERSION < 0x040800 - PyObjWrapper sipList( sipBuildResult( 0, "M", theList, sipClass_QStringList) ); -#else - PyObjWrapper sipList( sipBuildResult( 0, "D", theList, sipType_QStringList, NULL ) ); -#endif - if ( PyObject_HasAttrString(myModule , (char*)"openFiles") ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"openFiles", - (char*)"O", sipList.get())); - if( !res || !PyBool_Check( res )) { - PyErr_Print(); - opened = false; - } - else{ - opened = PyObject_IsTrue( res ); - - } - } -} - -/* - * Create new empty Data Object and return its entry - */ -QString SALOME_PYQT_ModuleLight::createObject(const QString& parent) -{ - SALOME_PYQT_DataObjectLight* obj=0; - if(!parent.isEmpty()) - { - SALOME_PYQT_DataObjectLight* parentObj = findObject(parent); - if(parentObj) - { - obj = new SALOME_PYQT_DataObjectLight(parentObj); - } - } - else - { - SALOME_PYQT_DataModelLight* dm = - dynamic_cast( dataModel()); - if(dm) - { - obj = new SALOME_PYQT_DataObjectLight(dm->getRoot()); - } - } - if (obj) - return obj->entry(); - else - return QString::null; -} - -/* - * Create new Data Object with name, icon and tooltip - * and return its entry - */ -QString SALOME_PYQT_ModuleLight::createObject(const QString& aname, - const QString& iconname, - const QString& tooltip, - const QString& parent) -{ - QString entry = createObject(parent); - SALOME_PYQT_DataObjectLight* obj = findObject(entry); - - if(obj) - { - obj->setName(aname); - obj->setToolTip(tooltip); - obj->setIcon(iconname); - return obj->entry(); - } - else - return QString::null; -} - -/* - * Find object by entry - */ -SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject(const QString& entry) -{ - SALOME_PYQT_DataObjectLight* obj = 0; - SALOME_PYQT_DataModelLight* dm = - dynamic_cast( dataModel()); - if(!entry.isEmpty() && dm ){ - for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) { - SALOME_PYQT_DataObjectLight* curentobj = - dynamic_cast( it.current() ); - - if(curentobj && curentobj->entry() == entry) { - obj = curentobj; - return obj; - } + SALOME_PYQT_DataObjectLight* obj = 0; + SALOME_PYQT_DataModelLight* dm = + dynamic_cast( dataModel() ); + if ( !entry.isEmpty() && dm ) { + for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current() && !obj; ++it ) { + SALOME_PYQT_DataObjectLight* curentobj = + dynamic_cast( it.current() ); + if ( curentobj && curentobj->entry() == entry ) + obj = curentobj; } } return obj; } - -/* - * Set Name for object - */ -void SALOME_PYQT_ModuleLight::setName(const QString& obj, const QString& name) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) { - dataObj->setName(name); - } -} - -/* - * Set Icon for object - */ -void SALOME_PYQT_ModuleLight::setIcon(const QString& obj, const QString& iconname) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) { - dataObj->setIcon(iconname); - } -} - -/* - * Return Name of object - */ -QString SALOME_PYQT_ModuleLight::getName(const QString& obj) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) { - return dataObj->name(); - } - return QString::null; -} - -/* - * Return Tool Tip of object - */ -QString SALOME_PYQT_ModuleLight::getToolTip(const QString& obj) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) { - return dataObj->toolTip(); - } - return QString::null; -} - - -/* - * Set Tool Tip for object - */ -void SALOME_PYQT_ModuleLight::setToolTip(const QString& obj, const QString& tooltip) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) { - dataObj->setToolTip(tooltip); - } -} - -/* - * Return color of object - */ -QColor SALOME_PYQT_ModuleLight::getColor(const QString& obj) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject( obj ); - if( dataObj ) { - return dataObj->color( SUIT_DataObject::Foreground ); - } - return QColor(); -} - -/* - * Set color for object - */ -void SALOME_PYQT_ModuleLight::setColor(const QString& obj, const QColor& color) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject( obj ); - if( dataObj ) { - dataObj->setColor( color ); - } -} - -/* - * Return entry of the referenced object (if any) - */ -QString SALOME_PYQT_ModuleLight::getReference(const QString& obj) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) { - return dataObj->refEntry(); - } - return QString::null; -} - - -/* - * Set entry of the referenced object - */ -void SALOME_PYQT_ModuleLight::setReference(const QString& obj, const QString& refEntry) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) { - dataObj->setRefEntry(refEntry); - } -} - -/* - * Remove object by entry - */ -void SALOME_PYQT_ModuleLight::removeObject(const QString& obj) -{ - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) { - dataObj->parent()->removeChild(dataObj); - } -} - - -/* - * Remove chields from object - */ -void SALOME_PYQT_ModuleLight::removeChild(const QString& obj) -{ - MESSAGE("SALOME_PYQT_ModuleLight::removeChild()"); - DataObjectList lst; - if(!obj.isEmpty()) - { - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) - { - dataObj->children(lst); - QListIterator it( lst ); - while( it.hasNext() ) - { - SALOME_PYQT_DataObjectLight* sobj = dynamic_cast( it.next() ); - dataObj->removeChild(sobj); - } - } - } - else - { - SALOME_PYQT_DataModelLight* dm = - dynamic_cast( dataModel()); - if(dm) - { - dm->getRoot()->children(lst); - QListIterator it( lst ); - while(it.hasNext() ) - { - SALOME_PYQT_DataObjectLight* sobj = dynamic_cast( it.next() ); - dm->getRoot()->removeChild(sobj); - } - } - } -} - -QStringList SALOME_PYQT_ModuleLight::getChildren(const QString& obj, const bool rec) -{ - DataObjectList lst; - QStringList entryList; - if(!obj.isEmpty()) - { - SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); - if(dataObj) - { - dataObj->children(lst,rec); - QListIterator it( lst ); - while(it.hasNext()) - { - SALOME_PYQT_DataObjectLight* sobj = dynamic_cast( it.next() ); - entryList.append(sobj->entry()); - } - } - } - else - { - SALOME_PYQT_DataModelLight* dm = - dynamic_cast( dataModel()); - if(dm) - { - dm->getRoot()->children(lst); - QListIterator it( lst ); - while( it.hasNext() ) - { - SALOME_PYQT_DataObjectLight* sobj = dynamic_cast( it.next() ); - entryList.append(sobj->entry()); - } - } - } - return entryList; -} - -/*! - * Create new instance of data model and return it. - */ -CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel() -{ - MESSAGE( "SALOME_PYQT_ModuleLight::createDataModel()" ); - return new SALOME_PYQT_DataModelLight(this); -} - -/*! - * Returns the Python module object currently loaded. - */ -PyObject* SALOME_PYQT_ModuleLight::getPythonModule() -{ - return myModule; -} - -bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const -{ - MESSAGE("SALOME_PYQT_ModuleLight::isDraggable()"); - // perform synchronous request to Python event dispatcher - bool draggable = false; - class IsDraggableEvent: public PyInterp_LockRequest - { - public: - IsDraggableEvent(PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj, - LightApp_DataObject* _data_object, - bool& _is_draggable ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj( _obj ) , - myDataObject( _data_object ), - myIsDraggable( _is_draggable ) {} - protected: - virtual void execute() - { - myIsDraggable = myObj->isDraggableEvent( myDataObject ); - } - - private: - SALOME_PYQT_ModuleLight* myObj; - LightApp_DataObject* myDataObject; - bool& myIsDraggable; - }; - - const LightApp_DataObject* data_object = dynamic_cast( what ); - - // Posting the request only if dispatcher is not busy! - // Executing the request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new IsDraggableEvent( myInterp, - const_cast( this ), - const_cast( data_object ), - draggable ) ); - return draggable; -} - -bool SALOME_PYQT_ModuleLight::isDraggableEvent( LightApp_DataObject* what ) -{ - MESSAGE("SALOME_PYQT_ModuleLight::isDraggableEvent()"); - - bool draggable = false; - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule || !what ) - return draggable; - - if ( PyObject_HasAttrString(myModule , (char*)"isDraggable") ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"isDraggable", - (char*)"s", what->entry().toLatin1().constData() ) ); - if( !res || !PyBool_Check( res )) { - PyErr_Print(); - draggable = false; - } - else{ - draggable = PyObject_IsTrue( res ); - } - } - - return draggable; -} - -bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const -{ - MESSAGE("SALOME_PYQT_ModuleLight::isDropAccepted()"); - // perform synchronous request to Python event dispatcher - bool dropAccepted = false; - class IsDropAcceptedEvent: public PyInterp_LockRequest - { - public: - IsDropAcceptedEvent(PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj, - LightApp_DataObject* _data_object, - bool& _is_drop_accepted ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj( _obj ) , - myDataObject( _data_object ), - myIsDropAccepted( _is_drop_accepted ) {} - protected: - virtual void execute() - { - myIsDropAccepted = myObj->isDropAcceptedEvent( myDataObject ); - } - - private: - SALOME_PYQT_ModuleLight* myObj; - LightApp_DataObject* myDataObject; - bool& myIsDropAccepted; - }; - - const LightApp_DataObject* data_object = dynamic_cast( where ); - - // Posting the request only if dispatcher is not busy! - // Executing the request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new IsDropAcceptedEvent( myInterp, - const_cast( this ), - const_cast( data_object ), - dropAccepted ) ); - return dropAccepted; -} - -bool SALOME_PYQT_ModuleLight::isDropAcceptedEvent( LightApp_DataObject* where ) -{ - MESSAGE("SALOME_PYQT_ModuleLight::isDropAcceptedEvent()"); - - bool dropAccepted = false; - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule || !where ) - return dropAccepted; - - if ( PyObject_HasAttrString(myModule , (char*)"isDropAccepted") ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"isDropAccepted", - (char*)"s", where->entry().toLatin1().constData() ) ); - if( !res || !PyBool_Check( res )) { - PyErr_Print(); - dropAccepted = false; - } - else{ - dropAccepted = PyObject_IsTrue( res ); - } - } - - return dropAccepted; -} - -void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where, - const int row, Qt::DropAction action ) -{ - MESSAGE("SALOME_PYQT_ModuleLight::dropObjects()"); - // perform synchronous request to Python event dispatcher - class DropObjectsEvent: public PyInterp_LockRequest - { - public: - DropObjectsEvent(PyInterp_Interp* _py_interp, - SALOME_PYQT_ModuleLight* _obj, - const DataObjectList& _what, - SUIT_DataObject* _where, - const int _row, - Qt::DropAction _action ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj( _obj ) , - myWhat( _what ), - myWhere( _where ), - myRow ( _row ), - myAction ( _action ){} - protected: - virtual void execute() - { - myObj->dropObjectsEvent( myWhat, myWhere, myRow, myAction ); - } - - private: - SALOME_PYQT_ModuleLight* myObj; - DataObjectList myWhat; - SUIT_DataObject* myWhere; - int myRow; - Qt::DropAction myAction; - }; - - // Posting the request only if dispatcher is not busy! - // Executing the request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new DropObjectsEvent( myInterp, this, what, where, row, action ) ); -} - -void SALOME_PYQT_ModuleLight::dropObjectsEvent( const DataObjectList& what, SUIT_DataObject* where, - const int row, Qt::DropAction action ) -{ - MESSAGE("SALOME_PYQT_ModuleLight::dropObjectsEvent()"); - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule || what.isEmpty() || !where ) - return; - - QStringList* theList = new QStringList(); - - LightApp_DataObject* whereObject = dynamic_cast( where ); - if ( !whereObject ) return; - - for ( int i = 0; i < what.count(); i++ ) { - LightApp_DataObject* dataObject = dynamic_cast( what[i] ); - if ( dataObject ) theList->append( dataObject->entry() ); - } - -#if SIP_VERSION < 0x040800 - PyObjWrapper sipList( sipBuildResult( 0, "M", theList, sipClass_QStringList) ); -#else - PyObjWrapper sipList( sipBuildResult( 0, "D", theList, sipType_QStringList, NULL) ); -#endif - if ( PyObject_HasAttrString(myModule, (char*)"dropObjects") ) { - PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"dropObjects", (char*)"Osii", - sipList.get(), - whereObject->entry().toLatin1().constData(), - row, action ) ); - - if( !res ) { - PyErr_Print(); - } - } -} diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h index c2c92eac3..6807e0705 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h @@ -17,206 +17,91 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File : SALOME_PYQT_Module.h +// File : SALOME_PYQT_ModuleLight.h // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) -// + #ifndef SALOME_PYQT_MODULELIGHT_H #define SALOME_PYQT_MODULELIGHT_H -#include "PyInterp_Interp.h" // // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! #include "SALOME_PYQT_GUILight.h" + +#include "PyInterp_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! #include "LightApp_Module.h" -#include "SALOME_PYQT_DataObjectLight.h" -#include -#include -#include -#include -#include #include +#include +#include -class SALOME_PYQT_RootObjectLight; -class SALOME_PYQT_PyInterp; -class SUIT_ViewWindow; -class QAction; -class QtxActionGroup; class QMenu; +class PyModuleHelper; +class SALOME_PYQT_DataObjectLight; - -class SALOME_PYQT_LIGHT_EXPORT SALOME_PYQT_ModuleLight: virtual public LightApp_Module +class SALOME_PYQT_LIGHT_EXPORT SALOME_PYQT_ModuleLight: public LightApp_Module { Q_OBJECT; -private: - class XmlHandler; - - //! study to Python subinterpreter map - typedef QMap InterpMap; - static SALOME_PYQT_ModuleLight* myInitModule; //!< Python GUI being initialized (not zero only during the initialization) - - XmlHandler* myXmlHandler; //!< XML resource file parser - QMap myWindowsMap; //!< windows map - QStringList myViewMgrList;//!< compatible view managers list - bool myLastActivateStatus; //!< latest module activation status - -protected: - PyObject* myModule; //!< Python GUI module - PyInterp_Interp* myInterp; //!< current Python subinterpreter - static InterpMap myInterpMap; //!< study to Python subinterpreter map - public: SALOME_PYQT_ModuleLight(); ~SALOME_PYQT_ModuleLight(); public: - static SALOME_PYQT_ModuleLight* getInitModule(); - - void initialize( CAM_Application* ); - void windows( QMap& ) const; - void viewManagers( QStringList& ) const; - void contextMenuPopup( const QString&, QMenu*, QString& ); - void createPreferences(); - void studyActivated(); - void preferencesChanged( const QString&, const QString& ); - - static int defaultMenuGroup(); - - int createTool( const QString& ); - int createTool( const int, const int, const int = -1 ); - int createTool( const int, const QString&, const int = -1 ); - int createTool( QAction*, const int, - const int = -1, const int = -1 ); - int createTool( QAction*, const QString&, - const int = -1, const int = -1 ); - - int createMenu( const QString&, const int, - const int = -1, const int = -1, const int = -1 ); - int createMenu( const QString&, const QString&, - const int = -1, const int = -1, const int = -1 ); - int createMenu( const int, const int, - const int = -1, const int = -1 ); - int createMenu( const int, const QString&, - const int = -1, const int = -1 ); - int createMenu( QAction*, const int, - const int = -1, const int = -1, const int = -1 ); - int createMenu( QAction*, const QString&, - const int = -1, const int = -1, const int = -1 ); - - QAction* separator(); - - QAction* action( const int ) const; - int actionId( const QAction* ) const; - QAction* createAction( const int, const QString&, const QString&, - const QString&, const QString&, const int, - const bool = false, QObject* = 0 ); - QtxActionGroup* createActionGroup( const int, const bool ); - - - QIcon loadIcon( const QString& fileName ); - - int addGlobalPreference( const QString& ); - int addPreference( const QString& ); - int addPreference( const QString&, const int, const int = LightApp_Preferences::Auto, - const QString& = QString(), - const QString& = QString() ); - QVariant preferenceProperty( const int, const QString& ) const; - void setPreferenceProperty( const int, const QString&, - const QVariant& ); - - void save(QStringList& theListOfFiles); - bool open(QStringList theListOfFiles); - void dumpPython(QStringList& theListOfFiles); - - /*create new SALOME_PYQT_DataObjectLight and return its entry*/ - QString createObject(const QString& parent); - QString createObject(const QString& name, - const QString& iconname, - const QString& tooltip, - const QString& parent); - /*Sets Name, Icon and Tool Tip for object*/ - void setName(const QString& obj,const QString& iconname); - void setIcon(const QString& obj,const QString& name); - void setToolTip(const QString& obj, const QString& tooltip); - - /*Gets Name and Tool Tip for object*/ - QString getName(const QString& obj); - QString getToolTip(const QString& obj); - - void setColor(const QString& obj, const QColor& color); - QColor getColor(const QString& obj); - - void setReference( const QString& obj, - const QString& refEntry ); - QString getReference( const QString& obj ); - - /*remove object*/ - void removeObject(const QString& obj); - /*remove child*/ - void removeChild(const QString& obj); - /*return list of child objets*/ - QStringList getChildren(const QString& obj, const bool rec); - - /*Access to the underlying Python module object */ - PyObject* getPythonModule(); - - /*Drag and drop support*/ - virtual bool isDraggable( const SUIT_DataObject* ) const; - virtual bool isDropAccepted( const SUIT_DataObject* ) const; - virtual void dropObjects( const DataObjectList&, SUIT_DataObject*, - const int, Qt::DropAction ); - -public slots: - virtual bool activateModule( SUIT_Study* ); - virtual bool deactivateModule( SUIT_Study* ); - void preferenceChanged( const QString&, - const QString&, - const QString& ); - void onGUIEvent(); - - void onActiveViewChanged( SUIT_ViewWindow* ); - void onViewTryClose( SUIT_ViewWindow* ); - void onViewClosed( SUIT_ViewWindow* ); - void onViewCloned( SUIT_ViewWindow* ); + // module activation, preferences, menus + void initialize( CAM_Application* ); + bool activateModule( SUIT_Study* ); + bool deactivateModule( SUIT_Study* ); + void windows( QMap& ) const; + void viewManagers( QStringList& ) const; + void studyActivated(); + void contextMenuPopup( const QString&, QMenu*, QString& ); + void createPreferences(); + void preferencesChanged( const QString&, const QString& ); + + // persistence & dump python + void save( QStringList& ); + bool load( const QStringList& ); + void dumpPython( QStringList& ); + + // drag-n-drop support + bool isDraggable( const SUIT_DataObject* ) const; + bool isDropAccepted( const SUIT_DataObject* ) const; + void dropObjects( const DataObjectList&, SUIT_DataObject*, + const int, Qt::DropAction ); + + // data model management + QString createObject( const QString& ); + QString createObject( const QString&, + const QString&, + const QString&, + const QString& ); + + void setName( const QString&, const QString& ); + QString getName( const QString& ) const; + + void setIcon( const QString&, const QString& ); + + void setToolTip( const QString&, const QString& ); + QString getToolTip( const QString& ) const; + + void setColor( const QString&, const QColor& ); + QColor getColor( const QString& ) const; + + void setReference( const QString&, const QString& ); + QString getReference( const QString& ) const; + + void removeObject( const QString& ); + void removeChildren( const QString& ); + + QStringList getChildren( const QString&, const bool = false ) const; protected: - /* create data model */ - virtual CAM_DataModel* createDataModel(); - virtual bool activateModuleInternal( SUIT_Study* ); + CAM_DataModel* createDataModel(); + +private: + SALOME_PYQT_DataObjectLight* + findObject( const QString& ) const; private: - void init( CAM_Application* ); - void activate( SUIT_Study* ); - void deactivate( SUIT_Study* ); - bool lastActivationStatus() const; - void customize( SUIT_Study* ); - void studyChanged( SUIT_Study* ); - void contextMenu( const QString&, QMenu* ); - void guiEvent( const int ); - void initPreferences(); - void prefChanged( const QString&, const QString& ); - - virtual void initInterp ( int ); - void importModule(); - void setWorkSpace(); - - void activeViewChanged( const SUIT_ViewWindow* ); - void viewTryClose( const SUIT_ViewWindow* ); - void viewClosed( const SUIT_ViewWindow* ); - void viewCloned( const SUIT_ViewWindow* ); - void connectView( const SUIT_ViewWindow* ); - - void saveEvent(QStringList& theListOfFiles); - void dumpEvent(QStringList& theListOfFiles); - void openEvent(QStringList theListOfFiles, bool& opened); - - bool isDraggableEvent( LightApp_DataObject* ); - bool isDropAcceptedEvent( LightApp_DataObject* ); - void dropObjectsEvent( const DataObjectList&, SUIT_DataObject*, - const int, Qt::DropAction ); - - SALOME_PYQT_DataObjectLight* findObject(const QString& entry); - - friend class XmlHandler; + PyModuleHelper* myHelper; }; #endif // SALOME_PYQT_MODULELIGHT_H diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx new file mode 100644 index 000000000..d867ec45b --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx @@ -0,0 +1,2625 @@ +// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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. +// +// 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_PyModule.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#include "SALOME_PYQT_PyModule.h" +#include "SALOME_PYQT_PyInterp.h" + +#include "LightApp_Application.h" +#include "LightApp_DataObject.h" +#include "LightApp_Module.h" +#include "LightApp_Study.h" +#include "PyInterp_Dispatcher.h" +#include "QtxActionMenuMgr.h" +#include "QtxWorkspace.h" +#include "QtxWorkstack.h" +#include "STD_MDIDesktop.h" +#include "STD_TabDesktop.h" +#include "SUITApp_init_python.hxx" +#include "SUIT_ResourceMgr.h" +#include "SUIT_ViewManager.h" +#include "SUIT_ViewModel.h" +#include "SUIT_ViewWindow.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sipAPISalomePyQtGUILight.h" + +/*! + \brief Default menu group number. + \internal +*/ +const int DEFAULT_GROUP = 40; + +/*! + \brief Mutex used to lock access from several threads to the shared + (static) data + \internal +*/ +QMutex myInitMutex; + +/*! + \var IsCallOldMethods + \brief Allow calling obsolete callback methods. + \internal + + If the macro CALL_OLD_METHODS is not defined, the invoking + of obsolete Python module's methods like setSetting(), definePopup(), + etc. is blocked. + + CALL_OLD_METHODS macro can be defined, for example, by adding + -DCALL_OLD_METHODS compilation option to the Makefile. +*/ +#ifdef CALL_OLD_METHODS +const bool IsCallOldMethods = true; +#else +const bool IsCallOldMethods = false; +#endif + +/*! + \brief Get tag name for the DOM element. + \internal + \param element DOM element + \return tag name or empty string if the element does not have tag name +*/ +static QString tagName( const QDomElement& element ) +{ + return element.tagName().trimmed(); +} + +/*! + \brief Get value of DOM element's attribute. + \internal + \param element DOM element + \param attName attribute name + \return attribute value or empty string if the element does not have such attribute +*/ +static QString attribute( const QDomElement& element, const QString& attName ) +{ + return element.attribute( attName ).trimmed(); +} + +/*! + \brief Inspect specified string for the boolean value. + \internal + + This function returns \c true if string represents boolean value: + - "true", "yes" or "1" for \c true + - "false", "no" or "0" for \c false + Second parameter allows to specify what boolean value is expected: + - 1: \c true + - 0: \c false + - other value is not taken into account (return represented value) + + \param value inspected string + \param check expected boolean value + \return boolean value represented by the string (\a check is not 1 or 0) + or \c true if value correspond to the specified \a check +*/ +static bool checkBool( const QString& value, const int check = -1 ) +{ + QString v = value.toLower(); + if ( ( v == "true" || v == "yes" || v == "1" ) && ( check != 0 ) ) + return true; + if ( ( v == "false" || v == "no" || v == "0" ) && ( check == 0 ) ) + return true; + return false; +} + +/*! + \brief Inspect specified string for the integer value. + \internal + + This function returns returns -1 if item is empty or represents + an invalid number. + \param value inspected string + \param def default value + \param shift shift value (it is added to the integer value to produce shifted result) +*/ +static int checkInt( const QString& value, const int def = -1, const int shift = -1 ) +{ + bool bOk; + int val = value.toInt( &bOk ); + if ( !bOk ) val = def; + if ( shift > 0 && bOk && val < 0 ) + val += shift; + return val; +} + +/*! + \class FuncMsg + \brief Function call in/out tracer. + \internal +*/ + +class FuncMsg +{ +public: + FuncMsg( const QString& funcName ) + { + myName = funcName; + MESSAGE( qPrintable( myName ) << " [ begin ]" ); + } + ~FuncMsg() + { + MESSAGE( qPrintable( myName ) << " [ end ]" ); + } + void message( const QString& msg ) + { + MESSAGE( qPrintable( myName ) << " : " << qPrintable( msg ) ); + } +private: + QString myName; +}; + +/*! + \class PyModuleHelper::InitLocker + \brief Initialization locker + \internal +*/ + +class PyModuleHelper::InitLocker +{ +public: + InitLocker( LightApp_Module* ); + ~InitLocker(); +}; + +/*! + \brief Constructor + \internal +*/ +PyModuleHelper::InitLocker::InitLocker( LightApp_Module* module ) +{ + QMutexLocker ml( &myInitMutex ); + myInitModule = module; +} + +/*! + \brief Destructor + \internal +*/ +PyModuleHelper::InitLocker::~InitLocker() +{ + QMutexLocker ml( &myInitMutex ); + myInitModule = 0; +} + +/*! + \class PyModuleHelper::XmlHandler + \brief XML resource files parser. + \internal + + This class is used to provide backward compatibility with + existing Python modules in which obsolete menu definition system + (via XML files) is used. +*/ + +class PyModuleHelper::XmlHandler +{ +public: + XmlHandler( PyModuleHelper* helper, const QString& fileName ); + void createActions(); + void createPopup( QMenu* menu, + const QString& context, + const QString& parent, + const QString& object ); + void activateMenus( bool ); + +private: + LightApp_Module* module() const; + QIcon loadIcon( const QString& fileName ); + + void createMenu( QDomNode& parentNode, + const int parentMenuId = -1, + QMenu* parentPopup = 0 ); + void createToolBar( QDomNode& parentNode ); + void insertPopupItems( QDomNode& parentNode, + QMenu* menu ); + +private: + PyModuleHelper* myHelper; + QDomDocument myDoc; + QList myMenuItems; +}; + + +/*! + \brief Constructor + \internal + \param module pointer to the GUI module + \param fileName path to the XML menu description file +*/ +PyModuleHelper::XmlHandler::XmlHandler( PyModuleHelper* helper, + const QString& fileName ) +: myHelper( helper ) +{ + if ( !fileName.isEmpty() ) { + QFile aFile( fileName ); + if ( aFile.open( QIODevice::ReadOnly ) ) { + myDoc.setContent( &aFile ); + } + } +} + +/*! + \brief Parse XML file and create actions. + \internal + + Called by PyModuleHelper::initialize() in order to create actions + (menus, toolbars). +*/ +void PyModuleHelper::XmlHandler::createActions() +{ + // get document element + QDomElement aDocElem = myDoc.documentElement(); + + // create 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 ); + } +} + +/*! + \brief Create popup menu. + \internal + \param menu popup menu + \param context popup menu context + \param context popup menu parent object name + \param context popup menu object name +*/ +void PyModuleHelper::XmlHandler::createPopup( QMenu* menu, + const QString& context, + const QString& parent, + const QString& object ) +{ + // 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" ); // not used // + 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; + } + } + } +} + +/*! + \brief Activate/deactivate menus + \internal + \param enable if \c true menus are activated, otherwise menus are deactivated +*/ +void PyModuleHelper::XmlHandler::activateMenus( bool enable ) +{ + if ( module() ) { + QtxActionMenuMgr* mgr = module()->menuMgr(); + foreach( int id, myMenuItems ) mgr->setEmptyEnabled( id, enable ); + } +} + +/*! + \brief Get owner module +*/ +LightApp_Module* PyModuleHelper::XmlHandler::module() const +{ + return myHelper->module(); +} + +/*! + \brief Load an icon from the module resources by the specified file name. + \param fileName icon file name + \return icon object +*/ + +QIcon PyModuleHelper::XmlHandler::loadIcon( const QString& fileName ) +{ + QIcon icon; + + if ( module() && !fileName.isEmpty() ) { + SUIT_ResourceMgr* resMgr = module()->getApp()->resourceMgr(); + QPixmap pixmap = resMgr->loadPixmap( module()->name(), + QApplication::translate( module()->name().toLatin1().data(), + fileName.toLatin1().data() ) ); + if ( !pixmap.isNull() ) + icon = QIcon( pixmap ); + } + + return icon; +} + +/*! + \brief Create main menu item and insert actions to it. + \internal + \param parentNode XML node with menu description + \param parentMenuId parent menu ID (-1 for top-level menu) + \param parentPopup parent popup menu (0 for top-level menu) +*/ +void PyModuleHelper::XmlHandler::createMenu( QDomNode& parentNode, + const int parentMenuId, + QMenu* parentPopup ) +{ + if ( !module() || 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" ) ); + int group = checkInt( attribute( parentElement, "group-id" ), + PyModuleHelper::defaultMenuGroup() ); + if ( !plabel.isEmpty() ) { + QMenu* popup = 0; + int menuId = -1; + // create menu + menuId = module()->createMenu( plabel, // label + parentMenuId, // parent menu ID, -1 for top-level menu + pid, // ID + group, // group ID + ppos ); // position + myMenuItems.append( menuId ); + 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" ) ); + int group = checkInt( attribute( elem, "group-id" ), + PyModuleHelper::defaultMenuGroup() ); + QString label = attribute( elem, "label-id" ); + QIcon icon = loadIcon( attribute( elem, "icon-id" ) ); + QString tooltip = attribute( elem, "tooltip-id" ); + QString accel = attribute( elem, "accel-id" ); + bool toggle = checkBool( attribute( elem, "toggle-id" ) ); + + // -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 = module()->createAction( id, // ID + tooltip, // tooltip + icon, // icon + label, // menu text + tooltip, // status-bar text + QKeySequence( accel ), // keyboard accelerator + module(), // action owner + toggle ); // toogled action + myHelper->connectAction( action ); + module()->createMenu( action, // action + menuId, // parent menu ID + id, // ID (same as for createAction()) + group, // group ID + pos ); // position + } + } + else if ( aTagName == "submenu" ) { + // create sub-menu + createMenu( node, menuId, popup ); + } + else if ( aTagName == "separator" ) { + // create menu separator + int id = checkInt( attribute( elem, "item-id" ) ); // separator can have ID + int pos = checkInt( attribute( elem, "pos-id" ) ); + int group = checkInt( attribute( elem, "group-id" ), + PyModuleHelper::defaultMenuGroup() ); + QAction* action = module()->separator(); + module()->createMenu( action, // separator action + menuId, // parent menu ID + id, // ID + group, // group ID + pos ); // position + } + } + node = node.nextSibling(); + } + } + } +} + +/*! + \brief Create a toolbar and insert actions to it. + \param parentNode XML node with toolbar description +*/ +void PyModuleHelper::XmlHandler::createToolBar( QDomNode& parentNode ) +{ + if ( !module() || parentNode.isNull() ) + return; + + QDomElement parentElement = parentNode.toElement(); + if ( !parentElement.isNull() ) { + QString aLabel = attribute( parentElement, "label-id" ); + if ( !aLabel.isEmpty() ) { + // create toolbar + int tbId = module()->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" ); + QIcon icon = loadIcon( attribute( elem, "icon-id" ) ); + QString tooltip = attribute( elem, "tooltip-id" ); + QString accel = attribute( elem, "accel-id" ); + bool toggle = checkBool( attribute( elem, "toggle-id" ) ); + + // -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 toolbar action + QAction* action = module()->createAction( id, // ID + tooltip, // tooltip + icon, // icon + label, // menu text + tooltip, // status-bar text + QKeySequence( accel ), // keyboard accelerator + module(), // action owner + toggle ); // toogled action + myHelper->connectAction( action ); + module()->createTool( action, tbId, -1, pos ); + } + } + else if ( aTagName == "separatorTB" || aTagName == "separator" ) { + // create toolbar separator + int pos = checkInt( attribute( elem, "pos-id" ) ); + QAction* action = module()->separator(); + module()->createTool( action, tbId, -1, pos ); + } + } + node = node.nextSibling(); + } + } + } +} + +/*! + \brief Fill popup menu with the items. + \param parentNode XML node with popup menu description + \param menu popup menu +*/ +void PyModuleHelper::XmlHandler::insertPopupItems( QDomNode& parentNode, QMenu* menu ) +{ + if ( !module() && 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 ); + QList actions = menu->actions(); + 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" ); + QIcon icon = loadIcon( attribute( elem, "icon-id" ) ); + QString tooltip = attribute( elem, "tooltip-id" ); + QString accel = attribute( elem, "accel-id" ); + bool toggle = checkBool( attribute( elem, "toggle-id" ) ); + + // -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 ) { + QAction* action = module()->createAction( id, // ID + tooltip, // tooltip + icon, // icon + label, // menu text + tooltip, // status-bar text + QKeySequence( accel ), // keyboard accelerator + module(), // action owner + toggle ); // toogled action + myHelper->connectAction( action ); + QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; + menu->insertAction( before, action ); + } + } + else if ( aTagName == "submenu" ) { + // create sub-menu + ////int id = checkInt( attribute( elem, "item-id" ) ); // not used // + int pos = checkInt( attribute( elem, "pos-id" ) ); + QString label = attribute( elem, "label-id" ); + QString icon = attribute( elem, "icon-id" ); + + QIcon anIcon; + if ( !icon.isEmpty() ) { + QPixmap pixmap = module()->getApp()->resourceMgr()->loadPixmap( module()->name(), icon ); + if ( !pixmap.isNull() ) + anIcon = QIcon( pixmap ); + } + + QMenu* newPopup = menu->addMenu( anIcon, label ); + QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; + menu->insertMenu( before, newPopup ); + insertPopupItems( node, newPopup ); + } + else if ( aTagName == "separator" ) { + // create menu separator + int pos = checkInt( attribute( elem, "pos-id" ) ); + QAction* action = module()->separator(); + QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; + menu->insertAction( before, action ); + } + } + node = node.nextSibling(); + } +} + +/*! + \class PyModuleHelper + \brief This class implements API helper for all the Python-based + SALOME GUI modules. +*/ + +PyModuleHelper::InterpMap PyModuleHelper::myInterpMap; +LightApp_Module* PyModuleHelper::myInitModule = 0; + +/*! + \brief Constructor + \param module owner module +*/ +PyModuleHelper::PyModuleHelper( LightApp_Module* module ) : + QObject( module ), + myModule( module ), + myPyModule( 0 ), + myInterp( 0 ), + myXmlHandler ( 0 ), + myLastActivateStatus( true ) +{ + setObjectName( "python_module_helper" ); +} + +/*! + \brief Destructor +*/ +PyModuleHelper::~PyModuleHelper() +{ + delete myXmlHandler; + if ( myInterp && myPyModule ) { + PyLockWrapper aLock = myInterp->GetLockWrapper(); + Py_XDECREF( myPyModule ); + } +} + +/*! + \brief Get the module being initialized. + + This is a little trick :) needed to provide an access from Python + (SalomePyQt) to the module being currently activated. The problem + that during the process of module initialization (initialize() + function) it is not yet available via application->activeModule() + call. + + This method returns valid pointer only if called in scope of + initialize() function or in several other specific cases. + + \return the module being currently initialized +*/ +LightApp_Module* PyModuleHelper::getInitModule() +{ + QMutexLocker ml( &myInitMutex ); + return myInitModule; +} + +/*! + \brief Get default menu group identifier + \return menu group ID (40 by default) +*/ +int PyModuleHelper::defaultMenuGroup() +{ + return DEFAULT_GROUP; +} + +/*! + \brief Get owner module + \return owner module +*/ +LightApp_Module* PyModuleHelper::module() const +{ + return myModule; +} + +/*! + \brief Get Python GUI module object + \return python module +*/ +PyObject* PyModuleHelper::pythonModule() const +{ + return myPyModule; +} + +/*! + \brief Connect action to the internal actionActivated() slot. + + Actions connected to internal actionActivated(), when activated, will + be forwarded to the Python GUI module OnGUIEvent() function. + + \param a action being connected +*/ +void PyModuleHelper::connectAction( QAction* a ) +{ + if ( myModule && a ) + QObject::connect( a, SIGNAL( triggered( bool ) ), + this, SLOT( actionActivated() ), + Qt::UniqueConnection ); +} + +/*! + \brief Get the dockable windows associated with the module. + + To fill the list of windows the correspondind Python module's windows() + method is called during the module initialization. + + By default, ObjectBrowser, PythonConsole and LogWindow windows are + associated to the module. + + Allowed dockable windows: + - LightApp_Application::WT_ObjectBrowser : object browser + - LightApp_Application::WT_PyConsole : python console + - LightApp_Application::WT_LogWindow : log messages output window + + Dock area is defined by Qt::DockWidgetArea enumeration: + - Qt::TopDockWidgetArea : top dock area + - Qt::BottomDockWidgetArea : bottom dock area + - Qt::LeftDockWidgetArea : left dock area + - Qt::RightDockWidgetArea : right dock area + + \return map of dockable windows in form { : } +*/ +QMap PyModuleHelper::windows() const +{ + FuncMsg fmsg( "PyModuleHelper::windows()" ); + + return myWindowsMap; +} + +/*! + \brief Define the compatible view windows associated with the module. + + The associated view windows are opened automatically when the module + is activated. + + To fill the list of views the correspondind Python module's views() + method is called during the module initialization. + By default, the list of view types is empty. + + \return list of view windows types +*/ +QStringList PyModuleHelper::viewManagers() const +{ + FuncMsg fmsg( "PyModuleHelper::viewManagers()" ); + + return myViewMgrList; +} + +/*! + \brief Initialization of the Python-based SALOME module. + + This method can be used for creation of the menus, toolbars and + other such staff. + + There are two ways to do this: + 1) for obsolete modules implementatino this method first tries to read + _.xml resource file which contains a menu, + toolbars and popup menus description; + 2) new modules can create menus by direct calling of the + corresponding methods of SalomePyQt Python API in the Python + module's initialize() method which is called from here. + + \note SALOME supports two modes of modules loading: + - immediate (all the modules are created and initialized + immediately when the application object is created; + - postponed modules loading (used currently); in this mode + the module is loaded only by explicit request. + If postponed modules loading is not used, the active + study might be not yet defined at this stage, so initialize() + method should not perform any study-based initialization. + Such actions can be better done in activate() function. + + \param app parent application object +*/ +void PyModuleHelper::initialize( CAM_Application* app ) +{ + FuncMsg fmsg( "PyModuleHelper::initialize()" ); + + // temporarily store module being currently activated + // in the global variable to make it accessible from + // Python API + InitLocker lock( myModule ); + + // try to get XML resource file name + SUIT_ResourceMgr* resMgr = myModule->getApp()->resourceMgr(); + if ( !myXmlHandler && resMgr ) { + // get current language + QString lang = resMgr->stringValue( "language", "language", "en" ); + // get menu description file name + QString aFileName = QString( "%1_%2.xml" ).arg( myModule->name() ).arg( lang ); + aFileName = resMgr->path( "resources", myModule->name(), aFileName ); + if ( !aFileName.isEmpty() && QFile::exists( aFileName ) ) { + // create XML handler instance + myXmlHandler = new XmlHandler( this, aFileName ); + // ask XML handler to create actions + myXmlHandler->createActions(); + } + } + + class InitializeReq : public PyInterp_Request + { + public: + InitializeReq( PyModuleHelper* _helper, + CAM_Application* _app ) + : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ), + myApp( _app ) + {} + protected: + virtual void execute() + { + myHelper->internalInitialize( myApp ); + } + private: + PyModuleHelper* myHelper; + CAM_Application* myApp; + }; + + // post request + PyInterp_Dispatcher::Get()->Exec( new InitializeReq( this, app ) ); +} + +/*! + \brief Activation of the module. + + This function is usually used in order to show the module's + specific menus and toolbars, update actions state and perform + other such actions required when the module is activated. + + \note Returning \c false from this function prevents the + module activation. + + \param study parent study + \return \c true if activation is successful and \c false otherwise +*/ +bool PyModuleHelper::activate( SUIT_Study* study ) +{ + FuncMsg fmsg( "PyModuleHelper::activate()" ); + + // reset the activation status to the default value + myLastActivateStatus = true; + + class ActivateReq : public PyInterp_Request + { + public: + ActivateReq( PyModuleHelper* _helper, + SUIT_Study* _study, + bool _customize ) + : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ), + myStudy ( _study ), + myCustomize( _customize ) + {} + protected: + virtual void execute() + { + if ( !myCustomize ) + myHelper->internalActivate( myStudy ); // first activation stage + else + myHelper->internalCustomize( myStudy ); // second activation stage + } + private: + PyModuleHelper* myHelper; + SUIT_Study* myStudy; + bool myCustomize; + }; + + // post request for activation (customize=false) + PyInterp_Dispatcher::Get()->Exec( new ActivateReq( this, study, false ) ); + + // check activation status (can be set to false by internalActivate()) + if ( myLastActivateStatus ) { + // activate menus, toolbars, etc + if ( myXmlHandler ) myXmlHandler->activateMenus( true ); + + // show menus / toolbars + myModule->setMenuShown( true ); + myModule->setToolShown( true ); + + // post request for customization (customize=true) + PyInterp_Dispatcher::Get()->Exec( new ActivateReq( this, study, true ) ); + + // check activation status (can be set to false by internalCustomize()) + if ( myLastActivateStatus ) { + // connect preferences changing signal + connect( myModule->getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ), + this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); + + // connect active view change signal + SUIT_Desktop* d = study->application()->desktop(); + connect( d, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), + this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) ); + // if active window exists, call activeViewChanged() function; + // temporary solution: if a getActiveView() in SalomePyQt available + // we no longer need this + SUIT_ViewWindow* view = d->activeWindow(); + if ( view ) activeViewChanged( view ); + // get all view currently opened in the study and connect their signals to + // the corresponding slots of the class. + foreach ( view, d->windows() ) connectView( view ); + } + else { + // hide menus / toolbars in case of error + myModule->setMenuShown( false ); + myModule->setToolShown( false ); + } + } + + return myLastActivateStatus; +} + +/*! + \brief Deactivation of the module. + + This function is usually used in order to hide the module's + specific menus and toolbars and perform other such actions + required when the module is deactivated. + + \param study parent study + \return \c true if deactivation is successful and \c false otherwise +*/ +bool PyModuleHelper::deactivate( SUIT_Study* study ) +{ + FuncMsg fmsg( "PyModuleHelper::deactivate()" ); + + class DeactivateReq : public PyInterp_LockRequest + { + public: + DeactivateReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + SUIT_Study* _study ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ), + myStudy ( _study ) + {} + protected: + virtual void execute() + { + myHelper->internalDeactivate( myStudy ); + } + private: + PyModuleHelper* myHelper; + SUIT_Study* myStudy; + }; + + // post request + PyInterp_Dispatcher::Get()->Exec( new DeactivateReq( myInterp, this, study ) ); + + // disconnect preferences changing signal + disconnect( myModule->getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ), + this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); + + // disconnect the SUIT_Desktop signal windowActivated() + SUIT_Desktop* d = study->application()->desktop(); + disconnect( d, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), + this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) ); + + // deactivate menus, toolbars, etc + if ( myXmlHandler ) myXmlHandler->activateMenus( false ); + + // hide menus / toolbars + myModule->setMenuShown( false ); + myModule->setToolShown( false ); + + return true; +} + +/*! + \brief Process module's preferences changing. + + Called when the module's own preferences are changed. + + \param section preference resources section + \param parameter preference resources parameter name +*/ +void PyModuleHelper::preferencesChanged( const QString& section, + const QString& parameter ) +{ + FuncMsg fmsg( "PyModuleHelper::preferencesChanged()" ); + + class PrefChangeReq : public PyInterp_LockRequest + { + public: + PrefChangeReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + const QString& _section, + const QString& _parameter ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper ( _helper ), + mySection( _section ), + myParameter( _parameter ) + {} + protected: + virtual void execute() + { + myHelper->internalPreferencesChanged( mySection, myParameter ); + } + private: + PyModuleHelper* myHelper; + QString mySection, myParameter; + }; + + // post the request only if dispatcher is not busy! + // execute request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new PrefChangeReq( myInterp, this, section, parameter ) ); +} + +/*! + \brief Process application preferences changing. + + Called when any application setting is changed. + + \param module preference module + \param section preference resources section + \param parameter preference resources parameter name +*/ +void PyModuleHelper::preferenceChanged( const QString& module, + const QString& section, + const QString& parameter ) +{ + FuncMsg fmsg( "PyModuleHelper::preferenceChanged()" ); + + // module's own preferences are processed by other preferencesChanged() method + if ( module != myModule->moduleName() ) { + // call helper + preferencesChanged( section, parameter ); + } +} + +/*! + \brief Process study activation. + + Called when study desktop is activated. Used for notifying the Python + module about changing of the active study. + + \param study study being activated +*/ +void PyModuleHelper::studyActivated( SUIT_Study* study ) +{ + FuncMsg fmsg( "PyModuleHelper::studyActivated()" ); + + // StudyChangedReq: request class for internal studyChanged() operation + class StudyChangedReq : public PyInterp_Request + { + public: + StudyChangedReq( PyModuleHelper* _helper, + SUIT_Study* _study ) + : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ), + myStudy ( _study ) + {} + protected: + virtual void execute() + { + myHelper->internalStudyChanged( myStudy ); + } + private: + PyModuleHelper* myHelper; + SUIT_Study* myStudy; + }; + + // post request + PyInterp_Dispatcher::Get()->Exec( new StudyChangedReq( this, study ) ); +} + +/*! + \brief Process action activation. + + Called when action is activated. Used for notifying the Python + module about any related action activation. + + \sa connectAction() +*/ +void PyModuleHelper::actionActivated() +{ + FuncMsg fmsg( "PyModuleHelper::actionActivated()" ); + + // perform synchronous request to Python event dispatcher + class ActionReq : public PyInterp_LockRequest + { + public: + ActionReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + int _id ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ), + myId ( _id ) + {} + protected: + virtual void execute() + { + myHelper->internalActionActivated( myId ); + } + private: + PyModuleHelper* myHelper; + int myId; + }; + + // get sender action + QAction* action = qobject_cast( sender() ); + if ( !action ) + return; + + // post request + PyInterp_Dispatcher::Get()->Exec( new ActionReq( myInterp, this, myModule->actionId( action ) ) ); +} + +/*! + \brief Process context popup menu request. + + Called when user activates popup menu in some window + (view, object browser, etc). + + \param context popup menu context (e.g. "ObjectBrowser") + \param menu popup menu +*/ +void PyModuleHelper::contextMenu( const QString& context, QMenu* menu ) +{ + FuncMsg fmsg( "PyModuleHelper::contextMenu()" ); + + class ContextMenuReq : public PyInterp_LockRequest + { + public: + ContextMenuReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + const QString& _context, + QMenu* _menu ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper ( _helper ), + myContext( _context ), + myMenu ( _menu ) + {} + protected: + virtual void execute() + { + myHelper->internalContextMenu( myContext, myMenu ); + } + private: + PyModuleHelper* myHelper; + QString myContext; + QMenu* myMenu; + }; + + // post request only if dispatcher is not busy! + // execute request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new ContextMenuReq( myInterp, this, context, menu ) ); +} + +/*! + \brief Export preferences for the Python module. + Called only once when the first instance of the module is created or + when common Preferences dialog box is first time invoked. +*/ +void PyModuleHelper::createPreferences() +{ + FuncMsg fmsg( "PyModuleHelper::createPreferences()" ); + + // temporary set myInitModule because createPreferences() method + // might be called during the module intialization process + InitLocker lock( myModule ); + + class CreatePrefReq : public PyInterp_LockRequest + { + public: + CreatePrefReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ) + {} + protected: + virtual void execute() + { + myHelper->internalCreatePreferences(); + } + private: + PyModuleHelper* myHelper; + }; + + // post request only if dispatcher is not busy! + // execute request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new CreatePrefReq( myInterp, this ) ); +} + +/*! + \brief Signal handler windowActivated(SUIT_ViewWindow*) of SUIT_Desktop + + Used to notify Python module that active view has been changed by the user. + + \param view view being activated +*/ +void PyModuleHelper::activeViewChanged( SUIT_ViewWindow* view ) +{ + FuncMsg fmsg( "PyModuleHelper::activeViewChanged()" ); + + // perform synchronous request to Python event dispatcher + class ActiveViewChangeReq : public PyInterp_LockRequest + { + public: + ActiveViewChangeReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + SUIT_ViewWindow* _view ) + : PyInterp_LockRequest( _py_interp, 0, true ), + myHelper( _helper ), + myView( _view ) + {} + protected: + virtual void execute() + { + myHelper->internalActiveViewChanged( myView ); + } + private: + PyModuleHelper* myHelper; + SUIT_ViewWindow* myView; + }; + + // connect view (if it is not connected yet) + connectView( view ); + + PyInterp_Dispatcher::Get()->Exec( new ActiveViewChangeReq( myInterp, this, view ) ); +} + +/*! + \brief Signal handler tryClose(SUIT_ViewWindow*) of a view + \param view view being closed +*/ +void PyModuleHelper::tryCloseView( SUIT_ViewWindow* view ) +{ + FuncMsg fmsg( "PyModuleHelper::tryCloseView()" ); + + class TryCloseViewReq : public PyInterp_LockRequest + { + public: + TryCloseViewReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + SUIT_ViewWindow* _view ) + : PyInterp_LockRequest( _py_interp, 0, true ), + myHelper( _helper ), + myView( _view ) + {} + protected: + virtual void execute() + { + myHelper->internalTryCloseView( myView ); + } + private: + PyModuleHelper* myHelper; + SUIT_ViewWindow* myView; + }; + + PyInterp_Dispatcher::Get()->Exec( new TryCloseViewReq( myInterp, this, view ) ); +} + +/*! + \brief Signal handler closing(SUIT_ViewWindow*) of a view + \param view view being closed +*/ +void PyModuleHelper::closeView( SUIT_ViewWindow* view ) +{ + FuncMsg fmsg( "PyModuleHelper::closeView()" ); + + class CloseViewReq : public PyInterp_LockRequest + { + public: + CloseViewReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + SUIT_ViewWindow* _view ) + : PyInterp_LockRequest( _py_interp, 0, true ), + myHelper( _helper ), + myView( _view ) + {} + protected: + virtual void execute() + { + myHelper->internalCloseView( myView ); + } + private: + PyModuleHelper* myHelper; + SUIT_ViewWindow* myView; + }; + + PyInterp_Dispatcher::Get()->Exec( new CloseViewReq( myInterp, this, view ) ); +} + +/*! + \brief Signal handler cloneView() of OCCViewer_ViewWindow + \param view view being cloned +*/ +void PyModuleHelper::cloneView( SUIT_ViewWindow* view ) +{ + FuncMsg fmsg( "PyModuleHelper::cloneView()" ); + + class CloneViewReq : public PyInterp_LockRequest + { + public: + CloneViewReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + SUIT_ViewWindow* _view ) + : PyInterp_LockRequest( _py_interp, 0, true ), + myHelper( _helper ), + myView( _view ) + {} + protected: + virtual void execute() + { + myHelper->internalCloneView( myView ); + } + private: + PyModuleHelper* myHelper; + SUIT_ViewWindow* myView; + }; + + PyInterp_Dispatcher::Get()->Exec( new CloneViewReq( myInterp, this, view ) ); +} + +/*! + \brief Save module data. Called when user saves study. + \param files output list of files where module stores data +*/ +void PyModuleHelper::save( QStringList& files ) +{ + FuncMsg fmsg( "PyModuleHelper::save()" ); + + // temporary set myInitModule because save() method + // might be called by the framework when this module is inactive, + // but still it should be possible to access this module's data + // from Python + InitLocker lock( myModule ); + + // perform synchronous request to Python event dispatcher + class SaveReq: public PyInterp_LockRequest + { + public: + SaveReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + QStringList& _files ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ) , + myFiles( _files ) + {} + protected: + virtual void execute() + { + myHelper->internalSave( myFiles ); + } + private: + PyModuleHelper* myHelper; + QStringList& myFiles; + }; + + // Posting the request only if dispatcher is not busy! + // Executing the request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new SaveReq( myInterp, this, files ) ); +} + +/* + \brief Load module data. Called when user opens study + and activates module. + \param files list of files where module data is stored +*/ +bool PyModuleHelper::load( const QStringList& files ) +{ + FuncMsg fmsg( "PyModuleHelper::load()" ); + + bool loaded = false; + + class LoadReq: public PyInterp_LockRequest + { + public: + LoadReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + QStringList _files, + bool& _loaded ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ) , + myFiles( _files ), + myLoaded( _loaded ) + {} + protected: + virtual void execute() + { + myHelper->internalLoad( myFiles, myLoaded ); + } + private: + PyModuleHelper* myHelper; + QStringList myFiles; + bool& myLoaded; + }; + + // Posting the request only if dispatcher is not busy! + // Executing the request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new LoadReq( myInterp, this, files, loaded ) ); + + return loaded; +} + +/*! + \brief Dump module data to the Python script. + Called when user activates dump study operation. + \param files output list of files where module stores python script +*/ +void PyModuleHelper::dumpPython( QStringList& files ) +{ + FuncMsg fmsg( "PyModuleHelper::dumpPython()" ); + + // temporary set myInitModule because dumpPython() method + // might be called by the framework when this module is inactive, + // but still it should be possible to access this module's data + // from Python + InitLocker lock( myModule ); + + class DumpPythonReq: public PyInterp_LockRequest + { + public: + DumpPythonReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + QStringList& _files ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ) , + myFiles( _files ) + {} + protected: + virtual void execute() + { + myHelper->internalDumpPython( myFiles ); + } + private: + PyModuleHelper* myHelper; + QStringList& myFiles; + }; + + // Posting the request only if dispatcher is not busy! + // Executing the request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new DumpPythonReq( myInterp, this, files ) ); +} + +/*! + \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 +*/ +bool PyModuleHelper::isDraggable( const SUIT_DataObject* what ) const +{ + FuncMsg fmsg( "PyModuleHelper::isDraggable()" ); + + bool draggable = false; + + // perform synchronous request to Python event dispatcher + class IsDraggableReq: public PyInterp_LockRequest + { + public: + IsDraggableReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + LightApp_DataObject* _data_object, + bool& _is_draggable ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ) , + myDataObject( _data_object ), + myIsDraggable( _is_draggable ) + {} + protected: + virtual void execute() + { + myIsDraggable = myHelper->internalIsDraggable( myDataObject ); + } + private: + PyModuleHelper* myHelper; + LightApp_DataObject* myDataObject; + bool& myIsDraggable; + }; + + const LightApp_DataObject* data_object = dynamic_cast( what ); + if ( data_object ) { + // Posting the request only if dispatcher is not busy! + // Executing the request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new IsDraggableReq( myInterp, + const_cast( this ), + const_cast( data_object ), + draggable ) ); + } + + return draggable; +} + +/*! + \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 +*/ +bool PyModuleHelper::isDropAccepted( const SUIT_DataObject* where ) const +{ + FuncMsg fmsg( "PyModuleHelper::isDropAccepted()" ); + + bool dropAccepted = false; + + // perform synchronous request to Python event dispatcher + class IsDropAcceptedReq: public PyInterp_LockRequest + { + public: + IsDropAcceptedReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + LightApp_DataObject* _data_object, + bool& _is_drop_accepted ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ) , + myDataObject( _data_object ), + myIsDropAccepted( _is_drop_accepted ) + {} + protected: + virtual void execute() + { + myIsDropAccepted = myHelper->internalIsDropAccepted( myDataObject ); + } + private: + PyModuleHelper* myHelper; + LightApp_DataObject* myDataObject; + bool& myIsDropAccepted; + }; + + const LightApp_DataObject* data_object = dynamic_cast( where ); + if ( data_object ) { + // Posting the request only if dispatcher is not busy! + // Executing the request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new IsDropAcceptedReq( myInterp, + const_cast( this ), + const_cast( data_object ), + dropAccepted ) ); + } + + return dropAccepted; +} + +/*! + \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) +*/ +void PyModuleHelper::dropObjects( const DataObjectList& what, SUIT_DataObject* where, + const int row, Qt::DropAction action ) +{ + FuncMsg fmsg( "PyModuleHelper::dropObjects()" ); + + // perform synchronous request to Python event dispatcher + class DropObjectsReq: public PyInterp_LockRequest + { + public: + DropObjectsReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + const DataObjectList& _what, + SUIT_DataObject* _where, + const int _row, + Qt::DropAction _action ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ) , + myWhat( _what ), + myWhere( _where ), + myRow( _row ), + myAction ( _action ) + {} + protected: + virtual void execute() + { + myHelper->internalDropObjects( myWhat, myWhere, myRow, myAction ); + } + private: + PyModuleHelper* myHelper; + DataObjectList myWhat; + SUIT_DataObject* myWhere; + int myRow; + Qt::DropAction myAction; + }; + + // Posting the request only if dispatcher is not busy! + // Executing the request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new DropObjectsReq( myInterp, this, what, where, row, action ) ); +} + +/*! + \brief Get module engine IOR + \return engine IOR as it is supplied by GUI Python module + */ +QString PyModuleHelper::engineIOR() const +{ + FuncMsg fmsg( "PyModuleHelper::engineIOR()" ); + + class EngineIORReq : public PyInterp_LockRequest + { + public: + EngineIORReq( PyInterp_Interp* _py_interp, + PyModuleHelper* _helper, + QString& _ior ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ), + myIOR( _ior ) + {} + protected: + virtual void execute() + { + myIOR = myHelper->internalEngineIOR(); + } + private: + PyModuleHelper* myHelper; + QString& myIOR; + }; + + static QString anIOR; + + if ( anIOR.isEmpty() ) { + // post request + PyInterp_Dispatcher::Get()->Exec( new EngineIORReq( myInterp, + const_cast( this ), + anIOR ) ); + } + + return anIOR; +} + +/*! + \brief Initialize python subinterpreter (one per study). + \internal + \param studyId study ID +*/ +void PyModuleHelper::initInterp( int studyId ) +{ + FuncMsg fmsg( "--- PyModuleHelper::initInterp()" ); + + // check study Id + if ( !studyId ) { + // Error! Study Id must not be 0! + myInterp = 0; + return; + } + + QMutexLocker ml( &myInitMutex ); + + // try to find the subinterpreter + if ( myInterpMap.contains( studyId ) ) { + // found! + myInterp = myInterpMap[ studyId ]; + return; + } + + myInterp = new SALOME_PYQT_PyInterp(); + myInterp->initialize(); + myInterpMap[ studyId ] = myInterp; + +#ifndef GUI_DISABLE_CORBA + if ( !SUIT_PYTHON::initialized ) { + // 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 + int embedded = 1; + PyObjWrapper aRes( PyObject_CallMethod( aMod, (char*)"salome_init", (char*)"ii", studyId, embedded ) ); + if ( !aRes ) { + // Error! + PyErr_Print(); + return; + } + } +#endif +} + +/*! + \brief Import Python GUI module and store reference to the module. + \internal + + Attention! initInterp() should be called first!!! +*/ +void PyModuleHelper::importModule() +{ + FuncMsg fmsg( "--- PyModuleHelper::importModule()" ); + + // check if the subinterpreter is initialized + if ( !myInterp ) { + // Error! Python subinterpreter should be initialized first! + myPyModule = 0; + return; + } + + // import Python GUI module and put it in attribute + // ... first get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + // ... then import a module + QString aMod = QString( "%1GUI" ).arg( myModule->name() ); + try { + myPyModule = PyImport_ImportModule( aMod.toLatin1().data() ); + } + catch (...) { + } + + if ( !myPyModule ) { + // Error! + PyErr_Print(); + return; + } +} + +/*! + \brief Set study workspace to the Python module. + \internal + + Calls setWorkSpace() method of the Python module with + PyQt QWidget object to use with interpreter. + + Attention! initInterp() and importModule() should be called first!!! +*/ +void PyModuleHelper::setWorkSpace() +{ + FuncMsg fmsg( "--- PyModuleHelper::setWorkSpace()" ); + + if ( !IsCallOldMethods ) + return; + + // check if the subinterpreter is initialized and Python module is imported + if ( !myInterp || !myPyModule ) { + // 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; + } + + // ... then get workspace object + QWidget* aWorkspace = 0; + if ( myModule->getApp()->desktop()->inherits( "STD_MDIDesktop" ) ) { + STD_MDIDesktop* d = dynamic_cast( myModule->getApp()->desktop() ); + if ( d ) + aWorkspace = d->workspace(); + } + else if ( myModule->getApp()->desktop()->inherits( "STD_TabDesktop" ) ) { + STD_TabDesktop* d = dynamic_cast( myModule->getApp()->desktop() ); + if ( d ) + aWorkspace = d->workstack(); + } +#if SIP_VERSION < 0x040800 + PyObjWrapper pyws( sipBuildResult( 0, "M", aWorkspace, sipClass_QWidget) ); +#else + PyObjWrapper pyws( sipBuildResult( 0, "D", aWorkspace, sipType_QWidget , NULL) ); +#endif + // ... and finally call Python module's setWorkSpace() method (obsolete) + if ( PyObject_HasAttrString( myPyModule, (char*)"setWorkSpace" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"setWorkSpace", (char*)"O", pyws.get() ) ); + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief Initialization callback function + \internal + + Performs the following actions: + - initialize or get the Python interpreter (one per study) + - import the Python module + - pass the workspace widget to the Python module + - call Python module's initialize() method + - call Python module's windows() method + - call Python module's views() method + + \param app parent application object +*/ +void PyModuleHelper::internalInitialize( CAM_Application* app ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalInitialize()" ); + + // reset interpreter to NULL + myInterp = 0; + + // get study Id + LightApp_Application* anApp = dynamic_cast( app ); + if ( !anApp ) + return; + LightApp_Study* aStudy = dynamic_cast( app->activeStudy() ); + if ( !aStudy ) + return; + int aStudyId = aStudy ? aStudy->id() : 0; + + // initialize Python subinterpreter (on per study) and put it in variable + initInterp( aStudyId ); + if ( !myInterp ) + return; // Error + + // import Python GUI module + importModule(); + if ( !myPyModule ) + return; // Error + + // 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 + if ( PyObject_HasAttrString( myPyModule, (char*)"initialize" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"initialize", (char*)"" ) ); + if ( !res ) { + PyErr_Print(); + } + } + + // get required dockable windows list from the Python module + // by calling windows() method + // ... first put default values + myWindowsMap.insert( LightApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea ); + myWindowsMap.insert( LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea ); + myWindowsMap.insert( LightApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea ); + + if ( PyObject_HasAttrString( myPyModule , (char*)"windows" ) ) { + PyObjWrapper res1( PyObject_CallMethod( myPyModule, (char*)"windows", (char*)"" ) ); + if ( !res1 ) { + PyErr_Print(); + } + else { + myWindowsMap.clear(); + if ( PyDict_Check( res1 ) ) { + PyObject* key; + PyObject* value; + Py_ssize_t 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; + } + } + } + } + } + + // get compatible view windows types from the Python module + // by calling views() method + if ( PyObject_HasAttrString( myPyModule , (char*)"views" ) ) { + PyObjWrapper res2( PyObject_CallMethod( myPyModule, (char*)"views", (char*)"" ) ); + if ( !res2 ) { + 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 ) ); + } + } + } + } + } +} + +/*! + \brief Activation callback function + \internal + + Performs the following actions: + - initialize or get the Python interpreter (one per study) + - import the Python GUI module + - call Python module's activate() method + + \param study parent study +*/ +void PyModuleHelper::internalActivate( SUIT_Study* study ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalActivate()" ); + + // get study Id + LightApp_Study* aStudy = dynamic_cast( study ); + int aStudyId = aStudy ? aStudy->id() : 0; + + // initialize Python subinterpreter (on per study) and put it in variable + initInterp( aStudyId ); + if ( !myInterp ) { + myLastActivateStatus = false; + return; // Error + } + + // import Python GUI module + importModule(); + if ( !myPyModule ) { + myLastActivateStatus = false; + return; // Error + } + + // get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + + // call Python module's activate() method (for the new modules) + if ( PyObject_HasAttrString( myPyModule , (char*)"activate" ) ) { + PyObject* res1 = PyObject_CallMethod( myPyModule, (char*)"activate", (char*)"" ); + if ( !res1 || !PyBool_Check( res1 ) ) { + PyErr_Print(); + // always true for old modules (no return value) + myLastActivateStatus = true; + } + else { + // detect return status + myLastActivateStatus = PyObject_IsTrue( res1 ); + } + } +} + +/*! + \brief Additional menu customization callback function + \internal + + Performs the following actions: + - get the Python interpreter (one per study) + - import the Python GUI module + - call Python module's setSettings() method (obsolete function, + used for compatibility with old code) + + \param study parent study +*/ +void PyModuleHelper::internalCustomize( SUIT_Study* study ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalCustomize()" ); + + // get study Id + LightApp_Study* aStudy = dynamic_cast( study ); + int aStudyId = aStudy ? aStudy->id() : 0; + + // initialize Python subinterpreter (on per study) and put it in variable + initInterp( aStudyId ); + if ( !myInterp ) { + myLastActivateStatus = false; + return; // Error + } + + // import Python GUI module + importModule(); + if ( !myPyModule ) { + myLastActivateStatus = false; + return; // Error + } + + // call Python module's setWorkSpace() method (obsolete) + setWorkSpace(); + + // get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + + if ( IsCallOldMethods ) { + // call Python module's setSettings() method (obsolete) + if ( PyObject_HasAttrString( myPyModule , (char*)"setSettings" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"setSettings", (char*)"" ) ); + if( !res ) { + PyErr_Print(); + } + myLastActivateStatus = myLastActivateStatus && true; + } + } +} + +/*! + \brief Deactivation callback function + \internal + + Performs the following actions: + - call Python module's deactivate() method + + \param study parent study +*/ +void PyModuleHelper::internalDeactivate( SUIT_Study* study ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalDeactivate()" ); + + // check that Python subinterpreter is initialized and Python module is imported + if ( !myInterp || !myPyModule ) { + // Error! Python subinterpreter should be initialized and module should be imported first! + return; + } + // then call Python module's deactivate() method + if ( PyObject_HasAttrString( myPyModule , (char*)"deactivate" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"deactivate", (char*)"" ) ); + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief Preference changing callback function. + \internal + + Performs the following actions: + - call Python module's preferenceChanged() method + + \param section resources section name + \param setting resources parameter name +*/ +void PyModuleHelper::internalPreferencesChanged( const QString& section, const QString& setting ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalPreferencesChanged()" ); + + // check that Python subinterpreter is initialized and Python module is imported + if ( !myInterp || !myPyModule ) { + // Error! Python subinterpreter should be initialized and module should be imported first! + return; + } + + if ( PyObject_HasAttrString( myPyModule, (char*)"preferenceChanged" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, + (char*)"preferenceChanged", + (char*)"ss", + section.toLatin1().constData(), + setting.toLatin1().constData() ) ); + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief Active study change callback function. + \internal + + Called when active the study is actived (user brings its + desktop to top): + - initialize or get the Python interpreter (one per study) + - import the Python GUI module + - call Python module's activeStudyChanged() method + + \param study study being activated +*/ +void PyModuleHelper::internalStudyChanged( SUIT_Study* study ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalStudyChanged()" ); + + // get study Id + LightApp_Study* aStudy = dynamic_cast( study ); + int id = aStudy ? aStudy->id() : 0; + + fmsg.message( QString( "study id = %1" ).arg( id ) ); + + // initialize Python subinterpreter (on per study) and put it in variable + initInterp( id ); + if ( !myInterp ) + return; // Error + + // import Python GUI module + importModule(); + if ( !myPyModule ) + return; // Error + + // call Python module's setWorkSpace() method + setWorkSpace(); + + // get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + + // call Python module's activeStudyChanged() method + if ( PyObject_HasAttrString( myPyModule, (char*)"activeStudyChanged" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"activeStudyChanged", (char*)"i", id ) ); + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief GUI event handling callback function + \internal + + Performs the following actions: + - calls Python module's OnGUIEvent() method + + \param id GUI action ID +*/ +void PyModuleHelper::internalActionActivated( int id ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalActionActivated()" ); + fmsg.message( QString( "action id = %1" ).arg( id ) ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myPyModule ) + return; // Error + + if ( PyObject_HasAttrString( myPyModule, (char*)"OnGUIEvent" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"OnGUIEvent", (char*)"i", id ) ); + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief Context popup menu handling callback function + \internal + + Performs the following actions: + - 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. + + \param context popup menu context + \param menu popup menu +*/ +void PyModuleHelper::internalContextMenu( const QString& context, QMenu* menu ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalContextMenu()" ); + fmsg.message( QString( "context: %1" ).arg( context ) ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myPyModule ) + return; // Error + + QString aContext( "" ), aObject( "" ), aParent( context ); + + if ( IsCallOldMethods && PyObject_HasAttrString( myPyModule, (char*)"definePopup" ) ) { + // call definePopup() Python module's function + // this is obsolete function, used only for compatibility reasons + PyObjWrapper res( PyObject_CallMethod( myPyModule, + (char*)"definePopup", + (char*)"sss", + context.toLatin1().constData(), + aObject.toLatin1().constData(), + aParent.toLatin1().constData() ) ); + if( !res ) { + PyErr_Print(); + } + else { + // parse return value + char *co, *ob, *pa; + if( PyArg_ParseTuple( res, "sss", &co, &ob, &pa ) ) { + aContext = co; + aObject = ob; + aParent = pa; + } + } + } // if ( IsCallOldMethods ... ) + + // first try to create menu via XML parser: + // we create popup menus without help of QtxPopupMgr + if ( myXmlHandler ) + myXmlHandler->createPopup( menu, aContext, aParent, aObject ); + +#if SIP_VERSION < 0x040800 + PyObjWrapper sipPopup( sipBuildResult( 0, "M", menu, sipClass_QMenu ) ); +#else + PyObjWrapper sipPopup( sipBuildResult( 0, "D", menu, sipType_QMenu, NULL ) ); +#endif + + // then call Python module's createPopupMenu() method (for new modules) + if ( PyObject_HasAttrString( myPyModule, (char*)"createPopupMenu" ) ) { + PyObjWrapper res1( PyObject_CallMethod( myPyModule, + (char*)"createPopupMenu", + (char*)"Os", + sipPopup.get(), + context.toLatin1().constData() ) ); + if( !res1 ) { + PyErr_Print(); + } + } + + if ( IsCallOldMethods && PyObject_HasAttrString( myPyModule, (char*)"customPopup" ) ) { + // call customPopup() Python module's function + // this is obsolete function, used only for compatibility reasons + PyObjWrapper res2( PyObject_CallMethod( myPyModule, + (char*)"customPopup", + (char*)"Osss", + sipPopup.get(), + aContext.toLatin1().constData(), + aObject.toLatin1().constData(), + aParent.toLatin1().constData() ) ); + if( !res2 ) { + PyErr_Print(); + } + } +} + +/*! + \brief Preferences initialization callback function. + \internal + + Performs the following actions: + - calls Python module's createPreferences() method +*/ +void PyModuleHelper::internalCreatePreferences() +{ + FuncMsg fmsg( "--- PyModuleHelper::internalCreatePreferences()" ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myPyModule ) + return; // Error + + if ( PyObject_HasAttrString( myPyModule, (char*)"createPreferences" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"createPreferences", (char*)"" ) ); + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief Active view changing callback function + \internal + \param view view being activated +*/ +void PyModuleHelper::internalActiveViewChanged( SUIT_ViewWindow* view ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalActiveViewChanged()" ); + + if ( !myInterp || !myPyModule || !view ) + return; + + fmsg.message( QString( "view id: %1" ).arg( view->getId() ) ); + + if ( PyObject_HasAttrString( myPyModule, (char*)"activeViewChanged" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"activeViewChanged", (char*)"i" , view->getId() ) ); + if ( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief View closing callback function + \internal + \param view view user tries to close +*/ +void PyModuleHelper::internalTryCloseView( SUIT_ViewWindow* view ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalTryCloseView()" ); + + if ( !myInterp || !myPyModule || !view ) + return; + + fmsg.message( QString( "view id: %1" ).arg( view->getId() ) ); + + if ( PyObject_HasAttrString( myPyModule, (char*)"viewTryClose" ) ) + { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"viewTryClose", (char*)"i", view->getId() ) ); + if ( !res ) + { + PyErr_Print(); + } + } +} + +/*! + \brief View closing callback function + \internal + \param view view being closed +*/ +void PyModuleHelper::internalCloseView( SUIT_ViewWindow* view ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalCloseView()" ); + + if ( !myInterp || !myPyModule || !view ) + return; + + fmsg.message( QString( "view id: %1" ).arg( view->getId() ) ); + + if ( PyObject_HasAttrString( myPyModule, (char*)"viewClosed" ) ) + { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"viewClosed", (char*)"i", view->getId() ) ); + if ( !res ) + { + PyErr_Print(); + } + } +} + +/*! + \brief View cloning callback function + \internal + \param view view being cloned +*/ +void PyModuleHelper::internalCloneView( SUIT_ViewWindow* view ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalCloneView()" ); + + if ( !myInterp || !myPyModule || !view ) + return; + + fmsg.message( QString( "view id: %1" ).arg( view->getId() ) ); + + if ( PyObject_HasAttrString( myPyModule, (char*)"viewCloned" ) ) + { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"viewCloned", (char*)"i", view->getId() ) ); + if( !res ) + PyErr_Print(); + } +} + +/*! + \brief Module data saving callback function. + \internal + \param files output list of files where module stores data +*/ +void PyModuleHelper::internalSave( QStringList& files ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalSave()" ); + + // Python interpreter should be initialized and Python module should be + // import firs + // files list should contain a path to the temporary directory as a first entry + if ( !myInterp || !myPyModule || files.isEmpty() ) + return; + + if ( PyObject_HasAttrString(myPyModule, (char*)"saveFiles") ) { + + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"saveFiles", + (char*)"s", files.first().toLatin1().constData() ) ); + + if ( !res ) { + PyErr_Print(); + } + else { + // parse the return value + // result can be one string... + if ( PyString_Check( res ) ) { + QString astr = PyString_AsString( res ); + files.append( astr ); + } + //also result can be a list... + else if ( PyList_Check( res ) ) { + int size = PyList_Size( res ); + for ( int i = 0; i < size; i++ ) { + PyObject* value = PyList_GetItem( res, i ); + if ( value && PyString_Check( value ) ) { + files.append( PyString_AsString( value ) ); + } + } + } + } + } +} + +/*! + \brief Module data loading callback function. + \internal + \param files list of files where module data is stored + \param opened output success flag +*/ +void PyModuleHelper::internalLoad( const QStringList& files, bool& opened ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalLoad()" ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myPyModule || files.isEmpty() ) + return; + + QStringList* theList = new QStringList( files ); + +#if SIP_VERSION < 0x040800 + PyObjWrapper sipList( sipBuildResult( 0, "M", theList, sipClass_QStringList ) ); +#else + PyObjWrapper sipList( sipBuildResult( 0, "D", theList, sipType_QStringList, NULL ) ); +#endif + if ( PyObject_HasAttrString(myPyModule , (char*)"openFiles") ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"openFiles", + (char*)"O", sipList.get())); + if( !res || !PyBool_Check( res )) { + PyErr_Print(); + opened = false; + } + else{ + opened = PyObject_IsTrue( res ); + } + } +} + +/*! + \brief Module dump python callback function. + \internal + \param files output list of files where module stores python script +*/ +void PyModuleHelper::internalDumpPython( QStringList& files ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalDumpPython()" ); + + // Python interpreter should be initialized and Python module should be + // import first + // files list should contain a path to the temporary directory + if ( !myInterp || !myPyModule || files.isEmpty() ) + return; + + if ( PyObject_HasAttrString(myPyModule, (char*)"dumpStudy") ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"dumpStudy", + (char*)"s", files.first().toLatin1().constData())); + + if ( !res ) { + PyErr_Print(); + } + else { + // parse the return value + // result can be one string... + if ( PyString_Check( res ) ) { + QString astr = PyString_AsString( res ); + //SCRUTE(astr); + files.append(astr); + } + //also result can be a list... + else if ( PyList_Check( res ) ) { + int size = PyList_Size( res ); + for ( int i = 0; i < size; i++ ) { + PyObject* value = PyList_GetItem( res, i ); + if( value && PyString_Check( value ) ) { + files.append( PyString_AsString( value ) ); + } + } + } + } + } +} + +/*! + \brief Check data object's 'draggable' status callback function. + \internal + \param what data object being tested + \return \c true if object can be dragged or \c false otherwise +*/ +bool PyModuleHelper::internalIsDraggable( LightApp_DataObject* what ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalIsDraggable()" ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myPyModule || !what ) + return false; + + bool draggable = false; + + if ( PyObject_HasAttrString(myPyModule , (char*)"isDraggable") ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"isDraggable", + (char*)"s", what->entry().toLatin1().constData() ) ); + if( !res || !PyBool_Check( res )) { + PyErr_Print(); + draggable = false; + } + else{ + draggable = PyObject_IsTrue( res ); + } + } + + return draggable; +} + +/*! + \brief Check data object's 'drop allowed' status callback function. + \internal + \param where data object being tested + \return \c true if if drop operation is supported by object or \c false otherwise +*/ +bool PyModuleHelper::internalIsDropAccepted( LightApp_DataObject* where ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalIsDropAccepted()" ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myPyModule || !where ) + return false; + + bool dropAccepted = false; + + if ( PyObject_HasAttrString(myPyModule , (char*)"isDropAccepted") ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"isDropAccepted", + (char*)"s", where->entry().toLatin1().constData() ) ); + if( !res || !PyBool_Check( res )) { + PyErr_Print(); + dropAccepted = false; + } + else{ + dropAccepted = PyObject_IsTrue( res ); + } + } + + return dropAccepted; +} + +/*! + \brief Data dropping callback function. + \internal + \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) +*/ +void PyModuleHelper::internalDropObjects( const DataObjectList& what, SUIT_DataObject* where, + const int row, Qt::DropAction action ) +{ + FuncMsg fmsg( "--- PyModuleHelper::internalDropObjects()" ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myPyModule || what.isEmpty() || !where ) + return; + + QStringList* theList = new QStringList(); + + LightApp_DataObject* whereObject = dynamic_cast( where ); + if ( !whereObject ) return; + + for ( int i = 0; i < what.count(); i++ ) { + LightApp_DataObject* dataObject = dynamic_cast( what[i] ); + if ( dataObject ) theList->append( dataObject->entry() ); + } + +#if SIP_VERSION < 0x040800 + PyObjWrapper sipList( sipBuildResult( 0, "M", theList, sipClass_QStringList) ); +#else + PyObjWrapper sipList( sipBuildResult( 0, "D", theList, sipType_QStringList, NULL) ); +#endif + if ( PyObject_HasAttrString(myPyModule, (char*)"dropObjects") ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"dropObjects", (char*)"Osii", + sipList.get(), + whereObject->entry().toLatin1().constData(), + row, action ) ); + + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief Get engine IOR callback function + \internal + + Tries to get engine IOR from the Python module using engineIOR() function. + That function can load module engine using appropriate container if required. + + \return engine IOR or empty string if it is not provided by Python module +*/ +QString PyModuleHelper::internalEngineIOR() const +{ + FuncMsg fmsg( "--- PyModuleHelper::internalEngineIOR()" ); + + QString ior; + + // Python interpreter should be initialized and Python module should be + // import first + if ( myInterp && myModule ) { + if ( PyObject_HasAttrString( myPyModule , "engineIOR" ) ) { + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"engineIOR", (char*)"" ) ); + if ( !res ) { + PyErr_Print(); + } + else { + // parse the return value, result chould be string + if ( PyString_Check( res ) ) { + ior = PyString_AsString( res ); + } + } + } + } + return ior; +} + +/*! + \brief Connects signals about activating and cloning view on internal slots + \param view view being connected +*/ +void PyModuleHelper::connectView( SUIT_ViewWindow* view ) +{ + SUIT_ViewManager* viewMgr = view->getViewManager(); + SUIT_ViewModel* viewModel = viewMgr ? viewMgr->getViewModel() : 0; + + // Connect tryCloseView() and deleteView() signals + if ( viewMgr ) { + connect( viewMgr, SIGNAL( tryCloseView( SUIT_ViewWindow* ) ), + this, SLOT( tryCloseView( SUIT_ViewWindow* ) ), + Qt::UniqueConnection ); + connect( viewMgr, SIGNAL( deleteView( SUIT_ViewWindow* ) ), + this, SLOT( closeView( SUIT_ViewWindow* ) ), + Qt::UniqueConnection ); + } + + // Connect cloneView() signal of an OCC View + if ( view->inherits( "OCCViewer_ViewWindow" ) ) { + connect( view, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), + this, SLOT( cloneView( SUIT_ViewWindow* ) ), + Qt::UniqueConnection ); + } + // Connect cloneView() signal of Plot2d View + else if ( viewModel && viewModel->inherits( "Plot2d_Viewer" ) ) { + connect( viewModel, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), + this, SLOT( cloneView( SUIT_ViewWindow* ) ), + Qt::UniqueConnection ); + } +} diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h new file mode 100644 index 000000000..b14a7c600 --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h @@ -0,0 +1,138 @@ +// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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. +// +// 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_PyModule.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#ifndef SALOME_PYQT_PYMODULE_H +#define SALOME_PYQT_PYMODULE_H + +#include "SALOME_PYQT_GUILight.h" + +#include "PyInterp_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! + +#include +#include +#include +#include +#include + +class CAM_Application; +class LightApp_DataObject; +class LightApp_Module; +class PyInterp_Interp; +class QAction; +class QMenu; +class SUIT_DataObject; +class SUIT_Study; +class SUIT_ViewWindow; + +typedef QList DataObjectList; + +class SALOME_PYQT_LIGHT_EXPORT PyModuleHelper : public QObject +{ + Q_OBJECT + +private: + class XmlHandler; + class InitLocker; + + typedef QMap InterpMap; + + static InterpMap myInterpMap; //!< study to Python subinterpreter map + static LightApp_Module* myInitModule; //!< Python GUI being initialized (not zero only during the initialization) + + LightApp_Module* myModule; //!< GUI module + PyObject* myPyModule; //!< Python GUI module + PyInterp_Interp* myInterp; //!< current Python subinterpreter + XmlHandler* myXmlHandler; //!< XML resource file parser + QMap myWindowsMap; //!< windows map + QStringList myViewMgrList; //!< compatible view managers list + bool myLastActivateStatus; //!< latest module activation status + +public: + PyModuleHelper( LightApp_Module* ); + ~PyModuleHelper(); + + static LightApp_Module* getInitModule(); + static int defaultMenuGroup(); + + LightApp_Module* module() const; + PyObject* pythonModule() const; + + void connectAction( QAction* ); + + QMap windows() const; + QStringList viewManagers() const; + +public slots: + void initialize( CAM_Application* ); + bool activate( SUIT_Study* study ); + bool deactivate( SUIT_Study* study ); + void preferencesChanged( const QString&, const QString& setting ); + void preferenceChanged( const QString&, const QString&, const QString& setting ); + void studyActivated( SUIT_Study* ); + void actionActivated(); + void contextMenu( const QString&, QMenu* ); + void createPreferences(); + void activeViewChanged( SUIT_ViewWindow* ); + void tryCloseView( SUIT_ViewWindow* ); + void closeView( SUIT_ViewWindow* ); + void cloneView( SUIT_ViewWindow* ); + void save( QStringList& ); + bool load( const QStringList& ); + void dumpPython( QStringList& files ); + bool isDraggable( const SUIT_DataObject* ) const; + bool isDropAccepted( const SUIT_DataObject* ) const; + void dropObjects( const DataObjectList&, SUIT_DataObject*, + const int, Qt::DropAction ); + QString engineIOR() const; + +private: + void initInterp( int ); + void importModule(); + void setWorkSpace(); + + void internalInitialize( CAM_Application* ); + void internalActivate( SUIT_Study* ); + void internalCustomize( SUIT_Study* ); + void internalDeactivate( SUIT_Study* ); + void internalPreferencesChanged( const QString&, const QString& ); + void internalStudyChanged( SUIT_Study* ); + void internalActionActivated( int ); + void internalContextMenu( const QString&, QMenu* ); + void internalCreatePreferences(); + void internalActiveViewChanged( SUIT_ViewWindow* ); + void internalTryCloseView( SUIT_ViewWindow* ); + void internalCloseView( SUIT_ViewWindow* ); + void internalCloneView( SUIT_ViewWindow* ); + void internalSave( QStringList& ); + void internalLoad( const QStringList&, bool& ); + void internalDumpPython( QStringList& ); + bool internalIsDraggable( LightApp_DataObject* ); + bool internalIsDropAccepted( LightApp_DataObject* ); + void internalDropObjects( const DataObjectList&, SUIT_DataObject*, + const int, Qt::DropAction ); + QString internalEngineIOR() const; + + void connectView( SUIT_ViewWindow* ); +}; + +#endif // SALOME_PYQT_PYMODULE_H diff --git a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx index 899508ad3..d526f2464 100644 --- a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx +++ b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx @@ -22,7 +22,7 @@ // File : SalomePyQt.cxx // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) -// + #ifdef WNT // E.A. : On windows with python 2.6, there is a conflict // E.A. : between pymath.h and Standard_math.h which define @@ -31,38 +31,28 @@ #include #endif -#include // this include must be first!!! -#include +#include "SALOME_PYQT_ModuleLight.h" // this include must be first!!! +#include "SALOME_PYQT_DataModelLight.h" +#include "SALOME_PYQT_PyModule.h" #include "SalomePyQt.h" -#include -#include -#include -#include -#include -#include +#include "LightApp_SelectionMgr.h" +#include "LogWindow.h" +#include "OCCViewer_ViewWindow.h" +#include "Plot2d_ViewManager.h" +#include "Plot2d_ViewWindow.h" +#include "QtxActionMenuMgr.h" +#include "QtxWorkstack.h" +#include "QtxTreeView.h" +#include "SALOME_Event.h" +#include "STD_TabDesktop.h" +#include "SUIT_DataBrowser.h" +#include "SUIT_ResourceMgr.h" +#include "SUIT_Session.h" +#include "SUIT_Tools.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include /*! \brief Get the currently active application. @@ -94,17 +84,47 @@ static LightApp_Study* getActiveStudy() This function returns correct result only if Python-based module is currently active. Otherwize, 0 is returned. */ -static SALOME_PYQT_ModuleLight* getActiveModule() +static LightApp_Module* getActiveModule() { - SALOME_PYQT_ModuleLight* module = 0; + LightApp_Module* module = 0; if ( LightApp_Application* anApp = getApplication() ) { - module = SALOME_PYQT_ModuleLight::getInitModule(); + module = PyModuleHelper::getInitModule(); if ( !module ) - module = dynamic_cast( anApp->activeModule() ); + module = dynamic_cast( anApp->activeModule() ); } return module; } +/*! + \brief Get the currently active Python module's helper. + \internal + This function returns correct result only if Python-based + module is currently active. Otherwize, 0 is returned. +*/ +static PyModuleHelper* getPythonHelper() +{ + LightApp_Module* module = getActiveModule(); + PyModuleHelper* helper = module ? qFindChild( module, "python_module_helper" ) : 0; + return helper; +} + +/*! + \brief Get SALOME verbose level + \internal + \return \c true if SALOME debug output is allowed or \c false otherwise +*/ +static bool verbose() +{ + bool isVerbose = false; + if ( getenv( "SALOME_VERBOSE" ) ) { + QString envVar = getenv( "SALOME_VERBOSE" ); + bool ok; + int value = envVar.toInt( &ok ); + isVerbose = ok && value != 0; + } + return isVerbose; +} + /*! \class SALOME_Selection \brief The class represents selection which can be used in Python. @@ -175,12 +195,14 @@ void SALOME_Selection::onSelMgrDestroyed() */ void SALOME_Selection::Clear() { - class TEvent: public SALOME_Event { + class TEvent: public SALOME_Event + { LightApp_SelectionMgr* mySelMgr; public: TEvent( LightApp_SelectionMgr* selMgr ) : mySelMgr( selMgr ) {} - virtual void Execute() { + virtual void Execute() + { if ( mySelMgr ) mySelMgr->clearSelected(); } @@ -201,12 +223,14 @@ void SALOME_Selection::ClearIObjects() */ void SALOME_Selection::ClearFilters() { - class TEvent: public SALOME_Event { + class TEvent: public SALOME_Event + { LightApp_SelectionMgr* mySelMgr; public: TEvent( LightApp_SelectionMgr* selMgr ) : mySelMgr( selMgr ) {} - virtual void Execute() { + virtual void Execute() + { if ( mySelMgr ) mySelMgr->clearFilters(); } @@ -439,7 +463,7 @@ int SalomePyQt::getStudyId() } /*! - \fn SALOME_Selection* SalomePyQt::getSelection() + \fn SALOME_Selection* SalomePyQt::getSelection(); \brief Get the selection object for the current study. Creates a Selection object if it has not been created yet. @@ -464,7 +488,7 @@ SALOME_Selection* SalomePyQt::getSelection() } /*! - \fn void SalomePyQt::putInfo( const QString& msg, const int sec ) + \fn void SalomePyQt::putInfo( const QString& msg, const int sec ); \brief Put an information message to the current application's desktop status bar. @@ -521,7 +545,7 @@ const QString SalomePyQt::getActiveComponent() } /*! - \fn PyObject* SalomePyQt::getActivePythonModule() + \fn PyObject* SalomePyQt::getActivePythonModule(); \brief Access to Python module object currently loaded into SALOME_PYQT_ModuleLight container. \return Python module object currently loaded into SALOME_PYQT_ModuleLight container */ @@ -531,12 +555,12 @@ class TGetActivePyModuleEvent: public SALOME_Event public: typedef PyObject* TResult; TResult myResult; - TGetActivePyModuleEvent() : myResult( 0 ) {} + TGetActivePyModuleEvent() : myResult( Py_None ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = (PyObject*)module->getPythonModule(); + PyModuleHelper* helper = getPythonHelper(); + if ( helper ) + myResult = (PyObject*)helper->pythonModule(); } }; PyObject* SalomePyQt::getActivePythonModule() @@ -545,7 +569,7 @@ PyObject* SalomePyQt::getActivePythonModule() } /*! - \fn bool SalomePyQt::activateModule( const QString& modName ) + \fn bool SalomePyQt::activateModule( const QString& modName ); \brief Activates SALOME module with the given name \return True if the module has been activated and False otherwise. */ @@ -618,6 +642,7 @@ void SalomePyQt::updateObjBrowser( const int studyId, bool updateSelection ) SalomePyQt::isModified() \return The modification status of the data model for the currently active Python module + \note This function is supported for "light" Python-based SALOME modules only. \sa setModified() */ class TIsModifiedEvent: public SALOME_Event @@ -628,14 +653,18 @@ public: TIsModifiedEvent() : myResult( false ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); + LightApp_Module* module = getActiveModule(); if ( !module ) return; SALOME_PYQT_DataModelLight* aModel = dynamic_cast( module->dataModel() ); - if ( aModel ) + if ( aModel ) { myResult = aModel->isModified(); + } + else { + if ( verbose() ) printf( "SalomePyQt.isModified() function is not supported for the current module.\n" ); + } } }; bool SalomePyQt::isModified() @@ -651,6 +680,8 @@ bool SalomePyQt::isModified() by the Python code in order to enable/disable "Save" operation depending on the module's data state. + \note This function is supported for "light" Python-based SALOME modules only. + \param New modification status of the data model \sa isModified() @@ -665,19 +696,22 @@ void SalomePyQt::setModified( bool flag ) : myFlag( flag ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); + LightApp_Module* module = getActiveModule(); if ( !module ) return; - SALOME_PYQT_DataModelLight* aModel = + SALOME_PYQT_DataModelLight* model = dynamic_cast( module->dataModel() ); - LightApp_Application* aLApp = - dynamic_cast( module->application() ); - if ( !aModel || !aLApp ) - return; - aModel->setModified( myFlag ); - aLApp->updateActions(); + LightApp_Application* app = module->getApp(); + + if ( model && app ) { + model->setModified( myFlag ); + app->updateActions(); + } + else { + if ( verbose() ) printf( "SalomePyQt.setModified() function is not supported for the current module.\n" ); + } } }; ProcessVoidEvent( new TEvent( flag ) ); @@ -713,7 +747,8 @@ void SalomePyQt::addStringSetting( const QString& name, const QString& value, bo public: TEvent( const QString& name, const QString& value, bool autoValue ) : myName( name ), myValue( value ), myAutoValue( autoValue ) {} - virtual void Execute() { + virtual void Execute() + { if ( SUIT_Session::session() ) { SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); QStringList sl = myName.split( ":", QString::SkipEmptyParts ); @@ -854,11 +889,13 @@ void SalomePyQt::addBoolSetting( const QString& name, const bool value, bool aut */ void SalomePyQt::removeSettings( const QString& name ) { - class TEvent: public SALOME_Event { + class TEvent: public SALOME_Event + { QString myName; public: TEvent( const QString& name ) : myName( name ) {} - virtual void Execute() { + virtual void Execute() + { if ( SUIT_Session::session() ) { SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); QStringList sl = myName.split( ":", QString::SkipEmptyParts ); @@ -1417,9 +1454,26 @@ QString SalomePyQt::getExistingDirectory( QWidget* parent, /*! \fn QString SalomePyQt::loadIcon( const QString& filename ); \brief Load an icon from the module resources by the specified file name. - \param filename icon file name + \param fileName icon file name \return icon object */ + +static QIcon loadIconInternal( const QString& module, const QString& fileName ) +{ + QIcon icon; + + LightApp_Application* app = getApplication(); + + if ( app && !fileName.isEmpty() ) { + QPixmap pixmap = app->resourceMgr()->loadPixmap( module, + QApplication::translate( module.toLatin1().data(), + fileName.toLatin1().data() ) ); + if ( !pixmap.isNull() ) + icon = QIcon( pixmap ); + } + return icon; +} + class TLoadIconEvent: public SALOME_Event { public: @@ -1432,15 +1486,7 @@ public: myFileName ( filename ) {} virtual void Execute() { - if ( LightApp_Application* anApp = getApplication() ) { - if ( !myFileName.isEmpty() ) { - QPixmap pixmap = anApp->resourceMgr()->loadPixmap( myModule, - QApplication::translate( myModule.toLatin1().data(), - myFileName.toLatin1().data() ) ); - if ( !pixmap.isNull() ) - myResult = QIcon( pixmap ); - } - } + myResult = loadIconInternal( myModule, myFileName ); } }; QIcon SalomePyQt::loadIcon( const QString& module, const QString& filename ) @@ -1536,7 +1582,7 @@ public: TDefMenuGroupEvent() : myResult( -1 ) {} virtual void Execute() { - myResult = SALOME_PYQT_ModuleLight::defaultMenuGroup(); + myResult = PyModuleHelper::defaultMenuGroup(); } }; int SalomePyQt::defaultMenuGroup() @@ -1558,7 +1604,7 @@ public: CrTool( QAction* action, const QString& tBar, const int id, const int idx ) : myCase( 4 ), myAction( action ), myTbName( tBar ), myId( id ), myIndex( idx ) {} - int execute( SALOME_PYQT_ModuleLight* module ) const + int execute( LightApp_Module* module ) const { if ( module ) { switch ( myCase ) { @@ -1595,7 +1641,7 @@ public: : myResult( -1 ), myCrTool( crTool ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); + LightApp_Module* module = getActiveModule(); if ( module ) myResult = myCrTool.execute( module ); } @@ -1718,12 +1764,9 @@ public: : myResult( -1 ), myCrMenu( crMenu ) {} virtual void Execute() { - if ( LightApp_Application* anApp = getApplication() ) - { - LightApp_Module* module = dynamic_cast( anApp->activeModule() ); - if ( module ) - myResult = myCrMenu.execute( module ); - } + LightApp_Module* module = getActiveModule(); + if ( module ) + myResult = myCrMenu.execute( module ); } }; @@ -1822,7 +1865,7 @@ public: : myResult( 0 ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); + LightApp_Module* module = getActiveModule(); if ( module ) myResult = (QAction*)module->separator(); } @@ -1834,12 +1877,12 @@ QAction* SalomePyQt::createSeparator() /*! \fn QAction* SalomePyQt::createAction( const int id, - const QString& menuText, - const QString& tipText, - const QString& statusText, - const QString& icon, - const int key, - const bool toggle ) + const QString& menuText, + const QString& tipText, + const QString& statusText, + const QString& icon, + const int key, + const bool toggle ); \brief Create an action which can be then used in the menu or toolbar. \param id the unique id action to be registered to \param menuText action text which should appear in menu @@ -1868,46 +1911,69 @@ public: myStatusText( statusText ), myIcon( icon ), myKey( key ), myToggle( toggle ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = (QAction*)module->createAction( myId, myTipText, myIcon, myMenuText, myStatusText, myKey, myToggle ); + LightApp_Module* module = getActiveModule(); + if ( module ) { + QIcon icon = loadIconInternal( module->name(), myIcon ); + myResult = (QAction*)module->action( myId ); + if ( myResult ) { + if ( myResult->toolTip().isEmpty() && !myTipText.isEmpty() ) + myResult->setToolTip( myTipText ); + if ( myResult->text().isEmpty() && !myMenuText.isEmpty() ) + myResult->setText( myMenuText ); + if ( myResult->icon().isNull() && !icon.isNull() ) + myResult->setIcon( icon ); + if ( myResult->statusTip().isEmpty() && !myStatusText.isEmpty() ) + myResult->setStatusTip( myStatusText ); + if ( myResult->shortcut().isEmpty() && myKey ) + myResult->setShortcut( myKey ); + if ( myResult->isCheckable() != myToggle ) + myResult->setCheckable( myToggle ); + } + else { + myResult = (QAction*)module->createAction( myId, myTipText, icon, myMenuText, myStatusText, myKey, module, myToggle ); + } + // for Python module, automatically connect action to callback slot + PyModuleHelper* helper = qFindChild( module, "python_module_helper" ); + if ( helper ) helper->connectAction( myResult ); + } } }; QAction* SalomePyQt::createAction( const int id, const QString& menuText, - const QString& tipText, const QString& statusText, - const QString& icon, const int key, const bool toggle ) + const QString& tipText, const QString& statusText, + const QString& icon, const int key, const bool toggle ) { return ProcessEvent( new TCreateActionEvent( id, menuText, tipText, statusText, icon, key, toggle ) ); } /*! - \fn QtxActionGroup* SalomePyQt::createActionGroup( const int id, const bool exclusive ) + \fn QtxActionGroup* SalomePyQt::createActionGroup( const int id, const bool exclusive ); \brief Create an action group which can be then used in the menu or toolbar \param id : the unique id action group to be registered to \param exclusive : if \c true the action group does exclusive toggling */ -struct TcreateActionGroupEvent: public SALOME_Event { +struct TCreateActionGroupEvent: public SALOME_Event +{ typedef QtxActionGroup* TResult; TResult myResult; int myId; bool myExclusive; - TcreateActionGroupEvent( const int id, const bool exclusive ) + TCreateActionGroupEvent( const int id, const bool exclusive ) : myId( id ), myExclusive( exclusive ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); + LightApp_Module* module = getActiveModule(); if ( module ) myResult = module->createActionGroup( myId, myExclusive ); } }; -QtxActionGroup* SalomePyQt::createActionGroup(const int id, const bool exclusive) +QtxActionGroup* SalomePyQt::createActionGroup( const int id, const bool exclusive ) { - return ProcessEvent( new TcreateActionGroupEvent( id, exclusive ) ); + return ProcessEvent( new TCreateActionGroupEvent( id, exclusive ) ); } /*! - \fn QAction* SalomePyQt::action( const int id ) + \fn QAction* SalomePyQt::action( const int id ); \brief Get action by specified identifier. \return action or 0 if action is not registered */ @@ -1922,7 +1988,7 @@ public: : myResult( 0 ), myId( id ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); + LightApp_Module* module = getActiveModule(); if ( module ) myResult = (QAction*)module->action( myId ); } @@ -1948,7 +2014,7 @@ public: : myResult( -1 ), myAction( action ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); + LightApp_Module* module = getActiveModule(); if ( module ) myResult = module->actionId( myAction ); } @@ -1975,9 +2041,12 @@ public: : myResult( -1 ), myLabel( label ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = module->addGlobalPreference( myLabel ); + LightApp_Module* module = getActiveModule(); + if ( module ) { + LightApp_Preferences* pref = module->getApp()->preferences(); + if ( pref ) + myResult = pref->addPreference( myLabel, -1 ); + } } }; int SalomePyQt::addGlobalPreference( const QString& label ) @@ -2002,9 +2071,15 @@ public: : myResult( -1 ), myLabel( label ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = module->addPreference( myLabel ); + LightApp_Module* module = getActiveModule(); + if ( module ) { + LightApp_Preferences* pref = module->getApp()->preferences(); + if ( pref ) { + int cId = pref->addPreference( module->moduleName(), -1 ); + if ( cId != -1 ) + myResult = pref->addPreference( myLabel, cId ); + } + } } }; int SalomePyQt::addPreference( const QString& label ) @@ -2043,9 +2118,12 @@ public: mySection( section ), myParam ( param ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = module->addPreference( myLabel, myPId, myType, mySection, myParam ); + LightApp_Module* module = getActiveModule(); + if ( module ) { + LightApp_Preferences* pref = module->getApp()->preferences(); + if ( pref ) + myResult = pref->addPreference( module->moduleName(), myLabel, myPId, myType, mySection, myParam ); + } } }; int SalomePyQt::addPreference( const QString& label, const int pId, const int type, @@ -2073,9 +2151,12 @@ public: : myId( id ), myProp( prop ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = module->preferenceProperty( myId, myProp ); + LightApp_Module* module = getActiveModule(); + if ( module ) { + LightApp_Preferences* pref = module->getApp()->preferences(); + if ( pref ) + myResult = pref->itemProperty( myProp, myId ); + } } }; QVariant SalomePyQt::preferenceProperty( const int id, const QString& prop ) @@ -2103,9 +2184,12 @@ void SalomePyQt::setPreferenceProperty( const int id, : myId( id ), myProp( prop ), myVar( var ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - module->setPreferenceProperty( myId, myProp, myVar ); + LightApp_Module* module = getActiveModule(); + if ( module ) { + LightApp_Preferences* pref = module->getApp()->preferences(); + if ( pref ) + pref->setItemProperty( myProp, myVar, myId ); + } } }; ProcessVoidEvent( new TEvent( id, prop, var) ); @@ -2138,32 +2222,35 @@ void SalomePyQt::addPreferenceProperty( const int id, : myId( id ), myProp( prop ), myIdx( idx), myVar( var ) {} virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); + LightApp_Module* module = getActiveModule(); if ( module ) { - QVariant var = module->preferenceProperty( myId, myProp ); - if ( var.isValid() ) { - if ( var.type() == QVariant::StringList ) { - QStringList sl = var.toStringList(); - if ( myIdx >= 0 && myIdx < sl.count() ) - sl[myIdx] = myVar.toString(); - else - sl.append( myVar.toString() ); - module->setPreferenceProperty( myId, myProp, sl ); - } - else if ( var.type() == QVariant::List ) { - QList vl = var.toList(); - if ( myIdx >= 0 && myIdx < vl.count() ) - vl[myIdx] = myVar; - else - vl.append( myVar ); - module->setPreferenceProperty( myId, myProp, vl ); - } - } - else { - QList vl; - vl.append( myVar ); - module->setPreferenceProperty( myId, myProp, vl ); - } + LightApp_Preferences* pref = module->getApp()->preferences(); + if ( pref ) { + QVariant var = pref->itemProperty( myProp, myId ); + if ( var.isValid() ) { + if ( var.type() == QVariant::StringList ) { + QStringList sl = var.toStringList(); + if ( myIdx >= 0 && myIdx < sl.count() ) + sl[myIdx] = myVar.toString(); + else + sl.append( myVar.toString() ); + pref->setItemProperty( myProp, sl, myId ); + } + else if ( var.type() == QVariant::List ) { + QList vl = var.toList(); + if ( myIdx >= 0 && myIdx < vl.count() ) + vl[myIdx] = myVar; + else + vl.append( myVar ); + pref->setItemProperty( myProp, vl, myId ); + } + } + else { + QList vl; + vl.append( myVar ); + pref->setItemProperty( myProp, vl, myId ); + } + } } } }; @@ -2250,7 +2337,7 @@ static SUIT_ViewWindow* getWnd( const int id ) } /*! - \fn QList SalomePyQt::getViews() + \fn QList SalomePyQt::getViews(); \brief Get list of integer identifiers of all the currently opened views \return list of integer identifiers of all the currently opened views */ @@ -2284,7 +2371,7 @@ QList SalomePyQt::getViews() } /*! - \fn int SalomePyQt::getActiveView() + \fn int SalomePyQt::getActiveView(); \brief Get integer identifier of the currently active view \return integer identifier of the currently active view */ @@ -2317,7 +2404,7 @@ int SalomePyQt::getActiveView() } /*! - \fn QString SalomePyQt::getViewType( const int id ) + \fn QString SalomePyQt::getViewType( const int id ); \brief Get type of the specified view, e.g. "OCCViewer" \param id window identifier \return view type @@ -2348,7 +2435,7 @@ QString SalomePyQt::getViewType( const int id ) } /*! - \fn bool SalomePyQt::setViewTitle( const int id, const QString& title ) + \fn bool SalomePyQt::setViewTitle( const int id, const QString& title ); \brief Change view caption \param id window identifier \param title new window title @@ -2383,7 +2470,7 @@ bool SalomePyQt::setViewTitle( const int id, const QString& title ) /*! - \fn QString SalomePyQt::getViewTitle( const int id ) + \fn QString SalomePyQt::getViewTitle( const int id ); \brief Get view caption \param id window identifier \return view caption @@ -2410,7 +2497,7 @@ QString SalomePyQt::getViewTitle( const int id ) } /*! - \fn QList SalomePyQt::findViews( const QString& type ) + \fn QList SalomePyQt::findViews( const QString& type ); \brief Get list of integer identifiers of all the currently opened views of the specified type \param type viewer type @@ -2453,7 +2540,7 @@ QList SalomePyQt::findViews( const QString& type ) } /*! - \fn bool SalomePyQt::activateView( const int id ) + \fn bool SalomePyQt::activateView( const int id ); \brief Activate view \param id window identifier \return \c true if operation is completed successfully and \c false otherwise @@ -2484,7 +2571,7 @@ bool SalomePyQt::activateView( const int id ) } /*! - \fn int SalomePyQt::createView( const QString& type ) + \fn int SalomePyQt::createView( const QString& type ); \brief Create new view and activate it \param type viewer type \return integer identifier of created view (or -1 if view could not be created) @@ -2520,7 +2607,7 @@ int SalomePyQt::createView( const QString& type ) } /*! - \fn int SalomePyQt::createView( const QString& type, QWidget* w ) + \fn int SalomePyQt::createView( const QString& type, QWidget* w ); \brief Create new view with custom widget embedded and activate it \param type viewer type \param w custom widget @@ -2559,7 +2646,7 @@ int SalomePyQt::createView( const QString& type, QWidget* w ) } /*! - \fn bool SalomePyQt::closeView( const int id ) + \fn bool SalomePyQt::closeView( const int id ); \brief Close view \param id window identifier \return \c true if operation is completed successfully and \c false otherwise @@ -2594,7 +2681,7 @@ bool SalomePyQt::closeView( const int id ) } /*! - \fn int SalomePyQt::cloneView( const int id ) + \fn int SalomePyQt::cloneView( const int id ); \brief Clone view (if this operation is supported for specified view type) \param id window identifier \return integer identifier of the cloned view or -1 or operation could not be performed @@ -2646,7 +2733,7 @@ int SalomePyQt::cloneView( const int id ) } /*! - \fn bool SalomePyQt::isViewVisible( const int id ) + \fn bool SalomePyQt::isViewVisible( const int id ); \brief Check whether view is visible ( i.e. it is on the top of the views stack) \param id window identifier \return \c true if view is visible and \c false otherwise @@ -2677,7 +2764,7 @@ bool SalomePyQt::isViewVisible( const int id ) } /*! - \fn bool SalomePyQt::setViewClosable( const int id, const bool on ) + \fn bool SalomePyQt::setViewClosable( const int id, const bool on ); \brief Set / clear view's "closable" option. By default any view is closable (i.e. can be closed by the user). \param id window identifier @@ -2703,7 +2790,7 @@ void SalomePyQt::setViewClosable( const int id, const bool on ) } /*! - \fn bool SalomePyQt::isViewClosable( const int id ) + \fn bool SalomePyQt::isViewClosable( const int id ); \brief Check whether view is closable (i.e. can be closed by the user) \param id window identifier \return \c true if view is closable or \c false otherwise @@ -2732,7 +2819,7 @@ bool SalomePyQt::isViewClosable( const int id ) } /*! - \fn bool SalomePyQt::groupAllViews() + \fn bool SalomePyQt::groupAllViews(); \brief Group all views to the single tab area \return \c true if operation is completed successfully and \c false otherwise */ @@ -2768,7 +2855,7 @@ bool SalomePyQt::groupAllViews() } /*! - \fn bool SalomePyQt::splitView( const int id, const Orientation ori, const Action action ) + \fn bool SalomePyQt::splitView( const int id, const Orientation ori, const Action action ); \brief Split tab area to which view with identifier belongs to \param id window identifier \param ori orientation of split operation @@ -2834,7 +2921,7 @@ bool SalomePyQt::splitView( const int id, const Orientation ori, const Action ac } /*! - \fn bool SalomePyQt::moveView( const int id, const int id_to, const bool before ) + \fn bool SalomePyQt::moveView( const int id, const int id_to, const bool before ); \brief Move view with the first identifier to the same area which another view with the second identifier belongs to \param id source window identifier @@ -2876,7 +2963,7 @@ bool SalomePyQt::moveView( const int id, const int id_to, const bool before ) } /*! - \fn QList SalomePyQt::neighbourViews( const int id ) + \fn QList SalomePyQt::neighbourViews( const int id ); \brief Get list of views identifiers that belongs to the same area as specified view (excluding it) \param id window identifier @@ -2920,314 +3007,435 @@ QList SalomePyQt::neighbourViews( const int id ) /*! - SalomePyQt::createObject(parent) - Create empty data object + \fn QString SalomePyQt::createObject( const QString& parent ); + \brief Create empty data object + \param parent entry of parent data object + \return entry of created data object */ -class TCreateEmptyObjectEvent: public SALOME_Event { + +class TCreateEmptyObjectEvent: public SALOME_Event +{ public: typedef QString TResult; TResult myResult; QString myParent; - TCreateEmptyObjectEvent(const QString& parent) : myParent( parent ) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = (QString)module->createObject(myParent); + TCreateEmptyObjectEvent( const QString& parent ) + : myParent( parent ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + myResult = module->createObject( myParent ); + } + else { + if ( verbose() ) printf( "SalomePyQt.createObject() function is not supported for the current module.\n" ); + } } }; -QString SalomePyQt::createObject(const QString& parent) +QString SalomePyQt::createObject( const QString& parent ) { - return ProcessEvent( new TCreateEmptyObjectEvent(parent) ); + return ProcessEvent( new TCreateEmptyObjectEvent( parent ) ); } /*! - SalomePyQt::createObject( name, icon, tooltip, parent ) - Create data object with name, icon and tooltip + \fn QString SalomePyQt::createObject( const QString& name, const QString& icon, + const QString& tooltip,const QString& parent ); + \brief Create new data object with specified name, icon and tooltip + \param name data object name + \param icon data object icon + \param toolTip data object tooltip + \param parent entry of parent data object + \return entry of created data object */ -class TCreateObjectEvent: public SALOME_Event { + +class TCreateObjectEvent: public SALOME_Event +{ public: typedef QString TResult; TResult myResult; QString myParent; QString myName; - QString myIconName; + QString myIcon; QString myToolTip; - TCreateObjectEvent(const QString& name, - const QString& iconname, - const QString& tooltip, - const QString& parent) : myName(name), - myIconName(iconname), - myToolTip(tooltip), - myParent( parent ){} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = (QString)module->createObject(myName, myIconName, - myToolTip, myParent); + TCreateObjectEvent( const QString& name, + const QString& icon, + const QString& tooltip, + const QString& parent ) + : myName( name ), + myIcon( icon ), + myToolTip( tooltip ), + myParent( parent ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + myResult = module->createObject( myName, myIcon, myToolTip, myParent ); + } + else { + if ( verbose() ) printf( "SalomePyQt.createObject() function is not supported for the current module.\n" ); + } } }; -QString SalomePyQt::createObject(const QString& name, - const QString& iconname, - const QString& tooltip, - const QString& parent) +QString SalomePyQt::createObject( const QString& name, + const QString& icon, + const QString& toolTip, + const QString& parent ) { - return ProcessEvent( new TCreateObjectEvent(name, iconname, tooltip, parent) ); + return ProcessEvent( new TCreateObjectEvent( name, icon, toolTip, parent ) ); } /*! - SalomePyQt::setName(obj,name) - Set object name + \fn void SalomePyQt::setName( const QString& entry, const QString& name ); + \brief Set data object name + \param entry data object entry + \param name data object name */ class TSetNameEvent: public SALOME_Event { public: - QString myObj; + QString myEntry; QString myName; - TSetNameEvent( const QString& obj, - const QString& name) : myObj(obj), - myName(name) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - module->setName(myObj,myName); + TSetNameEvent( const QString& entry, + const QString& name ) + : myEntry( entry ), + myName( name ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + module->setName( myEntry, myName ); + } + else { + if ( verbose() ) printf( "SalomePyQt.setName() function is not supported for the current module.\n" ); + } } }; -void SalomePyQt::setName(const QString& obj,const QString& name) +void SalomePyQt::setName( const QString& entry, const QString& name ) { - ProcessVoidEvent(new TSetNameEvent(obj,name)); + ProcessVoidEvent( new TSetNameEvent( entry, name ) ); } - /*! - SalomePyQt::setIcon(obj,icon) - Set object icon + \fn void SalomePyQt::setIcon( const QString& entry, const QString& icon ); + \brief Set data object icon + \param entry data object entry + \param icon data object icon file name (icon is loaded from module resources) */ + class TSetIconEvent: public SALOME_Event { public: - QString myObj; - QString myIconName; - TSetIconEvent( const QString& obj, - const QString& iconname) : myObj(obj), - myIconName(iconname) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - module->setIcon(myObj,myIconName); + QString myEntry; + QString myIcon; + TSetIconEvent( const QString& entry, + const QString& icon ) + : myEntry( entry ), + myIcon( icon ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + module->setIcon( myEntry, myIcon ); + } + else { + if ( verbose() ) printf( "SalomePyQt.setIcon() function is not supported for the current module.\n" ); + } } }; -void SalomePyQt::setIcon(const QString& obj,const QString& iconname) +void SalomePyQt::setIcon( const QString& entry, const QString& icon ) { - ProcessVoidEvent(new TSetIconEvent(obj,iconname)); + ProcessVoidEvent( new TSetIconEvent( entry, icon ) ); } /*! - SalomePyQt::setToolTip(obj,tooltip) - Set object tool tip + \fn void SalomePyQt::setToolTip( const QString& entry, const QString& toolTip ); + \brief Set data object tooltip + \param entry data object entry + \param toolTip data object tooltip */ + class TSetToolTipEvent: public SALOME_Event { public: - QString myObj; + QString myEntry; QString myToolTip; - TSetToolTipEvent( const QString& obj, - const QString& tooltip) : myObj(obj), - myToolTip(tooltip) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - module->setToolTip(myObj,myToolTip); + TSetToolTipEvent( const QString& entry, + const QString& toolTip ) + : myEntry( entry ), + myToolTip( toolTip ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + module->setToolTip( myEntry, myToolTip ); + } + else { + if ( verbose() ) printf( "SalomePyQt.setToolTip() function is not supported for the current module.\n" ); + } } }; -void SalomePyQt::setToolTip(const QString& obj,const QString& tooltip) +void SalomePyQt::setToolTip( const QString& entry, const QString& toolTip ) { - ProcessVoidEvent(new TSetToolTipEvent(obj,tooltip)); + ProcessVoidEvent( new TSetToolTipEvent( entry, toolTip ) ); } /*! - SalomePyQt::setReference(obj,refEntry) - Set entry to referenced object + \fn void SalomePyQt::setReference( const QString& entry, const QString& refEntry ); + \brief Set reference to another data object + \param entry data object entry + \param refEntry referenced data object entry */ + class TSetRefEvent: public SALOME_Event { public: - QString myObj; + QString myEntry; QString myRefEntry; - TSetRefEvent( const QString& obj, - const QString& refEntry) : myObj(obj), - myRefEntry(refEntry) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - module->setReference(myObj,myRefEntry); + TSetRefEvent( const QString& entry, + const QString& refEntry ) + : myEntry( entry ), + myRefEntry( refEntry ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + module->setReference( myEntry, myRefEntry ); + } + else { + if ( verbose() ) printf( "SalomePyQt.setReference() function is not supported for the current module.\n" ); + } } }; -void SalomePyQt::setReference(const QString& obj,const QString& refEntry) +void SalomePyQt::setReference( const QString& entry, const QString& refEntry ) { - ProcessVoidEvent(new TSetRefEvent(obj,refEntry)); + ProcessVoidEvent( new TSetRefEvent( entry, refEntry ) ); } /*! - SalomePyQt::setColor(obj,color) - Set object color -*/ + \fn void SalomePyQt::setColor( const QString& entry, const QColor& color ); + \brief Set data object color + \param entry data object entry + \param color data object color + */ + class TSetColorEvent: public SALOME_Event { public: - QString myObj; + QString myEntry; QColor myColor; - TSetColorEvent( const QString& obj, - const QColor& color) : myObj(obj), - myColor(color) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - module->setColor(myObj,myColor); + TSetColorEvent( const QString& entry, + const QColor& color ) + : myEntry( entry ), + myColor( color ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + module->setColor( myEntry, myColor ); + } + else { + if ( verbose() ) printf( "SalomePyQt.setColor() function is not supported for the current module.\n" ); + } } }; -void SalomePyQt::setColor(const QString& obj,const QColor& color) +void SalomePyQt::setColor( const QString& entry, const QColor& color ) { - ProcessVoidEvent(new TSetColorEvent(obj,color)); + ProcessVoidEvent( new TSetColorEvent( entry, color ) ); } /*! - SalomePyQt::getName(obj) - Return name of object + \fn QString SalomePyQt::getName( const QString& entry ); + \brief Get data object name + \param entry data object entry + \return data object name */ + class TGetNameEvent: public SALOME_Event { public: typedef QString TResult; TResult myResult; - QString myObj; - TGetNameEvent( const QString& obj ) : myObj(obj) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = (QString) module->getName(myObj); + QString myEntry; + TGetNameEvent( const QString& entry ) + : myEntry( entry ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + myResult = module->getName( myEntry ); + } + else { + if ( verbose() ) printf( "SalomePyQt.getName() function is not supported for the current module.\n" ); + } } }; - -QString SalomePyQt::getName(const QString& obj) +QString SalomePyQt::getName( const QString& entry ) { - return ProcessEvent(new TGetNameEvent(obj)); + return ProcessEvent( new TGetNameEvent( entry ) ); } /*! - SalomePyQt::getToolTip(obj) - Return tool tip of object + \fn QString SalomePyQt::getToolTip( const QString& entry ); + \brief Get data object tooltip + \param entry data object entry + \return data object tooltip */ + class TGetToolTipEvent: public SALOME_Event { public: typedef QString TResult; TResult myResult; - QString myObj; - TGetToolTipEvent( const QString& obj ) : myObj(obj) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = (QString)module->getToolTip(myObj); + QString myEntry; + TGetToolTipEvent( const QString& entry ) + : myEntry( entry ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + myResult = module->getToolTip( myEntry ); + } + else { + if ( verbose() ) printf( "SalomePyQt.getToolTip() function is not supported for the current module.\n" ); + } } }; -QString SalomePyQt::getToolTip(const QString& obj) +QString SalomePyQt::getToolTip( const QString& entry ) { - return ProcessEvent(new TGetToolTipEvent(obj)); + return ProcessEvent( new TGetToolTipEvent( entry ) ); } -/*! - SalomePyQt::getReference(obj) - Return entry of the referenced object (if any) +/* + \fn QString SalomePyQt::getReference( const QString& entry ); + \brief Get entry of the referenced object (if there's any) + \param entry data object entry + \return referenced data object entry */ + class TGetRefEvent: public SALOME_Event { public: typedef QString TResult; TResult myResult; - QString myObj; - TGetRefEvent( const QString& obj ) : myObj(obj) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = module->getReference(myObj); + QString myEntry; + TGetRefEvent( const QString& entry ) + : myEntry( entry ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + myResult = module->getReference( myEntry ); + } + else { + if ( verbose() ) printf( "SalomePyQt.getReference() function is not supported for the current module.\n" ); + } } }; -QString SalomePyQt::getReference(const QString& obj) +QString SalomePyQt::getReference( const QString& entry ) { - return ProcessEvent(new TGetRefEvent(obj)); + return ProcessEvent( new TGetRefEvent( entry ) ); } /*! - SalomePyQt::getColor(obj) - Return the color of the object + \fn QColor SalomePyQt::getColor( const QString& entry ); + \brief Get data object color + \param entry data object entry + \return data object color */ + class TGetColorEvent: public SALOME_Event { public: typedef QColor TResult; TResult myResult; - QString myObj; - TGetColorEvent( const QString& obj ) : myObj(obj) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = module->getColor(myObj); + QString myEntry; + TGetColorEvent( const QString& entry ) + : myEntry( entry ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + myResult = module->getColor( myEntry ); + } + else { + if ( verbose() ) printf( "SalomePyQt.getColor() function is not supported for the current module.\n" ); + } } }; -QColor SalomePyQt::getColor(const QString& obj) +QColor SalomePyQt::getColor( const QString& entry ) { - return ProcessEvent(new TGetColorEvent(obj)); + return ProcessEvent( new TGetColorEvent( entry ) ); } /*! - SalomePyQt::removeChild(obj) - Remove childrens from object + \fn void SalomePyQt::removeChildren( const QString& entry ); + \brief Remove all child data objects from specified data object + \param entry data object entry */ + class TRemoveChildEvent: public SALOME_Event { public: - QString myObj; - TRemoveChildEvent(const QString& obj) : myObj(obj) {} - - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - module->removeChild(myObj); + QString myEntry; + TRemoveChildEvent( const QString& entry ) + : myEntry( entry ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + module->removeChildren( myEntry ); + } + else { + if ( verbose() ) printf( "SalomePyQt.removeChildren() function is not supported for the current module.\n" ); + } } }; -void SalomePyQt::removeChild(const QString& obj) +void SalomePyQt::removeChildren( const QString& entry ) { - ProcessVoidEvent(new TRemoveChildEvent(obj)); + ProcessVoidEvent( new TRemoveChildEvent( entry ) ); +} +void SalomePyQt::removeChild( const QString& entry ) +{ + if ( verbose() ) printf( "SalomePyQt.removeChild() function is obsolete. Use SalomePyQt.removeChildren() instead." ); + removeChildren( entry ); } - /*! - SalomePyQt::removeObject(obj) - Remove object + \fn void SalomePyQt::removeObject( const QString& entry ); + \brief Remove object by entry + \param entry data object entry */ + class TRemoveObjectEvent: public SALOME_Event { public: - QString myObj; + QString myEntry; - TRemoveObjectEvent( const QString& obj) : myObj(obj) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - module->removeObject(myObj); + TRemoveObjectEvent( const QString& entry ) + : myEntry( entry ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + module->removeObject( myEntry ); + } + else { + if ( verbose() ) printf( "SalomePyQt.removeObject() function is not supported for the current module.\n" ); + } } }; -void SalomePyQt::removeObject(const QString& obj) +void SalomePyQt::removeObject( const QString& entry ) { - ProcessVoidEvent(new TRemoveObjectEvent(obj)); + ProcessVoidEvent( new TRemoveObjectEvent( entry ) ); } /*! - SalomePyQt::getChildren(obj) - Return the list of the child objects - if rec == true then function get all sub children. + \fn QStringList SalomePyQt::getChildren( const QString& entry, const bool recursive ); + \brief Get entries of all child data objects of specified data object + \param entry data object entry + \param recursive \c true for recursive processing */ class TGetChildrenEvent: public SALOME_Event @@ -3235,17 +3443,23 @@ class TGetChildrenEvent: public SALOME_Event public: typedef QStringList TResult; TResult myResult; - QString myObj; - bool myRec; - TGetChildrenEvent(const QString& obj, const bool rec) : myObj(obj), - myRec(rec) {} - virtual void Execute() { - SALOME_PYQT_ModuleLight* module = getActiveModule(); - if ( module ) - myResult = (QStringList)module->getChildren(myObj,myRec); + QString myEntry; + bool myRecursive; + TGetChildrenEvent( const QString& entry, const bool recursive ) + : myEntry( entry ), + myRecursive( recursive ) {} + virtual void Execute() + { + SALOME_PYQT_ModuleLight* module = dynamic_cast( getActiveModule() ); + if ( module ) { + myResult = module->getChildren( myEntry, myRecursive ); + } + else { + if ( verbose() ) printf( "SalomePyQt.getChildren() function is not supported for the current module.\n" ); + } } }; -QStringList SalomePyQt::getChildren(const QString& obj, const bool rec) +QStringList SalomePyQt::getChildren( const QString& entry, const bool recursive ) { - return ProcessEvent( new TGetChildrenEvent(obj,rec) ); + return ProcessEvent( new TGetChildrenEvent( entry, recursive ) ); } diff --git a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.h b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.h index 4f0decebc..f413631cc 100644 --- a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.h +++ b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.h @@ -36,7 +36,6 @@ #include class LightApp_SelectionMgr; -class LightApp_Application; class QMenuBar; class QMenu; class QWidget; @@ -140,27 +139,23 @@ public: static QStringList getOpenFileNames ( QWidget*, const QString&, const QStringList&, const QString& ); static QString getExistingDirectory( QWidget*, const QString&, const QString& ); - static QString createObject(const QString& parent = QString("")); - static QString createObject(const QString& name, - const QString& iconname, - const QString& tooltip, - const QString& parent = QString("")); + static QString createObject( const QString& parent = QString() ); + static QString createObject( const QString&, const QString&, const QString&, const QString& = QString() ); - static void removeObject( const QString& obj); - static void removeChild( const QString& obj = QString("")); - static QStringList getChildren(const QString& obj = QString(""), const bool rec = false); - static void setName(const QString& obj,const QString& name); - static void setIcon(const QString& obj,const QString& iconname); - static void setToolTip(const QString& obj,const QString& tooltip); - static QString getName(const QString& obj); - static QString getToolTip(const QString& obj); + static void removeObject( const QString&); + static void removeChildren( const QString& = QString() ); + static QStringList getChildren( const QString& = QString(), const bool = false ); + static void setName( const QString&, const QString& ); + static void setIcon( const QString&, const QString& ); + static void setToolTip( const QString&, const QString& ); + static QString getName( const QString& ); + static QString getToolTip( const QString& ); - static void setColor(const QString& obj,const QColor& color); - static QColor getColor(const QString& obj); + static void setColor( const QString&, const QColor& ); + static QColor getColor( const QString& ); - static void setReference( const QString& obj, - const QString& refEntry ); - static QString getReference( const QString& obj ); + static void setReference( const QString&, const QString& ); + static QString getReference( const QString& ); static QIcon loadIcon( const QString&, const QString& ); @@ -212,13 +207,6 @@ public: static QColor colorSetting ( const QString&, const QString&, const QColor& = QColor() ); static void removeSetting ( const QString&, const QString& ); static bool hasSetting ( const QString&, const QString& ); - // obsolete - static void addStringSetting( const QString&, const QString&, bool = true ); - static void addIntSetting ( const QString&, const int, bool = true ); - static void addBoolSetting ( const QString&, const bool, bool = true ); - static void addDoubleSetting( const QString&, const double, bool = true ); - static void removeSettings ( const QString& ); - static QString getSetting ( const QString& ); static int addGlobalPreference( const QString& ); static int addPreference( const QString& ); @@ -227,13 +215,8 @@ public: const QString& = QString(), const QString& = QString() ); static QVariant preferenceProperty( const int, const QString& ); - static void setPreferenceProperty( const int, - const QString&, - const QVariant& ); - static void addPreferenceProperty( const int, - const QString&, - const int, - const QVariant& ); + static void setPreferenceProperty( const int, const QString&, const QVariant& ); + static void addPreferenceProperty( const int, const QString&, const int, const QVariant& ); static void message( const QString&, bool = true ); static void clearMessages(); @@ -257,6 +240,16 @@ public: static bool splitView( const int, const Orientation, const Action ); static bool moveView( const int, const int, const bool ); static QList neighbourViews( const int ); + + // the following methods are obsolete + static void addStringSetting( const QString&, const QString&, bool = true ); + static void addIntSetting ( const QString&, const int, bool = true ); + static void addBoolSetting ( const QString&, const bool, bool = true ); + static void addDoubleSetting( const QString&, const double, bool = true ); + static void removeSettings ( const QString& ); + static QString getSetting ( const QString& ); + + static void removeChild( const QString& = QString() ); }; #endif // SALOME_PYQT_H diff --git a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip index 2eb35bd84..19927fffa 100644 --- a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip +++ b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip @@ -243,6 +243,7 @@ public: static QString getReference( const QString& ) /ReleaseGIL/ ; static void removeObject(const QString& ) /ReleaseGIL/ ; + static void removeChildren(const QString& = QString("") ) /ReleaseGIL/ ; static void removeChild(const QString& = QString("") ) /ReleaseGIL/ ; static QStringList getChildren(const QString&=QString("") , const bool = false) /ReleaseGIL/ ; diff --git a/src/SalomeApp/SalomeApp_Module.h b/src/SalomeApp/SalomeApp_Module.h index 83b432384..06310dbbf 100644 --- a/src/SalomeApp/SalomeApp_Module.h +++ b/src/SalomeApp/SalomeApp_Module.h @@ -41,7 +41,7 @@ class SUIT_DataObject; /*! * \brief Base class for all salome modules */ -class SALOMEAPP_EXPORT SalomeApp_Module : virtual public LightApp_Module +class SALOMEAPP_EXPORT SalomeApp_Module : public LightApp_Module { Q_OBJECT diff --git a/src/TreeData/Test/Makefile.am b/src/TreeData/Test/Makefile.am index cf7bf98db..3d680364d 100644 --- a/src/TreeData/Test/Makefile.am +++ b/src/TreeData/Test/Makefile.am @@ -48,7 +48,7 @@ COMMON_CPP_FLAGS = \ -I. COMMON_LIBS = \ - $(CORBA_LIBS) $(QT_LIBS) \ + $(CORBA_LIBS) $(QT_LIBS) $(VTK_LIBS) \ $(top_builddir)/src/TreeData/libSalomeTreeData.la \ $(top_builddir)/src/GuiHelpers/libSalomeGuiHelpers.la \ $(top_builddir)/src/SUIT/libsuit.la \ -- 2.39.2