]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
Qt 4.8 porting (fix problem with diamond inheritance in SALOME_PYQT packages)
authorvsr <vsr@opencascade.com>
Mon, 10 Dec 2012 09:08:16 +0000 (09:08 +0000)
committervsr <vsr@opencascade.com>
Mon, 10 Dec 2012 09:08:16 +0000 (09:08 +0000)
20 files changed:
src/CAM/CAM_Module.cxx
src/CAM/CAM_Module.h
src/GuiHelpers/StandardApp_Module.cxx
src/LightApp/LightApp_Module.cxx
src/LightApp/LightApp_Module.h
src/OCCViewer/OCCViewer_ViewFrame.cxx
src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx
src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h
src/SALOME_PYQT/SALOME_PYQT_GUILight/CMakeLists.txt
src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile.am
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx [new file with mode: 0644]
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h [new file with mode: 0644]
src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx
src/SALOME_PYQT/SalomePyQt/SalomePyQt.h
src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip
src/SalomeApp/SalomeApp_Module.h

index 9983c43d269fbfae149c887e83edac81b78b48c2..4901a9a42ee75e4f503c4677525658c6c7d28221 100755 (executable)
@@ -27,6 +27,7 @@
 #include "CAM_Study.h"
 
 #include <QtxAction.h>
+#include <QtxActionGroup.h>
 #include <QtxActionMenuMgr.h>
 #include <QtxActionToolMgr.h>
 
@@ -34,6 +35,8 @@
 #include <SUIT_Session.h>
 #include <SUIT_ResourceMgr.h>
 
+#include <QMenu>
+
 /*!
   \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<QtxActionGroup*>( action( id ) );
+  if ( !a ) {
+    a = new QtxActionGroup( this );
+    registerAction( id, a );
+  }
+  a->setExclusive( exclusive );
+  return a;
+}
+
 /*!
   \brief Register action in the internal action map.
 
index c469049b90708b6d5f2259fad891b4e3e534e0fc..1ac64e24ca8ffdf687f783ebdbfe70f3614b7d1c 100755 (executable)
@@ -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
index 6ace4942724f8781eabc81dd922a0c7431461d04..2582233781be989e9855f3ab179253e7332a2a4b 100644 (file)
@@ -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
index 5aa863e6ab493f3362bca8f7b76d765855ca62c0..745b17168b97e61297e18441ccc1c4dc922e92ed 100644 (file)
@@ -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 );
-}
index e52dd7d171d04998ee8369613c71d9aaf9e96d34..9348b075d90971cc0f017a9dc02eca4975e1f4d9 100644 (file)
@@ -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* );
index 2d3b66ae7957558ca19bfaa569c9894c7b34fe64..33dd99b7e75825d8fb50d12ce4bdeac6e6f73f46 100644 (file)
@@ -200,6 +200,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
index 8213a19ce81539b0cab7c15ffde296f31da427bb..45f827b5033d966f53073e0bfc62c534502a3bed 100644 (file)
 // File   : SALOME_PYQT_Module.cxx
 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
 
-#include <PyInterp_Dispatcher.h>
-
 #include "SALOME_PYQT_Module.h"
+#include "SALOME_PYQT_PyModule.h"
 #include "SalomeApp_Application.h"
-#include "SALOME_PYQT_ModuleLight.h"
 
 #include <SALOME_LifeCycleCORBA.hxx>
 #include <Container_init_python.hxx>
-#include <CORBA.h>
-
 
+//
+// 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<SALOME_PYQT_Module*>( 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 { <window_type> : <dock_area> }
+  \sa PyModuleHelper::windows()
+*/
+void SALOME_PYQT_Module::windows( QMap<int, int>& 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 );
 }
+
index f888a9dbcd9d8f6a0383054f41da0b6d1fe7e125..3b6e89ea3383ff29194fa5a029d5470f4e8e55bf 100644 (file)
 #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 <SALOMEconfig.h>
-#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<int, int>& ) 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
index b8e534ac4cb6c3cd7a3aa5fff42314c75a4ae3f8..b486ac979b235d98bc6c486c42f040d3a922831c 100755 (executable)
@@ -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
index 525818cac1dcaf98c11be7cb7930f2ca47799c41..c2d15f38d7c7321ae8c6045ed7edb2ba2d52fb58 100644 (file)
@@ -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)
index 70222af532abe81fd69ab64a25057f45f2af2ec9..b3526e8c4423f1960a5abfcca2cdcb3f18475bc5 100644 (file)
@@ -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);
   
 }
 
index 35ca6d19f1626def993951b6c7bafeade5db3483..47b02c8984b8b699d5487537f7b32b5fa79ee41d 100644 (file)
 #include <CAM_Module.h>
 #include "SALOME_PYQT_DataObjectLight.h"
 
-class SALOME_PYQT_RootObjectLight;
-
-
-
 class SALOME_PYQT_LIGHT_EXPORT SALOME_PYQT_DataModelLight : public LightApp_DataModel
 {
   Q_OBJECT
index b9a6aa3d279efefe1b271827ebb12022079871f9..f00641efa4faaf0e8be14cf7a4926db6e2964fa1 100644 (file)
 // 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 <SUITApp_init_python.hxx>
-#include <PyInterp_Interp.h>
-#include <PyConsole_Interp.h>
-#include <PyConsole_Console.h>
-#include <PyInterp_Dispatcher.h>
 
-#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 <Container_init_python.hxx>
-#endif
-
-#include <SUIT_ResourceMgr.h>
-#include <SUIT_DataObjectIterator.h>
-#include <SUIT_Desktop.h>
-#include <SUIT_ViewModel.h>
-#include <SUIT_ViewWindow.h>
-#include <SUIT_ViewManager.h>
-#include <STD_MDIDesktop.h>
-#include <STD_TabDesktop.h>
-#include <LightApp_Preferences.h>
-#include <LightApp_Application.h>
-#include <LightApp_Study.h>
-
-#include <QtxWorkstack.h>
-#include <QtxWorkspace.h>
-#include <QtxActionGroup.h>
-#include <QtxActionMenuMgr.h>
-#include <QtxActionToolMgr.h>
-
-#include <QFile>
-#include <QDomDocument>
-#include <QDomNode>
-#include <QDomElement>
-#include <QMenuBar>
-#include <QMenu>
-#include <QAction>
+#include "CAM_Application.h"
+#include "SUITApp_init_python.hxx"
+#include "SUIT_DataObjectIterator.h"
 
 #include "sipAPISalomePyQtGUILight.h"
 
-#include <sip.h>
-#if SIP_VERSION < 0x040700
-#include "sipQtGuiQWidget.h"
-#include "sipQtGuiQMenu.h"
-#endif
-
-#include <utilities.h>
-
-/*!
-  \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 <Container_init_python.hxx>
 #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<int>               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
-  <module>_<language>.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 { <window_type> : <dock_area> }
 \sa PyModuleHelper::windows()
 */
-bool SALOME_PYQT_ModuleLight::lastActivationStatus() const
+void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& 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<QAction*>( 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: { <window_type> : <dock_area> }
+  \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<int, int>& 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<LightApp_Application*>( app );
-  if ( !anApp )
-    return;
-  LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>( app->activeStudy() );
-  if ( !aStudy )
-    return;
-  int aStudyId = aStudy ? aStudy->id() : 0;
-
-  // initialize Python subinterpreter (on per study) and put it in <myInterp> variable
-  initInterp( aStudyId );
-  if ( !myInterp )
-    return; // Error
-
-  // import Python GUI module
-  importModule();
-  if ( !myModule )
-    return; // Error
-
-  // 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<LightApp_Study*>( theStudy );
-  int aStudyId = aStudy ? aStudy->id() : 0;
-
-  // initialize Python subinterpreter (on per study) and put it in <myInterp> 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<SUIT_ViewWindow*> 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<LightApp_Study*>( theStudy );
-  int aStudyId = aStudy ? aStudy->id() : 0;
-
-  // initialize Python subinterpreter (on per study) and put it in <myInterp> 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<SALOME_PYQT_DataModelLight*>( 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<LightApp_Study*>( theStudy );
-  int aStudyId = aStudy ? aStudy->id() : 0;
-
-  // initialize Python subinterpreter (on per study) and put it in <myInterp> variable
-  initInterp( aStudyId );
-  if ( !myInterp )
-    return; // Error
-
-  // import Python GUI module
-  importModule();
-  if ( !myModule )
-    return; // Error
-
-  if ( IsCallOldMethods ) {
-    // call 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 <myModule> 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<STD_MDIDesktop*>( getApp()->desktop() );
-      if ( aDesktop )
-        aWorkspace = aDesktop->workspace();
-    }
-    else if ( getApp()->desktop()->inherits( "STD_TabDesktop" ) ) {
-      STD_TabDesktop* aDesktop = dynamic_cast<STD_TabDesktop*>( 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<QtxActionGroup*>( 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<SALOME_PYQT_DataModelLight*>( 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<SUIT_DataObject*> 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<SALOME_PYQT_DataModelLight*>( dataModel() );
+    if ( dm ) dataObj = dm->getRoot();
+  }
+  if ( dataObj ) {
+    DataObjectList lst;
+    dataObj->children( lst, recursive );
+    QListIterator<SUIT_DataObject*> it( lst );
+    while ( it.hasNext() ) {
+      SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( 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 <item-id> attribute is missed in the XML file!
-            // also check if the action with given ID is already created
-            if ( id != -1 ) {
-              // create menu action
-              QAction* action = myModule->createAction( id,                     // ID
-                                                        tooltip,                // tooltip
-                                                        icon,                   // icon
-                                                        label,                  // menu text
-                                                        tooltip,                // status-bar text
-                                                        QKeySequence( accel ),  // keyboard accelerator
-                                                        toggle );               // toogled action
-              myModule->createMenu( action,   // action
-                                    menuId,   // parent menu ID
-                                    id,       // ID (same as for createAction())
-                                    group,    // group ID
-                                    pos );    // position
-            }
-          }
-          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 <item-id> 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<QAction*> 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 <item-id> 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<SALOME_PYQT_DataModelLight*>( 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<SALOME_PYQT_DataModelLight*>( dataModel());
-  if(!entry.isEmpty() && dm ){
-    for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) { 
-      SALOME_PYQT_DataObjectLight* curentobj =
-        dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.current() );
-      
-      if(curentobj && curentobj->entry() == entry) {
-        obj = curentobj;
-        return obj;
-      }
+  SALOME_PYQT_DataObjectLight* obj = 0;
+  SALOME_PYQT_DataModelLight* dm =
+    dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
+  if ( !entry.isEmpty() && dm ) {
+    for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current() && !obj; ++it ) { 
+      SALOME_PYQT_DataObjectLight* curentobj =
+        dynamic_cast<SALOME_PYQT_DataObjectLight*>( 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<SUIT_DataObject*> it( lst );
-      while( it.hasNext() )
-      {
-        SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.next() );
-        dataObj->removeChild(sobj);
-      }
-    }
-  }
-  else
-  {
-    SALOME_PYQT_DataModelLight* dm =
-      dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel());
-    if(dm)
-    {
-      dm->getRoot()->children(lst);
-      QListIterator<SUIT_DataObject*> it( lst );
-      while(it.hasNext() )
-      {
-        SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( 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<SUIT_DataObject*> it( lst );
-      while(it.hasNext())
-      {
-        SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.next() );
-        entryList.append(sobj->entry());
-      }
-    }
-  }
-  else
-  {
-    SALOME_PYQT_DataModelLight* dm =
-      dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel());
-    if(dm)
-    {
-      dm->getRoot()->children(lst);
-      QListIterator<SUIT_DataObject*> it( lst );
-      while( it.hasNext() )
-      {
-        SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( 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<const LightApp_DataObject*>( 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<SALOME_PYQT_ModuleLight*>( this ),
-                                                           const_cast<LightApp_DataObject*>( 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<const LightApp_DataObject*>( 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<SALOME_PYQT_ModuleLight*>( this ),
-                                                              const_cast<LightApp_DataObject*>( 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<LightApp_DataObject*>( where );
-  if ( !whereObject ) return;
-  
-  for ( int i = 0; i < what.count(); i++ ) {
-    LightApp_DataObject* dataObject = dynamic_cast<LightApp_DataObject*>( 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();
-    }
-  }
-}
index c2c92eac3c9fe270c1e8d5c450ced12318105e9d..6807e07050016c3c39daadd23d2f0e741dfa776b 100644 (file)
 // 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 <CAM_Module.h>
 
-#include <map>
-#include <QStringList>
-#include <QList>
-#include <QMap>
 #include <QIcon>
+#include <QMap>
+#include <QStringList>
 
-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<int, PyInterp_Interp*> InterpMap;
-  static SALOME_PYQT_ModuleLight* myInitModule; //!< Python GUI being initialized (not zero only during the initialization)
-
-  XmlHandler*                myXmlHandler; //!< XML resource file parser
-  QMap<int, int>             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<int, int>& ) 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<int, int>& ) 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 (file)
index 0000000..d867ec4
--- /dev/null
@@ -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 <QApplication>
+#include <QDomDocument>
+#include <QDomElement>
+#include <QDomNode>
+#include <QFile>
+#include <QMenu>
+#include <QMutex>
+
+#include <utilities.h>
+
+#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<int>       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 <item-id> attribute is missed in the XML file!
+            // also check if the action with given ID is already created
+            if ( id != -1 ) {
+              // create menu action
+              QAction* action = 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 <item-id> 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<QAction*> 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 <item-id> 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 { <window_type> : <dock_area> }
+*/
+QMap<int, int> 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
+  <module>_<language>.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<QAction*>( 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<const LightApp_DataObject*>( 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<PyModuleHelper*>( this ),
+                                                           const_cast<LightApp_DataObject*>( 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<const LightApp_DataObject*>( 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<PyModuleHelper*>( this ),
+                                                              const_cast<LightApp_DataObject*>( 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<PyModuleHelper*>( 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 <myPyModule> 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<STD_MDIDesktop*>( myModule->getApp()->desktop() );
+    if ( d )
+      aWorkspace = d->workspace();
+  }
+  else if ( myModule->getApp()->desktop()->inherits( "STD_TabDesktop" ) ) {
+    STD_TabDesktop* d = dynamic_cast<STD_TabDesktop*>( 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<LightApp_Application*>( app );
+  if ( !anApp )
+    return;
+  LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>( app->activeStudy() );
+  if ( !aStudy )
+    return;
+  int aStudyId = aStudy ? aStudy->id() : 0;
+
+  // initialize Python subinterpreter (on per study) and put it in <myInterp> variable
+  initInterp( aStudyId );
+  if ( !myInterp )
+    return; // Error
+
+  // import Python GUI module
+  importModule();
+  if ( !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<LightApp_Study*>( study );
+  int aStudyId = aStudy ? aStudy->id() : 0;
+
+  // initialize Python subinterpreter (on per study) and put it in <myInterp> 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<LightApp_Study*>( study );
+  int aStudyId = aStudy ? aStudy->id() : 0;
+
+  // initialize Python subinterpreter (on per study) and put it in <myInterp> 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<LightApp_Study*>( 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 <myInterp> 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<LightApp_DataObject*>( where );
+  if ( !whereObject ) return;
+  
+  for ( int i = 0; i < what.count(); i++ ) {
+    LightApp_DataObject* dataObject = dynamic_cast<LightApp_DataObject*>( 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 (file)
index 0000000..b14a7c6
--- /dev/null
@@ -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 <QIcon>
+#include <QList>
+#include <QMap>
+#include <QObject>
+#include <QStringList>
+
+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<SUIT_DataObject*> DataObjectList;
+
+class SALOME_PYQT_LIGHT_EXPORT PyModuleHelper : public QObject
+{
+  Q_OBJECT
+
+private:
+  class XmlHandler;
+  class InitLocker;
+
+  typedef QMap<int, PyInterp_Interp*> 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<int, int>             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<int, int>             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
index 899508ad39be2df1abc0c73bdaf6381e57af2a63..d526f2464930f99bbf6a458e9641b72260a04813 100644 (file)
@@ -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
 #include <pymath.h>
 #endif
 
-#include <SALOME_PYQT_ModuleLight.h> // this include must be first!!!
-#include <SALOME_PYQT_DataModelLight.h>
+#include "SALOME_PYQT_ModuleLight.h" // this include must be first!!!
+#include "SALOME_PYQT_DataModelLight.h"
+#include "SALOME_PYQT_PyModule.h"
 #include "SalomePyQt.h"
 
-#include <QApplication>
-#include <QMenuBar>
-#include <QMenu>
-#include <QImage>
-#include <QStringList>
-#include <QAction>
+#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 <SALOME_Event.h>
-
-#include <QtxActionMenuMgr.h>
-#include <QtxActionGroup.h>
-#include <QtxWorkstack.h>
-#include <QtxTreeView.h>
-#include <SUIT_Session.h>
-#include <SUIT_Desktop.h>
-#include <SUIT_ResourceMgr.h>
-#include <SUIT_Tools.h>
-#include <SUIT_ViewManager.h>
-#include <SUIT_ViewWindow.h>
-#include <SUIT_DataBrowser.h>
-#include <STD_TabDesktop.h>
-#include <LightApp_Application.h>
-#include <LightApp_Study.h>
-#include <LightApp_SelectionMgr.h>
-#include <LogWindow.h>
-#include <OCCViewer_ViewWindow.h>
-#include <Plot2d_ViewManager.h>
-#include <Plot2d_ViewWindow.h>
+#include <QAction>
+#include <QApplication>
 
 /*!
   \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<SALOME_PYQT_ModuleLight*>( anApp->activeModule() );
+      module = dynamic_cast<LightApp_Module*>( 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<PyModuleHelper*>( 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<SALOME_PYQT_DataModelLight*>( 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<SALOME_PYQT_DataModelLight*>( module->dataModel() );
-      LightApp_Application* aLApp = 
-       dynamic_cast<LightApp_Application*>( 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<LightApp_Module*>( 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<PyModuleHelper*>( 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<QVariant> vl = var.toList();
-            if ( myIdx >= 0 && myIdx < vl.count() ) 
-              vl[myIdx] = myVar;
-            else
-              vl.append( myVar );
-            module->setPreferenceProperty( myId, myProp, vl );
-          }
-        }
-        else {
-          QList<QVariant> 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<QVariant> vl = var.toList();
+             if ( myIdx >= 0 && myIdx < vl.count() ) 
+               vl[myIdx] = myVar;
+             else
+               vl.append( myVar );
+             pref->setItemProperty( myProp, vl, myId );
+           }
+         }
+         else {
+           QList<QVariant> vl;
+           vl.append( myVar );
+           pref->setItemProperty( myProp, vl, myId );
+         }
+       }
       }
     }
   };
@@ -2250,7 +2337,7 @@ static SUIT_ViewWindow* getWnd( const int id )
 }
 
 /*!
-  \fn QList<int> SalomePyQt::getViews()
+  \fn QList<int> 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<int> 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<int> SalomePyQt::findViews( const QString& type )
+  \fn QList<int> 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<int> 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<int> SalomePyQt::neighbourViews( const int id )
+  \fn QList<int> 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<int> 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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<SALOME_PYQT_ModuleLight*>( 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 ) ); 
 }
index 4f0decebc240b968a72b3b0dc11079af0744f2ab..f413631ccfb8bde7897a68c08caac17663fb7813 100644 (file)
@@ -36,7 +36,6 @@
 #include <LightApp_Preferences.h>
 
 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<int>        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
index 2eb35bd845a17ebd12e83a101e022457766284ea..19927fffa8430036578acf795eb90f29688e5dcc 100644 (file)
@@ -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/ ;
 
index 83b4323843630bf203b22cf6b3e2be21bd3182d8..06310dbbff879a191c7f62ca3accd6aee59c3e8f 100644 (file)
@@ -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