Salome HOME
bos #20215 Help panels into SALOME for new users
[modules/gui.git] / src / LightApp / LightApp_Application.cxx
index 626bbc6b3559b1de3df12a529218f8e836a494f5..d9379a40acc3b64d9c470d541c307e98ac8985e4 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -35,8 +35,8 @@
 #endif
 
 #ifndef DISABLE_PYCONSOLE
-  #include "LightApp_PyEditor.h"
   #include "PyConsole_Interp.h"
+  #include "LightApp_PyEditor.h"
   #include "PyConsole_Console.h"
 #endif
 
@@ -88,6 +88,7 @@
 #include <QtxFontEdit.h>
 #include <QtxToolBar.h>
 #include <QtxTreeView.h>
+#include <QtxInfoPanel.h>
 #include <QtxMRUAction.h>
 #include <QtxDockAction.h>
 #include <QtxDockWidget.h>
 #include <QTreeView>
 #include <QMimeData>
 #include <QShortcut>
+#include <QRegExp>
 
 #include <utilities.h>
 
@@ -230,8 +232,6 @@ static const char* imageEmptyIcon[] = {
 "....................",
 "...................."};
 
-int LightApp_Application::lastStudyId = 0;
-
 // Markers used to parse array with dockable windows and toolbars state.
 // For more details please see the qdockarealayout.cpp && qtoolbararealayout.cpp
 // in the Qt source code.
@@ -246,6 +246,14 @@ int LightApp_Application::lastStudyId = 0;
 //since the 'toolbar marker' is not unique, find index of first occurrence of the
 //'toolbar marker' in the array and check that next string is name of the toolbar
 
+void LightAppCleanUpAppResources()
+{
+  if ( LightApp_Application::_prefs_ ) {
+    delete LightApp_Application::_prefs_;
+    LightApp_Application::_prefs_ = 0;
+  }
+}
+
 namespace
 {
   int getToolbarMarkerIndex( QByteArray input, const QStringList& aFlags ) {
@@ -253,9 +261,9 @@ namespace
     int inputLen = input.length();
     QDataStream anInputData( &input, QIODevice::ReadOnly );
     while ( tmp < inputLen ) {
-      tmp = input.indexOf( QToolBarMarker, tmp + 1 );
+      tmp = input.indexOf( (uchar)QToolBarMarker, tmp + 1 );
       if ( tmp < 0 )
-       break;
+        break;
       anInputData.device()->seek( tmp );
       uchar mark;
       anInputData >> mark;
@@ -263,9 +271,9 @@ namespace
       anInputData >> lines;
 
       if ( lines == 0 && anInputData.atEnd() ) {
-       //Case then array doesn't contain information about toolbars,
-       aResult = tmp;
-       break;
+        //Case then array doesn't contain information about toolbars,
+        aResult = tmp;
+        break;
       }
 
       int pos;
@@ -275,10 +283,10 @@ namespace
       QString str;
       anInputData >> str;
       if ( aFlags.contains( str ) ) {
-       aResult = tmp;
-       break;
+        aResult = tmp;
+        break;
       }
-    }        
+    }
     return aResult;
   }
 
@@ -295,14 +303,6 @@ namespace
   }
 }
 
-/*!
-  \return last global id of study
-*/
-int LightApp_Application::studyId()
-{
-  return LightApp_Application::lastStudyId;
-}
-
 /*!Create new instance of LightApp_Application.*/
 extern "C" LIGHTAPP_EXPORT SUIT_Application* createApplication()
 {
@@ -439,6 +439,7 @@ LightApp_Application::~LightApp_Application()
   savePreferences();
   delete mySelMgr;
   delete myScreenHelper;
+  myPrefs = 0;
 }
 
 /*!Start application.*/
@@ -454,6 +455,8 @@ void LightApp_Application::start()
   desktop()->statusBar()->showMessage( "" );
 
   LightApp_EventFilter::Init();
+
+  onNewDoc();
 }
 
 /*!Closeapplication.*/
@@ -524,6 +527,9 @@ bool LightApp_Application::activateModule( const QString& modName )
 
   saveDockWindowsState();
 
+  if ( infoPanel() )
+    infoPanel()->clear();
+
   bool status = CAM_Application::activateModule( modName );
 
   updateModuleActions();
@@ -544,6 +550,7 @@ bool LightApp_Application::activateModule( const QString& modName )
 
   if ( activeModule() ) activeModule()->updateModuleVisibilityState();
 
+  updateActions();
   return true;
 }
 
@@ -586,21 +593,77 @@ void LightApp_Application::createActions()
   // Preferences
   createAction( PreferencesId, tr( "TOT_DESK_PREFERENCES" ), QIcon(),
                 tr( "MEN_DESK_PREFERENCES" ), tr( "PRP_DESK_PREFERENCES" ),
-                Qt::CTRL+Qt::Key_R, desk, false, this, SLOT( onPreferences() ) );
-
-  // Help menu:
+                Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onPreferences() ) );
 
-  // - Help for modules
+  // Help menu
 
   int helpMenu = createMenu( tr( "MEN_DESK_HELP" ), -1, -1, 1000 );
-  createMenu( separator(), helpMenu, -1, 10 );
+  
+  int id = LightApp_Application::UserID + FIRST_HELP_ID;
+
+  // a) Link to web site
+  QString url = resMgr->stringValue("GUI", "site_url");
+  if ( !url.isEmpty() ) {
+    QString title = tr ( "SALOME_SITE" );
+    QAction* as = createAction( WebSiteId, title,
+                               resMgr->loadPixmap( "LightApp", tr( "ICON_WWW" ), false ),
+                               title, title,
+                               0, desk, false, this, SLOT( onHelpContentsModule() ) );
+    as->setData( url );
+    createMenu( as, helpMenu, -1, 0 );
+  }
+
+  // b) Link to Forum
+  url = resMgr->stringValue("GUI", "forum_url");
+  if ( !url.isEmpty() ) {
+    QString title = tr ( "SALOME_FORUM" );
+    QAction* af = createAction( ForumId, title,
+                               resMgr->loadPixmap( "LightApp", tr( "ICON_WWW" ), false ),
+                               title, title,
+                               0, desk, false, this, SLOT( onHelpContentsModule() ) );
+    af->setData( url );
+    createMenu( af, helpMenu, -1, 0 );
+  }
+
+  // c) Link to YouTube channel
+  url = resMgr->stringValue("GUI", "channel_url");
+  if ( !url.isEmpty() ) {
+    createMenu( separator(), helpMenu, -1, 0 );
+    QString title = tr ( "SALOME_VIDEO_TUTORIALS" );
+    QAction* av = createAction( VideosId, title,
+                               resMgr->loadPixmap( "LightApp", tr( "ICON_LIFE_RIGN" ), false ),
+                               title, tr( "PRP_SALOME_VIDEO_TUTORIALS" ),
+                               0, desk, false, this, SLOT( onHelpContentsModule() ) );
+    av->setData( url );
+    createMenu( av, helpMenu, -1, 0 );
+  }
+
+  // d) Link to Tutorials
+
+  url = resMgr->stringValue("GUI", "tutorials_url");
+  if ( !url.isEmpty() ) {
+    QString title = tr ( "SALOME_TUTORIALS" );
+    QAction* as = createAction( TutorialsId, title,
+                               resMgr->loadPixmap( "LightApp", tr( "ICON_WWW" ), false ),
+                               title, tr( "PRP_SALOME_TUTORIALS" ),
+                               0, desk, false, this, SLOT( onHelpContentsModule() ) );
+    as->setData( url );
+    createMenu( as, helpMenu, -1, 0 );
+  }
+
+  // e) Help for modules
+
+  // - First create top-level menus to preserve correct order
+  QString userGuide = "User's Guide";
+  QString devGuide = "Developer's Guide";
+  createMenu( userGuide, helpMenu, -1, 5 );
+  createMenu( devGuide, helpMenu, -1, 5 );
+
   QStringList aModuleList;
   modules( aModuleList, false );
   aModuleList.prepend( "GUI" );
   aModuleList.prepend( "KERNEL" );
 
-  int id = LightApp_Application::UserID + FIRST_HELP_ID;
-
   QString aModule;
   foreach( aModule, aModuleList ) {
     if ( aModule.isEmpty() )                                         // module title (user name)
@@ -609,24 +672,39 @@ void LightApp_Application::createActions()
     QString helpSubMenu;                                             // help submenu name (empty if not needed)
     QString modName = moduleName( aModule );                         // module name
     if ( modName.isEmpty() ) modName = aModule;                      // for KERNEL and GUI
-    QString rootDir = QString( "%1_ROOT_DIR" ).arg( modName );       // module root dir variable
-    QString modDir  = getenv( rootDir.toLatin1().constData() );      // module root dir
+    QString rootDir = QString( "%1_ROOT_DIR" ).arg( modName );       // module root dir env variable
+    QString modDir  = Qtx::getenv( rootDir.toUtf8().constData() );        // module root dir path
     QString docSection;
     if (resMgr->hasValue( modName, "documentation" ) )
       docSection = resMgr->stringValue(modName, "documentation");
     else if ( resMgr->hasSection( modName + "_documentation" ) )
       docSection = modName + "_documentation";
     if ( !docSection.isEmpty() ) {
-      helpSubMenu = resMgr->stringValue( docSection, "sub_menu", "" ).arg( aModule );
+      helpSubMenu = resMgr->stringValue( docSection, "sub_menu", "" );
+      if ( helpSubMenu.contains( "%1" ) )
+        helpSubMenu = helpSubMenu.arg( aModule );
       QStringList listOfParam = resMgr->parameters( docSection );
       foreach( QString paramName, listOfParam ) {
         QString valueStr = resMgr->stringValue( docSection, paramName );
         if ( !valueStr.isEmpty() ) {
-          QFileInfo fi( valueStr );
-          if ( fi.isRelative() && !modDir.isEmpty() )
-            valueStr = Qtx::addSlash( modDir ) + valueStr;
-          if ( QFile::exists( valueStr ) )
-            helpData.insert( paramName.arg( aModule ), valueStr );
+          QStringList valueItems = valueStr.split( ";;", QString::SkipEmptyParts );
+          foreach( QString item, valueItems ) {
+            if ( item.startsWith( "http", Qt::CaseInsensitive ) ) {
+              QString key = paramName.contains( "%1" ) ? paramName.arg( aModule ) : paramName;
+              helpData.insert( key, item );
+              break;
+            }
+            else {
+              QFileInfo fi( item );
+              if ( fi.isRelative() && !modDir.isEmpty() )
+                item = Qtx::addSlash( modDir ) + item;
+              if ( QFile::exists( item ) ) {
+                QString key = paramName.contains( "%1" ) ? paramName.arg( aModule ) : paramName;
+                helpData.insert( key, item );
+                break;
+              }
+            }
+          }
         }
       }
     }
@@ -640,17 +718,24 @@ void LightApp_Application::createActions()
 
     IMapConstIterator<QString, QString > fileIt;
     for ( fileIt = helpData.begin(); fileIt != helpData.end(); fileIt++ ) {
-      QString helpFileName = fileIt.key();
+      QString helpItemPath = fileIt.key();
       // remove all '//' occurances 
-      while ( helpFileName.contains( "//" ) )
-        helpFileName.replace( "//", "" );
+      while ( helpItemPath.contains( "//" ) )
+        helpItemPath.replace( "//", "" );
       // obtain submenus hierarchy if given
-      QStringList smenus = helpFileName.split( "/" );
-      helpFileName = smenus.last();
-      smenus.removeLast();
-      QAction* a = createAction( id, helpFileName,
-                                 resMgr->loadPixmap( "STD", tr( "ICON_HELP" ), false ),
-                                 helpFileName, helpFileName,
+      QStringList smenus = helpItemPath.split( "/" );
+      helpItemPath = smenus.takeLast();
+      // workaround for User's Guide and Developer's Guide to avoid having single item in module's submenu.
+      if ( helpItemPath == userGuide || helpItemPath == devGuide ) {
+       QString menuPath = smenus.join( "/" );
+       QStringList allKeys = helpData.keys();
+       QStringList total = allKeys.filter( QRegExp( QString( "^%1" ).arg( menuPath ) ) );
+       if ( total.count() == 1 && smenus.count() > 0 )
+         helpItemPath = smenus.takeLast();
+      }
+      QPixmap helpIcon = fileIt.value().startsWith( "http", Qt::CaseInsensitive ) ? 
+        resMgr->loadPixmap( "STD", tr( "ICON_WWW" ), false ) : resMgr->loadPixmap( "STD", tr( "ICON_HELP" ), false );
+      QAction* a = createAction( id, helpItemPath, helpIcon, helpItemPath, helpItemPath,
                                  0, desk, false, this, SLOT( onHelpContentsModule() ) );
       a->setData( fileIt.value() );
       if ( !helpSubMenu.isEmpty() ) {
@@ -658,29 +743,33 @@ void LightApp_Application::createActions()
       }
       // create sub-menus hierarchy
       int menuId = helpMenu;
-      foreach ( QString subMenu, smenus ) {
-        menuId = createMenu( subMenu, menuId, -1, 0 );
-      }
-      createMenu( a, menuId, -1, 0 );
+      foreach ( QString subMenu, smenus )
+        menuId = createMenu( subMenu, menuId, -1, 5 );
+      createMenu( a, menuId, -1, ( menuId != helpMenu && (helpItemPath == userGuide || helpItemPath == devGuide) ) ? 0 : 5 );
       id++;
     }
   }
 
   // - Additional help items
 
-  createMenu( separator(), helpMenu, -1, 5 );
+  createMenu( separator(), helpMenu, -1, 10 );
 
   QStringList addHelpItems = resMgr->parameters( "add_help" );
-  foreach ( QString addHelpItem, addHelpItems ) {
-    QString valueStr = resMgr->stringValue( "add_help", addHelpItem );
-    if ( !valueStr.isEmpty() && QFile::exists( valueStr ) ) {
-      QAction* a = createAction( id, addHelpItem,
-                                 resMgr->loadPixmap( "STD", tr( "ICON_HELP" ), false ),
-                                 addHelpItem, addHelpItem,
-                                 0, desk, false, this, SLOT( onHelpContentsModule() ) );
-      a->setData( valueStr );
-      createMenu( a, helpMenu, -1, 5 );
-      id++;
+  foreach ( QString paramName, addHelpItems ) {
+    QString valueStr = resMgr->stringValue( "add_help", paramName );
+    if ( !valueStr.isEmpty() ) {
+      QStringList valueItems = valueStr.split( ";;", QString::SkipEmptyParts );
+      foreach( QString item, valueItems ) { 
+        if ( item.startsWith( "http", Qt::CaseInsensitive ) || QFile::exists( item ) ) {
+          QPixmap helpIcon = item.startsWith( "http", Qt::CaseInsensitive ) ? 
+            resMgr->loadPixmap( "STD", tr( "ICON_WWW" ), false ) : resMgr->loadPixmap( "STD", tr( "ICON_HELP" ), false );
+          QAction* a = createAction( id++, paramName, helpIcon, paramName, paramName,
+                                     0, desk, false, this, SLOT( onHelpContentsModule() ) );
+          a->setData( item );
+          createMenu( a, helpMenu, -1, 10 );
+          break;
+        }
+      }
     }
   }
 
@@ -715,14 +804,8 @@ void LightApp_Application::createActions()
     QStringList::Iterator it;
     for ( it = modList.begin(); it != modList.end(); ++it )
     {
-      if ( !isLibExists( *it ) )
-        continue;
-
       QString modName = moduleName( *it );
 
-      if ( !isModuleAccessible( *it ) )
-        continue;
-
       QString iconName;
       if ( iconMap.contains( *it ) )
         iconName = iconMap[*it];
@@ -731,12 +814,12 @@ void LightApp_Application::createActions()
       if ( icon.isNull() )
       {
         icon = modIcon;
-        INFOS ( "\n****************************************************************" << std::endl
-                <<  "*    Icon for " << (*it).toLatin1().constData()
-                << " not found. Using the default one." << std::endl
-                << "****************************************************************" << std::endl );
+        INFOS( std::endl <<
+               "****************************************************************" << std::endl <<
+               "     Warning: icon for " << qPrintable(*it) << " is not found!" << std::endl <<
+               "     Using the default icon." << std::endl <<
+               "****************************************************************" << std::endl);
       }
-
       icon = Qtx::scaleIcon( icon, iconSize );
 
       moduleAction->insertModule( *it, icon );
@@ -817,7 +900,7 @@ void LightApp_Application::createActions()
   createMenu( FullScreenId, viewMenu, 20, -1 );
 
   int modTBar = createTool( tr( "INF_TOOLBAR_MODULES" ),    // title (language-dependant)
-                           QString( "SalomeModules" ) );   // name (language-independant)
+                            QString( "SalomeModules" ) );   // name (language-independant)
   createTool( ModulesListId, modTBar );
 }
 
@@ -932,10 +1015,8 @@ void LightApp_Application::onNewWindow()
 */
 void LightApp_Application::onNewDoc()
 {
-#ifdef SINGLE_DESKTOP
   if ( !checkExistingDoc() )
     return;
-#endif
 
   //asl: fix for 0020515
   saveDockWindowsState();
@@ -950,12 +1031,14 @@ void LightApp_Application::onOpenDoc()
 {
   SUIT_Study* study = activeStudy();
   
-#ifdef SINGLE_DESKTOP
-  if ( !checkExistingDoc() )
+  if ( !checkExistingDoc( false ) )
+    return;
+  
+  QString aName = getFileName( true, QString(), getFileFilter( true ), QString(), 0 );
+  if ( aName.isNull() ) //Cancel
     return;
-#endif
   
-  CAM_Application::onOpenDoc();
+  onOpenDoc( aName );
   
   if ( !study ) // new study will be create in THIS application
   {
@@ -964,16 +1047,32 @@ void LightApp_Application::onOpenDoc()
   }
 }
 
+bool LightApp_Application::canOpenDoc( const QString& )
+{
+  return true;
+}
+
 /*!
   SLOT: Opens new document.
   \param aName - name of file
 */
 bool LightApp_Application::onOpenDoc( const QString& aName )
 {
-#ifdef SINGLE_DESKTOP
+  if ( !canOpenDoc(aName)) {
+    bool showError = !property("open_study_from_command_line").isValid() ||
+      !property("open_study_from_command_line").toBool();
+
+    putInfo( tr("OPEN_DOCUMENT_PROBLEM") );
+    if ( showError )
+      SUIT_MessageBox::critical( desktop(), tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
+
+    return false;
+  }
+
+  closeDoc(false);
+
   if ( !checkExistingDoc() )
     return false;
-#endif
 
   saveDockWindowsState();
 
@@ -1087,172 +1186,147 @@ void LightApp_Application::updateCommandsStatus()
 class RunBrowser: public QThread
 {
 public:
-  RunBrowser( LightApp_Application* app,
-              const QString&        theApp,
-              const QString&        theParams,
-              const QString&        theHelpFile,
-              const QString&        theContext = QString() )
-    : myApp( theApp ),
-      myParams( theParams ),
-      myContext( theContext ),
-      myStatus(0),
-      myLApp( app )
+  static void execute( LightApp_Application* application,
+                       const QString& browser,
+                       const QString& parameters,
+                       const QString& url )
+  {
+    (new RunBrowser( application, browser, parameters, url ))->start();
+  }
+
+protected:
+  RunBrowser( LightApp_Application* application,
+              const QString&        browser,
+              const QString&        parameters,
+              const QString&        url)
+    : myApplication( application ),
+      myBrowser( browser ),
+      myParameters( parameters ),
+      myUrl( url )
   {
-    //For the external browser always specify 'file://' protocol,
-    //because some WEB browsers (for example Mozilla Firefox) can't open local file without protocol.
-    myHelpFile = QString("file://%1").arg( QFileInfo( theHelpFile ).canonicalFilePath() );
+    if ( !myUrl.startsWith( "http", Qt::CaseInsensitive ) )
+    {
+      // normalize path
+      if ( myUrl.startsWith( "file://", Qt::CaseInsensitive ) )
+       myUrl = myUrl.remove( 0, QString( "file://" ).count() );
+      // For the external browser we always specify 'file://' protocol,
+      // because some web browsers (e.g. Mozilla Firefox) can't open local file without protocol.
+      myUrl = myUrl.prepend( "file://" );
+    }
+    connect(this, SIGNAL(finished()), SLOT(deleteLater()));
   }
 
   virtual void run()
   {
-    if ( !myApp.isEmpty() && !myHelpFile.isEmpty()) {
-      QString aCommand = QString( "%1 %2 \"%3%4\"" ).arg( myApp, myParams, myHelpFile, myContext.isEmpty() ? QString("") : QString( "#%1" ).arg( myContext ) );
-
+    if ( !myBrowser.isEmpty() && !myUrl.isEmpty() )
+    {
+#ifdef WIN32
+      QString cmdLine = QString( "\"%1\" %2 \"%3\"" ).arg( myBrowser, myParameters, myUrl );
+#else
+      QString cmdLine = QString( "%1 %2 \"%3\"" ).arg( myBrowser, myParameters, myUrl );
+#endif
       QProcess* proc = new QProcess();
-
-      proc->start( aCommand );
-      if ( !proc->waitForStarted() ) {
+      proc->start( cmdLine );
+      if ( !proc->waitForStarted() )
+      {
         SALOME_CustomEvent* ce2000 = new SALOME_CustomEvent( 2000 );
-        QString* msg = new QString( QObject::tr( "EXTERNAL_BROWSER_CANNOT_SHOW_PAGE" ).arg( myApp, myHelpFile ) );
+        QString* msg = new QString( QObject::tr( "EXTERNAL_BROWSER_CANNOT_SHOW_PAGE" ).arg( myBrowser, myUrl ) );
         ce2000->setData( msg );
-        QApplication::postEvent( myLApp, ce2000 );
+        QApplication::postEvent( myApplication, ce2000 );
       }
     }
   }
 
 private:
-  QString               myApp;
-  QString               myParams;
-  QString               myHelpFile;
-  QString               myContext;
-  int                   myStatus;
-  LightApp_Application* myLApp;
+  LightApp_Application* myApplication;
+  QString               myBrowser;
+  QString               myParameters;
+  QString               myUrl;
 };
 
-/*!
-  SLOT: Displays help contents for choosen module
-*/
-void LightApp_Application::onHelpContentsModule()
+void LightApp_Application::showHelp( const QString& path )
 {
-  const QAction* a = (QAction*) sender();
-  QString helpFile = a->data().toString();
-  if ( helpFile.isEmpty() ) return;
-
   SUIT_ResourceMgr* resMgr = resourceMgr();
-  QString platform;
-#ifdef WIN32
-  platform = "winapplication";
-#else
-  platform = "application";
-#endif
-  QString anApp = resMgr->stringValue("ExternalBrowser", platform);
-#ifdef WIN32
-  QString quote("\"");
-  anApp.prepend( quote );
-  anApp.append( quote );
-#endif
-  QString aParams = resMgr->stringValue("ExternalBrowser", "parameters");
+
 #if DISABLE_QTXWEBBROWSER
-  bool useExtBrowser = true;
+  bool useExternalBrowser = true;
 #else  
-  bool useExtBrowser = resMgr->booleanValue("ExternalBrowser", "use_external_browser", false );
+  bool useExternalBrowser = resMgr->booleanValue("ExternalBrowser", "use_external_browser", false );
+#endif
+
+  if ( useExternalBrowser )
+  {
+#ifdef WIN32
+    QString browser = resMgr->stringValue( "ExternalBrowser", "winapplication" ) ;
+#else
+    QString browser = resMgr->stringValue( "ExternalBrowser", "application" );
 #endif
+    QString parameters = resMgr->stringValue("ExternalBrowser", "parameters");
   
-  if( useExtBrowser ) {
-    if ( !anApp.isEmpty() ) {
-      RunBrowser* rs = new RunBrowser( this, anApp, aParams, helpFile );
-      rs->start();
+    if ( !browser.isEmpty() )
+    {
+      RunBrowser::execute( this, browser, parameters, path );
     }
-    else {
+    else
+    {
       if ( SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "DEFINE_EXTERNAL_BROWSER" ),
                                       SUIT_MessageBox::Yes | SUIT_MessageBox::No,
                                       SUIT_MessageBox::Yes ) == SUIT_MessageBox::Yes )
-
-        showPreferences( tr( "PREF_APP" ) );
+      {
+        QStringList path;
+        path << tr( "PREF_CATEGORY_SALOME" ) << tr( "PREF_TAB_GENERAL" )
+             << tr( "PREF_GROUP_EXT_BROWSER" ) << tr( "PREF_APP" );
+        showPreferences( path );
+      }
     }
   }
-  else {
-    QStringList parameters;
-    parameters << QString( "--language=%1" ).arg( resMgr->stringValue( "language", "language" ) );
-    parameters << QString( "--add=%1" ).arg( QApplication::instance()->applicationPid() );
-    parameters << helpFile;
-    QProcess::startDetached( "HelpBrowser", parameters );
+  else
+  {
+    QStringList cmdLine;
+    cmdLine << QString( "--language=%1" ).arg( resMgr->stringValue( "language", "language" ) );
+    cmdLine << QString( "--add=%1" ).arg( QApplication::instance()->applicationPid() );
+    cmdLine << path;
+    QProcess::startDetached( "HelpBrowser", cmdLine );
   }
 }
 
 /*!
-  SLOT: Displays help contents for choosen dialog
+  SLOT: Displays help contents for choosen module
 */
-void LightApp_Application::onHelpContextModule( const QString& theComponentName,
-                                                const QString& theFileName,
-                                                const QString& theContext )
-{
-  QString fileName = theFileName;
-  QString context  = theContext;
-  if ( !QFile::exists( fileName ) && theContext.isEmpty() ) {
-    // context might be passed within theFileName argument
-    QStringList comps = fileName.split("#");
-    if ( comps.count() > 1 ) {
-      context = comps.last();
-      comps.removeLast();
-      fileName = comps.join("#");
-    }
-  }
-
-  QString homeDir = "";
-  if ( !theComponentName.isEmpty() ) {
-    QString dir = getenv( ( theComponentName + "_ROOT_DIR" ).toLatin1().constData() );
-    if ( !dir.isEmpty() )
-      homeDir = Qtx::addSlash( Qtx::addSlash( dir )      +
-                               Qtx::addSlash( "share" )  +
-                               Qtx::addSlash( "doc" )    +
-                               Qtx::addSlash( "salome" ) +
-                               Qtx::addSlash( "gui" )    +
-                               Qtx::addSlash( theComponentName ) );
-  }
-
-  QString helpFile = QFileInfo( homeDir + fileName ).absoluteFilePath();
-  SUIT_ResourceMgr* resMgr = resourceMgr();
-        QString platform;
-#ifdef WIN32
-        platform = "winapplication";
-#else
-        platform = "application";
-#endif
-        QString anApp = resMgr->stringValue("ExternalBrowser", platform);
-#ifdef WIN32
-        QString quote("\"");
-        anApp.prepend( quote );
-        anApp.append( quote );
-#endif
-
-#if DISABLE_QTXWEBBROWSER
-  bool useExtBrowser = true;
-#else  
-  bool useExtBrowser = resMgr->booleanValue("ExternalBrowser", "use_external_browser", false );
-#endif
-
-  if(useExtBrowser) {
-    QString aParams = resMgr->stringValue("ExternalBrowser", "parameters");
+void LightApp_Application::onHelpContentsModule()
+{
+  const QAction* a = (QAction*) sender();
+  QString helpFile = a->data().toString();
+  if ( !helpFile.isEmpty() )
+    showHelp( helpFile );
+}
 
-    if ( !anApp.isEmpty() ) {
-      RunBrowser* rs = new RunBrowser( this, anApp, aParams, helpFile, context );
-      rs->start();
-    }
-    else {
-      if ( SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "DEFINE_EXTERNAL_BROWSER" ),
-                                      SUIT_MessageBox::Yes | SUIT_MessageBox::No,
-                                      SUIT_MessageBox::Yes ) == SUIT_MessageBox::Yes )
-        showPreferences( tr( "PREF_APP" ) );
+/*!
+  SLOT: Displays contextual help (e.g. for choosen dialog)
+*/
+void LightApp_Application::onHelpContextModule( const QString& component,
+                                                const QString& url,
+                                                const QString& context )
+{
+  QString path = url;
+  if ( !url.startsWith( "http", Qt::CaseInsensitive ) )
+  {
+    // local file path
+    QFileInfo fi( url );
+    if ( fi.isRelative() && !component.isEmpty() )
+    {
+      QString rootDir = Qtx::getenv( (component + "_ROOT_DIR").toLatin1().constData() );
+      if ( !rootDir.isEmpty() )
+      {
+       path = (QStringList() << rootDir << "share" << "doc" << "salome" << "gui" << component << url).join( QDir::separator() );
+      }
     }
   }
-  else {
-    QStringList parameters;
-    parameters << QString( "--language=%1" ).arg( resMgr->stringValue( "language", "language" ) );
-    parameters << QString( "--add=%1" ).arg( QApplication::instance()->applicationPid() );
-    parameters << QString( "%1#%2" ).arg( helpFile ).arg( context );
-    QProcess::startDetached( "HelpBrowser", parameters );
+  if ( !context.isEmpty() )
+  {
+    path += QString( "#%1" ).arg( context );
   }
+  showHelp( path );
 }
 
 /*!
@@ -1309,11 +1383,20 @@ void LightApp_Application::insertDockWindow( const int id, QWidget* wid )
   myWin.insert( id, wid );
 
   QtxDockWidget* dock = new QtxDockWidget( true, desktop() );
+  if ( id == WT_InfoPanel ) {
+    // Info panel's position is strongly limited to the right area;
+    // It is not movable and not floatable.
+    dock->setAllowedAreas( Qt::RightDockWidgetArea );
+    dock->setFeatures( QDockWidget::DockWidgetClosable );
+    connect( dock, SIGNAL( aboutToShow()), this, SLOT( onInfoPanelShown() ) );
+  }
+  else {
+    dock->setFeatures( QDockWidget::AllDockWidgetFeatures );
+  }
   connect( dock, SIGNAL(  destroyed( QObject* ) ), this, SLOT( onWCDestroyed( QObject* ) ) );
 
-  dock->setFeatures( QDockWidget::AllDockWidgetFeatures );
-  dock->setObjectName( wid->objectName().isEmpty() ? QString( "window_%1" ).arg( id ) : 
-                      QString( "%1Dock" ).arg( wid->objectName() ) );
+  dock->setObjectName( wid->objectName().isEmpty() ? QString( "window_%1" ).arg( id ) :
+                       QString( "%1Dock" ).arg( wid->objectName() ) );
   dock->setWidget( wid );
   dock->toggleViewAction()->setData( QVariant( wid->objectName() ) );
   connect( dock->toggleViewAction(), SIGNAL( triggered( bool ) ),
@@ -1357,10 +1440,9 @@ void LightApp_Application::placeDockWindow( const int id, Qt::DockWidgetArea pla
 /*!
   Gets window.
   \param flag - key for window
-  \param studyId - study id
   Flag used how identificator of window in windows list.
 */
-QWidget* LightApp_Application::getWindow( const int flag, const int )
+QWidget* LightApp_Application::getWindow( const int flag)
 {
   QWidget* wid = dockWindow( flag );
   if ( !wid )
@@ -1382,6 +1464,11 @@ SUIT_DataBrowser* LightApp_Application::objectBrowser()
   return qobject_cast<SUIT_DataBrowser*>( dockWindow( WT_ObjectBrowser ) );
 }
 
+QtxInfoPanel* LightApp_Application::infoPanel()
+{
+  return qobject_cast<QtxInfoPanel *>( dockWindow( WT_InfoPanel ));
+}
+
 /*!
   \return Log Window
 */
@@ -1469,7 +1556,8 @@ SUIT_ViewManager* LightApp_Application::getViewManager( const QString& vmType, c
       aVM = anActiveVM;
     }
 
-  if ( aVM && create )
+  bool keepDetached = property("keep_detached").toBool();
+  if ( aVM && (!aVM->getDetached() || keepDetached) && create )
   {
     if ( !aVM->getActiveView() )
       {
@@ -1495,7 +1583,7 @@ SUIT_ViewManager* LightApp_Application::getViewManager( const QString& vmType, c
   Creates view manager of some type
   \param vmType - type of view manager
 */
-SUIT_ViewManager* LightApp_Application::createViewManager( const QString& vmType )
+SUIT_ViewManager* LightApp_Application::createViewManager( const QString& vmType, bool detached )
 {
   SUIT_ResourceMgr* resMgr = resourceMgr();
 
@@ -1547,11 +1635,11 @@ SUIT_ViewManager* LightApp_Application::createViewManager( const QString& vmType
 #ifndef DISABLE_PVVIEWER
   if( vmType == PVViewer_Viewer::Type() )
   {
-    if ( viewMgr = dynamic_cast<PVViewer_ViewManager*>( getViewManager( vmType, false ) ) ) {
+    if (( viewMgr = dynamic_cast<PVViewer_ViewManager*>( getViewManager( vmType, false )))) {
       viewMgr->getActiveView()->setFocus();
       return 0;
     } else {
-      viewMgr = new PVViewer_ViewManager( activeStudy(), desktop(), logWindow() );
+      viewMgr = new PVViewer_ViewManager( activeStudy(), desktop() );
     }
   }
 #endif
@@ -1584,18 +1672,17 @@ SUIT_ViewManager* LightApp_Application::createViewManager( const QString& vmType
                            resMgr->booleanValue( "3DViewer", "relative_size", vm->trihedronRelative() ));
     vm->setInteractionStyle( resMgr->integerValue( "3DViewer", "navigation_mode", vm->interactionStyle() ) );
     vm->setProjectionType( resMgr->integerValue( "OCCViewer", "projection_mode", vm->projectionType() ) );
-  #if OCC_VERSION_LARGE > 0x06090000
     vm->setStereoType( resMgr->integerValue( "OCCViewer", "stereo_type", vm->stereoType() ) );
     vm->setAnaglyphFilter( resMgr->integerValue( "OCCViewer", "anaglyph_filter", vm->anaglyphFilter() ) );
     vm->setStereographicFocus( resMgr->integerValue( "OCCViewer", "focus_type", vm->stereographicFocusType() ),
                                resMgr->doubleValue( "OCCViewer", "focus_value", vm->stereographicFocusValue() ));
     vm->setInterocularDistance( resMgr->integerValue( "OCCViewer", "iod_type", vm->interocularDistanceType() ),
                                 resMgr->doubleValue( "OCCViewer", "iod_value", vm->interocularDistanceValue() ));
+    vm->setSelectionStyle((OCCViewer_ViewWindow::SelectionStyle) resMgr->integerValue( "OCCViewer", "adv_selection_mode", vm->selectionStyle() ) );
 
     vm->setReverseStereo( resMgr->booleanValue( "OCCViewer", "reverse_stereo", vm->isReverseStereo() ) );
     vm->setVSync( resMgr->booleanValue( "OCCViewer", "enable_vsync", vm->isVSync() ) );
     vm->setQuadBufferSupport( resMgr->booleanValue( "OCCViewer", "enable_quad_buffer_support", vm->isQuadBufferSupport() ) );
-  #endif
     vm->setZoomingStyle( resMgr->integerValue( "3DViewer", "zooming_mode", vm->zoomingStyle() ) );
     vm->enablePreselection( resMgr->booleanValue( "OCCViewer", "enable_preselection", vm->isPreselectionEnabled() ) );
     vm->enableSelection(    resMgr->booleanValue( "OCCViewer", "enable_selection",    vm->isSelectionEnabled() ) );
@@ -1653,6 +1740,7 @@ SUIT_ViewManager* LightApp_Application::createViewManager( const QString& vmType
   if ( !viewMgr )
     return 0;
 
+  viewMgr->setDetached(detached);
   addViewManager( viewMgr );
   SUIT_ViewWindow* viewWin = viewMgr->createViewWindow();
 
@@ -1733,6 +1821,7 @@ void LightApp_Application::onStudyCreated( SUIT_Study* theStudy )
   }
 
   getWindow( WT_ObjectBrowser );
+  getWindow( WT_InfoPanel );
 
   loadDockWindowsState();
 
@@ -1764,6 +1853,7 @@ void LightApp_Application::onStudyOpened( SUIT_Study* theStudy )
   }
 
   getWindow( WT_ObjectBrowser );
+  getWindow( WT_InfoPanel );
 
   loadDockWindowsState();
 
@@ -1788,17 +1878,17 @@ void LightApp_Application::onStudySaved( SUIT_Study* s )
 {
   QtxMRUAction* mru = ::qobject_cast<QtxMRUAction*>( action( MRUId ) );
   if ( mru && s )
-      mru->insert( s->studyName() );
+    mru->insert( s->studyName() );
 
   emit studySaved();
 }
 
 /*!Protected SLOT. On study closed.*/
-void LightApp_Application::onStudyClosed( SUIT_Study* s )
+void LightApp_Application::onStudyClosed( SUIT_Study* /*s*/ )
 {
   /*
   disconnect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
-             this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ) );
+              this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ) );
   */
 
   // stop auto-save timer
@@ -1934,7 +2024,12 @@ void LightApp_Application::onPreferences()
 }
 
 /*!Private SLOT. On preferences.*/
-void LightApp_Application::showPreferences( const QString& itemText )
+void LightApp_Application::showPreferences( const QString& path )
+{
+  showPreferences( QStringList() << path );
+}
+
+void LightApp_Application::showPreferences( const QStringList& path )
 {
   QApplication::setOverrideCursor( Qt::WaitCursor );
 
@@ -1945,7 +2040,7 @@ void LightApp_Application::showPreferences( const QString& itemText )
   if ( !prefDlg )
     return;
 
-  preferences()->activateItem( itemText );
+  preferences()->activateItem( path );
 
   if ( ( prefDlg->exec() == QDialog::Accepted || prefDlg->isSaved() ) &&  resourceMgr() )
   {
@@ -1998,8 +2093,6 @@ void LightApp_Application::updateActions()
 */
 SUIT_Study* LightApp_Application::createNewStudy()
 {
-  LightApp_Application::lastStudyId++;
-
   LightApp_Study* aStudy = new LightApp_Study( this );
 
   // Set up processing of major study-related events
@@ -2059,17 +2152,20 @@ QWidget* LightApp_Application::createWindow( const int flag )
 
     // Create OBSelector
     new LightApp_OBSelector( ob, mySelMgr );
-#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
-    ob->treeView()->header()->setResizeMode(SUIT_DataObject::VisibilityId, QHeaderView::Fixed);
-#else
     ob->treeView()->header()->setSectionResizeMode(SUIT_DataObject::VisibilityId, QHeaderView::Fixed);
-#endif
     ob->treeView()->header()->moveSection(SUIT_DataObject::NameId,SUIT_DataObject::VisibilityId);
     ob->treeView()->setColumnWidth(SUIT_DataObject::VisibilityId, VISIBILITY_COLUMN_WIDTH);
     ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
     wid = ob;
     ob->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
   }
+  else if ( flag == WT_InfoPanel)
+  {
+    QtxInfoPanel* ipanel = new QtxInfoPanel( desktop() );
+    ipanel->setObjectName( "infoPanel" );
+    ipanel->setWindowTitle( tr( "INFO_PANEL" ) );
+    wid = ipanel;
+  }
 #ifndef DISABLE_PYCONSOLE
   else  if ( flag == WT_PyConsole )
   {
@@ -2086,6 +2182,7 @@ QWidget* LightApp_Application::createWindow( const int flag )
   else if ( flag == WT_LogWindow )
   {
     LogWindow* logWin = new LogWindow( desktop() );
+    logWin->handleQtMessages( true );
     logWin->setObjectName( "logWindow" );
     logWin->setWindowTitle( tr( "LOG_WINDOW" ) );
     logWin->setProperty( "shortcut", QKeySequence( "Alt+Shift+L" ) );
@@ -2106,6 +2203,7 @@ void LightApp_Application::defaultWindows( QMap<int, int>& aMap ) const
 #endif
   if ( activeStudy() ) {
     aMap.insert( WT_ObjectBrowser, Qt::LeftDockWidgetArea );
+    aMap.insert( WT_InfoPanel, Qt::RightDockWidgetArea );
     //  aMap.insert( WT_LogWindow, Qt::DockBottom );
   }
 }
@@ -2132,6 +2230,7 @@ LightApp_Preferences* LightApp_Application::preferences( const bool crt ) const
   {
     _prefs_ = new LightApp_Preferences( resourceMgr() );
     that->createPreferences( _prefs_ );
+    qAddPostRoutine( LightAppCleanUpAppResources );
   }
 
   that->myPrefs = _prefs_;
@@ -2153,42 +2252,48 @@ LightApp_Preferences* LightApp_Application::preferences( const bool crt ) const
     if ( !app )
       continue;
 
-    QStringList modNameList;
-    app->modules( modNameList, false );
+    // all modules available in current session
+    QStringList names;
+    app->modules( names, false );
 
-    QMap<QString, QString> iconMap;
-    app->moduleIconNames( iconMap );
+    // icons of modules
+    QMap<QString, QString> icons;
+    app->moduleIconNames( icons );
 
-    for ( QStringList::const_iterator it = modNameList.begin(); it != modNameList.end(); ++it )
+    // step 1: iterate through list of all available modules
+    // and add empty preferences page
+    for ( QStringList::const_iterator it = names.begin(); it != names.end(); ++it )
     {
-      if ( !app->isLibExists( *it ) || _prefs_->hasModule( *it ) )
-        continue;
-
-      int modId = _prefs_->addPreference( *it );
-      if ( iconMap.contains( *it ) )
-        _prefs_->setItemIcon( modId, Qtx::scaleIcon( resMgr->loadPixmap( moduleName( *it ), iconMap[*it], false ), 20 ) );
+      if ( !_prefs_->hasModule( *it ) ) // prevent possible duplications
+      {
+        int modId = _prefs_->addPreference( *it ); // add empty page
+        if ( icons.contains( *it ) )               // set icon
+          _prefs_->setItemIcon( modId, Qtx::scaleIcon( resMgr->loadPixmap( moduleName( *it ),
+                                                                           icons[*it], false ), 20 ) );
+      }
     }
 
-    ModuleList modList;
-    app->modules( modList );
-    QListIterator<CAM_Module*> itr( modList );
+    // step 2: iterate through list of all loaded modules
+    // and initialize their preferences
+    ModuleList loadedModules;
+    app->modules( loadedModules );
+    QListIterator<CAM_Module*> itr( loadedModules );
     while ( itr.hasNext() )
     {
-      LightApp_Module* mod = 0;
-
-      CAM_Module* anItem = itr.next();
-      if ( anItem->inherits( "LightApp_Module" ) )
-        mod = (LightApp_Module*)anItem;
+      LightApp_Module* module = 0;
+      CAM_Module* m = itr.next();
+      if ( m->inherits( "LightApp_Module" ) )
+        module = (LightApp_Module*)m;
 
-      if ( mod && !_prefs_->hasModule( mod->moduleName() ) )
+      if ( module && !_prefs_->hasModule( module->moduleName() ) )
       {
-        _prefs_->addPreference( mod->moduleName() );
-        mod->createPreferences();
-        that->emptyPreferences( mod->moduleName() );
+        _prefs_->addPreference( module->moduleName() ); // add page (for sure, had to be done at step 1)
+        module->createPreferences();                    // initialize preferences
+        that->emptyPreferences( module->moduleName() ); // show dummy page if module does not export any preferences
       }
     }
   }
-  _prefs_->setItemProperty( "info", tr( "PREFERENCES_NOT_LOADED" ) );
+  _prefs_->setItemProperty( "info", tr( "PREFERENCES_NOT_LOADED" ) ); // dummy page for modules which are not loaded yet
 
   return myPrefs;
 }
@@ -2218,8 +2323,6 @@ void LightApp_Application::emptyPreferences( const QString& modName )
   if ( !item || !item->isEmpty() )
     return;
 
-  //  printf( "---------------------> Modify for empty module.\n" );
-
   QtxPagePrefFrameItem* frm = new QtxPagePrefFrameItem( item->title(), item->parentItem() );
   frm->setIcon( item->icon() );
   frm->setStretch( false );
@@ -2282,6 +2385,12 @@ void LightApp_Application::createPreferences( LightApp_Preferences* pref )
   pref->addPreference( tr( "PREF_OPAQUE_RESIZE" ), lookGroup, LightApp_Preferences::Bool, "desktop", "opaque_resize" );
   // .... -> drop-down buttons 
   pref->addPreference( tr( "PREF_DROP_DOWN_BUTTONS" ), lookGroup, LightApp_Preferences::Bool, "viewers", "drop_down_buttons" );
+  // .... -> Notification timeout
+  int delay = pref->addPreference( tr( "PREF_NOTIFY_TIMEOUT" ), lookGroup, LightApp_Preferences::IntSpin, "notification", "timeout" );
+  pref->setItemProperty( "special", tr("PREF_NOTIFY_TIMEOUT_NONE"), delay );
+  pref->setItemProperty( "min", 0, delay );
+  pref->setItemProperty( "max", 100, delay );
+  pref->setItemProperty( "suffix", " sec", delay );
   // ... "Look and feel" group <<end>>
 
   // ... "Study properties" group <<start>>
@@ -2358,7 +2467,7 @@ void LightApp_Application::createPreferences( LightApp_Preferences* pref )
   pref->setItemProperty( "columns", 2, fullScreenGroup );
   // .... -> automatic hiding toolbars
   pref->addPreference( tr( "PREF_FULL_SCREEN_AUTO" ), fullScreenGroup,
-                      LightApp_Preferences::Bool, "OCCViewer", "automatic_hiding" );
+                       LightApp_Preferences::Bool, "OCCViewer", "automatic_hiding" );
   // ... "Full-screen" group <<end>>
 
   // .. "General" preferences tab <<end>>
@@ -2413,7 +2522,7 @@ void LightApp_Application::createPreferences( LightApp_Preferences* pref )
   anIndicesList << 0                       << 1;
   pref->setItemProperty( "strings", aValuesList,   occProjMode );
   pref->setItemProperty( "indexes", anIndicesList, occProjMode );
-#if OCC_VERSION_LARGE > 0x06090000
+
   // .... -> Stereo group
   int stereoGroup = pref->addPreference( tr( "PREF_GROUP_STEREO" ), occGroup);
   pref->setItemProperty( "columns", 2, stereoGroup );
@@ -2477,14 +2586,14 @@ void LightApp_Application::createPreferences( LightApp_Preferences* pref )
 
   // .... -> Reverse stereo
   pref->addPreference( tr( "PREF_REVERSE_STEREO" ), stereoGroup,
-                      LightApp_Preferences::Bool, "OCCViewer", "reverse_stereo" );
+                       LightApp_Preferences::Bool, "OCCViewer", "reverse_stereo" );
   // .... -> Enable V-Sync
   pref->addPreference( tr( "PREF_ENABLE_VSYNC" ), stereoGroup,
-                      LightApp_Preferences::Bool, "OCCViewer", "enable_vsync" );
+                       LightApp_Preferences::Bool, "OCCViewer", "enable_vsync" );
   // .... -> Enable quad-buffer support
   pref->addPreference( tr( "PREF_ENABLE_QUAD_BUFFER_SUPPORT" ), stereoGroup,
-                      LightApp_Preferences::Bool, "OCCViewer", "enable_quad_buffer_support" );
-#endif
+                       LightApp_Preferences::Bool, "OCCViewer", "enable_quad_buffer_support" );
+
   // ... "Background" group <<start>>
   int bgGroup = pref->addPreference( tr( "PREF_VIEWER_BACKGROUND" ), occGroup );
   //  pref->setItemProperty( "columns", 2, bgGroup );
@@ -2543,20 +2652,29 @@ void LightApp_Application::createPreferences( LightApp_Preferences* pref )
 
   // ... "Selection" group <<start>>
   int occSelectionGroup = pref->addPreference( tr( "PREF_GROUP_SELECTION" ), occGroup );
-  pref->setItemProperty( "columns", 2, occSelectionGroup );
+  pref->setItemProperty( "columns", 3, occSelectionGroup );
   // .... -> enable preselection
-  pref->addPreference( tr( "PREF_ENABLE_PRESELECTION" ), occSelectionGroup, 
-                      LightApp_Preferences::Bool, "OCCViewer", "enable_preselection" );
+  pref->addPreference( tr( "PREF_ENABLE_PRESELECTION" ), occSelectionGroup,
+                       LightApp_Preferences::Bool, "OCCViewer", "enable_preselection" );
   // .... -> enable selection
-  pref->addPreference( tr( "PREF_ENABLE_SELECTION" ), occSelectionGroup, 
-                      LightApp_Preferences::Bool, "OCCViewer", "enable_selection" );
+  pref->addPreference( tr( "PREF_ENABLE_SELECTION" ), occSelectionGroup,
+                       LightApp_Preferences::Bool, "OCCViewer", "enable_selection" );
+  // .... -> selection style
+  int aSeleStyle = pref->addPreference( tr( "PREF_SELECTION_STYLE" ), occSelectionGroup,
+                       LightApp_Preferences::Selector, "OCCViewer", "adv_selection_mode" );
+  aValuesList.clear();
+  anIndicesList.clear();
+  aValuesList   << tr("PREF_POLYGON_SELECTION") << tr("PREF_CIRCLE_SELECTION");
+  anIndicesList << 0 << 1;
+  pref->setItemProperty( "strings", aValuesList, aSeleStyle);
+  pref->setItemProperty( "indexes", anIndicesList, aSeleStyle);
   // ... "Selection" group <<end>>
 
   // ... "Clipping" group <<start>>
   int occClippingGroup = pref->addPreference( tr( "PREF_GROUP_CLIPPING" ), occGroup );
   // .... -> clipping color
   pref->addPreference( tr( "PREF_CLIPPING_COLOR" ), occClippingGroup,
-               LightApp_Preferences::Color, "OCCViewer", "clipping_color" );
+                       LightApp_Preferences::Color, "OCCViewer", "clipping_color" );
   int texturePref = pref->addPreference( "", occClippingGroup, LightApp_Preferences::Frame );
   pref->setItemProperty( "columns", 2, texturePref );
   // .... -> use default texture
@@ -2931,6 +3049,20 @@ void LightApp_Application::createPreferences( LightApp_Preferences* pref )
   pref->addPreference( tr( "PREF_PY_LINE_NUMBS_AREA" ), pyDispGroup,
     LightApp_Preferences::Bool, "PyEditor", "LineNumberArea" );
   // ... "Display settings" group <<end>>
+
+  // ... "Editor settings" group <<start>>
+  int pyEditGroup = pref->addPreference( tr( "PREF_GROUP_PY_EDITOR" ), pyeditTab );
+  // ... -> navigation mode
+  int pyCompletion = pref->addPreference( tr( "PREF_PY_COMPLETION_MODE" ), pyEditGroup,
+                                          LightApp_Preferences::Selector, "PyEditor", "CompletionPolicy" );
+  aValuesList.clear();
+  anIndicesList.clear();
+  aValuesList   << tr("PREF_PY_NONE") << tr("PREF_PY_AUTO") << tr("PREF_PY_MANUAL") << tr("PREF_PY_ALWAYS");
+  anIndicesList << 0                  << 1                  << 2                    << 3                   ;
+  pref->setItemProperty( "strings", aValuesList, pyCompletion );
+  pref->setItemProperty( "indexes", anIndicesList, pyCompletion );
+  // ... "Editor settings" group <<end>>
+
   // ... "Tab settings" group <<start>>
   int pyTabGroup = pref->addPreference( tr( "PREF_GROUP_PY_TAB" ), pyeditTab );
   pref->setItemProperty( "columns", 2, pyTabGroup );
@@ -3245,7 +3377,28 @@ void LightApp_Application::preferencesChanged( const QString& sec, const QString
     }
   }
 #endif
-#if OCC_VERSION_LARGE > 0x06090000
+
+
+#ifndef DISABLE_OCCVIEWER
+  if (sec == QString("OCCViewer") && param == QString("adv_selection_mode"))
+  {
+    int mode = resMgr->integerValue("OCCViewer", "adv_selection_mode", 0);
+    QList<SUIT_ViewManager*> lst;
+    viewManagers(OCCViewer_Viewer::Type(), lst);
+    QListIterator<SUIT_ViewManager*> it(lst);
+    while (it.hasNext())
+    {
+      SUIT_ViewModel* vm = it.next()->getViewModel();
+      if (!vm || !vm->inherits("OCCViewer_Viewer"))
+        continue;
+
+      OCCViewer_Viewer* occVM = (OCCViewer_Viewer*)vm;
+      occVM->setSelectionStyle((OCCViewer_ViewWindow::SelectionStyle)mode);
+    }
+  }
+#endif
+
+
 #ifndef DISABLE_OCCVIEWER
   if ( sec == QString( "OCCViewer" ) && param == QString( "stereo_type" ) )
   {
@@ -3382,7 +3535,7 @@ void LightApp_Application::preferencesChanged( const QString& sec, const QString
     }
   }
 #endif
-#endif
+
   if ( sec == QString( "3DViewer" ) && param == QString( "zooming_mode" ) )
   {
     int mode = resMgr->integerValue( "3DViewer", "zooming_mode", 0 );
@@ -3671,10 +3824,15 @@ void LightApp_Application::preferencesChanged( const QString& sec, const QString
   }
   if ( sec == "desktop" && param == "opaque_resize" ) {
     bool opaqueResize = resMgr->booleanValue( "desktop", "opaque_resize", false );
-    QMainWindow::DockOptions dopts = desktop()->dockOptions();
-    if ( opaqueResize ) dopts |= QMainWindow::AnimatedDocks;
-    else                dopts &= ~QMainWindow::AnimatedDocks;
-    desktop()->setDockOptions( dopts );
+    // RNV: This code has been commented, because clearing of the QMainWindow::AnimatedDocks option
+    //      leads to strange behaviour of the dockable windows (at least at qt-5.6.1):
+    //      any dockable window can't be docked to the another area, except initial area.
+    //      It is possible to move window to another area, but it always returns to the initial area.
+    //
+    //    QMainWindow::DockOptions dopts = desktop()->dockOptions();
+    //    if ( opaqueResize ) dopts |= QMainWindow::AnimatedDocks;
+    //     else                dopts &= ~QMainWindow::AnimatedDocks;
+    //    desktop()->setDockOptions( dopts );
     desktop()->setOpaqueResize( opaqueResize );
     if ( dynamic_cast<STD_TabDesktop*>( desktop() ) )
       dynamic_cast<STD_TabDesktop*>( desktop() )->workstack()->setOpaqueResize( opaqueResize );
@@ -3690,7 +3848,7 @@ void LightApp_Application::preferencesChanged( const QString& sec, const QString
     if ( !vm || !vm->inherits( "Plot2d_Viewer" ) )
       continue;
 
-    Plot2d_Viewer* Plot2dVM = dynamic_cast<Plot2d_Viewer*>( vm );
+    //Plot2d_Viewer* Plot2dVM = dynamic_cast<Plot2d_Viewer*>( vm );
 
     viewMgr->setViewModel( vm  );
     Plot2d_ViewWindow* wnd = dynamic_cast<Plot2d_ViewWindow*>( viewMgr->getActiveView() );
@@ -3742,10 +3900,10 @@ void LightApp_Application::loadPreferences()
   if ( desktop() ) {
     desktop()->retrieveGeometry( aResMgr->stringValue( "desktop", "geometry" ) );
     bool opaqueResize = aResMgr->booleanValue( "desktop", "opaque_resize", false );
-    QMainWindow::DockOptions dopts = desktop()->dockOptions();
-    if ( opaqueResize ) dopts |= QMainWindow::AnimatedDocks;
-    else                dopts &= ~QMainWindow::AnimatedDocks;
-    desktop()->setDockOptions( dopts );
+    //    QMainWindow::DockOptions dopts = desktop()->dockOptions();
+    //    if ( opaqueResize ) dopts |= QMainWindow::AnimatedDocks;
+    //    else                dopts &= ~QMainWindow::AnimatedDocks;
+    //    desktop()->setDockOptions( dopts );
     desktop()->setOpaqueResize( opaqueResize );
     if ( dynamic_cast<STD_TabDesktop*>( desktop() ) )
       dynamic_cast<STD_TabDesktop*>( desktop() )->workstack()->setOpaqueResize( opaqueResize );
@@ -3865,17 +4023,8 @@ void LightApp_Application::afterCloseDoc()
 void LightApp_Application::updateModuleActions()
 {
   QString modName;
-  if ( activeModule() ) {
+  if ( activeModule() )
     modName = activeModule()->moduleName();
-    if ( !isModuleAccessible( modName ) ) {
-      QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
-      foreach( SUIT_Application* app, apps ) {
-        LightApp_Application* lapp = dynamic_cast<LightApp_Application*>( app );
-        if ( lapp && lapp != this )
-          lapp->removeModuleAction( modName );
-      }
-    }
-  }
 
   LightApp_ModuleAction* moduleAction =
     qobject_cast<LightApp_ModuleAction*>( action( ModulesListId ) );
@@ -3891,6 +4040,73 @@ void LightApp_Application::removeModuleAction( const QString& modName )
     moduleAction->removeModule( modName );
 }
 
+bool LightApp_Application::checkModule( const QString& title )
+{
+  if ( title.isEmpty() )
+    return false;
+
+  QString library = moduleLibrary( title, true );
+  if ( library.isEmpty() )
+    return false;
+
+  QString name = moduleName( title );
+
+  bool isPyModule = library.contains( "SalomePyQtGUI" ) || library.contains( "SalomePyQtGUILight" );
+
+  QStringList paths;
+#if defined(WIN32)
+  paths = QString( Qtx::getenv( "PATH" ) ).split( ";", QString::SkipEmptyParts );
+#elif defined(__APPLE__)
+  paths = QString( Qtx::getenv( "DYLD_LIBRARY_PATH" ) ).split( ":", QString::SkipEmptyParts );
+#else
+  paths = QString( Qtx::getenv( "LD_LIBRARY_PATH" ) ).split( ":", QString::SkipEmptyParts );
+#endif
+
+  bool isFound = false;
+  QStringList::const_iterator it;
+  for ( it = paths.begin(); it != paths.end() && !isFound; ++it )
+  {
+    isFound = QFileInfo( Qtx::addSlash( *it ) + library ).exists();
+  }
+
+  if ( !isFound )
+  {
+    INFOS( std::endl <<
+           "****************************************************************" << std::endl <<
+           "     Warning: library " << qPrintable( library ) << " is not found!" << std::endl <<
+           "     Module " << qPrintable( title ) << " will not be available in GUI mode!" << std::endl <<
+           "****************************************************************" << std::endl);
+    return false;
+  }
+
+  if ( isPyModule )
+  {
+    QString pyModule = QString( "%1GUI.py" ).arg( name );
+#if defined(WIN32)
+    paths = QString( Qtx::getenv( "PYTHONPATH" ) ).split( ";", QString::SkipEmptyParts );
+#else
+    paths = QString( Qtx::getenv( "PYTHONPATH" ) ).split( ":", QString::SkipEmptyParts );
+#endif
+    isFound = false;
+    for ( it = paths.begin(); it != paths.end() && !isFound; ++it )
+    {
+      isFound = QFileInfo( Qtx::addSlash( *it ) + pyModule ).exists();
+    }
+
+    if ( !isFound )
+    {
+      INFOS( std::endl <<
+             "****************************************************************" << std::endl <<
+             "     Warning: Python module " << qPrintable( pyModule ) << " is not found!" << std::endl <<
+             "     Module " << qPrintable( title ) << " will not be available in GUI mode!" << std::endl <<
+             "****************************************************************" << std::endl);
+      return false;
+    }
+  }
+
+  return true;
+}
+
 /*!
   Gets current windows.
   \param winMap - output current windows map.
@@ -3937,13 +4153,45 @@ void LightApp_Application::updateWindows()
   for ( WinMap::ConstIterator it = myWin.begin(); it != myWin.end(); ++it )
   {
     QWidget* wid = it.value();
+    if ( !wid )
+      continue;
     if ( winMap.contains( it.key() ) )
       wid->setVisible( true );
-    else
+    else if ( !activeStudy() )
       delete wid;
+    else
+      wid->setVisible( false );
   }
 
   loadDockWindowsState();
+
+  if ( !activeModule() && infoPanel() )
+  {
+    infoPanel()->clear();
+    infoPanel()->setTitle( tr( "INFO_WELCOME_TO_SALOME" ) );
+
+    int grp = infoPanel()->addGroup( tr( "INFO_GETTING_STARTED" ) );
+    infoPanel()->addAction( action( FileNewId ), grp );
+    infoPanel()->addLabel( action( FileNewId )->statusTip(), grp );
+    infoPanel()->addAction( action( FileOpenId ), grp );
+    infoPanel()->addLabel( action( FileOpenId )->statusTip(), grp );
+    infoPanel()->addAction( action( TutorialsId ), grp );
+    infoPanel()->addLabel( action( TutorialsId )->statusTip(), grp );
+    infoPanel()->addAction( action( VideosId ), grp );
+    infoPanel()->addLabel( action( VideosId )->statusTip(), grp );
+
+    LightApp_ModuleAction* ma = qobject_cast<LightApp_ModuleAction*>(action(ModulesListId));
+    if ( ma && ma->count() > 0 )
+    {
+      grp = infoPanel()->addGroup( tr( "INFO_AVAILABLE_MODULES" ) );
+      foreach ( QString mname, ma->modules() )
+      {
+        infoPanel()->addAction( ma->moduleAction( mname ), grp );
+        if ( !moduleDescription( mname ).isEmpty() )
+          infoPanel()->addLabel( moduleDescription( mname ), grp );
+      }
+    }
+  }
 }
 
 /*!
@@ -4035,11 +4283,11 @@ void LightApp_Application::loadDockWindowsState()
   if(tbMap) {
     QList<QToolBar*> tbList = findToolBars();
     for ( QList<QToolBar*>::iterator tit = tbList.begin(); tit != tbList.end(); ++tit )
-      {        
-       QToolBar* tb = *tit;
-       if ( tbMap->contains( tb->objectName() ) ) {      
-         tb->setVisible( (*tbMap)[tb->objectName()] );
-       }
+      { 
+        QToolBar* tb = *tit;
+        if ( tbMap->contains( tb->objectName() ) ) {      
+          tb->setVisible( (*tbMap)[tb->objectName()] );
+        }
       }
   }
 
@@ -4047,14 +4295,14 @@ void LightApp_Application::loadDockWindowsState()
     QList<QDockWidget*> dwList = desktop()->findChildren<QDockWidget*>();
     for ( QList<QDockWidget*>::iterator dit = dwList.begin(); dit != dwList.end(); ++dit )
       {
-       QDockWidget* dw = *dit;
-       
-       QObject* po = Qtx::findParent( dw, "QMainWindow" );
-       if ( po != desktop() )
-         continue;
-       
-       if ( dwMap->contains( dw->objectName() ) )
-         dw->setVisible( (*dwMap)[dw->objectName()] );
+        QDockWidget* dw = *dit;
+        
+        QObject* po = Qtx::findParent( dw, "QMainWindow" );
+        if ( po != desktop() )
+          continue;
+        
+        if ( dwMap->contains( dw->objectName() ) )
+          dw->setVisible( (*dwMap)[dw->objectName()] );
       }
   }
   */
@@ -4453,94 +4701,6 @@ void LightApp_Application::onGroupAllWindow()
     wgStack->stack();
 }
 
-/*!
-  \return if the library of module exists
-  \param moduleTitle - title of module
-*/
-bool LightApp_Application::isLibExists( const QString& moduleTitle ) const
-{
-  if( moduleTitle.isEmpty() )
-    return false;
-
-  QString lib = moduleLibrary( moduleTitle );
-
-  //abd: changed libSalomePyQtGUI to SalomePyQtGUI for WIN32
-  bool isPythonModule = lib.contains("SalomePyQtGUI");
-  bool isPythonLightModule = lib.contains("SalomePyQtGUILight");
-
-  QStringList paths;
-#if defined(WIN32)
-  paths = QString(::getenv( "PATH" )).split( ";", QString::SkipEmptyParts );
-#elif defined(__APPLE__)
-  paths = QString(::getenv( "DYLD_LIBRARY_PATH" )).split( ":", QString::SkipEmptyParts );
-#else
-  paths = QString(::getenv( "LD_LIBRARY_PATH" )).split( ":", QString::SkipEmptyParts );
-#endif
-
-  bool isLibFound = false;
-  QStringList::const_iterator anIt = paths.begin(), aLast = paths.end();
-  for( ; anIt!=aLast; anIt++ )
-  {
-    QFileInfo inf( Qtx::addSlash( *anIt ) + lib );
-
-    if( inf.exists() )
-      {
-        isLibFound = true;
-        break;
-      }
-  }
-
-  if ( !isLibFound )
-    {
-      INFOS( "\n****************************************************************" << std::endl
-          << "*    Warning: library " << lib.toLatin1().constData() << " cannot be found" << std::endl
-          << "*    Module " << moduleTitle.toLatin1().constData() << " will not be available in GUI mode" << std::endl
-          << "****************************************************************" << std::endl );
-    }
-  else if ( !isPythonModule && !isPythonLightModule)
-    return true;
-
-  if ( isPythonModule || isPythonLightModule)
-    {
-      QString pylib = moduleName( moduleTitle ) + QString(".py");
-      QString pylibgui = moduleName( moduleTitle ) + QString("GUI.py");
-
-      // Check the python library
-// #ifdef WIN32
-//       paths = QString(::getenv( "PATH" )).split( ";", QString::SkipEmptyParts );
-// #else
-      paths = QString(::getenv( "PYTHONPATH" )).split( ":", QString::SkipEmptyParts );
-// #endif
-      bool isPyLib = false, isPyGuiLib = false;
-      QStringList::const_iterator anIt = paths.begin(), aLast = paths.end();
-      for( ; anIt!=aLast; anIt++ )
-        {
-          QFileInfo inf( Qtx::addSlash( *anIt ) + pylib );
-          QFileInfo infgui( Qtx::addSlash( *anIt ) + pylibgui );
-
-          if(!isPythonLightModule)
-            if( !isPyLib && inf.exists() )
-              isPyLib = true;
-
-          if( !isPyGuiLib && infgui.exists() )
-            isPyGuiLib = true;
-
-          if ((isPyLib || isPythonLightModule ) && isPyGuiLib && isLibFound)
-            return true;
-        }
-
-      printf( "\n****************************************************************\n" );
-      printf( "*    Warning: python library for %s cannot be found:\n", moduleTitle.toLatin1().constData() );
-      if (!isPyLib)
-        printf( "*    No module named %s\n", moduleName( moduleTitle ).toLatin1().constData() );
-      if (!isPyGuiLib)
-        printf( "*    No module named %s\n", (moduleName( moduleTitle ) + QString("GUI")).toLatin1().constData() );
-      printf( "****************************************************************\n" );
-      return true;
-  }
-  return false;
-}
-
 /*!
   \return default name for an active study
 */
@@ -4571,7 +4731,12 @@ bool LightApp_Application::event( QEvent* e )
                                   d ? *d : "",
                                   SUIT_MessageBox::Yes | SUIT_MessageBox::No,
                                   SUIT_MessageBox::Yes ) == SUIT_MessageBox::Yes )
-      showPreferences( tr( "PREF_APP" ) );
+    {
+      QStringList path;
+      path << tr( "PREF_CATEGORY_SALOME" ) << tr( "PREF_TAB_GENERAL" )
+           << tr( "PREF_GROUP_EXT_BROWSER" ) << tr( "PREF_APP" );
+      showPreferences( path );
+    }
     if( d )
       delete d;
     return true;
@@ -4796,9 +4961,9 @@ QString LightApp_Application::browseObjects( const QStringList& theEntryList,
         SUIT_DataOwnerPtrList aList;
 #ifndef DISABLE_SALOMEOBJECT
         Handle(SALOME_InteractiveObject) aSObj = new SALOME_InteractiveObject
-          ( anObject->entry().toLatin1().constData(),
+          ( anObject->entry().toUtf8().constData(),
             anObject->componentDataType().toLatin1().constData(),
-            anObject->name().toLatin1().constData() );
+            anObject->name().toUtf8().constData() );
         LightApp_DataOwner* owner = new LightApp_DataOwner( aSObj  );
 #else
         LightApp_DataOwner* owner = new LightApp_DataOwner( anEntry );
@@ -4838,7 +5003,7 @@ bool LightApp_Application::renameAllowed( const QString& /*entry*/) const {
   \param name new name of the object
   \brief Return \c true if rename operation finished successfully, \c false otherwise.
 */
-bool LightApp_Application::renameObject( const QString& entry, const QString& ) {
+bool LightApp_Application::renameObject( const QString& /*entry*/, const QString& /*name*/ ) {
   return false;
 }
 
@@ -4857,6 +5022,34 @@ void LightApp_Application::onDesktopMessage( const QString& message )
     if ( !vtype.isEmpty() )
       getViewManager( vtype, true );
   }
+  else if ( message.toLower().startsWith("register_module_in_study" ) ) {
+    QString moduleName = message.split( sectionSeparator ).last();
+    // Check name of current activating module name in order to avoid ciclik 
+    // call because of messages
+    if (!property("activateModule").toBool()) {
+      CAM_Module* mod = module(moduleName);
+      if (!mod)
+        mod = module(moduleTitle(moduleName));
+      if (!mod) {
+        mod = loadModule(moduleName);
+        if (!mod)
+          mod = loadModule(moduleTitle(moduleName));
+        if (mod) {
+          addModule(mod);
+        }
+      }
+      if (mod) {
+        CAM_Study* anActiveStudy = dynamic_cast<CAM_Study*>(activeStudy());
+        if (anActiveStudy) {
+          mod->connectToStudy(anActiveStudy);
+          LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>(mod->dataModel());
+          if(aDM) {
+            aDM->initRootObject();
+          }
+        }
+      }
+    }
+  }
   else {
     QStringList data = message.split( sectionSeparator );
     if ( data.count() > 1 ) {
@@ -4887,6 +5080,12 @@ void LightApp_Application::onDesktopMessage( const QString& message )
   }
 }
 
+void LightApp_Application::onInfoPanelShown()
+{
+  if ( activeModule() && activeModule()->inherits( "LightApp_Module" ) )
+    ((LightApp_Module*)activeModule())->updateInfoPanel();
+}
+
 /*!
   Internal method. 
   Returns all top level toolbars.
@@ -4897,10 +5096,10 @@ QList<QToolBar*> LightApp_Application::findToolBars( const QStringList& names )
   QList<QToolBar*> aResult;
   QList<QToolBar*> tbList = desktop()->findChildren<QToolBar*>();
   for ( QList<QToolBar*>::iterator tit = tbList.begin(); tit != tbList.end(); ++tit ) {
-    QToolBar* tb = *tit;    
+    QToolBar* tb = *tit;
     QObject* po = Qtx::findParent( tb, "QMainWindow" );
     if ( po != desktop() )
-      continue;        
+      continue;
     if ( names.isEmpty() || names.contains( tb->objectName() ) )
       aResult.append(tb);
   }
@@ -4909,12 +5108,12 @@ QList<QToolBar*> LightApp_Application::findToolBars( const QStringList& names )
 
 /*!
   Internal method to parse toolbars and dockable windows state.
- */
-QByteArray LightApp_Application::processState(QByteArray& input, 
-                                             const bool processWin, 
-                                             const bool processTb, 
-                                             const bool isRestoring, 
-                                             QByteArray defaultState) {
+*/
+QByteArray LightApp_Application::processState(QByteArray& input,
+                                              const bool processWin,
+                                              const bool processTb,
+                                              const bool isRestoring,
+                                              QByteArray defaultState) {
 
   QByteArray aRes;
   bool hasDefaultState  = !defaultState.isEmpty();
@@ -4929,7 +5128,7 @@ QByteArray LightApp_Application::processState(QByteArray& input,
     tmpInputData >> version;
     tmpInputData >> dockmarker;
     tmpInputData >> nbDocWin;
-  }  
+  }
   if(processWin && processTb && !isRestoring) {
     aRes = input;
   } else if(!processWin && !processTb ) {
@@ -4940,7 +5139,7 @@ QByteArray LightApp_Application::processState(QByteArray& input,
     QList<QToolBar*> aToolBars = findToolBars();
 
     QStringList aNames;
-    for ( QList<QToolBar*>::iterator tit = aToolBars.begin(); tit != aToolBars.end(); ++tit ) {        
+    for ( QList<QToolBar*>::iterator tit = aToolBars.begin(); tit != aToolBars.end(); ++tit ) {
       QToolBar* tb = *tit;
       aNames.append(tb->objectName());
     }
@@ -4950,11 +5149,11 @@ QByteArray LightApp_Application::processState(QByteArray& input,
       return aRes;
     QDataStream anInputData(&input, QIODevice::ReadOnly);
 
-    int toolBarMarkerIndexDef;
+    int toolBarMarkerIndexDef = 0;
     if(hasDefaultState) {
       toolBarMarkerIndexDef = getToolbarMarkerIndex(defaultState, aNames);
       if(toolBarMarkerIndexDef < 0)
-       return aRes;      
+        return aRes;
     }
     QDataStream anInputDataDef(&defaultState, QIODevice::ReadOnly);
 
@@ -4970,28 +5169,28 @@ QByteArray LightApp_Application::processState(QByteArray& input,
     } else {
       //Write date from default settings
       if(hasDefaultState) {
-       aTargetData = &anInputDataDef;
-       aTargetIndex = toolBarMarkerIndexDef;
+        aTargetData = &anInputDataDef;
+        aTargetIndex = toolBarMarkerIndexDef;
       } else {
-       //If no default state, write current snapshot of the dockable windows
-       if(isRestoring) {
-         aTargetData = &anInputDataCur;
-         int toolBarMarkerIndexCur = getToolbarMarkerIndex(currentArr, aNames);
-         aTargetIndex = toolBarMarkerIndexCur;
-       }         
+        //If no default state, write current snapshot of the dockable windows
+        if(isRestoring) {
+          aTargetData = &anInputDataCur;
+          int toolBarMarkerIndexCur = getToolbarMarkerIndex(currentArr, aNames);
+          aTargetIndex = toolBarMarkerIndexCur;
+        }
       }
     }
 
     if(aTargetData && aTargetIndex >= 0 ) {
       aTargetData->device()->seek(0);
       while( aTargetData->device()->pos() < aTargetIndex ) {
-       uchar ch;
-       *aTargetData >> ch;
-       aData<<ch;
+        uchar ch;
+        *aTargetData >> ch;
+        aData<<ch;
       }
       isDockWinWriten = true;
     }
-    
+
     aTargetData = 0;
     aTargetIndex = -1;
 
@@ -5000,34 +5199,34 @@ QByteArray LightApp_Application::processState(QByteArray& input,
       aTargetIndex = toolBarMarkerIndex;
     } else {
       if(hasDefaultState) {
-       aTargetData = &anInputDataDef;
-       aTargetIndex = toolBarMarkerIndexDef;   
-      }      
+        aTargetData = &anInputDataDef;
+        aTargetIndex = toolBarMarkerIndexDef;
+      }
     }
 
     if(aTargetData && aTargetIndex >= 0) {
       int index;
       if(!isDockWinWriten ) {
-       //Write version marker
-       int marker, version;
-       aTargetData->device()->seek(0);
-       *aTargetData >> marker;
-       *aTargetData >> version;
-       aData << marker;
-       aData << version;
-       aData << (uchar) QDockWidgetMarker;
-       aData << (int) 0;
-       int shift = 4*sizeof(int) + sizeof(QSize);
-       index = aTargetIndex - shift;
+        //Write version marker
+        int marker, version;
+        aTargetData->device()->seek(0);
+        *aTargetData >> marker;
+        *aTargetData >> version;
+        aData << marker;
+        aData << version;
+        aData << (uchar) QDockWidgetMarker;
+        aData << (int) 0;
+        int shift = 4*sizeof(int) + sizeof(QSize);
+        index = aTargetIndex - shift;
       } else {
-       index = aTargetIndex;
+        index = aTargetIndex;
       }
-      
+
       aTargetData->device()->seek(index);
       while(!aTargetData->atEnd()) {
-       uchar ch;
-       *aTargetData >> ch;
-       aData << ch;
+        uchar ch;
+        *aTargetData >> ch;
+        aData << ch;
       }
     } else { // Not treat toolbars
       aData << (uchar) QToolBarMarker;
@@ -5054,7 +5253,7 @@ void LightApp_Application::emitOperationFinished( const QString& theModuleName,
   Update visibility state of given objects
 */
 void LightApp_Application::updateVisibilityState( DataObjectList& theList,
-                                                 SUIT_ViewModel*  theViewModel )
+                                                  SUIT_ViewModel*  theViewModel )
 {
   if ( !theViewModel || theList.isEmpty() ) return;
 
@@ -5073,14 +5272,14 @@ void LightApp_Application::updateVisibilityState( DataObjectList& theList,
     if ( anObjModule ) {
       LightApp_Displayer* aDisplayer = anObjModule->displayer();
       if ( aDisplayer ) {
-       Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
+        Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
         if ( aDisplayer->canBeDisplayed( obj->entry(), theViewModel->getType() ) ) {
           if ( aView && aDisplayer->IsDisplayed( obj->entry(), aView ) )
             anObjState = Qtx::ShownState;
           else
             anObjState = Qtx::HiddenState;
         }
-       aStudy->setVisibilityState( obj->entry(), anObjState );
+        aStudy->setVisibilityState( obj->entry(), anObjState );
       }
     }
   }
@@ -5123,30 +5322,37 @@ void LightApp_Application::onViewManagerRemoved( SUIT_ViewManager* )
 /*!
   Check existing document.
 */
-bool LightApp_Application::checkExistingDoc()
+bool LightApp_Application::checkExistingDoc( bool closeExistingDoc )
 {
   bool result = true;
   if( activeStudy() ) {
-    int answer = SUIT_MessageBox::question( desktop(), 
-                                           tr( "APPCLOSE_CAPTION" ), 
+    int answer = !activeStudy()->isModified() ? 1 :
+                 SUIT_MessageBox::question( desktop(),
+                                           tr( "APPCLOSE_CAPTION" ),
                                            tr( "STUDYCLOSE_DESCRIPTION" ),
-                                           tr( "APPCLOSE_SAVE" ), 
+                                           tr( "APPCLOSE_SAVE" ),
                                            tr( "APPCLOSE_CLOSE" ),
                                            tr( "APPCLOSE_CANCEL" ), 0 );
     if(answer == 0) {
       if ( activeStudy()->isSaved() ) {
-       onSaveDoc();
-       closeDoc( false );
+        onSaveDoc();
+               if (closeExistingDoc) {
+                       closeDoc(false);
+               }
       } else if ( onSaveAsDoc() ) {
-       if( !closeDoc( false ) ) {
-         result = false;
-       }
+         if (closeExistingDoc) {
+           if( !closeDoc( false ) ) {
+             result = false;
+           }
+        }
       } else {
-       result = false;
-      }        
+        result = false;
+      }
     }
     else if( answer == 1 ) {
-      closeDoc( false );
+      if (closeExistingDoc) {
+       closeDoc( false );
+      }
     } else if( answer == 2 ) {
       result = false;
     }