Salome HOME
INT PAL 0022812: TC6.4.0: prefernces work only for a new study
[modules/gui.git] / src / SalomeApp / SalomeApp_Application.cxx
1 // Copyright (C) 2007-2015  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_TOOLS").toUtf8().data(),tr("MEN_DESK_PLUGINS").toUtf8().data());
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 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
1041 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
1042 {
1043   LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
1044   QAction* send = (QAction*)sender();
1045   QString aWinName = send->data().toString();
1046   if ( theIsVisible && aWinName == "objectBrowser" )
1047     objectBrowserColumnsVisibility();
1048 }
1049
1050 /*!Gets file filter.
1051  *\retval QString "(*.hdf)"
1052  */
1053 QString SalomeApp_Application::getFileFilter() const
1054 {
1055   return "(*.hdf)";
1056 }
1057
1058 /*!Create window.*/
1059 QWidget* SalomeApp_Application::createWindow( const int flag )
1060 {
1061   QWidget* wid = 0;
1062 #ifndef DISABLE_PYCONSOLE
1063   if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1064 #else
1065   wid = LightApp_Application::createWindow(flag);
1066 #endif
1067
1068   SUIT_ResourceMgr* resMgr = resourceMgr();
1069
1070   if ( flag == WT_ObjectBrowser )
1071   {
1072     SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1073     if ( ob ) {
1074       // temporary commented
1075       //ob->setUpdater( new SalomeApp_Updater() );
1076
1077 #ifdef WITH_SALOMEDS_OBSERVER
1078       //do not activate the automatic update of Qt tree through signal/slot
1079       ob->setAutoUpdate(false);
1080       //activate update of modified objects only
1081       ob->setUpdateModified(true);
1082 #endif
1083
1084       connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1085
1086       QString
1087         ValueCol = QObject::tr( "VALUE_COLUMN" ),
1088         IORCol = QObject::tr( "IOR_COLUMN" ),
1089         RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1090         EntryCol = QObject::tr( "ENTRY_COLUMN" );
1091
1092       SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1093       treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1094       treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1095       treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1096       treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1097       treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1098       treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1099       treeModel->setAppropriate( IORCol, Qtx::Toggled );
1100       treeModel->setAppropriate( RefCol, Qtx::Toggled );
1101
1102       bool autoSize      = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1103       bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1104       bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1105
1106       ob->setAutoSizeFirstColumn(autoSizeFirst);
1107       ob->setAutoSizeColumns(autoSize);
1108       ob->setResizeOnExpandItem(resizeOnExpandItem);
1109       ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1110
1111       // temporary commented
1112       /*
1113       for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1114       {
1115       ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1116       ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1117                                                     QString().sprintf( "visibility_column_%d", i ), true ) );
1118       }
1119       */
1120
1121       // temporary commented
1122       /*
1123         ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1124         ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1125         ob->resize( desktop()->width()/3, ob->height() );
1126       */
1127     }
1128   }
1129 #ifndef DISABLE_PYCONSOLE
1130   else if ( flag == WT_PyConsole )
1131   {
1132     PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), getPyInterp() );
1133     pyCons->setObjectName( "pythonConsole" );
1134     pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1135     pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1136     pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1137     pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1138     wid = pyCons;
1139     //pyCons->resize( pyCons->width(), desktop()->height()/4 );
1140     pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
1141   }
1142   else if ( flag == WT_NoteBook )
1143   {
1144     SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1145     if ( appStudy ) {
1146       _PTR(Study) aStudy = appStudy->studyDS();
1147       setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1148       //to receive signal in NoteBook that it's variable was modified
1149       connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1150                getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1151     }
1152     wid = getNoteBook();
1153     wid->setObjectName( "noteBook" );
1154   }
1155 #endif
1156   return wid;
1157 }
1158
1159 /*!Create preferences.*/
1160 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1161 {
1162   LightApp_Application::createPreferences(pref);
1163
1164   if ( !pref )
1165     return;
1166
1167   int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1168   int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1169   int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1170   for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1171   {
1172     pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1173                          LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1174   }
1175   pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1176
1177   // adding preference to LightApp_Application handled preferences..  a bit of hacking with resources..
1178   int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1179   int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1180   pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1181   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1182   pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1183   pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1184   pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1185   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1186   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1187 }
1188
1189 /*!Update desktop title.*/
1190 void SalomeApp_Application::updateDesktopTitle() {
1191   QString aTitle = applicationName();
1192   QString aVer = applicationVersion();
1193   if ( !aVer.isEmpty() )
1194     aTitle += QString( " " ) + aVer;
1195
1196   if ( activeStudy() )
1197   {
1198     QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1199     if ( !sName.isEmpty() ) {
1200       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1201       if ( study ) {
1202         _PTR(Study) stdDS = study->studyDS();
1203         if(stdDS) {
1204           if ( stdDS->GetProperties()->IsLocked() ) {
1205             aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1206           } else {
1207             aTitle += QString( " - [%1]" ).arg( sName );
1208           }
1209         }
1210       }
1211     }
1212   }
1213
1214   desktop()->setWindowTitle( aTitle );
1215 }
1216
1217 int SalomeApp_Application::closeChoice( const QString& docName )
1218 {
1219   QStringList buttons;
1220   QMap<int, int> choices;
1221   int idx = 0;
1222   buttons << tr ("APPCLOSE_SAVE");                // Save & Close
1223   choices.insert( idx++, CloseSave );             // ...
1224   buttons << tr ("APPCLOSE_CLOSE");               // Close w/o saving
1225   choices.insert( idx++, CloseDiscard );          // ...
1226   if ( myIsCloseFromExit ) {
1227     buttons << tr ("APPCLOSE_UNLOAD_SAVE");       // Save & Disconnect
1228     choices.insert( idx++, CloseDisconnectSave );     // ...
1229     buttons << tr ("APPCLOSE_UNLOAD");            // Disconnect
1230     choices.insert( idx++, CloseDisconnect );         // ...
1231   }
1232   buttons << tr ("APPCLOSE_CANCEL");              // Cancel
1233   choices.insert( idx++, CloseCancel );           // ...
1234
1235   int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1236                                           tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1237   return choices[answer];
1238 }
1239
1240 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1241 {
1242   bool res = true;
1243   switch( choice )
1244   {
1245   case CloseSave:
1246     if ( activeStudy()->isSaved() )
1247       onSaveDoc();
1248     else if ( !onSaveAsDoc() )
1249       res = false;
1250     break;
1251   case CloseDiscard:
1252     break;
1253   case CloseDisconnectSave:
1254     if ( activeStudy()->isSaved() )
1255       onSaveDoc();
1256     else if ( !onSaveAsDoc() )
1257       res = false;
1258   case CloseDisconnect:
1259     closeActiveDoc( false );
1260     closePermanently = false;
1261     break;
1262   case CloseCancel:
1263   default:
1264     res = false;
1265   }
1266   return res;
1267 }
1268
1269 int SalomeApp_Application::openChoice( const QString& aName )
1270 {
1271   int choice = LightApp_Application::openChoice( aName );
1272
1273   if ( QFileInfo( aName ).exists() ) {
1274     if ( choice == OpenNew ) { // The document isn't already open.
1275       bool exist = false;
1276       std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1277       for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1278         if ( aName == QString( lst[i].c_str() ) )
1279           exist = true;
1280       }
1281       // The document already exists in the study manager.
1282       // Do you want to reload it?
1283       if ( exist ) {
1284         int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1285                                                 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1286         if ( answer == SUIT_MessageBox::Yes )
1287           choice = OpenRefresh;
1288         else
1289           choice = OpenCancel;
1290       }
1291     }
1292   } else { // file is not exist on disk
1293     SUIT_MessageBox::warning( desktop(),
1294                               QObject::tr("WRN_WARNING"),
1295                               QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1296     return false;
1297   }
1298
1299   return choice;
1300 }
1301
1302 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1303 {
1304   bool res = false;
1305   int choice = aChoice;
1306   switch ( choice )
1307   {
1308   case OpenRefresh:
1309     {
1310       _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1311       if ( aStudy )
1312       {
1313         studyMgr()->Close( aStudy );
1314         choice = OpenNew;
1315       }
1316     }
1317   default:
1318     res = LightApp_Application::openAction( choice, aName );
1319     break;
1320   }
1321
1322   return res;
1323 }
1324
1325 /*!
1326   \brief Get map of the operations which can be performed
1327   on the module activation.
1328
1329   The method should return the map of the kind \c {<id>:<name>}
1330   where \c <id> is an integer identifier of the operation and
1331   \c <name> is a title for the button to be added to the
1332   dialog box. After user selects the required operation by the
1333   clicking the corresponding button in the dialog box, its identifier
1334   is passed to the moduleActionSelected() method to process
1335   the made choice.
1336
1337   \return map of the operations
1338   \sa moduleActionSelected()
1339 */
1340 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1341 {
1342   QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1343
1344   opmap.insert( LoadStudyId,     tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1345
1346   opmap.insert( NewAndScriptId,  tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1347   return opmap;
1348 }
1349
1350 /*!
1351   \brief Called when the used selectes required operation chosen
1352   from "Activate module" dialog box.
1353
1354   Performs the required operation according to the user choice.
1355
1356   \param id operation identifier
1357   \sa activateModuleActions()
1358 */
1359 void SalomeApp_Application::moduleActionSelected( const int id )
1360 {
1361   switch ( id ) {
1362   case LoadStudyId:
1363     onLoadDoc();
1364     break;
1365   case NewAndScriptId:
1366     onNewWithScript();
1367     break;
1368   default:
1369     LightApp_Application::moduleActionSelected( id );
1370     break;
1371   }
1372 }
1373
1374 /*!Gets CORBA::ORB_var*/
1375 CORBA::ORB_var SalomeApp_Application::orb()
1376 {
1377   ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1378   static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1379   return _orb;
1380 }
1381
1382 /*!Create and return SALOMEDS_StudyManager.*/
1383 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1384 {
1385   static _PTR(StudyManager) _sm;
1386   if(!_sm) _sm = ClientFactory::StudyManager();
1387   return _sm.get();
1388 }
1389
1390 /*!Create and return SALOME_NamingService.*/
1391 SALOME_NamingService* SalomeApp_Application::namingService()
1392 {
1393   static SALOME_NamingService _ns(orb());
1394   return &_ns;
1395 }
1396
1397 /*!Create and return SALOME_LifeCycleCORBA.*/
1398 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1399 {
1400   static SALOME_LifeCycleCORBA _lcc( namingService() );
1401   return &_lcc;
1402 }
1403
1404 /*!Private SLOT. On preferences.*/
1405 void SalomeApp_Application::onProperties()
1406 {
1407   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1408   if( !study )
1409     return;
1410
1411   _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1412   SB->NewCommand();
1413
1414   SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1415   int res = aDlg.exec();
1416   if( res==QDialog::Accepted && aDlg.isChanged() )
1417     SB->CommitCommand();
1418   else
1419     SB->AbortCommand();
1420
1421   //study->updateCaptions();
1422   updateDesktopTitle();
1423   updateActions();
1424 }
1425
1426 /*!Insert items in popup, which necessary for current application*/
1427 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1428 {
1429   LightApp_SelectionMgr* mgr = selectionMgr();
1430   bool cacheIsOn = mgr->isSelectionCacheEnabled();
1431   mgr->setSelectionCacheEnabled( true );
1432
1433   LightApp_Application::contextMenuPopup( type, thePopup, title );
1434
1435   // temporary commented
1436   /*OB_Browser* ob = objectBrowser();
1437   if ( !ob || type != ob->popupClientType() )
1438     return;*/
1439
1440   // Get selected objects
1441   SALOME_ListIO aList;
1442   mgr->selectedObjects( aList, QString(), false );
1443
1444   // add GUI state commands: restore, rename
1445   if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1446        QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1447     thePopup->addSeparator();
1448     thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1449     thePopup->addAction( tr( "MEN_RENAME_VS" ),  objectBrowser(),
1450                          SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1451     thePopup->addAction( tr( "MEN_DELETE_VS" ),  this, SLOT( onDeleteGUIState() ) );
1452   }
1453
1454   // "Delete reference" item should appear only for invalid references
1455
1456   // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1457   bool isInvalidRefs = false;
1458   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1459   if ( aStudy ) {
1460     _PTR(Study) aStudyDS = aStudy->studyDS();
1461     _PTR(SObject) anObj;
1462     
1463     for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1464     {
1465       if( it.Value()->hasEntry() )
1466       {
1467         _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1468         while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1469           aRefObj = anObj;
1470         
1471         if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1472           isInvalidRefs = true;
1473       }
1474     }
1475     
1476     // Add "Delete reference" item to popup
1477     if ( isInvalidRefs )
1478     {
1479       thePopup->addSeparator();
1480       thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1481       return;
1482     }
1483
1484     // "Activate module" item should appear only if it's necessary
1485     if ( aList.Extent() == 1 ) {
1486       aList.Clear();
1487       mgr->selectedObjects( aList );
1488       
1489       Handle(SALOME_InteractiveObject) aIObj = aList.First();
1490       
1491       // add extra popup menu (defined in XML)
1492       if ( myExtActions.size() > 0 ) {
1493         // Use only first selected object
1494         SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1495         if ( study ) {
1496           _PTR(Study) stdDS = study->studyDS();
1497           if ( stdDS ) {
1498             _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1499             if ( aSO ) {
1500               _PTR( GenericAttribute ) anAttr;
1501               std::string auid = "AttributeUserID";
1502               auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1503               if ( aSO->FindAttribute( anAttr, auid ) ) {
1504                 _PTR(AttributeUserID) aAttrID = anAttr;
1505                 QString aId = aAttrID->Value().c_str();
1506                 if ( myExtActions.contains( aId ) ) {
1507                   thePopup->addAction(myExtActions[aId]);
1508                 }
1509               }
1510             }
1511           }
1512         }
1513       }
1514       
1515       // check if item is a "GUI state" item (also a first level object)
1516       QString entry( aIObj->getEntry() );
1517       if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1518         QString aModuleName( aIObj->getComponentDataType() );
1519         QString aModuleTitle = moduleTitle( aModuleName );
1520         CAM_Module* currentModule = activeModule();
1521         if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1522           thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1523       }
1524     }
1525   }
1526
1527   mgr->setSelectionCacheEnabled( cacheIsOn );
1528 }
1529
1530 /*!Update obect browser:
1531  1.if 'updateModels' true, update existing data models;
1532  2. update "non-existing" (not loaded yet) data models;
1533  3. update object browser if it exists */
1534 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1535 {
1536   // update "non-existing" (not loaded yet) data models
1537   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1538   if ( study )
1539   {
1540     _PTR(Study) stdDS = study->studyDS();
1541     if( stdDS )
1542     {
1543       for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1544       {
1545         _PTR(SComponent) aComponent ( it->Value() );
1546
1547 #ifndef WITH_SALOMEDS_OBSERVER
1548         // with GUI observers this check is not needed anymore
1549         if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1550           continue; // skip the magic "Interface Applicative" component
1551 #endif
1552         if ( !objectBrowser() )
1553           getWindow( WT_ObjectBrowser );
1554         const bool isAutoUpdate = objectBrowser()->autoUpdate();
1555         objectBrowser()->setAutoUpdate( false );
1556         SalomeApp_DataModel::synchronize( aComponent, study );
1557         objectBrowser()->setAutoUpdate( isAutoUpdate );
1558       }
1559     }
1560   }
1561
1562   // create data objects that correspond to GUI state save points
1563   if ( study ) updateSavePointDataObjects( study );
1564
1565   // update existing data models (already loaded SComponents)
1566   LightApp_Application::updateObjectBrowser( updateModels );
1567 }
1568
1569 /*!Display Catalog Genenerator dialog */
1570 void SalomeApp_Application::onCatalogGen()
1571 {
1572   ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1573   aDlg.exec();
1574 }
1575
1576 /*!Display Registry Display dialog */
1577 void SalomeApp_Application::onRegDisplay()
1578 {
1579   CORBA::ORB_var anOrb = orb();
1580   ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1581   regWnd->show();
1582   regWnd->raise();
1583   regWnd->activateWindow();
1584 }
1585
1586 /*!find original object by double click on item */
1587 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1588 {
1589   // Issue 21379: References are supported at LightApp_DataObject level
1590   LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1591
1592   if( obj && obj->isReference() )
1593   {
1594     QString entry = obj->refEntry();
1595
1596     SUIT_DataOwnerPtrList aList;
1597     aList.append( new LightApp_DataOwner( entry ) );
1598     selectionMgr()->setSelected( aList, false );
1599
1600     SUIT_DataBrowser* ob = objectBrowser();
1601
1602     QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1603     if ( !aSelectedIndexes.isEmpty() )
1604       ob->treeView()->scrollTo( aSelectedIndexes.first() );
1605   }
1606 }
1607
1608 /*!
1609   Creates new view manager
1610   \param type - type of view manager
1611 */
1612 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1613 {
1614   return createViewManager(type);
1615 }
1616
1617
1618 /*!Global utility function, returns selected GUI Save point object's ID */
1619 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1620 {
1621   SALOME_ListIO aList;
1622   selMgr->selectedObjects( aList );
1623   if( aList.Extent() > 0 ) {
1624     Handle(SALOME_InteractiveObject) aIObj = aList.First();
1625     QString entry( aIObj->getEntry() );
1626     QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1627     if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1628       return -1;
1629     bool ok; // conversion to integer is ok?
1630     int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1631     return ok ? savePoint : -1;
1632   }
1633   return -1;
1634 }
1635
1636 /*!Called on Restore GUI State popup command*/
1637 void SalomeApp_Application::onRestoreGUIState()
1638 {
1639   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1640   if ( savePoint == -1 )
1641     return;
1642   SalomeApp_VisualState( this ).restoreState( savePoint );
1643 }
1644
1645 /*!Called on Delete GUI State popup command*/
1646 void SalomeApp_Application::onDeleteGUIState()
1647 {
1648   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1649   if ( savePoint == -1 )
1650     return;
1651   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1652   if ( !study )
1653     return;
1654
1655   study->removeSavePoint( savePoint );
1656   updateSavePointDataObjects( study );
1657 }
1658
1659 /*!Called on New study operation*/
1660 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1661 {
1662   LightApp_Application::onStudyCreated( study );
1663
1664 //#ifndef DISABLE_PYCONSOLE
1665 //  desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1666 //                               windowDock( getWindow( WT_ObjectBrowser ) ) );
1667 //#endif
1668
1669   loadDockWindowsState();
1670
1671   objectBrowserColumnsVisibility();
1672 }
1673
1674 /*!Called on Open study operation*/
1675 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1676 {
1677   LightApp_Application::onStudyOpened( study );
1678
1679 //#ifndef DISABLE_PYCONSOLE
1680 //  desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1681 //                               windowDock( getWindow( WT_ObjectBrowser ) ) );
1682 //#endif
1683
1684   loadDockWindowsState();
1685
1686   objectBrowserColumnsVisibility();
1687
1688   // temporary commented
1689   /*if ( objectBrowser() ) {
1690     updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1691     objectBrowser()->updateTree( study->root() );
1692   }*/
1693 }
1694
1695 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1696 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1697 {
1698
1699   SUIT_DataBrowser* ob = objectBrowser();
1700   LightApp_SelectionMgr* selMgr = selectionMgr();
1701
1702   if ( !study || !ob || !selMgr )
1703     return;
1704
1705   // find GUI states root object
1706   SUIT_DataObject* guiRootObj = 0;
1707   DataObjectList ch;
1708   study->root()->children( ch );
1709   DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1710   for ( ; it != last ; ++it ) {
1711     if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1712       guiRootObj = *it;
1713       break;
1714     }
1715   }
1716   std::vector<int> savePoints = study->getSavePoints();
1717   // case 1: no more save points but they existed in study's tree
1718   if ( savePoints.empty() && guiRootObj ) {
1719     //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1720     //    : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1721     const bool isAutoUpdate = ob->autoUpdate();
1722     selMgr->clearSelected();
1723     ob->setAutoUpdate(true);
1724     DataObjectList ch = guiRootObj->children();
1725     for( int i = 0; i < ch.size(); i++ )
1726       delete ch[i];
1727     delete guiRootObj;
1728     ob->setAutoUpdate(isAutoUpdate);
1729     return;
1730   }
1731   // case 2: no more save points but root does not exist either
1732   if ( savePoints.empty() && !guiRootObj )
1733     return;
1734   // case 3: save points but no root for them - create it
1735   if ( !savePoints.empty() && !guiRootObj )
1736     guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1737   // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1738   // to be always the last one in the tree.  Here we check - if it is not the last one - remove and
1739   // re-create it.
1740   if ( guiRootObj->nextBrother() ) {
1741     study->root()->removeChild(guiRootObj);
1742     study->root()->appendChild(guiRootObj);
1743     //study->root()->dump();
1744   }
1745
1746   // store data objects in a map id-to-DataObject
1747   QMap<int,SalomeApp_SavePointObject*> mapDO;
1748   ch.clear();
1749   guiRootObj->children( ch );
1750   for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1751     SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1752     if ( dobj )
1753       mapDO[dobj->getId()] = dobj;
1754   }
1755
1756   // iterate new save points.  if DataObject with such ID not found in map - create DataObject
1757   // if in the map - remove it from map.
1758   for ( int i = 0; i < savePoints.size(); i++ )
1759     if ( !mapDO.contains( savePoints[i] ) )
1760       new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1761     else
1762       mapDO.remove( savePoints[i] );
1763
1764   // delete DataObjects that are still in the map -- their IDs were not found in data model
1765   if( mapDO.size() > 0) {
1766     //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1767     //    : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1768     selMgr->clearSelected();
1769     const bool isAutoUpdate = ob->autoUpdate();
1770     ob->setAutoUpdate(true);
1771     for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1772       delete it.value();
1773     ob->setAutoUpdate(isAutoUpdate);
1774   }
1775 }
1776
1777 /*! Check data object */
1778 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1779 {
1780   if (theObj)
1781     return true;
1782
1783   return false;
1784 }
1785
1786 /*!
1787   Opens other study into active Study. If Study is empty - creates it.
1788   \param theName - name of study
1789 */
1790 bool SalomeApp_Application::useStudy( const QString& theName )
1791 {
1792   createEmptyStudy();
1793   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1794   bool res = false;
1795   if (aStudy)
1796     res = aStudy->loadDocument( theName );
1797   updateDesktopTitle();
1798   updateCommandsStatus();
1799   return res;
1800 }
1801
1802 /*! Show/hide object browser colums according to preferences */
1803 void SalomeApp_Application::objectBrowserColumnsVisibility()
1804 {
1805   if ( objectBrowser() )
1806     for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1807     {
1808       bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1809       objectBrowser()->treeView()->setColumnHidden( i, !shown );
1810     }
1811 }
1812
1813 #ifndef DISABLE_PYCONSOLE
1814 /*! Set SalomeApp_NoteBook pointer */
1815 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1816 {
1817   myNoteBook = theNoteBook;
1818 }
1819
1820 /*! Return SalomeApp_NoteBook pointer */
1821 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1822 {
1823   return myNoteBook;
1824 }
1825 #endif
1826
1827 /*!
1828  * Define extra actions defined in module definition XML file.
1829  * Additional popup items sections can be defined by parameter "popupitems".
1830  * Supported attributes:
1831  * title - title of menu item,
1832  * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1833  * method - method which has to be called when menu item is selected
1834  * Example:
1835  * <section name="MODULENAME">
1836  *   <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1837  * </section>
1838  * <section name="importmed">
1839  *   <parameter name="title" value="My menu"/>
1840  *   <parameter name="objectid" value="VISU.Result"/>
1841  *   <parameter name="method" value="nameOfModuleMethod"/>
1842  * </section>
1843  */
1844 void SalomeApp_Application::createExtraActions()
1845 {
1846   myExtActions.clear();
1847   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1848
1849   QStringList aModules;
1850   modules(aModules, false);
1851   foreach(QString aModile, aModules) {
1852     QString aModName = moduleName(aModile);
1853     QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1854     if (!aSectionStr.isNull()) {
1855       QStringList aSections = aSectionStr.split(':');
1856       foreach(QString aSection, aSections) {
1857         QString aTitle = resMgr->stringValue(aSection, "title",    QString());
1858         QString aId    = resMgr->stringValue(aSection, "objectid", QString());
1859         QString aSlot  = resMgr->stringValue(aSection, "method",   QString());
1860         if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1861           continue;
1862
1863         QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1864         if (aModuleName.isNull())
1865           aModuleName = aModName;
1866
1867         QAction* aAction = new QAction(aTitle, this);
1868         QStringList aData;
1869         aData<<aModuleName<<aSlot;
1870         aAction->setData(aData);
1871         connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1872         myExtActions[aId] = aAction;
1873       }
1874     }
1875   }
1876 }
1877
1878 /*!
1879  * Called when extra action is selected
1880  */
1881 void SalomeApp_Application::onExtAction()
1882 {
1883   QAction* aAction = ::qobject_cast<QAction*>(sender());
1884   if (!aAction)
1885     return;
1886
1887   QVariant aData = aAction->data();
1888   QStringList aDataList = aData.value<QStringList>();
1889   if (aDataList.size() != 2)
1890     return;
1891
1892   LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1893   SALOME_ListIO aListIO;
1894   aSelectionMgr->selectedObjects(aListIO);
1895   const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1896   if (aListIO.Extent() < 1)
1897     return;
1898   if (!anIO->hasEntry())
1899     return;
1900
1901   QString aEntry(anIO->getEntry());
1902
1903   QApplication::setOverrideCursor( Qt::WaitCursor );
1904   QString aModuleTitle = moduleTitle(aDataList[0]);
1905   activateModule(aModuleTitle);
1906   QApplication::restoreOverrideCursor();
1907
1908   QCoreApplication::processEvents();
1909
1910   CAM_Module* aModule = activeModule();
1911   if (!aModule)
1912     return;
1913
1914   if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1915     printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1916 }
1917
1918 /*!
1919   Checks that an object can be renamed.
1920   \param entry entry of the object
1921   \brief Return \c true if object can be renamed
1922 */
1923 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1924 {
1925   return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1926 }
1927
1928 /*!
1929   Rename object by entry.
1930   \param entry entry of the object
1931   \param name new name of the object
1932   \brief Return \c true if rename operation finished successfully, \c false otherwise.
1933 */
1934 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1935 {
1936   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1937
1938   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1939
1940   if(!aStudy || savePoint == -1)
1941     return false;
1942
1943   if ( !name.isNull() && !name.isEmpty() ) {
1944     aStudy->setNameOfSavePoint( savePoint, name );
1945     updateSavePointDataObjects( aStudy );
1946
1947     //Mark study as modified
1948     aStudy->Modified();
1949     return true;
1950   }
1951   return false;
1952 }
1953
1954 #ifndef DISABLE_PYCONSOLE
1955 //============================================================================
1956 /*! Function : onUpdateStudy
1957  *  Purpose  : Slot to update the study.
1958  */
1959 //============================================================================
1960 void SalomeApp_Application::onUpdateStudy()
1961 {
1962   QApplication::setOverrideCursor( Qt::WaitCursor );
1963
1964   if( !updateStudy() )
1965     SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1966
1967   QApplication::restoreOverrideCursor();
1968 }
1969
1970 //============================================================================
1971 /*! Function : updateStudy
1972  *  Purpose  : Update study by dumping the study to Python script and loading it.
1973  *             It is used to apply variable modifications done in NoteBook to created objects.
1974  */
1975 //============================================================================
1976 bool SalomeApp_Application::updateStudy()
1977 {
1978   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1979   if ( !study || !myNoteBook )
1980     return false;
1981
1982   myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1983   myNoteBook->setDumpedStudyName( study->studyName() );
1984
1985   _PTR(Study) studyDS = study->studyDS();
1986
1987   // get unique temporary directory name
1988   QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1989   if( aTmpDir.isEmpty() )
1990     return false;
1991
1992   if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1993     aTmpDir.remove( aTmpDir.length() - 1, 1 );
1994
1995   // dump study to the temporary directory
1996   QString aScriptName( "notebook" );
1997   bool toPublish = true;
1998   bool isMultiFile = false;
1999   bool toSaveGUI = true;
2000
2001   int savePoint;
2002   _PTR(AttributeParameter) ap;
2003   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
2004   if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
2005   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
2006     ip->setDumpPython(studyDS);
2007     savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
2008   }
2009   bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
2010   if ( toSaveGUI )
2011     study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
2012
2013   if( ok )
2014     myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
2015   else
2016     return false;
2017
2018   QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
2019   int anIndex = aList.indexOf( this );
2020
2021   // Disconnect dialog from application desktop in case if:
2022   // 1) Application is not the first application in the session
2023   // 2) Application is the first application in session but not the only.
2024   bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
2025   if( changeDesktop ) {
2026
2027     SalomeApp_Application* app = this;
2028     if( anIndex > 0 && anIndex < aList.count() )
2029       app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
2030     else if(anIndex == 0 && aList.count() > 1)
2031       app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
2032
2033     if( !app )
2034       return false;
2035
2036     // creation a new study and restoring will be done in another application
2037     connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
2038              app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
2039   }
2040
2041   QString aDumpScript = myNoteBook->getDumpedStudyScript();
2042   QString aStudyName = myNoteBook->getDumpedStudyName();
2043   bool isStudySaved = myNoteBook->isDumpedStudySaved();
2044   // clear a study (delete all objects)
2045   onCloseDoc( false );
2046
2047   if( !changeDesktop ) {
2048     ok = onRestoreStudy( aDumpScript,
2049                          aStudyName,
2050                          isStudySaved );
2051   }
2052
2053   return ok;
2054 }
2055 #endif
2056
2057 //============================================================================
2058 /*! Function : onRestoreStudy
2059  *  Purpose  : Load the dumped study from Python script
2060  */
2061 //============================================================================
2062 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2063                                             const QString& theStudyName,
2064                                             bool theIsStudySaved )
2065 {
2066   bool ok = true;
2067
2068   // create a new study
2069   onNewDoc();
2070
2071   // get active application
2072   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2073
2074   // load study from the temporary directory
2075   QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
2076
2077 #ifndef DISABLE_PYCONSOLE
2078   PyConsole_Console* pyConsole = app->pythonConsole();
2079   if ( pyConsole )
2080     pyConsole->execAndWait( command );
2081 #endif
2082
2083   // remove temporary directory
2084   QFileInfo aScriptInfo = QFileInfo( theDumpScript );
2085   QString aStudyName = aScriptInfo.baseName();
2086   QDir aDir = aScriptInfo.absoluteDir();
2087   QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2088   for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2089     ok = aDir.remove( *it ) && ok;
2090   if( ok )
2091     ok = aDir.rmdir( aDir.absolutePath() );
2092
2093   if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2094   {
2095 #ifndef DISABLE_PYCONSOLE
2096     _PTR(Study) aStudyDS = newStudy->studyDS();
2097     app->getNoteBook()->Init( aStudyDS );
2098     newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2099     newStudy->Modified();
2100     updateDesktopTitle();
2101     updateActions();
2102 #endif
2103   }
2104   else
2105     ok = false;
2106
2107   return ok;
2108 }
2109
2110 /*!
2111   Close the Application
2112 */
2113 void SalomeApp_Application::afterCloseDoc()
2114 {
2115 #ifndef DISABLE_PYCONSOLE
2116   // emit signal to restore study from Python script
2117   if ( myNoteBook ) {
2118     emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2119                             myNoteBook->getDumpedStudyName(),
2120                             myNoteBook->isDumpedStudySaved() );
2121   }
2122 #endif
2123   LightApp_Application::afterCloseDoc();
2124 }
2125
2126 /*
2127   Asks to close existing document.
2128 */
2129 bool SalomeApp_Application::checkExistingDoc()
2130 {
2131   bool result = LightApp_Application::checkExistingDoc();
2132   if ( result && !activeStudy() ) {
2133     SALOMEDSClient_StudyManager* aMgr = studyMgr();
2134     if ( aMgr ) {
2135       std::vector<std::string> List = studyMgr()->GetOpenStudies();
2136       if( List.size() > 0 ) {
2137         SUIT_MessageBox::critical( desktop(), tr( "WRN_WARNING" ), tr( "ERR_ACTIVEDOC_LOAD" ));
2138         result = false;
2139       }
2140     }
2141   }
2142   return result;
2143 }
2144
2145
2146 #ifndef DISABLE_PYCONSOLE
2147
2148 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2149 {
2150   return new SalomeApp_PyInterp();
2151 }
2152
2153 #endif // DISABLE_PYCONSOLE