Salome HOME
Merge branch occ/shape_reparation_2
[modules/gui.git] / src / SalomeApp / SalomeApp_Application.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File:      SalomeApp_Application.cxx
24 // Created:   10/22/2004 3:23:45 PM
25 // Author:    Sergey LITONIN
26
27 #ifdef WIN32
28   // E.A. : On windows with python 2.6, there is a conflict
29   // E.A. : between pymath.h and Standard_math.h which define
30   // E.A. : some same symbols : acosh, asinh, ...
31   #include <Standard_math.hxx>
32   #ifndef DISABLE_PYCONSOLE
33     #include <pymath.h>
34   #endif
35 #endif
36
37 #ifndef DISABLE_PYCONSOLE
38   #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
39   #include <PyConsole_Console.h>
40   #include "SalomeApp_NoteBook.h"
41 #endif
42 #include "SalomeApp_Application.h"
43 #include "SalomeApp_Study.h"
44 #include "SalomeApp_DataModel.h"
45 #include "SalomeApp_DataObject.h"
46 #include "SalomeApp_VisualState.h"
47 #include "SalomeApp_StudyPropertiesDlg.h"
48 #include "SalomeApp_LoadStudiesDlg.h"
49 #include "SalomeApp_ExitDlg.h"
50
51 #include <LightApp_Application.h>
52 #include <LightApp_Module.h>
53 #include <LightApp_Preferences.h>
54 #include <LightApp_SelectionMgr.h>
55 #include <LightApp_NameDlg.h>
56 #include <LightApp_DataOwner.h>
57
58 #include <CAM_Module.h>
59
60 #include <SUIT_Tools.h>
61 #include <SUIT_Session.h>
62 #include <SUIT_Desktop.h>
63 #include <SUIT_DataBrowser.h>
64 #include <SUIT_FileDlg.h>
65 #include <SUIT_FileValidator.h>
66 #include <SUIT_MessageBox.h>
67 #include <SUIT_ResourceMgr.h>
68 #include <SUIT_TreeModel.h>
69 #include <SUIT_ViewWindow.h>
70 #include <SUIT_ViewManager.h>
71 #include <SUIT_ViewModel.h>
72 #include <SUIT_OverrideCursor.h>
73
74 #include <QtxTreeView.h>
75
76 #include <SALOME_EventFilter.h>
77
78 // temporary commented
79 //#include <OB_ListItem.h>
80
81
82 #include <Utils_ORB_INIT.hxx>
83 #include <Utils_SINGLETON.hxx>
84 #include <SALOME_LifeCycleCORBA.hxx>
85
86 #include <QApplication>
87 #include <QAction>
88 #include <QRegExp>
89 #include <QCheckBox>
90 #include <QPushButton>
91 #include <QLabel>
92 #include <QListWidget>
93 #include <QGridLayout>
94 #include <QMenu>
95 #include <QtDebug>
96
97 #include <SALOMEDSClient_ClientFactory.hxx>
98 #include <Basics_Utils.hxx>
99
100 #include <SALOME_ListIO.hxx>
101 #include <SALOME_Prs.h>
102
103
104 #include <ToolsGUI_CatalogGeneratorDlg.h>
105 #include <ToolsGUI_RegWidget.h>
106
107 #include <vector>
108
109 #include <SALOMEDS_Tool.hxx>
110
111 /*!Internal class that updates object browser item properties */
112 // temporary commented
113 /*class SalomeApp_Updater : public OB_Updater
114 {
115 public:
116   SalomeApp_Updater() : OB_Updater(){};
117   virtual ~SalomeApp_Updater(){};
118   virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
119 };
120
121 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
122 {
123   if( !theObj || !theItem )
124     return;
125
126   SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
127   if( !SAObj )
128     return;
129
130   _PTR(SObject) SObj = SAObj->object();
131   if( !SObj )
132     return;
133   _PTR( GenericAttribute ) anAttr;
134
135   // Selectable
136   if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
137   {
138     _PTR(AttributeSelectable) aAttrSel = anAttr;
139     theItem->setSelectable( aAttrSel->IsSelectable() );
140   }
141   // Expandable
142   if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
143   {
144     _PTR(AttributeExpandable) aAttrExpand = anAttr;
145     theItem->setExpandable( aAttrExpand->IsExpandable() );
146   }
147   // Opened
148   //this attribute is not supported in the version of SALOME 3.x
149   //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
150   //{
151   //  _PTR(AttributeOpened) aAttrOpen = anAttr;
152   //  theItem->setOpen( aAttrOpen->IsOpened() );
153   //}
154 }*/
155
156 /*!Create new instance of SalomeApp_Application.*/
157 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
158 {
159   return new SalomeApp_Application();
160 }
161
162 /*!Constructor.*/
163 SalomeApp_Application::SalomeApp_Application()
164   : LightApp_Application(), 
165     myIsSiman( false ),
166     myIsCloseFromExit( false )
167 {
168 }
169
170 /*!Destructor.
171  *\li Destroy event filter.
172  */
173 SalomeApp_Application::~SalomeApp_Application()
174 {
175   // Do not destroy. It's a singleton !
176   //SALOME_EventFilter::Destroy();
177 }
178
179 /*!Start application.*/
180 void SalomeApp_Application::start()
181 {
182   // process the command line options before start: to createActions in accordance to the options
183   static bool isFirst = true;
184   if ( isFirst ) {
185     isFirst = false;
186
187     QString hdffile;
188     QStringList pyfiles;
189     QString loadStudy;
190
191     for (int i = 1; i < qApp->argc(); i++) {
192       QRegExp rxs ("--study-hdf=(.+)");
193       if ( rxs.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxs.capturedTexts().count() > 1 ) {
194         QString file = rxs.capturedTexts()[1];
195         QFileInfo fi ( file );
196         QString extension = fi.suffix().toLower();
197         if ( extension == "hdf" && fi.exists() )
198           hdffile = fi.absoluteFilePath();
199       }
200       else {
201         QRegExp rxp ("--pyscript=\\[(.+)\\]");
202         QRegExp rxl ("--siman-study=(.+)");
203         if ( rxp.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxp.capturedTexts().count() > 1 ) {
204           // pyscript
205           QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
206           for (int k = 0; k < dictList.count(); ++k) {
207             QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
208             if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
209               for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
210                 pyfiles += rxd.capturedTexts()[m];
211               }
212             }
213           }
214         }
215 #ifdef WITH_SIMANIO
216         if ( rxl.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxl.capturedTexts().count() > 1 ) {
217           // siman
218           loadStudy = rxl.capturedTexts()[1];
219           myIsSiman = true;
220         }
221 #endif
222       }
223     }
224     // Here pyfiles elements are: "script_name": [list_of_"arg"s]
225     // For example: "/absolute/path/to/my_script.py": ["1", "2"]
226
227     LightApp_Application::start();
228     SALOME_EventFilter::Init();
229
230     if ( !hdffile.isEmpty() )       // open hdf file given as parameter
231       onOpenDoc( hdffile );
232     else if ( pyfiles.count() > 0 ) // create new study
233       onNewDoc();
234     else if (!loadStudy.isEmpty()) {// load study by name
235       if (onLoadDoc(loadStudy))
236         updateObjectBrowser(true);
237     }
238
239 #ifndef DISABLE_PYCONSOLE
240     // import/execute python scripts
241     if ( pyfiles.count() > 0 && activeStudy() ) {
242       SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
243       PyConsole_Console* pyConsole = pythonConsole();
244       if ( appStudy && pyConsole ) {
245         _PTR(Study) aStudy = appStudy->studyDS();
246         if ( !aStudy->GetProperties()->IsLocked() ) {
247           // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
248           // Path is absolute, script has .py extension
249           for (uint j = 0; j < pyfiles.count(); j++ ) {
250             // Extract scripts and their arguments, if any
251             QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
252             if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
253               QString script = rxp.capturedTexts()[1];
254               QString args = "";
255               QStringList argList = rxp.capturedTexts()[2].split(",", QString::SkipEmptyParts);
256               for (uint k = 0; k < argList.count(); k++ ) {
257                 QString arg = argList[k].trimmed();
258                 arg.remove( QRegExp("^[\"]") );
259                 arg.remove( QRegExp("[\"]$") );
260                 args += arg+",";
261               }
262               args.remove( QRegExp("[,]$") );
263               if (!args.isEmpty()) {
264                 args = "args:"+args;
265               }
266
267               script.remove( QRegExp("^python.*[\\s]+") );
268               QString cmd = script+" "+args;
269               QString command = QString( "execfile(r\"%1\")" ).arg(cmd.trimmed());
270               pyConsole->exec(command);
271             }
272           } // end for loop on pyfiles QStringList
273         }
274       }
275     }
276 #endif
277   } else {
278     LightApp_Application::start();
279     SALOME_EventFilter::Init();
280   }
281 }
282
283 /*!Create actions:*/
284 void SalomeApp_Application::createActions()
285 {
286   LightApp_Application::createActions();
287
288   SUIT_Desktop* desk = desktop();
289
290   //! Save GUI state
291   // "Save GUI State" command is moved to VISU module
292   //  createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
293   //            tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
294   //            0, desk, false, this, SLOT( onSaveGUIState() ) );
295
296   //! Dump study
297   createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
298                 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
299                 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
300
301   //! Load script
302   createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
303                 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
304                 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
305
306   //! Properties
307   createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
308                 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
309                 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
310
311   //! Catalog Generator
312   createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ),  QIcon(),
313                 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
314                 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
315
316   //! Registry Display
317   createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ),  QIcon(),
318                 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
319                 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
320
321   createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(),
322                 tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ),
323                 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
324
325   createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(),
326                 tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ),
327                 Qt::CTRL+Qt::Key_U, desk, false, this, SLOT( onUnloadDoc() ) );
328
329
330 #ifdef WITH_SIMANIO
331   if (myIsSiman) {
332     // check-in operations for SIMAN study  
333     createAction( SimanCheckInId, tr( "TOT_SIMAN_CHECK_IN" ), QIcon(),
334                 tr( "MEN_SIMAN_CHECK_IN" ), tr( "PRP_SIMAN_CHECK_IN" ),
335                 0, desk, false, this, SLOT( onCheckIn() ) );
336     createAction( SimanLocalCheckInId, tr( "TOT_SIMAN_LOCAL_CHECK_IN" ), QIcon(),
337                 tr( "MEN_SIMAN_LOCAL_CHECK_IN" ), tr( "PRP_SIMAN_LOCAL_CHECK_IN" ),
338                 0, desk, false, this, SLOT( onLocalCheckIn() ) );
339   }
340 #endif
341
342   int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
343
344   // "Save GUI State" command is renamed to "Save VISU State" and
345   // creation of menu item is moved to VISU
346   //  createMenu( SaveGUIStateId, fileMenu, 10, -1 );
347
348   createMenu( ConnectId,    fileMenu, 5 );
349   createMenu( DisconnectId, fileMenu, 5 );
350   createMenu( separator(),  fileMenu, -1, 5 );
351
352 #ifdef WITH_SIMANIO
353   if (myIsSiman) {
354     // check-in operation for SIMAN study
355     // last argument "5" locates this just after "Save As" but certain constant is bad => insert after the separator
356     createMenu( SimanCheckInId, fileMenu, 5);
357     createMenu( SimanLocalCheckInId, fileMenu, 5);
358     createMenu( separator(), fileMenu, 5 );
359   }
360 #endif
361   createMenu( DumpStudyId, fileMenu, 10, -1 );
362   createMenu( LoadScriptId, fileMenu, 10, -1 );
363   createMenu( separator(), fileMenu, -1, 10, -1 );
364   createMenu( PropertiesId, fileMenu, 10, -1 );
365   createMenu( separator(), fileMenu, -1, 10, -1 );
366
367   int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
368   createMenu( CatalogGenId, toolsMenu, 10, -1 );
369   createMenu( RegDisplayId, toolsMenu, 10, -1 );
370   createMenu( separator(), toolsMenu, -1, 15, -1 );
371
372   createExtraActions();
373
374 #ifndef DISABLE_PYCONSOLE
375 #ifndef DISABLE_SALOMEOBJECT
376   // import Python module that manages SALOME plugins
377   {
378     PyLockWrapper lck; // acquire GIL
379     PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
380     PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_PLUGINS_TOOLS").toStdString().c_str(),tr("MEN_DESK_PLUGINS").toStdString().c_str());
381     if ( !res )
382       PyErr_Print();
383   }
384   // end of SALOME plugins loading
385 #endif
386 #endif
387
388 }
389
390 /*!
391   \brief Close application.
392 */
393 void SalomeApp_Application::onExit()
394 {
395   bool killServers = false;
396   bool result = true;
397
398   if ( exitConfirmation() ) {
399     SalomeApp_ExitDlg dlg( desktop() );
400     result = dlg.exec() == QDialog::Accepted;
401     killServers = dlg.isServersShutdown();
402   }
403
404   if ( result ) {
405     if ( !killServers ) myIsCloseFromExit = true;
406     SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
407     if ( SUIT_Session::session()->applications().count() > 0 ) myIsCloseFromExit = false;
408   }
409 }
410
411 /*!SLOT. Load document.*/
412 void SalomeApp_Application::onLoadDoc()
413 {
414   QString studyName;
415
416   std::vector<std::string> List = studyMgr()->GetOpenStudies();
417
418   // rnv: According to the single-study approach on the server side
419   //      can be only one study. So if it is exists connect to them,  
420   //      overwise show warning message: "No active study on the server"
421
422   /*
423   SUIT_Session* aSession = SUIT_Session::session();
424   QList<SUIT_Application*> aAppList = aSession->applications();
425
426   QStringList unloadedStudies;
427
428   for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
429      studyName = List[ind].c_str();
430      // Add to list only unloaded studies
431      bool isAlreadyOpen = false;
432      QListIterator<SUIT_Application*> it( aAppList );
433      while ( it.hasNext() && !isAlreadyOpen ) {
434        SUIT_Application* aApp = it.next();
435        if( !aApp || !aApp->activeStudy() )
436          continue;
437        if ( aApp->activeStudy()->studyName() == studyName )
438          isAlreadyOpen = true;
439      }
440
441      if ( !isAlreadyOpen )
442        unloadedStudies << studyName;
443   }
444   studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
445   if ( studyName.isEmpty() )
446     return;
447   */
448
449   if(List.size() <= 0) {
450     SUIT_MessageBox::warning( desktop(),
451                               QObject::tr("WRN_WARNING"),
452                               QObject::tr("WRN_NO_STUDY_ON SERV") );
453     return;
454   }
455   
456   studyName = List[0].c_str();
457
458 #ifndef WIN32
459   // this code replaces marker of windows drive and path become invalid therefore
460   // defines placed there
461   studyName.replace( QRegExp(":"), "/" );
462 #endif
463
464   if ( onLoadDoc( studyName ) ) {
465     updateWindows();
466     updateViewManagers();
467     updateObjectBrowser( true );
468   }
469 }
470
471 /*!SLOT. Unload document.*/
472 void SalomeApp_Application::onUnloadDoc( bool ask )
473 {
474   if ( ask ) {
475     activeStudy()->abortAllOperations();
476     if ( activeStudy()->isModified() ) {
477       QString docName = activeStudy()->studyName().trimmed();
478       int answer = SUIT_MessageBox::question( desktop(), tr( "DISCONNECT_CAPTION" ),
479                                             tr( "DISCONNECT_DESCRIPTION" ),
480                                             tr( "DISCONNECT_SAVE" ), 
481                                             tr( "DISCONNECT_WO_SAVE" ),
482                                             tr( "APPCLOSE_CANCEL" ), 0 );
483       if ( answer == 0 ) { // save before unload
484         if ( activeStudy()->isSaved() )
485           onSaveDoc();
486         else if ( !onSaveAsDoc() )
487           return;
488       }
489       else if ( answer == 2 ) // Cancel
490         return;
491     }
492   }
493   closeActiveDoc( false );
494 }
495
496 /*!SLOT. Create new study and load script*/
497 void SalomeApp_Application::onNewWithScript()
498 {
499   QStringList filtersList;
500   filtersList.append(tr("PYTHON_FILES_FILTER"));
501   filtersList.append(tr("ALL_FILES_FILTER"));
502
503   QString anInitialPath = "";
504   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
505     anInitialPath = QDir::currentPath();
506
507   QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
508
509   if ( !aFile.isEmpty() )
510   {
511     onNewDoc();
512
513     QString command = QString("execfile(r\"%1\")").arg(aFile);
514
515 #ifndef DISABLE_PYCONSOLE
516     PyConsole_Console* pyConsole = pythonConsole();
517
518     if ( pyConsole )
519       pyConsole->exec( command );
520 #endif
521   }
522 }
523
524
525 /*!SLOT. Load document with \a aName.*/
526 bool SalomeApp_Application::onLoadDoc( const QString& aName )
527 {
528 #ifdef SINGLE_DESKTOP
529   if ( !LightApp_Application::closeDoc() )
530     return false;
531 #endif
532   bool res = true;
533   if ( !activeStudy() ) {
534     // if no study - load in current desktop
535     res = useStudy( aName );
536   }
537   else {
538     // if study exists - load in new desktop. Check: is the same file is loaded?
539     SUIT_Session* aSession = SUIT_Session::session();
540     QList<SUIT_Application*> aAppList = aSession->applications();
541     bool isAlreadyOpen = false;
542     SalomeApp_Application* aApp = 0;
543     for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
544           it != aAppList.end() && !isAlreadyOpen; ++it ) {
545       aApp = dynamic_cast<SalomeApp_Application*>( *it );
546       if ( aApp && aApp->activeStudy()->studyName() == aName )
547         isAlreadyOpen = true;
548     }
549     if ( !isAlreadyOpen ) {
550       aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
551       if ( aApp )
552         res = aApp->useStudy( aName );
553     }
554     else {
555       aApp->desktop()->activateWindow();
556     }
557   }
558
559   return res;
560 }
561
562 /*!SLOT. Parse message for desktop.*/
563 void SalomeApp_Application::onDesktopMessage( const QString& message )
564 {
565   if (message.indexOf("simanCheckoutDone ") == 0) {
566 #ifdef WITH_SIMANIO
567     // Load document with a name, specified in aMessage.
568     onLoadDoc(message.section(' ', 1));
569 #else
570     printf( "****************************************************************\n" );
571     printf( "*    Warning: SALOME is built without SIMAN support.\n" );
572     printf( "****************************************************************\n" );
573 #endif
574   }
575   else if (message.indexOf("studyCreated:") == 0) {
576     // Enable 'Connect' action
577     updateCommandsStatus();
578   }
579   else if (message.indexOf("studyClosed:") == 0) {
580     /* message also contains ID of the closed study,
581        but as soon as SALOME is mono-study application for the moment,
582        this ID is not needed now.*/
583     //long aStudyId = message.section(':', 1).toLong();
584     // Disconnect GUI from active study, because it was closed on DS side.
585     closeActiveDoc( false );
586     // Disable 'Connect' action
587     QAction* a = action( ConnectId );
588     if ( a )
589       a->setEnabled( false );
590   }
591   else if ( message.toLower() == "connect_to_study" ) {
592     onLoadDoc();
593   }
594   LightApp_Application::onDesktopMessage( message );
595 }
596
597 /*!SLOT. Copy objects to study maneger from selection maneger..*/
598 void SalomeApp_Application::onCopy()
599 {
600   SALOME_ListIO list;
601   LightApp_SelectionMgr* mgr = selectionMgr();
602   mgr->selectedObjects(list);
603
604   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
605   if(study == NULL) return;
606
607   _PTR(Study) stdDS = study->studyDS();
608   if(!stdDS) return;
609
610   SALOME_ListIteratorOfListIO it( list );
611   if(it.More())
612     {
613       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
614       try {
615         studyMgr()->Copy(so);
616         onSelectionChanged();
617       }
618       catch(...) {
619       }
620     }
621 }
622
623 /*!SLOT. Paste objects to study maneger from selection manager.*/
624 void SalomeApp_Application::onPaste()
625 {
626   SALOME_ListIO list;
627   LightApp_SelectionMgr* mgr = selectionMgr();
628   mgr->selectedObjects(list);
629
630   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
631   if(study == NULL) return;
632
633   _PTR(Study) stdDS = study->studyDS();
634   if(!stdDS) return;
635
636   if ( stdDS->GetProperties()->IsLocked() ) {
637     SUIT_MessageBox::warning( desktop(),
638                               QObject::tr("WRN_WARNING"),
639                               QObject::tr("WRN_STUDY_LOCKED") );
640     return;
641   }
642
643   SALOME_ListIteratorOfListIO it( list );
644   if(it.More())
645     {
646       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
647       try {
648         studyMgr()->Paste(so);
649         updateObjectBrowser( true );
650         updateActions(); //SRN: BugID IPAL9377, case 3
651       }
652       catch(...) {
653       }
654     }
655 }
656
657 /*!Check the application on closing.
658  * \retval true if possible, else false
659  */
660 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
661 {
662   return LightApp_Application::isPossibleToClose( closePermanently );
663 }
664
665 /*! Check if the study is locked */
666 void SalomeApp_Application::onCloseDoc( bool ask )
667 {
668   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
669
670   if (study != NULL) {
671     _PTR(Study) stdDS = study->studyDS();
672     if(stdDS && stdDS->IsStudyLocked()) {
673       if ( SUIT_MessageBox::question( desktop(),
674                                       QObject::tr( "WRN_WARNING" ),
675                                       QObject::tr( "CLOSE_LOCKED_STUDY" ),
676                                       SUIT_MessageBox::Yes | SUIT_MessageBox::No,
677                                       SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
678
679     }
680   }
681   LightApp_Application::onCloseDoc( ask );
682 }
683
684 /*!Sets enable or disable some actions on selection changed.*/
685 void SalomeApp_Application::onSelectionChanged()
686 {
687    SALOME_ListIO list;
688    LightApp_SelectionMgr* mgr = selectionMgr();
689    mgr->selectedObjects(list);
690
691    bool canCopy  = false;
692    bool canPaste = false;
693
694    LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
695
696    if ( m ) {
697      canCopy  = m->canCopy();
698      canPaste = m->canPaste();
699    }
700
701    SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
702    if (study) {
703      _PTR(Study) stdDS = study->studyDS();
704
705      if (stdDS) {
706        SALOME_ListIteratorOfListIO it ( list );
707
708        if (it.More() && list.Extent() == 1) {
709          _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
710
711          if ( so ) {
712            canCopy  = canCopy  || studyMgr()->CanCopy(so);
713            canPaste = canPaste || studyMgr()->CanPaste(so);
714          }
715        }
716      }
717    }
718
719    action(EditCopyId)->setEnabled(canCopy);
720    action(EditPasteId)->setEnabled(canPaste);
721 }
722
723 /*!Delete references.*/
724 void SalomeApp_Application::onDeleteInvalidReferences()
725 {
726   SALOME_ListIO aList;
727   LightApp_SelectionMgr* mgr = selectionMgr();
728   mgr->selectedObjects( aList, QString(), false );
729
730   if( aList.IsEmpty() )
731     return;
732
733   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
734   _PTR(Study) aStudyDS = aStudy->studyDS();
735   _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
736   _PTR(SObject) anObj;
737
738   for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
739     if ( it.Value()->hasEntry() )
740     {
741       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
742       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
743         aRefObj = anObj;
744
745       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
746          aStudyBuilder->RemoveReference( aSObject );
747     }
748   updateObjectBrowser();
749 }
750
751 /*!Private SLOT. */
752 void SalomeApp_Application::onOpenWith()
753 {
754   QApplication::setOverrideCursor( Qt::WaitCursor );
755   SALOME_ListIO aList;
756   LightApp_SelectionMgr* mgr = selectionMgr();
757   mgr->selectedObjects(aList);
758   if (aList.Extent() != 1)
759     {
760       QApplication::restoreOverrideCursor();
761       return;
762     }
763   Handle(SALOME_InteractiveObject) aIObj = aList.First();
764   QString aModuleName(aIObj->getComponentDataType());
765   QString aModuleTitle = moduleTitle(aModuleName);
766   activateModule(aModuleTitle);
767   QApplication::restoreOverrideCursor();
768 }
769
770 /*!
771   Creates new study
772 */
773 SUIT_Study* SalomeApp_Application::createNewStudy()
774 {
775   SalomeApp_Study* aStudy = new SalomeApp_Study( this );
776
777   // Set up processing of major study-related events
778   connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
779   connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
780   connect( aStudy, SIGNAL( saved  ( SUIT_Study* ) ), this, SLOT( onStudySaved  ( SUIT_Study* ) ) );
781   connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
782
783 #ifndef DISABLE_PYCONSOLE
784   //to receive signal in application that NoteBook's variable was modified
785   connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
786            this, SIGNAL(notebookVarUpdated(QString)) );
787 #endif
788
789   return aStudy;
790 }
791
792 /*!
793   Enable/Disable menu items and toolbar buttons. Rebuild menu
794 */
795 void SalomeApp_Application::updateCommandsStatus()
796 {
797   LightApp_Application::updateCommandsStatus();
798
799   // Dump study menu
800   QAction* a = action( DumpStudyId );
801   if ( a )
802     a->setEnabled( activeStudy() );
803
804   // Load script menu
805   a = action( LoadScriptId );
806   if( a )
807     a->setEnabled( pythonConsole() );
808
809   // Properties menu
810   a = action( PropertiesId );
811   if( a )
812     a->setEnabled( activeStudy() );
813
814   // Save GUI state menu
815   a = action( SaveGUIStateId );
816   if( a )
817     a->setEnabled( activeStudy() );
818
819   // Connect study menu
820   a = action( ConnectId );
821   if( a )
822     a->setEnabled( !activeStudy() && studyMgr()->GetOpenStudies().size() > 0 );
823
824   // Disconnect study menu
825   a = action( DisconnectId );
826   if( a )
827     a->setEnabled( activeStudy() );
828
829   // update state of Copy/Paste menu items
830   onSelectionChanged();
831 }
832
833 /*!
834   \class DumpStudyFileDlg
835   Private class used in Dump Study operation.  Consists 2 check boxes:
836   "Publish in study" and "Save GUI parameters"
837 */
838 class DumpStudyFileDlg : public SUIT_FileDlg
839 {
840 public:
841   DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
842   {
843     QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
844     if ( grid )
845     {
846       QWidget *hB = new QWidget( this );
847       myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
848       myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
849       mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
850
851       QHBoxLayout *layout = new QHBoxLayout;
852       layout->addWidget(myPublishChk);
853       layout->addWidget(myMultiFileChk);
854       layout->addWidget(mySaveGUIChk);
855       hB->setLayout(layout);
856
857       QPushButton* pb = new QPushButton(this);
858
859       int row = grid->rowCount();
860       grid->addWidget( new QLabel("", this), row, 0 );
861       grid->addWidget( hB, row, 1, 1, 3 );
862       grid->addWidget( pb, row, 5 );
863
864       pb->hide();
865     }
866   }
867   QCheckBox* myPublishChk;
868   QCheckBox* myMultiFileChk;
869   QCheckBox* mySaveGUIChk;
870 };
871
872 class DumpStudyFileValidator : public SUIT_FileValidator
873 {
874  public:
875   DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
876   virtual ~DumpStudyFileValidator() {};
877   virtual bool canSave( const QString& file, bool permissions );
878 };
879
880 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
881 {
882   QFileInfo fi( file );
883   if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
884     SUIT_MessageBox::critical( parent(),
885                                QObject::tr("WRN_WARNING"),
886                                QObject::tr("WRN_FILE_NAME_BAD") );
887     return false;
888   }
889   return SUIT_FileValidator::canSave( file, permissions);
890 }
891
892 /*!Private SLOT. On dump study.*/
893 void SalomeApp_Application::onDumpStudy( )
894 {
895   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
896   if ( !appStudy ) return;
897   _PTR(Study) aStudy = appStudy->studyDS();
898
899   QStringList aFilters;
900   aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
901
902   bool anIsPublish = true;
903   bool anIsMultiFile = false;
904   bool anIsSaveGUI = true;
905
906   if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
907     anIsPublish   = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
908     anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
909     anIsSaveGUI   = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
910   }
911
912   DumpStudyFileDlg fd( desktop() );
913   fd.setValidator( new DumpStudyFileValidator( &fd ) );
914   fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
915   fd.setFilters( aFilters );
916   fd.myPublishChk->setChecked( anIsPublish );
917   fd.myMultiFileChk->setChecked( anIsMultiFile );
918   fd.mySaveGUIChk->setChecked( anIsSaveGUI );
919   if ( fd.exec() == QDialog::Accepted )
920   {
921     QString aFileName = fd.selectedFile();
922
923     bool toPublish = fd.myPublishChk->isChecked();
924     bool isMultiFile = fd.myMultiFileChk->isChecked();
925     bool toSaveGUI = fd.mySaveGUIChk->isChecked();
926
927     if ( !aFileName.isEmpty() ) {
928       QFileInfo aFileInfo(aFileName);
929       if( aFileInfo.isDir() ) // IPAL19257
930         return;
931
932       // Issue 21377 - dump study implementation moved to SalomeApp_Study class
933       bool res;
934       {
935         SUIT_OverrideCursor wc;
936         res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
937       }
938       if ( !res )
939         SUIT_MessageBox::warning( desktop(),
940                                   QObject::tr("WRN_WARNING"),
941                                   tr("WRN_DUMP_STUDY_FAILED") );
942     }
943   }
944 }
945
946 /*!Private SLOT. On load script.*/
947 void SalomeApp_Application::onLoadScript( )
948 {
949   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
950   if ( appStudy ) {
951     _PTR(Study) aStudy = appStudy->studyDS();
952     if ( aStudy->GetProperties()->IsLocked() ) {
953       SUIT_MessageBox::warning( desktop(),
954                                 QObject::tr("WRN_WARNING"),
955                                 QObject::tr("WRN_STUDY_LOCKED") );
956       return;
957     }
958   }
959
960   QStringList filtersList;
961   filtersList.append(tr("PYTHON_FILES_FILTER"));
962   filtersList.append(tr("ALL_FILES_FILTER"));
963
964   QString anInitialPath = "";
965   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
966     anInitialPath = QDir::currentPath();
967   
968 #ifdef WITH_SIMANIO
969   // MPV: if it is SIMAN study, make the initial path as the path to the Siman scripts storage
970   if (myIsSiman) {
971     SALOMEDSClient_StudyManager* aMgr = studyMgr();
972     aMgr->GetSimanStudy()->StudyId();
973     anInitialPath = QString(QDir::separator()) + "tmp" + QDir::separator() + "SimanSalome" + QDir::separator() + 
974       aMgr->GetSimanStudy()->StudyId().c_str() + QDir::separator() +
975       aMgr->GetSimanStudy()->ScenarioId().c_str() + QDir::separator() + aMgr->GetSimanStudy()->UserId().c_str();
976   }
977 #endif
978
979   QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
980
981   if ( !aFile.isEmpty() )
982   {
983     QString command = QString("execfile(r\"%1\")").arg(aFile);
984
985 #ifndef DISABLE_PYCONSOLE
986     PyConsole_Console* pyConsole = pythonConsole();
987
988     if ( pyConsole )
989       pyConsole->exec( command );
990 #endif
991   }
992 }
993
994 /*!Private SLOT. On save GUI state.*/
995 void SalomeApp_Application::onSaveGUIState()
996 {
997   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
998   if ( study ) {
999     SalomeApp_VisualState( this ).storeState();
1000     updateSavePointDataObjects( study );
1001     updateObjectBrowser();
1002   }
1003   updateActions();
1004 }
1005
1006 /*!Public SLOT. On SIMAN check in operation.*/
1007 void SalomeApp_Application::onCheckIn()
1008 {
1009 #ifdef WITH_SIMANIO
1010   setMenuShown(SimanCheckInId, false); // check in may be performed only once
1011   setMenuShown(SimanLocalCheckInId, false);
1012   SALOMEDSClient_StudyManager* aMgr = studyMgr();
1013   aMgr->GetSimanStudy()->CheckIn("");
1014 #else
1015   printf( "****************************************************************\n" );
1016   printf( "*    Warning: SALOME is built without SIMAN support.\n" );
1017   printf( "****************************************************************\n" );
1018 #endif
1019 }
1020
1021 /*!Public SLOT. On SIMAN local check in operation.*/
1022 void SalomeApp_Application::onLocalCheckIn()
1023 {
1024 #ifdef WITH_SIMANIO
1025   // get the active module
1026   CAM_Module* aModule = activeModule();
1027   if (!aModule) return; // there is no active module
1028   
1029   setMenuShown(SimanCheckInId, false); // check in may be performed only once
1030   setMenuShown(SimanLocalCheckInId, false);
1031   SALOMEDSClient_StudyManager* aMgr = studyMgr();
1032   aMgr->GetSimanStudy()->CheckIn(aModule->name().toLatin1().data());
1033 #else
1034   printf( "****************************************************************\n" );
1035   printf( "*    Warning: SALOME is built without SIMAN support.\n" );
1036   printf( "****************************************************************\n" );
1037 #endif
1038 }
1039
1040 /*!Gets file filter.
1041  *\retval QString "(*.hdf)"
1042  */
1043 QString SalomeApp_Application::getFileFilter() const
1044 {
1045   return "(*.hdf)";
1046 }
1047
1048 /*!Create window.*/
1049 QWidget* SalomeApp_Application::createWindow( const int flag )
1050 {
1051   QWidget* wid = 0;
1052 #ifndef DISABLE_PYCONSOLE
1053   if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1054 #else
1055   wid = LightApp_Application::createWindow(flag);
1056 #endif
1057
1058   SUIT_ResourceMgr* resMgr = resourceMgr();
1059
1060   if ( flag == WT_ObjectBrowser )
1061   {
1062     SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1063     if ( ob ) {
1064       // temporary commented
1065       //ob->setUpdater( new SalomeApp_Updater() );
1066
1067 #ifdef WITH_SALOMEDS_OBSERVER
1068       //do not activate the automatic update of Qt tree through signal/slot
1069       ob->setAutoUpdate(false);
1070       //activate update of modified objects only
1071       ob->setUpdateModified(true);
1072 #endif
1073
1074       connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1075
1076       QString
1077         ValueCol = QObject::tr( "VALUE_COLUMN" ),
1078         IORCol = QObject::tr( "IOR_COLUMN" ),
1079         RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1080         EntryCol = QObject::tr( "ENTRY_COLUMN" );
1081
1082       SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1083       treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1084       treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1085       treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1086       treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1087       treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1088       treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1089       treeModel->setAppropriate( IORCol, Qtx::Toggled );
1090       treeModel->setAppropriate( RefCol, Qtx::Toggled );
1091
1092       bool autoSize      = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1093       bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1094       bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1095
1096       ob->setAutoSizeFirstColumn(autoSizeFirst);
1097       ob->setAutoSizeColumns(autoSize);
1098       ob->setResizeOnExpandItem(resizeOnExpandItem);
1099       ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1100
1101       // temporary commented
1102       /*
1103       for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1104       {
1105       ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1106       ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1107                                                     QString().sprintf( "visibility_column_%d", i ), true ) );
1108       }
1109       */
1110
1111       // temporary commented
1112       /*
1113         ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1114         ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1115         ob->resize( desktop()->width()/3, ob->height() );
1116       */
1117     }
1118   }
1119 #ifndef DISABLE_PYCONSOLE
1120   else if ( flag == WT_PyConsole )
1121   {
1122     PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), getPyInterp() );
1123     pyCons->setObjectName( "pythonConsole" );
1124     pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1125     pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1126     pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1127     pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1128     wid = pyCons;
1129     //pyCons->resize( pyCons->width(), desktop()->height()/4 );
1130     pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
1131   }
1132   else if ( flag == WT_NoteBook )
1133   {
1134     SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1135     if ( appStudy ) {
1136       _PTR(Study) aStudy = appStudy->studyDS();
1137       setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1138       //to receive signal in NoteBook that it's variable was modified
1139       connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1140                getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1141     }
1142     wid = getNoteBook();
1143     wid->setObjectName( "noteBook" );
1144   }
1145 #endif
1146   return wid;
1147 }
1148
1149 /*!Create preferences.*/
1150 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1151 {
1152   LightApp_Application::createPreferences(pref);
1153
1154   if ( !pref )
1155     return;
1156
1157   int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1158   int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1159   int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1160   for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1161   {
1162     pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1163                          LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1164   }
1165   pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1166
1167   // adding preference to LightApp_Application handled preferences..  a bit of hacking with resources..
1168   int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1169   int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1170   pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1171   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1172   pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1173   pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1174   pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1175   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1176   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1177 }
1178
1179 /*!Update desktop title.*/
1180 void SalomeApp_Application::updateDesktopTitle() {
1181   QString aTitle = applicationName();
1182   QString aVer = applicationVersion();
1183   if ( !aVer.isEmpty() )
1184     aTitle += QString( " " ) + aVer;
1185
1186   if ( activeStudy() )
1187   {
1188     QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1189     if ( !sName.isEmpty() ) {
1190       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1191       if ( study ) {
1192         _PTR(Study) stdDS = study->studyDS();
1193         if(stdDS) {
1194           if ( stdDS->GetProperties()->IsLocked() ) {
1195             aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1196           } else {
1197             aTitle += QString( " - [%1]" ).arg( sName );
1198           }
1199         }
1200       }
1201     }
1202   }
1203
1204   desktop()->setWindowTitle( aTitle );
1205 }
1206
1207 int SalomeApp_Application::closeChoice( const QString& docName )
1208 {
1209   QStringList buttons;
1210   QMap<int, int> choices;
1211   int idx = 0;
1212   buttons << tr ("APPCLOSE_SAVE");                // Save & Close
1213   choices.insert( idx++, CloseSave );             // ...
1214   buttons << tr ("APPCLOSE_CLOSE");               // Close w/o saving
1215   choices.insert( idx++, CloseDiscard );          // ...
1216   if ( myIsCloseFromExit ) {
1217     buttons << tr ("APPCLOSE_UNLOAD_SAVE");       // Save & Disconnect
1218     choices.insert( idx++, CloseDisconnectSave );     // ...
1219     buttons << tr ("APPCLOSE_UNLOAD");            // Disconnect
1220     choices.insert( idx++, CloseDisconnect );         // ...
1221   }
1222   buttons << tr ("APPCLOSE_CANCEL");              // Cancel
1223   choices.insert( idx++, CloseCancel );           // ...
1224
1225   int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1226                                           tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1227   return choices[answer];
1228 }
1229
1230 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1231 {
1232   bool res = true;
1233   switch( choice )
1234   {
1235   case CloseSave:
1236     if ( activeStudy()->isSaved() )
1237       onSaveDoc();
1238     else if ( !onSaveAsDoc() )
1239       res = false;
1240     break;
1241   case CloseDiscard:
1242     break;
1243   case CloseDisconnectSave:
1244     if ( activeStudy()->isSaved() )
1245       onSaveDoc();
1246     else if ( !onSaveAsDoc() )
1247       res = false;
1248   case CloseDisconnect:
1249     closeActiveDoc( false );
1250     closePermanently = false;
1251     break;
1252   case CloseCancel:
1253   default:
1254     res = false;
1255   }
1256   return res;
1257 }
1258
1259 int SalomeApp_Application::openChoice( const QString& aName )
1260 {
1261   int choice = LightApp_Application::openChoice( aName );
1262
1263   if ( QFileInfo( aName ).exists() ) {
1264     if ( choice == OpenNew ) { // The document isn't already open.
1265       bool exist = false;
1266       std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1267       for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1268         if ( aName == QString( lst[i].c_str() ) )
1269           exist = true;
1270       }
1271       // The document already exists in the study manager.
1272       // Do you want to reload it?
1273       if ( exist ) {
1274         int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1275                                                 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1276         if ( answer == SUIT_MessageBox::Yes )
1277           choice = OpenRefresh;
1278         else
1279           choice = OpenCancel;
1280       }
1281     }
1282   } else { // file is not exist on disk
1283     SUIT_MessageBox::warning( desktop(),
1284                               QObject::tr("WRN_WARNING"),
1285                               QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1286     return false;
1287   }
1288
1289   return choice;
1290 }
1291
1292 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1293 {
1294   bool res = false;
1295   int choice = aChoice;
1296   switch ( choice )
1297   {
1298   case OpenRefresh:
1299     {
1300       _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1301       if ( aStudy )
1302       {
1303         studyMgr()->Close( aStudy );
1304         choice = OpenNew;
1305       }
1306     }
1307   default:
1308     res = LightApp_Application::openAction( choice, aName );
1309     break;
1310   }
1311
1312   return res;
1313 }
1314
1315 /*!
1316   \brief Get map of the operations which can be performed
1317   on the module activation.
1318
1319   The method should return the map of the kind \c {<id>:<name>}
1320   where \c <id> is an integer identifier of the operation and
1321   \c <name> is a title for the button to be added to the
1322   dialog box. After user selects the required operation by the
1323   clicking the corresponding button in the dialog box, its identifier
1324   is passed to the moduleActionSelected() method to process
1325   the made choice.
1326
1327   \return map of the operations
1328   \sa moduleActionSelected()
1329 */
1330 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1331 {
1332   QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1333
1334   opmap.insert( LoadStudyId,     tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1335
1336   opmap.insert( NewAndScriptId,  tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1337   return opmap;
1338 }
1339
1340 /*!
1341   \brief Called when the used selectes required operation chosen
1342   from "Activate module" dialog box.
1343
1344   Performs the required operation according to the user choice.
1345
1346   \param id operation identifier
1347   \sa activateModuleActions()
1348 */
1349 void SalomeApp_Application::moduleActionSelected( const int id )
1350 {
1351   switch ( id ) {
1352   case LoadStudyId:
1353     onLoadDoc();
1354     break;
1355   case NewAndScriptId:
1356     onNewWithScript();
1357     break;
1358   default:
1359     LightApp_Application::moduleActionSelected( id );
1360     break;
1361   }
1362 }
1363
1364 /*!Gets CORBA::ORB_var*/
1365 CORBA::ORB_var SalomeApp_Application::orb()
1366 {
1367   ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1368   static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1369   return _orb;
1370 }
1371
1372 /*!Create and return SALOMEDS_StudyManager.*/
1373 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1374 {
1375   static _PTR(StudyManager) _sm;
1376   if(!_sm) _sm = ClientFactory::StudyManager();
1377   return _sm.get();
1378 }
1379
1380 /*!Create and return SALOME_NamingService.*/
1381 SALOME_NamingService* SalomeApp_Application::namingService()
1382 {
1383   static SALOME_NamingService _ns(orb());
1384   return &_ns;
1385 }
1386
1387 /*!Create and return SALOME_LifeCycleCORBA.*/
1388 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1389 {
1390   static SALOME_LifeCycleCORBA _lcc( namingService() );
1391   return &_lcc;
1392 }
1393
1394 /*!Private SLOT. On preferences.*/
1395 void SalomeApp_Application::onProperties()
1396 {
1397   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1398   if( !study )
1399     return;
1400
1401   _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1402   SB->NewCommand();
1403
1404   SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1405   int res = aDlg.exec();
1406   if( res==QDialog::Accepted && aDlg.isChanged() )
1407     SB->CommitCommand();
1408   else
1409     SB->AbortCommand();
1410
1411   //study->updateCaptions();
1412   updateDesktopTitle();
1413   updateActions();
1414 }
1415
1416 /*!Insert items in popup, which necessary for current application*/
1417 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1418 {
1419   LightApp_SelectionMgr* mgr = selectionMgr();
1420   bool cacheIsOn = mgr->isSelectionCacheEnabled();
1421   mgr->setSelectionCacheEnabled( true );
1422
1423   LightApp_Application::contextMenuPopup( type, thePopup, title );
1424
1425   // temporary commented
1426   /*OB_Browser* ob = objectBrowser();
1427   if ( !ob || type != ob->popupClientType() )
1428     return;*/
1429
1430   // Get selected objects
1431   SALOME_ListIO aList;
1432   mgr->selectedObjects( aList, QString(), false );
1433
1434   // add GUI state commands: restore, rename
1435   if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1436        QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1437     thePopup->addSeparator();
1438     thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1439     thePopup->addAction( tr( "MEN_RENAME_VS" ),  objectBrowser(),
1440                          SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1441     thePopup->addAction( tr( "MEN_DELETE_VS" ),  this, SLOT( onDeleteGUIState() ) );
1442   }
1443
1444   // "Delete reference" item should appear only for invalid references
1445
1446   // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1447   bool isInvalidRefs = false;
1448   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1449   if ( aStudy ) {
1450     _PTR(Study) aStudyDS = aStudy->studyDS();
1451     _PTR(SObject) anObj;
1452     
1453     for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1454     {
1455       if( it.Value()->hasEntry() )
1456       {
1457         _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1458         while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1459           aRefObj = anObj;
1460         
1461         if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1462           isInvalidRefs = true;
1463       }
1464     }
1465     
1466     // Add "Delete reference" item to popup
1467     if ( isInvalidRefs )
1468     {
1469       thePopup->addSeparator();
1470       thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1471       return;
1472     }
1473
1474     // "Activate module" item should appear only if it's necessary
1475     if ( aList.Extent() == 1 ) {
1476       aList.Clear();
1477       mgr->selectedObjects( aList );
1478       
1479       Handle(SALOME_InteractiveObject) aIObj = aList.First();
1480       
1481       // add extra popup menu (defined in XML)
1482       if ( myExtActions.size() > 0 ) {
1483         // Use only first selected object
1484         SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1485         if ( study ) {
1486           _PTR(Study) stdDS = study->studyDS();
1487           if ( stdDS ) {
1488             _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1489             if ( aSO ) {
1490               _PTR( GenericAttribute ) anAttr;
1491               std::string auid = "AttributeUserID";
1492               auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1493               if ( aSO->FindAttribute( anAttr, auid ) ) {
1494                 _PTR(AttributeUserID) aAttrID = anAttr;
1495                 QString aId = aAttrID->Value().c_str();
1496                 if ( myExtActions.contains( aId ) ) {
1497                   thePopup->addAction(myExtActions[aId]);
1498                 }
1499               }
1500             }
1501           }
1502         }
1503       }
1504       
1505       // check if item is a "GUI state" item (also a first level object)
1506       QString entry( aIObj->getEntry() );
1507       if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1508         QString aModuleName( aIObj->getComponentDataType() );
1509         QString aModuleTitle = moduleTitle( aModuleName );
1510         CAM_Module* currentModule = activeModule();
1511         if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1512           thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1513       }
1514     }
1515   }
1516
1517   mgr->setSelectionCacheEnabled( cacheIsOn );
1518 }
1519
1520 /*!Update obect browser:
1521  1.if 'updateModels' true, update existing data models;
1522  2. update "non-existing" (not loaded yet) data models;
1523  3. update object browser if it exists */
1524 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1525 {
1526   // update "non-existing" (not loaded yet) data models
1527   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1528   if ( study )
1529   {
1530     _PTR(Study) stdDS = study->studyDS();
1531     if( stdDS )
1532     {
1533       for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1534       {
1535         _PTR(SComponent) aComponent ( it->Value() );
1536
1537 #ifndef WITH_SALOMEDS_OBSERVER
1538         // with GUI observers this check is not needed anymore
1539         if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1540           continue; // skip the magic "Interface Applicative" component
1541 #endif
1542         if ( !objectBrowser() )
1543           getWindow( WT_ObjectBrowser );
1544         const bool isAutoUpdate = objectBrowser()->autoUpdate();
1545         objectBrowser()->setAutoUpdate( false );
1546         SalomeApp_DataModel::synchronize( aComponent, study );
1547         objectBrowser()->setAutoUpdate( isAutoUpdate );
1548       }
1549     }
1550   }
1551
1552   // create data objects that correspond to GUI state save points
1553   if ( study ) updateSavePointDataObjects( study );
1554
1555   // update existing data models (already loaded SComponents)
1556   LightApp_Application::updateObjectBrowser( updateModels );
1557 }
1558
1559 /*!Display Catalog Genenerator dialog */
1560 void SalomeApp_Application::onCatalogGen()
1561 {
1562   ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1563   aDlg.exec();
1564 }
1565
1566 /*!Display Registry Display dialog */
1567 void SalomeApp_Application::onRegDisplay()
1568 {
1569   CORBA::ORB_var anOrb = orb();
1570   ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1571   regWnd->show();
1572   regWnd->raise();
1573   regWnd->activateWindow();
1574 }
1575
1576 /*!find original object by double click on item */
1577 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1578 {
1579   // Issue 21379: References are supported at LightApp_DataObject level
1580   LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1581
1582   if( obj && obj->isReference() )
1583   {
1584     QString entry = obj->refEntry();
1585
1586     SUIT_DataOwnerPtrList aList;
1587     aList.append( new LightApp_DataOwner( entry ) );
1588     selectionMgr()->setSelected( aList, false );
1589
1590     SUIT_DataBrowser* ob = objectBrowser();
1591
1592     QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1593     if ( !aSelectedIndexes.isEmpty() )
1594       ob->treeView()->scrollTo( aSelectedIndexes.first() );
1595   }
1596 }
1597
1598 /*!
1599   Creates new view manager
1600   \param type - type of view manager
1601 */
1602 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1603 {
1604   return createViewManager(type);
1605 }
1606
1607
1608 /*!Global utility function, returns selected GUI Save point object's ID */
1609 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1610 {
1611   SALOME_ListIO aList;
1612   selMgr->selectedObjects( aList );
1613   if( aList.Extent() > 0 ) {
1614     Handle(SALOME_InteractiveObject) aIObj = aList.First();
1615     QString entry( aIObj->getEntry() );
1616     QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1617     if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1618       return -1;
1619     bool ok; // conversion to integer is ok?
1620     int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1621     return ok ? savePoint : -1;
1622   }
1623   return -1;
1624 }
1625
1626 /*!Called on Restore GUI State popup command*/
1627 void SalomeApp_Application::onRestoreGUIState()
1628 {
1629   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1630   if ( savePoint == -1 )
1631     return;
1632   SalomeApp_VisualState( this ).restoreState( savePoint );
1633 }
1634
1635 /*!Called on Delete GUI State popup command*/
1636 void SalomeApp_Application::onDeleteGUIState()
1637 {
1638   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1639   if ( savePoint == -1 )
1640     return;
1641   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1642   if ( !study )
1643     return;
1644
1645   study->removeSavePoint( savePoint );
1646   updateSavePointDataObjects( study );
1647 }
1648
1649 /*!Called on New study operation*/
1650 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1651 {
1652   LightApp_Application::onStudyCreated( study );
1653
1654 //#ifndef DISABLE_PYCONSOLE
1655 //  desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1656 //                               windowDock( getWindow( WT_ObjectBrowser ) ) );
1657 //#endif
1658
1659   loadDockWindowsState();
1660
1661   objectBrowserColumnsVisibility();
1662 }
1663
1664 /*!Called on Open study operation*/
1665 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1666 {
1667   LightApp_Application::onStudyOpened( study );
1668
1669 //#ifndef DISABLE_PYCONSOLE
1670 //  desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1671 //                               windowDock( getWindow( WT_ObjectBrowser ) ) );
1672 //#endif
1673
1674   loadDockWindowsState();
1675
1676   objectBrowserColumnsVisibility();
1677
1678   // temporary commented
1679   /*if ( objectBrowser() ) {
1680     updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1681     objectBrowser()->updateTree( study->root() );
1682   }*/
1683 }
1684
1685 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1686 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1687 {
1688
1689   SUIT_DataBrowser* ob = objectBrowser();
1690   LightApp_SelectionMgr* selMgr = selectionMgr();
1691
1692   if ( !study || !ob || !selMgr )
1693     return;
1694
1695   // find GUI states root object
1696   SUIT_DataObject* guiRootObj = 0;
1697   DataObjectList ch;
1698   study->root()->children( ch );
1699   DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1700   for ( ; it != last ; ++it ) {
1701     if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1702       guiRootObj = *it;
1703       break;
1704     }
1705   }
1706   std::vector<int> savePoints = study->getSavePoints();
1707   // case 1: no more save points but they existed in study's tree
1708   if ( savePoints.empty() && guiRootObj ) {
1709     //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1710     //    : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1711     const bool isAutoUpdate = ob->autoUpdate();
1712     selMgr->clearSelected();
1713     ob->setAutoUpdate(true);
1714     DataObjectList ch = guiRootObj->children();
1715     for( int i = 0; i < ch.size(); i++ )
1716       delete ch[i];
1717     delete guiRootObj;
1718     ob->setAutoUpdate(isAutoUpdate);
1719     return;
1720   }
1721   // case 2: no more save points but root does not exist either
1722   if ( savePoints.empty() && !guiRootObj )
1723     return;
1724   // case 3: save points but no root for them - create it
1725   if ( !savePoints.empty() && !guiRootObj )
1726     guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1727   // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1728   // to be always the last one in the tree.  Here we check - if it is not the last one - remove and
1729   // re-create it.
1730   if ( guiRootObj->nextBrother() ) {
1731     study->root()->removeChild(guiRootObj);
1732     study->root()->appendChild(guiRootObj);
1733     //study->root()->dump();
1734   }
1735
1736   // store data objects in a map id-to-DataObject
1737   QMap<int,SalomeApp_SavePointObject*> mapDO;
1738   ch.clear();
1739   guiRootObj->children( ch );
1740   for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1741     SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1742     if ( dobj )
1743       mapDO[dobj->getId()] = dobj;
1744   }
1745
1746   // iterate new save points.  if DataObject with such ID not found in map - create DataObject
1747   // if in the map - remove it from map.
1748   for ( int i = 0; i < savePoints.size(); i++ )
1749     if ( !mapDO.contains( savePoints[i] ) )
1750       new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1751     else
1752       mapDO.remove( savePoints[i] );
1753
1754   // delete DataObjects that are still in the map -- their IDs were not found in data model
1755   if( mapDO.size() > 0) {
1756     //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1757     //    : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1758     selMgr->clearSelected();
1759     const bool isAutoUpdate = ob->autoUpdate();
1760     ob->setAutoUpdate(true);
1761     for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1762       delete it.value();
1763     ob->setAutoUpdate(isAutoUpdate);
1764   }
1765 }
1766
1767 /*! Check data object */
1768 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1769 {
1770   if (theObj)
1771     return true;
1772
1773   return false;
1774 }
1775
1776 /*!
1777   Opens other study into active Study. If Study is empty - creates it.
1778   \param theName - name of study
1779 */
1780 bool SalomeApp_Application::useStudy( const QString& theName )
1781 {
1782   createEmptyStudy();
1783   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1784   bool res = false;
1785   if (aStudy)
1786     res = aStudy->loadDocument( theName );
1787   updateDesktopTitle();
1788   updateCommandsStatus();
1789   return res;
1790 }
1791
1792 /*! Show/hide object browser colums according to preferences */
1793 void SalomeApp_Application::objectBrowserColumnsVisibility()
1794 {
1795   if ( objectBrowser() )
1796     for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1797     {
1798       bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1799       objectBrowser()->treeView()->setColumnHidden( i, !shown );
1800     }
1801 }
1802
1803 #ifndef DISABLE_PYCONSOLE
1804 /*! Set SalomeApp_NoteBook pointer */
1805 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1806 {
1807   myNoteBook = theNoteBook;
1808 }
1809
1810 /*! Return SalomeApp_NoteBook pointer */
1811 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1812 {
1813   return myNoteBook;
1814 }
1815 #endif
1816
1817 /*!
1818  * Define extra actions defined in module definition XML file.
1819  * Additional popup items sections can be defined by parameter "popupitems".
1820  * Supported attributes:
1821  * title - title of menu item,
1822  * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1823  * method - method which has to be called when menu item is selected
1824  * Example:
1825  * <section name="MODULENAME">
1826  *   <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1827  * </section>
1828  * <section name="importmed">
1829  *   <parameter name="title" value="My menu"/>
1830  *   <parameter name="objectid" value="VISU.Result"/>
1831  *   <parameter name="method" value="nameOfModuleMethod"/>
1832  * </section>
1833  */
1834 void SalomeApp_Application::createExtraActions()
1835 {
1836   myExtActions.clear();
1837   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1838
1839   QStringList aModules;
1840   modules(aModules, false);
1841   foreach(QString aModile, aModules) {
1842     QString aModName = moduleName(aModile);
1843     QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1844     if (!aSectionStr.isNull()) {
1845       QStringList aSections = aSectionStr.split(':');
1846       foreach(QString aSection, aSections) {
1847         QString aTitle = resMgr->stringValue(aSection, "title",    QString());
1848         QString aId    = resMgr->stringValue(aSection, "objectid", QString());
1849         QString aSlot  = resMgr->stringValue(aSection, "method",   QString());
1850         if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1851           continue;
1852
1853         QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1854         if (aModuleName.isNull())
1855           aModuleName = aModName;
1856
1857         QAction* aAction = new QAction(aTitle, this);
1858         QStringList aData;
1859         aData<<aModuleName<<aSlot;
1860         aAction->setData(aData);
1861         connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1862         myExtActions[aId] = aAction;
1863       }
1864     }
1865   }
1866 }
1867
1868 /*!
1869  * Called when extra action is selected
1870  */
1871 void SalomeApp_Application::onExtAction()
1872 {
1873   QAction* aAction = ::qobject_cast<QAction*>(sender());
1874   if (!aAction)
1875     return;
1876
1877   QVariant aData = aAction->data();
1878   QStringList aDataList = aData.value<QStringList>();
1879   if (aDataList.size() != 2)
1880     return;
1881
1882   LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1883   SALOME_ListIO aListIO;
1884   aSelectionMgr->selectedObjects(aListIO);
1885   const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1886   if (aListIO.Extent() < 1)
1887     return;
1888   if (!anIO->hasEntry())
1889     return;
1890
1891   QString aEntry(anIO->getEntry());
1892
1893   QApplication::setOverrideCursor( Qt::WaitCursor );
1894   QString aModuleTitle = moduleTitle(aDataList[0]);
1895   activateModule(aModuleTitle);
1896   QApplication::restoreOverrideCursor();
1897
1898   QCoreApplication::processEvents();
1899
1900   CAM_Module* aModule = activeModule();
1901   if (!aModule)
1902     return;
1903
1904   if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1905     printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1906 }
1907
1908 /*!
1909   Checks that an object can be renamed.
1910   \param entry entry of the object
1911   \brief Return \c true if object can be renamed
1912 */
1913 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1914 {
1915   return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1916 }
1917
1918 /*!
1919   Rename object by entry.
1920   \param entry entry of the object
1921   \param name new name of the object
1922   \brief Return \c true if rename operation finished successfully, \c false otherwise.
1923 */
1924 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1925 {
1926   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1927
1928   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1929
1930   if(!aStudy || savePoint == -1)
1931     return false;
1932
1933   if ( !name.isNull() && !name.isEmpty() ) {
1934     aStudy->setNameOfSavePoint( savePoint, name );
1935     updateSavePointDataObjects( aStudy );
1936
1937     //Mark study as modified
1938     aStudy->Modified();
1939     return true;
1940   }
1941   return false;
1942 }
1943
1944 #ifndef DISABLE_PYCONSOLE
1945 //============================================================================
1946 /*! Function : onUpdateStudy
1947  *  Purpose  : Slot to update the study.
1948  */
1949 //============================================================================
1950 void SalomeApp_Application::onUpdateStudy()
1951 {
1952   QApplication::setOverrideCursor( Qt::WaitCursor );
1953
1954   if( !updateStudy() )
1955     SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1956
1957   QApplication::restoreOverrideCursor();
1958 }
1959
1960 //============================================================================
1961 /*! Function : updateStudy
1962  *  Purpose  : Update study by dumping the study to Python script and loading it.
1963  *             It is used to apply variable modifications done in NoteBook to created objects.
1964  */
1965 //============================================================================
1966 bool SalomeApp_Application::updateStudy()
1967 {
1968   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1969   if ( !study || !myNoteBook )
1970     return false;
1971
1972   myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1973   myNoteBook->setDumpedStudyName( study->studyName() );
1974
1975   _PTR(Study) studyDS = study->studyDS();
1976
1977   // get unique temporary directory name
1978   QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1979   if( aTmpDir.isEmpty() )
1980     return false;
1981
1982   if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1983     aTmpDir.remove( aTmpDir.length() - 1, 1 );
1984
1985   // dump study to the temporary directory
1986   QString aScriptName( "notebook" );
1987   bool toPublish = true;
1988   bool isMultiFile = false;
1989   bool toSaveGUI = true;
1990
1991   int savePoint;
1992   _PTR(AttributeParameter) ap;
1993   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1994   if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1995   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1996     ip->setDumpPython(studyDS);
1997     savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1998   }
1999   bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
2000   if ( toSaveGUI )
2001     study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
2002
2003   if( ok )
2004     myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
2005   else
2006     return false;
2007
2008   QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
2009   int anIndex = aList.indexOf( this );
2010
2011   // Disconnect dialog from application desktop in case if:
2012   // 1) Application is not the first application in the session
2013   // 2) Application is the first application in session but not the only.
2014   bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
2015   if( changeDesktop ) {
2016
2017     SalomeApp_Application* app = this;
2018     if( anIndex > 0 && anIndex < aList.count() )
2019       app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
2020     else if(anIndex == 0 && aList.count() > 1)
2021       app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
2022
2023     if( !app )
2024       return false;
2025
2026     // creation a new study and restoring will be done in another application
2027     connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
2028              app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
2029   }
2030
2031   QString aDumpScript = myNoteBook->getDumpedStudyScript();
2032   QString aStudyName = myNoteBook->getDumpedStudyName();
2033   bool isStudySaved = myNoteBook->isDumpedStudySaved();
2034   // clear a study (delete all objects)
2035   onCloseDoc( false );
2036
2037   if( !changeDesktop ) {
2038     ok = onRestoreStudy( aDumpScript,
2039                          aStudyName,
2040                          isStudySaved );
2041   }
2042
2043   return ok;
2044 }
2045 #endif
2046
2047 //============================================================================
2048 /*! Function : onRestoreStudy
2049  *  Purpose  : Load the dumped study from Python script
2050  */
2051 //============================================================================
2052 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2053                                             const QString& theStudyName,
2054                                             bool theIsStudySaved )
2055 {
2056   bool ok = true;
2057
2058   // create a new study
2059   onNewDoc();
2060
2061   // get active application
2062   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2063
2064   // load study from the temporary directory
2065   QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
2066
2067 #ifndef DISABLE_PYCONSOLE
2068   PyConsole_Console* pyConsole = app->pythonConsole();
2069   if ( pyConsole )
2070     pyConsole->execAndWait( command );
2071 #endif
2072
2073   // remove temporary directory
2074   QFileInfo aScriptInfo = QFileInfo( theDumpScript );
2075   QString aStudyName = aScriptInfo.baseName();
2076   QDir aDir = aScriptInfo.absoluteDir();
2077   QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2078   for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2079     ok = aDir.remove( *it ) && ok;
2080   if( ok )
2081     ok = aDir.rmdir( aDir.absolutePath() );
2082
2083   if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2084   {
2085 #ifndef DISABLE_PYCONSOLE
2086     _PTR(Study) aStudyDS = newStudy->studyDS();
2087     app->getNoteBook()->Init( aStudyDS );
2088     newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2089     newStudy->Modified();
2090     updateDesktopTitle();
2091     updateActions();
2092 #endif
2093   }
2094   else
2095     ok = false;
2096
2097   return ok;
2098 }
2099
2100 /*!
2101   Close the Application
2102 */
2103 void SalomeApp_Application::afterCloseDoc()
2104 {
2105 #ifndef DISABLE_PYCONSOLE
2106   // emit signal to restore study from Python script
2107   if ( myNoteBook ) {
2108     emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2109                             myNoteBook->getDumpedStudyName(),
2110                             myNoteBook->isDumpedStudySaved() );
2111   }
2112 #endif
2113   LightApp_Application::afterCloseDoc();
2114 }
2115
2116 /*
2117   Asks to close existing document.
2118 */
2119 bool SalomeApp_Application::checkExistingDoc()
2120 {
2121   bool result = LightApp_Application::checkExistingDoc();
2122   if ( result && !activeStudy() ) {
2123     SALOMEDSClient_StudyManager* aMgr = studyMgr();
2124     if ( aMgr ) {
2125       std::vector<std::string> List = studyMgr()->GetOpenStudies();
2126       if( List.size() > 0 ) {
2127         SUIT_MessageBox::critical( desktop(), tr( "WRN_WARNING" ), tr( "ERR_ACTIVEDOC_LOAD" ));
2128         result = false;
2129       }
2130     }
2131   }
2132   return result;
2133 }
2134
2135
2136 #ifndef DISABLE_PYCONSOLE
2137
2138 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2139 {
2140   return new SalomeApp_PyInterp();
2141 }
2142
2143 #endif // DISABLE_PYCONSOLE