Salome HOME
bos #29467 SALOME GUI logger
[modules/gui.git] / src / SALOME_PYQT / SalomePyQt / SalomePyQt.cxx
index 67c57f31d7a844f315f5ae778d81cc46e1633762..9d990cc115408f35253aa7c37000d8445270b936 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -42,6 +42,9 @@
 #include "OCCViewer_ViewWindow.h"
 #include "OCCViewer_ViewFrame.h"
 #endif // DISABLE_OCCVIEWER
+#ifndef DISABLE_VTKVIEWER
+#include "SVTK_ViewWindow.h"
+#endif // DISABLE_VTKVIEWER
 #ifndef DISABLE_PLOT2DVIEWER
 #include "Plot2d_ViewManager.h"
 #include "Plot2d_ViewWindow.h"
 #include "PVViewer_ViewManager.h"
 #include "PVViewer_ViewModel.h"
 #endif // DISABLE_PVVIEWER
+#ifndef DISABLE_PV3DVIEWER
+#include "PV3DViewer_ViewManager.h"
+#include "PV3DViewer_ViewModel.h"
+#endif // DISABLE_PV3DVIEWER
 #include "QtxActionMenuMgr.h"
 #include "QtxWorkstack.h"
 #include "QtxTreeView.h"
+#include "QtxInfoPanel.h"
 #include "SALOME_Event.h"
 #include "STD_TabDesktop.h"
 #include "SUIT_DataBrowser.h"
@@ -67,6 +75,9 @@
 #include <QApplication>
 #include <QPaintEvent>
 #include <QCoreApplication>
+#include <QVBoxLayout>
+
+#include <utilities.h>
 
 namespace
 {
@@ -174,7 +185,7 @@ namespace
     if ( app && !fileName.isEmpty() ) {
       QPixmap pixmap = app->resourceMgr()->loadPixmap( module, 
                                                        QApplication::translate( module.toLatin1().data(), 
-                                                                                fileName.toLatin1().data() ) );
+                                                                                fileName.toUtf8().data() ) );
       if ( !pixmap.isNull() )
         icon = QIcon( pixmap );
     }
@@ -218,6 +229,25 @@ namespace
     \internal
   */
   const char* DEFAULT_SECTION = "SalomePyQt";
+
+  struct Activator
+  {
+    QWidget* myActiveWindow;
+    QWidget* myFocusedWidget;
+    Activator()
+    {
+      myActiveWindow = QApplication::activeWindow();
+      myFocusedWidget = QApplication::focusWidget();
+      QApplication::setActiveWindow( getApplication()->desktop() );
+    }
+    ~Activator()
+    {
+      if ( myActiveWindow )
+       QApplication::setActiveWindow( myActiveWindow );
+      if ( myFocusedWidget )
+       myFocusedWidget->setFocus();
+    }
+  };
 }
 
 /*!
@@ -243,6 +273,7 @@ SALOME_Selection* SALOME_Selection::GetSelection( LightApp_Application* app )
   return sel;
 }
 
+
 /*!
   \brief Constructor.
   \param p parent object
@@ -327,6 +358,90 @@ void SALOME_Selection::ClearFilters()
   ProcessVoidEvent( new TEvent( mySelMgr ) );
 }
 
+/*!
+  \class UserDefinedContent
+  \brief The class represents base class for user defined widget that
+  can be inserted to the Preferences dialog.
+*/
+
+/*!
+  \brief Constructor
+*/
+UserDefinedContent::UserDefinedContent()
+  : QWidget()
+{
+}
+
+/*!
+  \brief Called from Preferences dialog to store settings to the resource file.
+*/
+void UserDefinedContent::store()
+{
+}
+
+/*!
+  \brief Called from Preferences dialog to restore settings from the resource file.
+*/
+void UserDefinedContent::retrieve()
+{
+}
+
+/*!
+  \class SgPyQtUserDefinedContent
+  \brief A Wrapper for UserDefinedContent class.
+  \internal
+*/
+class SgPyQtUserDefinedContent: public QtxUserDefinedContent
+{
+public:
+  SgPyQtUserDefinedContent(UserDefinedContent*);
+  virtual ~SgPyQtUserDefinedContent();
+
+  void store( QtxResourceMgr*, QtxPreferenceMgr* );
+  void retrieve( QtxResourceMgr*, QtxPreferenceMgr* );
+
+private:
+  UserDefinedContent* myContent;
+};
+
+/*!
+  \brief Create custom item for Preferences dialog wrapping widget passed from Python.
+  \internal
+*/
+SgPyQtUserDefinedContent::SgPyQtUserDefinedContent(UserDefinedContent* content)
+  : QtxUserDefinedContent( 0 ), myContent( content )
+{
+  QVBoxLayout* l = new QVBoxLayout( this );
+  l->setContentsMargins( 0, 0, 0, 0 );
+  l->addWidget( myContent );
+}
+
+/*!
+  \brief Destructor.
+  \internal
+*/
+SgPyQtUserDefinedContent::~SgPyQtUserDefinedContent()
+{
+}
+
+/*!
+  \brief Called from Preferences dialog to store settings to the resource file.
+  \internal
+*/
+void SgPyQtUserDefinedContent::store( QtxResourceMgr*, QtxPreferenceMgr* )
+{
+  myContent->store();
+}
+
+/*!
+  \brief Called from Preferences dialog to restore settings from the resource file.
+  \internal
+*/
+void SgPyQtUserDefinedContent::retrieve( QtxResourceMgr*, QtxPreferenceMgr* )
+{
+  myContent->retrieve();
+}
+
 /*!
   \class SalomePyQt
   \brief The class provides utility functions which can be used in the Python
@@ -345,6 +460,29 @@ void SALOME_Selection::ClearFilters()
   \endcode
 */
 
+/*!
+  \fn QString SalomePyQt::getAppName();
+  \brief Get application name
+  \return application name
+*/
+
+QString SalomePyQt::getAppName()
+{
+  LightApp_Application* app = getApplication();
+  return app == 0 ? QString() : QString(app->metaObject()->className()).split("_").first();
+}
+
+/*!
+  \fn bool SalomePyQt::isLightApp();
+  \brief Check if SALOME GUI is running in "light" mode.
+  \return \c true if this is a "light" application; \c false otherwise
+*/
+
+bool SalomePyQt::isLightApp()
+{
+  return SalomePyQt::getAppName() != "SalomeApp";
+}
+
 /*!
   \fn QWidget* SalomePyQt::getDesktop();
   \brief Get the active application's desktop window.
@@ -511,54 +649,99 @@ QTreeView* SalomePyQt::getObjectBrowser()
 }
 
 /*!
-  \fn int SalomePyQt::getStudyId();
-  \brief Get active study's identifier.
-  \return active study ID or 0 if there is no active study
+  \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.
+
+  \return selection object (0 on error)
 */
 
-class TGetStudyIdEvent: public SALOME_Event
+class TGetSelectionEvent: public SALOME_Event 
 {
 public:
-  typedef int TResult;
+  typedef SALOME_Selection* TResult;
   TResult myResult;
-  TGetStudyIdEvent() : myResult( 0 ) {}
+  TGetSelectionEvent() : myResult( 0 ) {}
+  virtual void Execute() 
+  {
+    myResult = SALOME_Selection::GetSelection( getApplication() );
+  }
+};
+SALOME_Selection* SalomePyQt::getSelection()
+{
+  return ProcessEvent( new TGetSelectionEvent() );
+}
+
+/*!
+  \fn QStringList* SalomePyQt::setSelection(const QStringList& );
+  \brief Send local selection for notification.
+
+  The list of locally selected objects (study entries) is sent for notification of
+  other listening entities (modules, viewers...).
+*/
+
+class TSetSelectionEvent: public SALOME_Event
+{
+  QStringList myEntryList;
+public:
+  TSetSelectionEvent(const QStringList& entryList) : myEntryList(entryList) {}
   virtual void Execute()
   {
-    if ( LightApp_Study* aStudy = getActiveStudy() ) {
-      myResult = aStudy->id();
-    }
+       SALOME_PYQT_ModuleLight* module = dynamic_cast<SALOME_PYQT_ModuleLight*>( getActiveModule() );
+       if ( !module ) return;
+       module->setLocalSelected(myEntryList);
   }
 };
-int SalomePyQt::getStudyId()
+void SalomePyQt::setSelection( const QStringList& entryList)
 {
-  return ProcessEvent( new TGetStudyIdEvent() );
+  return ProcessVoidEvent( new TSetSelectionEvent(entryList) );
 }
 
 /*!
-  \fn SALOME_Selection* SalomePyQt::getSelection();
-  \brief Get the selection object for the current study.
+  \fn void SalomePyQt::enableSelector();
+  \brief enable PyQt_Selector (on module activation, for instance)
+*/
 
-  Creates a Selection object if it has not been created yet.
+class TEnableSelectorEvent: public SALOME_Event
+{
+public:
+       TEnableSelectorEvent() {}
+  virtual void Execute()
+  {
+       SALOME_PYQT_ModuleLight* module = dynamic_cast<SALOME_PYQT_ModuleLight*>( getActiveModule() );
+       if ( !module ) return;
+       module->enableSelector();
+  }
+};
+void SalomePyQt::enableSelector()
+{
+  return ProcessVoidEvent( new TEnableSelectorEvent() );
+}
 
-  \return selection object (0 on error)
+
+/*!
+  \fn void SalomePyQt::disableSelector();
+  \brief disable PyQt_Selector (on module activation, for instance)
 */
 
-class TGetSelectionEvent: public SALOME_Event 
+class TdisableSelectorEvent: public SALOME_Event
 {
 public:
-  typedef SALOME_Selection* TResult;
-  TResult myResult;
-  TGetSelectionEvent() : myResult( 0 ) {}
-  virtual void Execute() 
+       TdisableSelectorEvent() {}
+  virtual void Execute()
   {
-    myResult = SALOME_Selection::GetSelection( getApplication() );
+       SALOME_PYQT_ModuleLight* module = dynamic_cast<SALOME_PYQT_ModuleLight*>( getActiveModule() );
+       if ( !module ) return;
+       module->disableSelector();
   }
 };
-SALOME_Selection* SalomePyQt::getSelection()
+void SalomePyQt::disableSelector()
 {
-  return ProcessEvent( new TGetSelectionEvent() );
+  return ProcessVoidEvent( new TdisableSelectorEvent() );
 }
 
+
 /*!
   \fn void SalomePyQt::putInfo( const QString& msg, const int sec );
   \brief Put an information message to the current application's 
@@ -590,6 +773,123 @@ void SalomePyQt::putInfo( const QString& msg, const int sec )
   ProcessVoidEvent( new TPutInfoEvent( msg, sec ) );
 }
 
+/*!
+  \fn int SalomePyQt::showNotification( const QString& msg, const QString& title, const int sec );
+  \brief Show notification in the application's desktop window.
+
+  Optional third delay parameter (\a sec) can be used to specify
+  time of the notification diplaying in seconds. If this parameter is less
+  or equal to zero, the permanent notification will be put.
+
+  Notification can be forcibly hidden via hideNotification() method.
+
+  \param msg message text 
+  \param title title text 
+  \param sec notification displaying time in seconds
+  \return unique ID of the notification (can be used to hide notification)
+  \sa hideNotification()
+*/
+
+class TShowNotifyEvent: public SALOME_Event
+{
+  QString myMsg;
+  QString myTitle;
+  int     mySecs;
+
+public:
+  typedef int TResult;
+  TResult myResult;
+
+public:
+  TShowNotifyEvent( const QString& msg, const QString& title, const int sec = -1 ) : myMsg( msg ), myTitle( title), mySecs( sec ), myResult( -1 ) {}
+  virtual void Execute()
+  {
+    if ( LightApp_Application* anApp = getApplication() ) {
+      myResult = anApp->showNotification( myMsg, myTitle, mySecs * 1000 );
+    }
+  }
+};
+
+int SalomePyQt::showNotification( const QString& msg, const QString& title, const int sec )
+{
+  return ProcessEvent( new TShowNotifyEvent( msg, title, sec ) );
+}
+
+/*!
+  \fn void SalomePyQt::hideNotification( const QString& msg );
+  \brief Remove notification with given message text from the application's desktop.
+
+  \param msg message text
+  \sa showNotification()
+*/
+
+/*!
+  \fn void SalomePyQt::hideNotification( const int id );
+  \brief Remove notification with given \a id from the application's desktop.
+
+  \param id notification id
+  \sa showNotification()
+*/
+
+class THideNotifyEvent: public SALOME_Event
+{
+  int     myId;
+  QString myMsg;
+
+public:
+  THideNotifyEvent( const QString& msg ) : myId( -1 ), myMsg( msg ) {}
+  THideNotifyEvent( const int id ) : myId( id ) {}
+  virtual void Execute()
+  {
+    if ( LightApp_Application* anApp = getApplication() ) {
+      if ( myId >= 0 )
+       anApp->hideNotification( myId );
+      else
+       anApp->hideNotification( myMsg );
+    }
+  }
+};
+
+void SalomePyQt::hideNotification( const QString& msg )
+{
+  ProcessVoidEvent( new THideNotifyEvent( msg ) );
+}
+
+void SalomePyQt::hideNotification( const int id )
+{
+  ProcessVoidEvent( new THideNotifyEvent( id ) );
+}
+
+/*!
+  \fn QStringList SalomePyQt::getComponents();
+  \brief Get all modules used in current GUI session.
+  \return List of modules
+*/
+
+class TGetComponentsEvent: public SALOME_Event
+{
+public:
+  typedef QStringList TResult;
+  TResult myResult;
+  TGetComponentsEvent() {}
+  virtual void Execute() 
+  {
+    if ( LightApp_Application* anApp = getApplication() )
+    {
+      QStringList titles;
+      anApp->modules( titles, false );
+      foreach ( QString title, titles )
+      {
+       myResult << anApp->moduleName( title );
+      }
+    }
+  }
+};
+QStringList SalomePyQt::getComponents()
+{
+  return ProcessEvent( new TGetComponentsEvent() );
+}
+
 /*!
   \fn const QString SalomePyQt::getActiveComponent();
   \brief Get the currently active module name (for the current study).
@@ -657,6 +957,7 @@ public:
   virtual void Execute() 
   {
     if ( LightApp_Application* anApp = getApplication() ) {
+      Activator activator;
       myResult = anApp->activateModule( myModuleName );
     }
   }
@@ -667,37 +968,45 @@ bool SalomePyQt::activateModule( const QString& modName )
 }
 
 /*!
-  \brief Update an Object Browser of the specified (by identifier) study.
+  \fn void SalomePyQt::registerModule( const QString& modName);
+  \brief Registers module in the study tree
+*/
 
-  If \a studyId <= 0 the active study's object browser is updated.
-  The \a updateSelection parameter is obsolete and currently is not used. 
-  This parameter will be removed in future, so try to avoid its usage in 
-  your code.
+void SalomePyQt::registerModule( const QString& modName)
+{
+  class TEvent: public SALOME_Event
+  {
+    QString myName;
+  public:
+    TEvent(const QString& name): myName(name) {}
+    virtual void Execute()
+    {
+      if ( LightApp_Application* anApp = getApplication() ) {
+       anApp->desktop()->emitMessage(QString("register_module_in_study/%1").arg(myName));
+      }
+    }
+  };
+  ProcessVoidEvent( new TEvent(modName) );
+}
 
-  \brief studyId study identifier
-  \brief updateSelection update selection flag (not used)
-  \sa getActiveStudy()
+/*!
+  \brief Update an Object Browser of the study.
 */
-void SalomePyQt::updateObjBrowser( const int studyId, bool updateSelection )
+void SalomePyQt::updateObjBrowser()
 {  
   class TEvent: public SALOME_Event
   {
-    int  myStudyId;
-    bool myUpdateSelection;
   public:
-    TEvent( const int studyId, bool updateSelection ) 
-      : myStudyId( studyId ), myUpdateSelection( updateSelection ) {}
+    TEvent() {}
     virtual void Execute()
     {
       if ( SUIT_Session::session() ) {
-        if ( getActiveStudy() && myStudyId <= 0 )
-          myStudyId = getActiveStudy()->id();
-        if ( myStudyId > 0 ) {
+        if ( getActiveStudy() ) {
           QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
           QList<SUIT_Application*>::Iterator it;
           for( it = apps.begin(); it != apps.end(); ++it ) {
             LightApp_Application* anApp = dynamic_cast<LightApp_Application*>( *it );
-            if ( anApp && anApp->activeStudy() && anApp->activeStudy()->id() == myStudyId ) {
+            if ( anApp && anApp->activeStudy() ) {
               anApp->updateObjectBrowser();
               return;
             }
@@ -706,7 +1015,7 @@ void SalomePyQt::updateObjBrowser( const int studyId, bool updateSelection )
       }
     }
   };
-  ProcessVoidEvent( new TEvent( studyId, updateSelection ) );
+  ProcessVoidEvent( new TEvent() );
 }
 
 
@@ -1241,6 +1550,34 @@ void SalomePyQt::addSetting( const QString& section, const QString& name, const
   ProcessVoidEvent( new TEvent( section, name, value ) );
 }
 
+/*!
+  \brief Add font setting to the application preferences.
+  \param section resources file section name 
+  \param name setting name
+  \param value new setting value
+*/
+void SalomePyQt::addSetting( const QString& section, const QString& name, const QFont& value )
+{
+  class TEvent: public SALOME_Event 
+  {
+    QString    mySection;
+    QString    myName;
+    QFont      myValue;
+  public:
+    TEvent( const QString& section, const QString& name, const QFont& value ) 
+      : mySection( section ), myName( name ), myValue( value ) {}
+    virtual void Execute() 
+    {
+      if ( SUIT_Session::session() ) {
+        SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+        if ( !mySection.isEmpty() && !myName.isEmpty() )
+          resMgr->setValue( mySection, myName, myValue );
+      }
+    }
+  };
+  ProcessVoidEvent( new TEvent( section, name, value ) );
+}
+
 /*!
   \fn int SalomePyQt::integerSetting( const QString& section, 
                                       const QString& name, 
@@ -1366,7 +1703,7 @@ public:
   bool mySubst;
   TResult myDefault;
   TGetStrSettingEvent( const QString& section, const QString& name, const QString& def, const bool subst ) 
-    : mySection( section ), myName( name ), myDefault( def ), mySubst( subst ) {}
+    : mySection( section ), myName( name ), mySubst( subst ), myDefault( def ) {}
   virtual void Execute() 
   {
     if ( SUIT_Session::session() ) {
@@ -1417,7 +1754,7 @@ QColor SalomePyQt::colorSetting ( const QString& section, const QString& name, c
 /*!
   \fn QByteArray SalomePyQt::byteArraySetting( const QString& section, 
                                                const QString& name, 
-                                               const QByteArray def );
+                                               const QByteArray& def );
   \brief Get byte array setting from the application preferences.
   \param section resources file section name 
   \param name setting name
@@ -1449,24 +1786,58 @@ QByteArray SalomePyQt::byteArraySetting ( const QString& section, const QString&
 }
 
 /*!
-  \brief Remove setting from the application preferences.
+  \fn QByteArray SalomePyQt::fontSetting( const QString& section, 
+                                          const QString& name, 
+                                          const QFont& def );
+  \brief Get font setting from the application preferences.
   \param section resources file section name 
   \param name setting name
+  \param def default value which is returned if the setting is not found
+  \return setting value
 */
-void SalomePyQt::removeSetting( const QString& section, const QString& name )
+
+class TGetFontSettingEvent: public SALOME_Event 
 {
-  class TEvent: public SALOME_Event 
+public:
+  typedef QFont TResult;
+  TResult myResult;
+  QString mySection;
+  QString myName;
+  TResult myDefault;
+  TGetFontSettingEvent( const QString& section, const QString& name, const QFont& def ) 
+    : mySection( section ), myName( name ), myDefault( def ) {}
+  virtual void Execute() 
   {
-    QString mySection;
-    QString myName;
-  public:
-    TEvent( const QString& section, const QString& name ) : mySection( section ), myName( name ) {}
-    virtual void Execute() 
-    {
-      if ( SUIT_Session::session() ) {
-        SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
-        if ( !mySection.isEmpty() && !myName.isEmpty() )
-          resMgr->remove( mySection, myName );
+    if ( SUIT_Session::session() ) {
+      SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+      myResult = ( !mySection.isEmpty() && !myName.isEmpty() ) ? resMgr->fontValue( mySection, myName, myDefault ) : myDefault;
+    }
+  }
+};
+QFont SalomePyQt::fontSetting ( const QString& section, const QString& name, const QFont& def )
+{
+  return ProcessEvent( new TGetFontSettingEvent( section, name, def ) );
+}
+
+/*!
+  \brief Remove setting from the application preferences.
+  \param section resources file section name 
+  \param name setting name
+*/
+void SalomePyQt::removeSetting( const QString& section, const QString& name )
+{
+  class TEvent: public SALOME_Event 
+  {
+    QString mySection;
+    QString myName;
+  public:
+    TEvent( const QString& section, const QString& name ) : mySection( section ), myName( name ) {}
+    virtual void Execute() 
+    {
+      if ( SUIT_Session::session() ) {
+        SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+        if ( !mySection.isEmpty() && !myName.isEmpty() )
+          resMgr->remove( mySection, myName );
       }
     }
   };
@@ -1771,29 +2142,49 @@ public:
   CrTool( const QString& tBar, const QString& nBar ) 
     : myCase( 0 ), myTbTitle( tBar ), myTbName( nBar)  {}
   CrTool( const int id, const int tBar, const int idx ) 
-    : myCase( 1 ), myId( id ), myTbId( tBar ), myIndex( idx ) {}
+    : myCase( 1 ), myTbId( tBar ), myId( id ), myIndex( idx ) {}
   CrTool( const int id, const QString& tBar, const int idx )
-    : myCase( 2 ), myId( id ), myTbTitle( tBar ), myIndex( idx ) {}
+    : myCase( 2 ), myTbTitle( tBar ), myId( id ), myIndex( idx ) {}
   CrTool( QAction* action, const int tbId, const int id, const int idx )
-    : myCase( 3 ), myAction( action ), myTbId( tbId ), myId( id ), myIndex( idx ) {}
+    : myCase( 3 ), myTbId( tbId ), myAction( action ), myId( id ), myIndex( idx ) {}
   CrTool( QAction* action, const QString& tBar, const int id, const int idx )
-    : myCase( 4 ), myAction( action ), myTbTitle( tBar ), myId( id ), myIndex( idx ) {}
+    : myCase( 4 ), myTbTitle( tBar ), myAction( action ), myId( id ), myIndex( idx ) {}
 
-  int execute( LightApp_Module* module ) const
+  int execute() const
   {
-    if ( module ) {
-      switch ( myCase ) {
-      case 0:
-        return module->createTool( myTbTitle, myTbName );
-      case 1:
-        return module->createTool( myId, myTbId, myIndex );
-      case 2:
-        return module->createTool( myId, myTbTitle, myIndex );
-      case 3:
-        return module->createTool( myAction, myTbId, myId, myIndex );
-      case 4:
-        return module->createTool( myAction, myTbTitle, myId, myIndex );
-      }
+    switch ( myCase ) {
+    case 0:
+      if ( getActiveModule() )
+        return getActiveModule()->createTool( myTbTitle, myTbName );
+      else if ( getApplication() )
+        return getApplication()->createTool( myTbTitle, myTbName );
+      break;
+    case 1:
+      if ( getActiveModule() )
+        return getActiveModule()->createTool( myId, myTbId, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createTool( myId, myTbId, myIndex );
+      break;
+    case 2:
+      if ( getActiveModule() )
+        return getActiveModule()->createTool( myId, myTbTitle, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createTool( myId, myTbTitle, myIndex );
+      break;
+    case 3:
+      if ( getActiveModule() )
+        return getActiveModule()->createTool( myAction, myTbId, myId, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createTool( myAction, myTbId, myId, myIndex );
+      break;
+    case 4:
+      if ( getActiveModule() )
+        return getActiveModule()->createTool( myAction, myTbTitle, myId, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createTool( myAction, myTbTitle, myId, myIndex );
+      break;
+    default:
+      break;
     }
     return -1;
   }
@@ -1817,9 +2208,7 @@ public:
     : myResult( -1 ), myCrTool( crTool ) {}
   virtual void Execute() 
   {
-    LightApp_Module* module = getActiveModule();
-    if ( module )
-      myResult = myCrTool.execute( module );
+    myResult = myCrTool.execute();
   }
 };
 
@@ -1871,6 +2260,30 @@ int SalomePyQt::createTool( QAction* a, const int tBar, const int id, const int
   return ProcessEvent( new TCreateToolEvent( CrTool( a, tBar, id, idx ) ) );
 }
 
+
+/*!
+  \brief Clear given toolbar.
+  \param title toolbar's title
+*/
+void SalomePyQt::clearTool( const QString& title )
+{
+  class TEvent: public SALOME_Event
+  {
+    QString myTitle;
+  public:
+    TEvent( const QString& title ) 
+      : myTitle( title ) {}
+    virtual void Execute() 
+    {
+      if ( getActiveModule() )
+        return getActiveModule()->clearTool( myTitle );
+      else if ( getApplication() )
+        return getApplication()->clearTool( myTitle );
+    }
+  };
+  ProcessVoidEvent( new TEvent( title ) );
+}
+
 /*!
   \brief Insert action to the toolbar.
   \param a action
@@ -1888,35 +2301,59 @@ class CrMenu
 {
 public:
   CrMenu( const QString& subMenu, const int menu, const int id, const int group, const int idx ) 
-    : myCase( 0 ), mySubMenuName( subMenu ), myMenuId( menu ), myId( id ), myGroup( group ), myIndex( idx ) {}
+    : myCase( 0 ), myMenuId( menu ), mySubMenuName( subMenu ), myGroup( group ), myId( id ), myIndex( idx ) {}
   CrMenu( const QString& subMenu, const QString& menu, const int id, const int group, const int idx ) 
-    : myCase( 1 ), mySubMenuName( subMenu ), myMenuName( menu ), myId( id ), myGroup( group ), myIndex( idx ) {}
+    : myCase( 1 ), myMenuName( menu ), mySubMenuName( subMenu ), myGroup( group ), myId( id ), myIndex( idx ) {}
   CrMenu( const int id, const int menu, const int group, const int idx ) 
-    : myCase( 2 ), myId( id ), myMenuId( menu ), myGroup( group ), myIndex( idx ) {}
+    : myCase( 2 ), myMenuId( menu ), myGroup( group ), myId( id ), myIndex( idx ) {}
   CrMenu( const int id, const QString& menu, const int group, const int idx ) 
-    : myCase( 3 ), myId( id ), myMenuName( menu ), myGroup( group ), myIndex( idx ) {}
+    : myCase( 3 ), myMenuName( menu ), myGroup( group ), myId( id ), myIndex( idx ) {}
   CrMenu( QAction* action, const int menu, const int id, const int group, const int idx ) 
-    : myCase( 4 ), myAction( action ), myMenuId( menu ), myId( id ), myGroup( group ), myIndex( idx ) {}
+    : myCase( 4 ), myMenuId( menu ), myGroup( group ), myAction( action ), myId( id ), myIndex( idx ) {}
   CrMenu( QAction* action, const QString& menu, const int id, const int group, const int idx ) 
-    : myCase( 5 ), myAction( action ), myMenuName( menu ), myId( id ), myGroup( group ), myIndex( idx ) {}
+    : myCase( 5 ), myMenuName( menu ), myGroup( group ), myAction( action ), myId( id ), myIndex( idx ) {}
 
-  int execute( LightApp_Module* module ) const
+  int execute() const
   {
-    if ( module ) {
-      switch ( myCase ) {
-      case 0:
-        return module->createMenu( mySubMenuName, myMenuId, myId, myGroup, myIndex );
-      case 1:
-        return module->createMenu( mySubMenuName, myMenuName, myId, myGroup, myIndex );
-      case 2:
-        return module->createMenu( myId, myMenuId, myGroup, myIndex );
-      case 3:
-        return module->createMenu( myId, myMenuName, myGroup, myIndex );
-      case 4:
-        return module->createMenu( myAction, myMenuId, myId, myGroup, myIndex );
-      case 5:
-        return module->createMenu( myAction, myMenuName, myId, myGroup, myIndex );
-      }
+    switch ( myCase ) {
+    case 0:
+      if ( getActiveModule() )
+        return getActiveModule()->createMenu( mySubMenuName, myMenuId, myId, myGroup, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createMenu( mySubMenuName, myMenuId, myId, myGroup, myIndex );
+      break;
+    case 1:
+      if ( getActiveModule() )
+        return getActiveModule()->createMenu( mySubMenuName, myMenuName, myId, myGroup, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createMenu( mySubMenuName, myMenuName, myId, myGroup, myIndex );
+      break;
+    case 2:
+      if ( getActiveModule() )
+        return getActiveModule()->createMenu( myId, myMenuId, myGroup, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createMenu( myId, myMenuId, myGroup, myIndex );
+      break;
+    case 3:
+      if ( getActiveModule() )
+        return getActiveModule()->createMenu( myId, myMenuName, myGroup, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createMenu( myId, myMenuName, myGroup, myIndex );
+      break;
+    case 4:
+      if ( getActiveModule() )
+        return getActiveModule()->createMenu( myAction, myMenuId, myId, myGroup, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createMenu( myAction, myMenuId, myId, myGroup, myIndex );
+      break;
+    case 5:
+      if ( getActiveModule() )
+        return getActiveModule()->createMenu( myAction, myMenuName, myId, myGroup, myIndex );
+      else if ( getApplication() )
+        return getApplication()->createMenu( myAction, myMenuName, myId, myGroup, myIndex );
+      break;
+    default:
+      break;
     }
     return -1;
   }
@@ -1941,9 +2378,7 @@ public:
     : myResult( -1 ), myCrMenu( crMenu ) {}
   virtual void Execute()
   {
-    LightApp_Module* module = getActiveModule();
-    if ( module )
-      myResult = myCrMenu.execute( module );
+    myResult = myCrMenu.execute();
   }
 };
 
@@ -2306,159 +2741,441 @@ public:
 int SalomePyQt::addPreference( const QString& label, const int pId, const int type,
                                const QString& section, const QString& param )
 {
-  return ProcessEvent( new TAddPrefParamEvent( label, pId, type, section, param ) );
+  return ProcessEvent( new TAddPrefParamEvent( label, pId, type, section, param ) );
+}
+
+/*!
+  \fn QVariant SalomePyQt::preferenceProperty( const int id, const QString& prop );
+  \brief Get the preferences property.
+  \param id preferences identifier
+  \param prop preferences property name
+  \return preferences property value or null QVariant if property is not set
+*/
+
+class TPrefPropEvent: public SALOME_Event
+{
+public:
+  typedef QVariant TResult;
+  TResult myResult;
+  int     myId;
+  QString myProp;
+  TPrefPropEvent( const int id, const QString& prop )
+    : myId( id ), myProp( prop ) {}
+  virtual void Execute()
+  {
+    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 )
+{
+  return ProcessEvent( new TPrefPropEvent( id, prop ) );
+}
+
+/*!
+  \brief Set the preferences property.
+  \param id preferences identifier
+  \param prop preferences property name
+  \param var preferences property value
+*/
+void SalomePyQt::setPreferenceProperty( const int id, 
+                                        const QString& prop,
+                                        const QVariant& var )
+{
+  class TEvent: public SALOME_Event
+  {
+    int      myId;
+    QString  myProp;
+    QVariant myVar;
+  public:
+    TEvent( const int id, const QString& prop, const QVariant& var ) 
+      : myId( id ), myProp( prop ), myVar( var ) {}
+    virtual void Execute() 
+    {
+      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 ) );
+}
+
+/*!
+  \brief Set specific widget as a custom preferences item.
+  \param id preferences identifier
+  \param prop preferences property name
+  \param widget custom widget
+*/
+void SalomePyQt::setPreferencePropertyWg( const int id, 
+                                          const QString& prop,
+                                          UserDefinedContent* widget )
+{
+  class TEvent: public SALOME_Event
+  {
+    int      myId;
+    QString  myProp;
+    UserDefinedContent* myWidget;
+  public:
+    TEvent( const int id, const QString& prop, UserDefinedContent* widget ) 
+      : myId( id ), myProp( prop ), myWidget( widget ) {}
+    virtual void Execute() 
+    {
+      LightApp_Module* module = getActiveModule();
+      if ( module ) {
+       LightApp_Preferences* pref = module->getApp()->preferences();
+       if ( pref ) {
+         pref->setItemProperty( myProp, (qint64) new SgPyQtUserDefinedContent( myWidget ), myId );
+        }
+      }
+    }
+  };
+  ProcessVoidEvent( new TEvent( id, prop, widget ) );
+}
+
+/*!
+  \brief Add the property value to the list of values.
+
+  This method allows creating properties which are QList<QVariant>
+  - there is no way to pass such values directly to QVariant parameter with PyQt.
+
+  \param id preferences identifier
+  \param prop preferences property name
+  \param idx preferences property index
+  \param var preferences property value for the index \a idx
+*/
+void SalomePyQt::addPreferenceProperty( const int id, 
+                                        const QString& prop,
+                                        const int idx, 
+                                        const QVariant& var )
+{
+  class TEvent: public SALOME_Event
+  {
+    int      myId;
+    QString  myProp;
+    int      myIdx;
+    QVariant myVar;
+  public:
+    TEvent( const int id, const QString& prop, const int idx, const QVariant& var ) 
+      : myId( id ), myProp( prop ), myIdx( idx), myVar( var ) {}
+    virtual void Execute()
+    {
+      LightApp_Module* module = getActiveModule();
+      if ( module ) {
+       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 );
+         }
+       }
+      }
+    }
+  };
+  ProcessVoidEvent( new TEvent( id, prop, idx, var) );
+}
+
+/*!
+  \brief Put the message to the Log messages output window
+  \param msg message text (it can be of simple rich text format)
+  \param addSeparator boolean flag which specifies if it is necessary 
+         to separate the message with predefined separator
+*/
+void SalomePyQt::message( const QString& msg, bool addSeparator )
+{
+  class TEvent: public SALOME_Event
+  {
+    QString  myMsg;
+    bool     myAddSep;
+  public:
+    TEvent( const QString& msg, bool addSeparator ) 
+      : myMsg( msg ), myAddSep( addSeparator ) {}
+    virtual void Execute()
+    {
+      if ( LightApp_Application* anApp = getApplication() ) {
+        LogWindow* lw = anApp->logWindow();
+        if ( lw )
+          lw->putMessage( myMsg, myAddSep );
+      }
+    }
+  };
+  ProcessVoidEvent( new TEvent( msg, addSeparator ) );
+}
+
+/*!
+  \brief Set the title to the Help panel.
+  \param title Title text (empty string removes title)
+*/
+void SalomePyQt::infoSetTitle( const QString& title )
+{
+  class TEvent: public SALOME_Event
+  {
+    QString myTitle;
+  public:
+    TEvent( const QString& title ) 
+      : myTitle( title ) {}
+    virtual void Execute()
+    {
+      if ( LightApp_Application* anApp = getApplication() ) {
+        QtxInfoPanel* ip = anApp->infoPanel();
+        if ( ip )
+          ip->setTitle( myTitle );
+      }
+    }
+  };
+  ProcessVoidEvent( new TEvent( title ) );
+}
+
+/*!
+  \fn int SalomePyQt::infoAddLabel( const QString& text, const int groupId )
+  \brief Insert left-aligned text label into the Help panel
+  \param text Label text
+  \param groupId Parent group's identifier (defaults to -1 for top-level group)
+  \return Label's identifier
+*/
+
+class TInfoAddLabel2paramEvent: public SALOME_Event
+{
+public:
+  typedef int TResult;
+  TResult myResult;
+  QString myText;
+  int     myGroupId;
+  TInfoAddLabel2paramEvent( const QString& text, const int groupId )
+    : myText( text ), myGroupId( groupId ) {}
+  virtual void Execute()
+  {
+    if ( LightApp_Application* anApp = getApplication() ) {
+      QtxInfoPanel* ip = anApp->infoPanel();
+      if ( ip )
+        myResult = ip->addLabel( myText, myGroupId );
+    }
+  }
+};
+int SalomePyQt::infoAddLabel( const QString& text, const int groupId )
+{
+  return ProcessEvent( new TInfoAddLabel2paramEvent( text, groupId ) );
+}
+
+/*!
+  \fn int SalomePyQt::infoAddLabel( const QString& text, Qt::Alignment alignment, const int groupId )
+  \brief Insert text label into the Help panel
+  \param text Label text
+  \param alignment Alignment flag for text label
+  \param groupId Parent group's identifier (defaults to -1 for top-level group)
+  \return Label's identifier
+*/
+
+class TInfoAddLabel3paramEvent: public SALOME_Event
+{
+public:
+  typedef int TResult;
+  TResult myResult;
+  QString myText;
+  Qt::Alignment myAlignment;
+  int     myGroupId;
+  TInfoAddLabel3paramEvent( const QString& text, Qt::Alignment alignment, const int groupId )
+    : myText( text ), myAlignment( alignment ), myGroupId( groupId ) {}
+  virtual void Execute()
+  {
+    if ( LightApp_Application* anApp = getApplication() ) {
+      QtxInfoPanel* ip = anApp->infoPanel();
+      if ( ip )
+        myResult = ip->addLabel( myText, myAlignment, myGroupId );
+    }
+  }
+};
+int SalomePyQt::infoAddLabel( const QString& text, Qt::Alignment alignment, const int groupId )
+{
+  return ProcessEvent( new TInfoAddLabel3paramEvent( text, alignment, groupId ) );
+}
+
+/*!
+  \fn int SalomePyQt::infoAddAction( QAction* action, const int groupId )
+  \brief Insert action button into the Help panel
+  \param action Action being added
+  \param groupId Parent group's identifier (defaults to -1 for top-level group)
+  \return Action's identifier
+*/
+
+class TInfoAddActionEvent: public SALOME_Event
+{
+public:
+  typedef int TResult;
+  TResult myResult;
+  QAction* myAction;
+  int     myGroupId;
+  TInfoAddActionEvent( QAction* action, const int groupId )
+    : myAction( action ), myGroupId( groupId ) {}
+  virtual void Execute()
+  {
+    if ( LightApp_Application* anApp = getApplication() ) {
+      QtxInfoPanel* ip = anApp->infoPanel();
+      if ( ip )
+        myResult = ip->addAction( myAction, myGroupId );
+    }
+  }
+};
+int SalomePyQt::infoAddAction( QAction* action, const int groupId )
+{
+  return ProcessEvent( new TInfoAddActionEvent( action, groupId ) );
 }
 
 /*!
-  \fn QVariant SalomePyQt::preferenceProperty( const int id, const QString& prop );
-  \brief Get the preferences property.
-  \param id preferences identifier
-  \param prop preferences property name
-  \return preferences property value or null QVariant if property is not set
+  \fn int SalomePyQt::infoAddGroup( const QString& text, const int groupId )
+  \brief Create a (sub-)group in the Help panel
+  \param text Group title
+  \param groupId Parent group's identifier (defaults to -1 for top-level group)
+  \return Group's identifier
 */
 
-class TPrefPropEvent: public SALOME_Event
+class TInfoAddGroupEvent: public SALOME_Event
 {
 public:
-  typedef QVariant TResult;
+  typedef int TResult;
   TResult myResult;
-  int     myId;
-  QString myProp;
-  TPrefPropEvent( const int id, const QString& prop )
-    : myId( id ), myProp( prop ) {}
+  QString myText;
+  int     myGroupId;
+  TInfoAddGroupEvent( const QString& text, const int groupId )
+    : myText( text ), myGroupId( groupId ) {}
   virtual void Execute()
   {
-    LightApp_Module* module = getActiveModule();
-    if ( module ) {
-      LightApp_Preferences* pref = module->getApp()->preferences();
-      if ( pref )
-       myResult = pref->itemProperty( myProp, myId );
+    if ( LightApp_Application* anApp = getApplication() ) {
+      QtxInfoPanel* ip = anApp->infoPanel();
+      if ( ip )
+        myResult = ip->addGroup( myText, myGroupId );
     }
   }
 };
-QVariant SalomePyQt::preferenceProperty( const int id, const QString& prop )
+int SalomePyQt::infoAddGroup( const QString& text, const int groupId )
 {
-  return ProcessEvent( new TPrefPropEvent( id, prop ) );
+  return ProcessEvent( new TInfoAddGroupEvent( text, groupId ) );
 }
 
 /*!
-  \brief Set the preferences property.
-  \param id preferences identifier
-  \param prop preferences property name
-  \param var preferences property value
+  \brief Remove item from the Help panel
+  \param id Item's (label's, action's, group's, ...) identifier
 */
-void SalomePyQt::setPreferenceProperty( const int id, 
-                                        const QString& prop,
-                                        const QVariant& var )
+void SalomePyQt::infoRemove( const int id )
 {
   class TEvent: public SALOME_Event
   {
-    int      myId;
-    QString  myProp;
-    QVariant myVar;
+    int myId;
   public:
-    TEvent( const int id, const QString& prop, const QVariant& var ) 
-      : myId( id ), myProp( prop ), myVar( var ) {}
-    virtual void Execute() 
+    TEvent( const int id ) 
+      : myId( id ) {}
+    virtual void Execute()
     {
-      LightApp_Module* module = getActiveModule();
-      if ( module ) {
-       LightApp_Preferences* pref = module->getApp()->preferences();
-       if ( pref )
-         pref->setItemProperty( myProp, myVar, myId );
+      if ( LightApp_Application* anApp = getApplication() ) {
+        QtxInfoPanel* ip = anApp->infoPanel();
+        if ( ip )
+          ip->remove( myId );
       }
     }
   };
-  ProcessVoidEvent( new TEvent( id, prop, var) );
+  ProcessVoidEvent( new TEvent( id ) );
 }
 
 /*!
-  \brief Add the property value to the list of values.
-
-  This method allows creating properties which are QList<QVariant>
-  - there is no way to pass such values directly to QVariant parameter with PyQt.
+  \brief Clear Help panel's contents
+  \param groupId Group's identifier (default is -1, to clear whole panel)
+*/
+void SalomePyQt::infoClear( const int groupId )
+{
+  class TEvent: public SALOME_Event
+  {
+    int myGroupId;
+  public:
+    TEvent( const int groupId ) 
+      : myGroupId( groupId ) {}
+    virtual void Execute()
+    {
+      if ( LightApp_Application* anApp = getApplication() ) {
+        QtxInfoPanel* ip = anApp->infoPanel();
+        if ( ip )
+          ip->clear( myGroupId );
+      }
+    }
+  };
+  ProcessVoidEvent( new TEvent( groupId ) );
+}
 
-  \param id preferences identifier
-  \param prop preferences property name
-  \param idx preferences property index
-  \param var preferences property value for the index \a idx
+/*!
+  \brief Set item's visibility in the Help panel
+  \param id Item's (label's, action's, group's, ...) identifier
+  \param visible Visibility flag
 */
-void SalomePyQt::addPreferenceProperty( const int id, 
-                                        const QString& prop,
-                                        const int idx, 
-                                        const QVariant& var )
+void SalomePyQt::infoSetVisible( const int id, bool visible )
 {
   class TEvent: public SALOME_Event
   {
-    int      myId;
-    QString  myProp;
-    int      myIdx;
-    QVariant myVar;
+    int myId;
+    bool myVisible;
   public:
-    TEvent( const int id, const QString& prop, const int idx, const QVariant& var ) 
-      : myId( id ), myProp( prop ), myIdx( idx), myVar( var ) {}
+    TEvent( const int id, bool visible ) 
+      : myId( id ), myVisible( visible ) {}
     virtual void Execute()
     {
-      LightApp_Module* module = getActiveModule();
-      if ( module ) {
-       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 );
-         }
-       }
+      if ( LightApp_Application* anApp = getApplication() ) {
+        QtxInfoPanel* ip = anApp->infoPanel();
+        if ( ip )
+          ip->setVisible( myId, myVisible );
       }
     }
   };
-  ProcessVoidEvent( new TEvent( id, prop, idx, var) );
+  ProcessVoidEvent( new TEvent( id, visible ) );
 }
 
 /*!
-  \brief Put the message to the Log messages output window
-  \param msg message text (it can be of simple rich text format)
-  \param addSeparator boolean flag which specifies if it is necessary 
-         to separate the message with predefined separator
+  \brief Enable/disable item in the Help panel
+  \param id Item's (label's, action's, group's, ...) identifier
+  \param enabled Enabled state
 */
-void SalomePyQt::message( const QString& msg, bool addSeparator )
+void SalomePyQt::infoSetEnabled( const int id, bool enabled )
 {
   class TEvent: public SALOME_Event
   {
-    QString  myMsg;
-    bool     myAddSep;
+    int myId;
+    bool myEnabled;
   public:
-    TEvent( const QString& msg, bool addSeparator ) 
-      : myMsg( msg ), myAddSep( addSeparator ) {}
+    TEvent( const int id, bool enabled ) 
+      : myId( id ), myEnabled( enabled ) {}
     virtual void Execute()
     {
       if ( LightApp_Application* anApp = getApplication() ) {
-        LogWindow* lw = anApp->logWindow();
-        if ( lw )
-          lw->putMessage( myMsg, myAddSep );
+        QtxInfoPanel* ip = anApp->infoPanel();
+        if ( ip )
+          ip->setEnabled( myId, myEnabled );
       }
     }
   };
-  ProcessVoidEvent( new TEvent( msg, addSeparator ) );
+  ProcessVoidEvent( new TEvent( id, enabled ) );
 }
 
 /*!
@@ -2737,6 +3454,18 @@ public:
             myResult = true;
           }
 #endif // DISABLE_PVVIEWER
+        }
+        else if ( type == "ParaView3D") {
+#ifndef DISABLE_PV3DVIEWER
+          // specific processing for ParaView3D viewer:
+          // hierarchy of ParaView3D viewer is much more complex than for usual view;
+          // we look for sub-widget named "Viewport"
+          QList<QWidget*> lst = wnd->findChildren<QWidget*>( "Viewport" );
+          if ( !lst.isEmpty() ) {
+            lst[0]->resize( myWndWidth, myWndHeight );
+            myResult = true;
+          }
+#endif // DISABLE_PV3DVIEWER
         }
         else {
           if ( wnd->centralWidget() ) {
@@ -2753,6 +3482,85 @@ bool SalomePyQt::setViewSize( const int w, const int h, const int id )
   return ProcessEvent( new TSetViewSize( w, h, id ) );
 }
 
+/*!
+  \fn bool SalomePyQt::setViewRotationPoint( const double x, const double y, const double z, const int id );
+  \brief Set view rotation point
+  \param x coordinate X view rotation point
+  \param y coordinate Y view rotation point
+  \param z coordinate Z view rotation point
+  \param id window identifier
+  \return \c true if operation is completed successfully and \c false otherwise 
+*/
+
+class TSetViewRotationPoint: public SALOME_Event
+{
+public:
+  typedef bool TResult;
+  TResult myResult;
+  double myX;
+  double myY;
+  double myZ;
+  int myWndId;
+  TSetViewRotationPoint( const double x, const double y, const double z, const int id )
+    : myResult( false ),
+      myX( x ),
+      myY( y ),
+      myZ( z ),
+      myWndId( id ) {}
+  virtual void Execute() 
+  {
+    SUIT_ViewWindow* wnd = 0;
+    if ( !myWndId ) {
+      if ( LightApp_Application* anApp = getApplication() ) {
+        SUIT_ViewManager* vm = anApp->activeViewManager();
+        if ( vm )
+          wnd = vm->getActiveView();
+      }
+    }
+    else {
+      wnd = dynamic_cast<SUIT_ViewWindow*>( getWnd( myWndId ) );
+    }
+    if ( wnd ) {
+      SUIT_ViewManager* viewMgr = wnd->getViewManager();
+      if ( viewMgr ) {
+        QString type = viewMgr->getType();
+        if ( type == "OCCViewer") {
+#ifndef DISABLE_OCCVIEWER
+          // specific processing for OCC viewer:
+          // OCC view can embed up to 4 sub-views, split according to the specified layout;
+          // - if there is only one sub-view active; its rotation point will be changed;
+          // - if there are several sub-views, rotaion points of each of them will be changed.
+          OCCViewer_ViewWindow* occView = qobject_cast<OCCViewer_ViewWindow*>( wnd );
+          if ( occView ) {
+            for ( int i = OCCViewer_ViewFrame::BOTTOM_RIGHT; i <= OCCViewer_ViewFrame::TOP_RIGHT; i++ ) {
+              if ( occView && occView->getView( i ) ) {
+                occView->getView( i )->activateSetRotationSelected( myX, myY, myZ );
+                myResult = true;
+              }
+            }
+          }
+#endif // DISABLE_OCCVIEWER
+        }
+        else if ( type == "VTKViewer") {
+#ifndef DISABLE_VTKVIEWER
+          SVTK_ViewWindow* vtkView = qobject_cast<SVTK_ViewWindow*>( wnd );
+          if ( vtkView )
+          {
+            double aCenter[3] = { myX, myY, myZ };
+            vtkView->activateSetRotationSelected( (void*)aCenter );
+            myResult = true;
+          }
+#endif // DISABLE_VTKVIEWER
+        }
+      }
+    }
+  }
+};
+bool SalomePyQt::setViewRotationPoint( const double x, const double y, const double z, const int id )
+{
+  return ProcessEvent( new TSetViewRotationPoint( x, y, z, id ) );
+}
+
 /*!
   \fn QString SalomePyQt::getViewTitle( const int id );
   \brief Get view caption  
@@ -2809,7 +3617,10 @@ public:
         for ( int i = 0, n = vec.size(); i < n; i++ ) {
           SUIT_ViewWindow* wnd = vec[ i ];
           if ( wnd )
-            myResult.append( wnd->getId() );
+            {
+              MESSAGE("SUIT_ViewWindow*: "<< wnd << " id: " << wnd->getId());
+              myResult.append( wnd->getId() );
+            }
         }
       }
     }
@@ -2839,7 +3650,9 @@ public:
   virtual void Execute() 
   {
     SUIT_ViewWindow* wnd = getWnd( myWndId );
+    MESSAGE("window id:" << myWndId << " SUIT_ViewWindow*: " << wnd);
     if ( wnd ) {
+      Activator activator;
       wnd->setFocus();
       myResult = true;
     }
@@ -2850,6 +3663,67 @@ bool SalomePyQt::activateView( const int id )
   return ProcessEvent( new TActivateView( id ) );
 }
 
+/*!
+  \fn bool SalomePyQt::activateManagerAndView( const int id );
+  \brief Activate view manager and view: useful for a view embedded in a module main Window
+  \param id window identifier
+  \return \c true if operation is completed successfully and \c false otherwise
+ */
+
+class TActivateViewManagerAndView: public SALOME_Event
+{
+public:
+  typedef bool TResult;
+  TResult myResult;
+  int myWndId;
+  TActivateViewManagerAndView( const int id )
+    : myResult( false ),
+      myWndId( id ) {}
+  virtual void Execute()
+  {
+    SUIT_ViewWindow* wnd = getWnd( myWndId );
+    MESSAGE("window id:" << myWndId << " SUIT_ViewWindow*: " << wnd);
+    if ( wnd )
+      {
+        LightApp_Application* app  = getApplication();
+        app->desktop()->windowActivated(wnd); // equivalent to app->setActiveViewManager(wnd->getViewManager())
+        wnd->setFocus();
+        myResult = true;
+      }
+  }
+};
+bool SalomePyQt::activateViewManagerAndView( const int id )
+{
+  return ProcessEvent( new TActivateViewManagerAndView( id ) );
+}
+
+/*!
+ *
+ */
+
+class TGetViewWidget: public SALOME_Event
+{
+public:
+  typedef QWidget* TResult;
+  TResult myResult;
+  int myWndId;
+  TGetViewWidget( const int id )
+    : myResult( 0 ),
+      myWndId( id ) {}
+  virtual void Execute()
+  {
+    SUIT_ViewWindow* wnd = getWnd( myWndId );
+    if ( wnd ) {
+        myResult = (QWidget*)wnd;
+    }
+  }
+};
+QWidget* SalomePyQt::getViewWidget( const int id)
+{
+  return ProcessEvent( new TGetViewWidget( id ) );
+}
+
+
 /*!
   \fn int SalomePyQt::createView( const QString& type, bool visible = true, const int width = 0, const int height = 0 );
   \brief Create new view and activate it
@@ -2869,17 +3743,19 @@ public:
   bool myVisible;
   int myWidth;
   int myHeight;
-  TCreateView( const QString& theType, bool visible, const int width, const int height )
+  bool myDetached;
+  TCreateView( const QString& theType, bool visible, const int width, const int height, bool detached )
     : myResult( -1 ),
       myType( theType ),
       myVisible(visible),
       myWidth(width),
-      myHeight(height) {}
+      myHeight(height),
+      myDetached(detached) {}
   virtual void Execute() 
   {
     LightApp_Application* app  = getApplication();
     if ( app ) {
-      SUIT_ViewManager* viewMgr = app->createViewManager( myType );
+      SUIT_ViewManager* viewMgr = app->createViewManager( myType, myDetached );
       if ( viewMgr ) {
         QWidget* wnd = viewMgr->getActiveView();
         myResult = viewMgr->getActiveView()->getId();
@@ -2902,9 +3778,9 @@ public:
     }
   }
 };
-int SalomePyQt::createView( const QString& type, bool visible, const int width, const int height )
+int SalomePyQt::createView( const QString& type, bool visible, const int width, const int height, bool detached )
 {
-  int ret = ProcessEvent( new TCreateView( type, visible, width, height ) );
+  int ret = ProcessEvent( new TCreateView( type, visible, width, height, detached ) );
   QCoreApplication::processEvents();
   return ret;
 }
@@ -3404,10 +4280,10 @@ public:
                      const QString& icon,
                      const QString& tooltip,
                      const QString& parent )
-    : myName( name ),
+    : myParent( parent ),
+      myName( name ),
       myIcon( icon ),
-      myToolTip( tooltip ),
-      myParent( parent ) {}
+      myToolTip( tooltip ) {}
   virtual void Execute()
   {
     SALOME_PYQT_ModuleLight* module = dynamic_cast<SALOME_PYQT_ModuleLight*>( getActiveModule() );
@@ -4228,3 +5104,63 @@ void SalomePyQt::stopPyLog()
   };
   ProcessVoidEvent( new TEvent() );
 }
+
+/*!
+  \brief Log GUI event.
+  \param eventDescription GUI event description.
+*/
+void SalomePyQt::logUserEvent( const QString& eventDescription )
+{
+  class TEvent: public SALOME_Event
+  {
+    QString myEventDescription;
+  public:
+    TEvent( const QString& theDescription ) : myEventDescription( theDescription ) {}
+    virtual void Execute() 
+    {
+      LightApp_Application::logUserEvent( myEventDescription );
+    }
+  };
+  ProcessVoidEvent( new TEvent( eventDescription ) );
+}
+
+/*!
+  \brief Log given action.
+  \param action GUI action being logged.
+  \param moduleName optional name of module, owning an action
+*/
+void SalomePyQt::logAction( QAction* action, const QString& moduleName )
+{
+  class TEvent: public SALOME_Event
+  {
+    QAction* myAction;
+    QString myModuleName;
+  public:
+    TEvent( QAction* theAction, const QString& theModuleName ) : myAction( theAction ), myModuleName( theModuleName ) {}
+    virtual void Execute() 
+    {
+      LightApp_Application::logAction( myAction, myModuleName );
+    }
+  };
+  ProcessVoidEvent( new TEvent( action, moduleName ) );
+}
+
+/*!
+  \brief Enable/disable action logging.
+*/
+void SalomePyQt::setActionLoggingEnabled( bool enabled )
+{
+  class TEvent: public SALOME_Event
+  {
+    bool myEnabled;
+  public:
+    TEvent( bool theEnabled ) : myEnabled( theEnabled ) {}
+    virtual void Execute() 
+    {
+      LightApp_Module* module = getActiveModule();
+      if ( module )
+        module->setActionLoggingEnabled( myEnabled );
+    }
+  };
+  ProcessVoidEvent( new TEvent( enabled ) );
+}