Salome HOME
Merge branch 'master' into V7_5_BR
[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     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    SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
695    if (study != NULL) {
696      _PTR(Study) stdDS = study->studyDS();
697
698      if (stdDS) {
699        SALOME_ListIteratorOfListIO it ( list );
700
701        if (it.More() && list.Extent() == 1) {
702          _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
703
704          if ( so ) {
705              canCopy = studyMgr()->CanCopy(so);
706              canPaste = studyMgr()->CanPaste(so);
707          }
708        }
709      }
710    }
711
712    action(EditCopyId)->setEnabled(canCopy);
713    action(EditPasteId)->setEnabled(canPaste);
714 }
715
716 /*!Delete references.*/
717 void SalomeApp_Application::onDeleteInvalidReferences()
718 {
719   SALOME_ListIO aList;
720   LightApp_SelectionMgr* mgr = selectionMgr();
721   mgr->selectedObjects( aList, QString(), false );
722
723   if( aList.IsEmpty() )
724     return;
725
726   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
727   _PTR(Study) aStudyDS = aStudy->studyDS();
728   _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
729   _PTR(SObject) anObj;
730
731   for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
732     if ( it.Value()->hasEntry() )
733     {
734       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
735       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
736         aRefObj = anObj;
737
738       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
739          aStudyBuilder->RemoveReference( aSObject );
740     }
741   updateObjectBrowser();
742 }
743
744 /*!Private SLOT. */
745 void SalomeApp_Application::onOpenWith()
746 {
747   QApplication::setOverrideCursor( Qt::WaitCursor );
748   SALOME_ListIO aList;
749   LightApp_SelectionMgr* mgr = selectionMgr();
750   mgr->selectedObjects(aList);
751   if (aList.Extent() != 1)
752     {
753       QApplication::restoreOverrideCursor();
754       return;
755     }
756   Handle(SALOME_InteractiveObject) aIObj = aList.First();
757   QString aModuleName(aIObj->getComponentDataType());
758   QString aModuleTitle = moduleTitle(aModuleName);
759   activateModule(aModuleTitle);
760   QApplication::restoreOverrideCursor();
761 }
762
763 /*!
764   Creates new study
765 */
766 SUIT_Study* SalomeApp_Application::createNewStudy()
767 {
768   SalomeApp_Study* aStudy = new SalomeApp_Study( this );
769
770   // Set up processing of major study-related events
771   connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
772   connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
773   connect( aStudy, SIGNAL( saved  ( SUIT_Study* ) ), this, SLOT( onStudySaved  ( SUIT_Study* ) ) );
774   connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
775
776 #ifndef DISABLE_PYCONSOLE
777   //to receive signal in application that NoteBook's variable was modified
778   connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
779            this, SIGNAL(notebookVarUpdated(QString)) );
780 #endif
781
782   return aStudy;
783 }
784
785 /*!
786   Enable/Disable menu items and toolbar buttons. Rebuild menu
787 */
788 void SalomeApp_Application::updateCommandsStatus()
789 {
790   LightApp_Application::updateCommandsStatus();
791
792   // Dump study menu
793   QAction* a = action( DumpStudyId );
794   if ( a )
795     a->setEnabled( activeStudy() );
796
797   // Load script menu
798   a = action( LoadScriptId );
799   if( a )
800     a->setEnabled( pythonConsole() );
801
802   // Properties menu
803   a = action( PropertiesId );
804   if( a )
805     a->setEnabled( activeStudy() );
806
807   // Save GUI state menu
808   a = action( SaveGUIStateId );
809   if( a )
810     a->setEnabled( activeStudy() );
811
812   // Connect study menu
813   a = action( ConnectId );
814   if( a )
815     a->setEnabled( !activeStudy() && studyMgr()->GetOpenStudies().size() > 0 );
816
817   // Disconnect study menu
818   a = action( DisconnectId );
819   if( a )
820     a->setEnabled( activeStudy() );
821
822   // update state of Copy/Paste menu items
823   onSelectionChanged();
824 }
825
826 /*!
827   \class DumpStudyFileDlg
828   Private class used in Dump Study operation.  Consists 2 check boxes:
829   "Publish in study" and "Save GUI parameters"
830 */
831 class DumpStudyFileDlg : public SUIT_FileDlg
832 {
833 public:
834   DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
835   {
836     QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
837     if ( grid )
838     {
839       QWidget *hB = new QWidget( this );
840       myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
841       myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
842       mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
843
844       QHBoxLayout *layout = new QHBoxLayout;
845       layout->addWidget(myPublishChk);
846       layout->addWidget(myMultiFileChk);
847       layout->addWidget(mySaveGUIChk);
848       hB->setLayout(layout);
849
850       QPushButton* pb = new QPushButton(this);
851
852       int row = grid->rowCount();
853       grid->addWidget( new QLabel("", this), row, 0 );
854       grid->addWidget( hB, row, 1, 1, 3 );
855       grid->addWidget( pb, row, 5 );
856
857       pb->hide();
858     }
859   }
860   QCheckBox* myPublishChk;
861   QCheckBox* myMultiFileChk;
862   QCheckBox* mySaveGUIChk;
863 };
864
865 class DumpStudyFileValidator : public SUIT_FileValidator
866 {
867  public:
868   DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
869   virtual ~DumpStudyFileValidator() {};
870   virtual bool canSave( const QString& file, bool permissions );
871 };
872
873 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
874 {
875   QFileInfo fi( file );
876   if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
877     SUIT_MessageBox::critical( parent(),
878                                QObject::tr("WRN_WARNING"),
879                                QObject::tr("WRN_FILE_NAME_BAD") );
880     return false;
881   }
882   return SUIT_FileValidator::canSave( file, permissions);
883 }
884
885 /*!Private SLOT. On dump study.*/
886 void SalomeApp_Application::onDumpStudy( )
887 {
888   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
889   if ( !appStudy ) return;
890   _PTR(Study) aStudy = appStudy->studyDS();
891
892   QStringList aFilters;
893   aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
894
895   bool anIsPublish = true;
896   bool anIsMultiFile = false;
897   bool anIsSaveGUI = true;
898
899   if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
900     anIsPublish   = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
901     anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
902     anIsSaveGUI   = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
903   }
904
905   DumpStudyFileDlg fd( desktop() );
906   fd.setValidator( new DumpStudyFileValidator( &fd ) );
907   fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
908   fd.setFilters( aFilters );
909   fd.myPublishChk->setChecked( anIsPublish );
910   fd.myMultiFileChk->setChecked( anIsMultiFile );
911   fd.mySaveGUIChk->setChecked( anIsSaveGUI );
912   if ( fd.exec() == QDialog::Accepted )
913   {
914     QString aFileName = fd.selectedFile();
915
916     bool toPublish = fd.myPublishChk->isChecked();
917     bool isMultiFile = fd.myMultiFileChk->isChecked();
918     bool toSaveGUI = fd.mySaveGUIChk->isChecked();
919
920     if ( !aFileName.isEmpty() ) {
921       QFileInfo aFileInfo(aFileName);
922       if( aFileInfo.isDir() ) // IPAL19257
923         return;
924
925       // Issue 21377 - dump study implementation moved to SalomeApp_Study class
926       bool res;
927       {
928         SUIT_OverrideCursor wc;
929         res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
930       }
931       if ( !res )
932         SUIT_MessageBox::warning( desktop(),
933                                   QObject::tr("WRN_WARNING"),
934                                   tr("WRN_DUMP_STUDY_FAILED") );
935     }
936   }
937 }
938
939 /*!Private SLOT. On load script.*/
940 void SalomeApp_Application::onLoadScript( )
941 {
942   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
943   if ( appStudy ) {
944     _PTR(Study) aStudy = appStudy->studyDS();
945     if ( aStudy->GetProperties()->IsLocked() ) {
946       SUIT_MessageBox::warning( desktop(),
947                                 QObject::tr("WRN_WARNING"),
948                                 QObject::tr("WRN_STUDY_LOCKED") );
949       return;
950     }
951   }
952
953   QStringList filtersList;
954   filtersList.append(tr("PYTHON_FILES_FILTER"));
955   filtersList.append(tr("ALL_FILES_FILTER"));
956
957   QString anInitialPath = "";
958   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
959     anInitialPath = QDir::currentPath();
960   
961 #ifdef WITH_SIMANIO
962   // MPV: if it is SIMAN study, make the initial path as the path to the Siman scripts storage
963   if (myIsSiman) {
964     SALOMEDSClient_StudyManager* aMgr = studyMgr();
965     aMgr->GetSimanStudy()->StudyId();
966     anInitialPath = QString(QDir::separator()) + "tmp" + QDir::separator() + "SimanSalome" + QDir::separator() + 
967       aMgr->GetSimanStudy()->StudyId().c_str() + QDir::separator() +
968       aMgr->GetSimanStudy()->ScenarioId().c_str() + QDir::separator() + aMgr->GetSimanStudy()->UserId().c_str();
969   }
970 #endif
971
972   QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
973
974   if ( !aFile.isEmpty() )
975   {
976     QString command = QString("execfile(r\"%1\")").arg(aFile);
977
978 #ifndef DISABLE_PYCONSOLE
979     PyConsole_Console* pyConsole = pythonConsole();
980
981     if ( pyConsole )
982       pyConsole->exec( command );
983 #endif
984   }
985 }
986
987 /*!Private SLOT. On save GUI state.*/
988 void SalomeApp_Application::onSaveGUIState()
989 {
990   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
991   if ( study ) {
992     SalomeApp_VisualState( this ).storeState();
993     updateSavePointDataObjects( study );
994     updateObjectBrowser();
995   }
996   updateActions();
997 }
998
999 /*!Public SLOT. On SIMAN check in operation.*/
1000 void SalomeApp_Application::onCheckIn()
1001 {
1002 #ifdef WITH_SIMANIO
1003   setMenuShown(SimanCheckInId, false); // check in may be performed only once
1004   setMenuShown(SimanLocalCheckInId, false);
1005   SALOMEDSClient_StudyManager* aMgr = studyMgr();
1006   aMgr->GetSimanStudy()->CheckIn("");
1007 #else
1008   printf( "****************************************************************\n" );
1009   printf( "*    Warning: SALOME is built without SIMAN support.\n" );
1010   printf( "****************************************************************\n" );
1011 #endif
1012 }
1013
1014 /*!Public SLOT. On SIMAN local check in operation.*/
1015 void SalomeApp_Application::onLocalCheckIn()
1016 {
1017 #ifdef WITH_SIMANIO
1018   // get the active module
1019   CAM_Module* aModule = activeModule();
1020   if (!aModule) return; // there is no active module
1021   
1022   setMenuShown(SimanCheckInId, false); // check in may be performed only once
1023   setMenuShown(SimanLocalCheckInId, false);
1024   SALOMEDSClient_StudyManager* aMgr = studyMgr();
1025   aMgr->GetSimanStudy()->CheckIn(aModule->name().toLatin1().data());
1026 #else
1027   printf( "****************************************************************\n" );
1028   printf( "*    Warning: SALOME is built without SIMAN support.\n" );
1029   printf( "****************************************************************\n" );
1030 #endif
1031 }
1032
1033 /*!Gets file filter.
1034  *\retval QString "(*.hdf)"
1035  */
1036 QString SalomeApp_Application::getFileFilter() const
1037 {
1038   return "(*.hdf)";
1039 }
1040
1041 /*!Create window.*/
1042 QWidget* SalomeApp_Application::createWindow( const int flag )
1043 {
1044   QWidget* wid = 0;
1045 #ifndef DISABLE_PYCONSOLE
1046   if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1047 #else
1048   wid = LightApp_Application::createWindow(flag);
1049 #endif
1050
1051   SUIT_ResourceMgr* resMgr = resourceMgr();
1052
1053   if ( flag == WT_ObjectBrowser )
1054   {
1055     SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1056     if ( ob ) {
1057       // temporary commented
1058       //ob->setUpdater( new SalomeApp_Updater() );
1059
1060 #ifdef WITH_SALOMEDS_OBSERVER
1061       //do not activate the automatic update of Qt tree through signal/slot
1062       ob->setAutoUpdate(false);
1063       //activate update of modified objects only
1064       ob->setUpdateModified(true);
1065 #endif
1066
1067       connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1068
1069       QString
1070         ValueCol = QObject::tr( "VALUE_COLUMN" ),
1071         IORCol = QObject::tr( "IOR_COLUMN" ),
1072         RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1073         EntryCol = QObject::tr( "ENTRY_COLUMN" );
1074
1075       SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1076       treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1077       treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1078       treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1079       treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1080       treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1081       treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1082       treeModel->setAppropriate( IORCol, Qtx::Toggled );
1083       treeModel->setAppropriate( RefCol, Qtx::Toggled );
1084
1085       bool autoSize      = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1086       bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1087       bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1088
1089       ob->setAutoSizeFirstColumn(autoSizeFirst);
1090       ob->setAutoSizeColumns(autoSize);
1091       ob->setResizeOnExpandItem(resizeOnExpandItem);
1092       ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1093
1094       // temporary commented
1095       /*
1096       for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1097       {
1098       ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1099       ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1100                                                     QString().sprintf( "visibility_column_%d", i ), true ) );
1101       }
1102       */
1103
1104       // temporary commented
1105       /*
1106         ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1107         ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1108         ob->resize( desktop()->width()/3, ob->height() );
1109       */
1110     }
1111   }
1112 #ifndef DISABLE_PYCONSOLE
1113   else if ( flag == WT_PyConsole )
1114   {
1115     PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), getPyInterp() );
1116     pyCons->setObjectName( "pythonConsole" );
1117     pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1118     pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1119     pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1120     pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1121     wid = pyCons;
1122     //pyCons->resize( pyCons->width(), desktop()->height()/4 );
1123     pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
1124   }
1125   else if ( flag == WT_NoteBook )
1126   {
1127     SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1128     if ( appStudy ) {
1129       _PTR(Study) aStudy = appStudy->studyDS();
1130       setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1131       //to receive signal in NoteBook that it's variable was modified
1132       connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1133                getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1134     }
1135     wid = getNoteBook();
1136     wid->setObjectName( "noteBook" );
1137   }
1138 #endif
1139   return wid;
1140 }
1141
1142 /*!Create preferences.*/
1143 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1144 {
1145   LightApp_Application::createPreferences(pref);
1146
1147   if ( !pref )
1148     return;
1149
1150   int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1151   int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1152   int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1153   for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1154   {
1155     pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1156                          LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1157   }
1158   pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1159
1160   // adding preference to LightApp_Application handled preferences..  a bit of hacking with resources..
1161   int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1162   int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1163   pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1164   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1165   pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1166   pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1167   pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1168   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1169   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1170 }
1171
1172 /*!Update desktop title.*/
1173 void SalomeApp_Application::updateDesktopTitle() {
1174   QString aTitle = applicationName();
1175   QString aVer = applicationVersion();
1176   if ( !aVer.isEmpty() )
1177     aTitle += QString( " " ) + aVer;
1178
1179   if ( activeStudy() )
1180   {
1181     QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1182     if ( !sName.isEmpty() ) {
1183       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1184       if ( study ) {
1185         _PTR(Study) stdDS = study->studyDS();
1186         if(stdDS) {
1187           if ( stdDS->GetProperties()->IsLocked() ) {
1188             aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1189           } else {
1190             aTitle += QString( " - [%1]" ).arg( sName );
1191           }
1192         }
1193       }
1194     }
1195   }
1196
1197   desktop()->setWindowTitle( aTitle );
1198 }
1199
1200 int SalomeApp_Application::closeChoice( const QString& docName )
1201 {
1202   QStringList buttons;
1203   QMap<int, int> choices;
1204   int idx = 0;
1205   buttons << tr ("APPCLOSE_SAVE");                // Save & Close
1206   choices.insert( idx++, CloseSave );             // ...
1207   buttons << tr ("APPCLOSE_CLOSE");               // Close w/o saving
1208   choices.insert( idx++, CloseDiscard );          // ...
1209   if ( myIsCloseFromExit ) {
1210     buttons << tr ("APPCLOSE_UNLOAD_SAVE");       // Save & Disconnect
1211     choices.insert( idx++, CloseDisconnectSave );     // ...
1212     buttons << tr ("APPCLOSE_UNLOAD");            // Disconnect
1213     choices.insert( idx++, CloseDisconnect );         // ...
1214   }
1215   buttons << tr ("APPCLOSE_CANCEL");              // Cancel
1216   choices.insert( idx++, CloseCancel );           // ...
1217
1218   int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1219                                           tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1220   return choices[answer];
1221 }
1222
1223 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1224 {
1225   bool res = true;
1226   switch( choice )
1227   {
1228   case CloseSave:
1229     if ( activeStudy()->isSaved() )
1230       onSaveDoc();
1231     else if ( !onSaveAsDoc() )
1232       res = false;
1233     break;
1234   case CloseDiscard:
1235     break;
1236   case CloseDisconnectSave:
1237     if ( activeStudy()->isSaved() )
1238       onSaveDoc();
1239     else if ( !onSaveAsDoc() )
1240       res = false;
1241   case CloseDisconnect:
1242     closeActiveDoc( false );
1243     closePermanently = false;
1244     break;
1245   case CloseCancel:
1246   default:
1247     res = false;
1248   }
1249   return res;
1250 }
1251
1252 int SalomeApp_Application::openChoice( const QString& aName )
1253 {
1254   int choice = LightApp_Application::openChoice( aName );
1255
1256   if ( QFileInfo( aName ).exists() ) {
1257     if ( choice == OpenNew ) { // The document isn't already open.
1258       bool exist = false;
1259       std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1260       for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1261         if ( aName == QString( lst[i].c_str() ) )
1262           exist = true;
1263       }
1264       // The document already exists in the study manager.
1265       // Do you want to reload it?
1266       if ( exist ) {
1267         int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1268                                                 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1269         if ( answer == SUIT_MessageBox::Yes )
1270           choice = OpenRefresh;
1271         else
1272           choice = OpenCancel;
1273       }
1274     }
1275   } else { // file is not exist on disk
1276     SUIT_MessageBox::warning( desktop(),
1277                               QObject::tr("WRN_WARNING"),
1278                               QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1279     return false;
1280   }
1281
1282   return choice;
1283 }
1284
1285 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1286 {
1287   bool res = false;
1288   int choice = aChoice;
1289   switch ( choice )
1290   {
1291   case OpenRefresh:
1292     {
1293       _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1294       if ( aStudy )
1295       {
1296         studyMgr()->Close( aStudy );
1297         choice = OpenNew;
1298       }
1299     }
1300   default:
1301     res = LightApp_Application::openAction( choice, aName );
1302     break;
1303   }
1304
1305   return res;
1306 }
1307
1308 /*!
1309   \brief Get map of the operations which can be performed
1310   on the module activation.
1311
1312   The method should return the map of the kind \c {<id>:<name>}
1313   where \c <id> is an integer identifier of the operation and
1314   \c <name> is a title for the button to be added to the
1315   dialog box. After user selects the required operation by the
1316   clicking the corresponding button in the dialog box, its identifier
1317   is passed to the moduleActionSelected() method to process
1318   the made choice.
1319
1320   \return map of the operations
1321   \sa moduleActionSelected()
1322 */
1323 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1324 {
1325   QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1326
1327   opmap.insert( LoadStudyId,     tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1328
1329   opmap.insert( NewAndScriptId,  tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1330   return opmap;
1331 }
1332
1333 /*!
1334   \brief Called when the used selectes required operation chosen
1335   from "Activate module" dialog box.
1336
1337   Performs the required operation according to the user choice.
1338
1339   \param id operation identifier
1340   \sa activateModuleActions()
1341 */
1342 void SalomeApp_Application::moduleActionSelected( const int id )
1343 {
1344   switch ( id ) {
1345   case LoadStudyId:
1346     onLoadDoc();
1347     break;
1348   case NewAndScriptId:
1349     onNewWithScript();
1350     break;
1351   default:
1352     LightApp_Application::moduleActionSelected( id );
1353     break;
1354   }
1355 }
1356
1357 /*!Gets CORBA::ORB_var*/
1358 CORBA::ORB_var SalomeApp_Application::orb()
1359 {
1360   ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1361   static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1362   return _orb;
1363 }
1364
1365 /*!Create and return SALOMEDS_StudyManager.*/
1366 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1367 {
1368   static _PTR(StudyManager) _sm;
1369   if(!_sm) _sm = ClientFactory::StudyManager();
1370   return _sm.get();
1371 }
1372
1373 /*!Create and return SALOME_NamingService.*/
1374 SALOME_NamingService* SalomeApp_Application::namingService()
1375 {
1376   static SALOME_NamingService _ns(orb());
1377   return &_ns;
1378 }
1379
1380 /*!Create and return SALOME_LifeCycleCORBA.*/
1381 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1382 {
1383   static SALOME_LifeCycleCORBA _lcc( namingService() );
1384   return &_lcc;
1385 }
1386
1387 /*!Private SLOT. On preferences.*/
1388 void SalomeApp_Application::onProperties()
1389 {
1390   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1391   if( !study )
1392     return;
1393
1394   _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1395   SB->NewCommand();
1396
1397   SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1398   int res = aDlg.exec();
1399   if( res==QDialog::Accepted && aDlg.isChanged() )
1400     SB->CommitCommand();
1401   else
1402     SB->AbortCommand();
1403
1404   //study->updateCaptions();
1405   updateDesktopTitle();
1406   updateActions();
1407 }
1408
1409 /*!Insert items in popup, which necessary for current application*/
1410 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1411 {
1412   LightApp_SelectionMgr* mgr = selectionMgr();
1413   bool cacheIsOn = mgr->isSelectionCacheEnabled();
1414   mgr->setSelectionCacheEnabled( true );
1415
1416   LightApp_Application::contextMenuPopup( type, thePopup, title );
1417
1418   // temporary commented
1419   /*OB_Browser* ob = objectBrowser();
1420   if ( !ob || type != ob->popupClientType() )
1421     return;*/
1422
1423   // Get selected objects
1424   SALOME_ListIO aList;
1425   mgr->selectedObjects( aList, QString(), false );
1426
1427   // add GUI state commands: restore, rename
1428   if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1429        QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1430     thePopup->addSeparator();
1431     thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1432     thePopup->addAction( tr( "MEN_RENAME_VS" ),  objectBrowser(),
1433                          SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1434     thePopup->addAction( tr( "MEN_DELETE_VS" ),  this, SLOT( onDeleteGUIState() ) );
1435   }
1436
1437   // "Delete reference" item should appear only for invalid references
1438
1439   // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1440   bool isInvalidRefs = false;
1441   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1442   if ( aStudy ) {
1443     _PTR(Study) aStudyDS = aStudy->studyDS();
1444     _PTR(SObject) anObj;
1445     
1446     for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1447     {
1448       if( it.Value()->hasEntry() )
1449       {
1450         _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1451         while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1452           aRefObj = anObj;
1453         
1454         if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1455           isInvalidRefs = true;
1456       }
1457     }
1458     
1459     // Add "Delete reference" item to popup
1460     if ( isInvalidRefs )
1461     {
1462       thePopup->addSeparator();
1463       thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1464       return;
1465     }
1466
1467     // "Activate module" item should appear only if it's necessary
1468     if ( aList.Extent() == 1 ) {
1469       aList.Clear();
1470       mgr->selectedObjects( aList );
1471       
1472       Handle(SALOME_InteractiveObject) aIObj = aList.First();
1473       
1474       // add extra popup menu (defined in XML)
1475       if ( myExtActions.size() > 0 ) {
1476         // Use only first selected object
1477         SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1478         if ( study ) {
1479           _PTR(Study) stdDS = study->studyDS();
1480           if ( stdDS ) {
1481             _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1482             if ( aSO ) {
1483               _PTR( GenericAttribute ) anAttr;
1484               std::string auid = "AttributeUserID";
1485               auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1486               if ( aSO->FindAttribute( anAttr, auid ) ) {
1487                 _PTR(AttributeUserID) aAttrID = anAttr;
1488                 QString aId = aAttrID->Value().c_str();
1489                 if ( myExtActions.contains( aId ) ) {
1490                   thePopup->addAction(myExtActions[aId]);
1491                 }
1492               }
1493             }
1494           }
1495         }
1496       }
1497       
1498       // check if item is a "GUI state" item (also a first level object)
1499       QString entry( aIObj->getEntry() );
1500       if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1501         QString aModuleName( aIObj->getComponentDataType() );
1502         QString aModuleTitle = moduleTitle( aModuleName );
1503         CAM_Module* currentModule = activeModule();
1504         if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1505           thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1506       }
1507     }
1508   }
1509
1510   mgr->setSelectionCacheEnabled( cacheIsOn );
1511 }
1512
1513 /*!Update obect browser:
1514  1.if 'updateModels' true, update existing data models;
1515  2. update "non-existing" (not loaded yet) data models;
1516  3. update object browser if it exists */
1517 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1518 {
1519   // update "non-existing" (not loaded yet) data models
1520   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1521   if ( study )
1522   {
1523     _PTR(Study) stdDS = study->studyDS();
1524     if( stdDS )
1525     {
1526       for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1527       {
1528         _PTR(SComponent) aComponent ( it->Value() );
1529
1530 #ifndef WITH_SALOMEDS_OBSERVER
1531         // with GUI observers this check is not needed anymore
1532         if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1533           continue; // skip the magic "Interface Applicative" component
1534 #endif
1535         if ( !objectBrowser() )
1536           getWindow( WT_ObjectBrowser );
1537         const bool isAutoUpdate = objectBrowser()->autoUpdate();
1538         objectBrowser()->setAutoUpdate( false );
1539         SalomeApp_DataModel::synchronize( aComponent, study );
1540         objectBrowser()->setAutoUpdate( isAutoUpdate );
1541       }
1542     }
1543   }
1544
1545   // create data objects that correspond to GUI state save points
1546   if ( study ) updateSavePointDataObjects( study );
1547
1548   // update existing data models (already loaded SComponents)
1549   LightApp_Application::updateObjectBrowser( updateModels );
1550 }
1551
1552 /*!Display Catalog Genenerator dialog */
1553 void SalomeApp_Application::onCatalogGen()
1554 {
1555   ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1556   aDlg.exec();
1557 }
1558
1559 /*!Display Registry Display dialog */
1560 void SalomeApp_Application::onRegDisplay()
1561 {
1562   CORBA::ORB_var anOrb = orb();
1563   ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1564   regWnd->show();
1565   regWnd->raise();
1566   regWnd->activateWindow();
1567 }
1568
1569 /*!find original object by double click on item */
1570 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1571 {
1572   // Issue 21379: References are supported at LightApp_DataObject level
1573   LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1574
1575   if( obj && obj->isReference() )
1576   {
1577     QString entry = obj->refEntry();
1578
1579     SUIT_DataOwnerPtrList aList;
1580     aList.append( new LightApp_DataOwner( entry ) );
1581     selectionMgr()->setSelected( aList, false );
1582
1583     SUIT_DataBrowser* ob = objectBrowser();
1584
1585     QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1586     if ( !aSelectedIndexes.isEmpty() )
1587       ob->treeView()->scrollTo( aSelectedIndexes.first() );
1588   }
1589 }
1590
1591 /*!
1592   Creates new view manager
1593   \param type - type of view manager
1594 */
1595 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1596 {
1597   return createViewManager(type);
1598 }
1599
1600
1601 /*!Global utility function, returns selected GUI Save point object's ID */
1602 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1603 {
1604   SALOME_ListIO aList;
1605   selMgr->selectedObjects( aList );
1606   if( aList.Extent() > 0 ) {
1607     Handle(SALOME_InteractiveObject) aIObj = aList.First();
1608     QString entry( aIObj->getEntry() );
1609     QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1610     if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1611       return -1;
1612     bool ok; // conversion to integer is ok?
1613     int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1614     return ok ? savePoint : -1;
1615   }
1616   return -1;
1617 }
1618
1619 /*!Called on Restore GUI State popup command*/
1620 void SalomeApp_Application::onRestoreGUIState()
1621 {
1622   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1623   if ( savePoint == -1 )
1624     return;
1625   SalomeApp_VisualState( this ).restoreState( savePoint );
1626 }
1627
1628 /*!Called on Delete GUI State popup command*/
1629 void SalomeApp_Application::onDeleteGUIState()
1630 {
1631   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1632   if ( savePoint == -1 )
1633     return;
1634   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1635   if ( !study )
1636     return;
1637
1638   study->removeSavePoint( savePoint );
1639   updateSavePointDataObjects( study );
1640 }
1641
1642 /*!Called on New study operation*/
1643 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1644 {
1645   LightApp_Application::onStudyCreated( study );
1646
1647 //#ifndef DISABLE_PYCONSOLE
1648 //  desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1649 //                               windowDock( getWindow( WT_ObjectBrowser ) ) );
1650 //#endif
1651
1652   loadDockWindowsState();
1653
1654   objectBrowserColumnsVisibility();
1655 }
1656
1657 /*!Called on Open study operation*/
1658 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1659 {
1660   LightApp_Application::onStudyOpened( study );
1661
1662 //#ifndef DISABLE_PYCONSOLE
1663 //  desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1664 //                               windowDock( getWindow( WT_ObjectBrowser ) ) );
1665 //#endif
1666
1667   loadDockWindowsState();
1668
1669   objectBrowserColumnsVisibility();
1670
1671   // temporary commented
1672   /*if ( objectBrowser() ) {
1673     updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1674     objectBrowser()->updateTree( study->root() );
1675   }*/
1676 }
1677
1678 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1679 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1680 {
1681
1682   SUIT_DataBrowser* ob = objectBrowser();
1683   LightApp_SelectionMgr* selMgr = selectionMgr();
1684
1685   if ( !study || !ob || !selMgr )
1686     return;
1687
1688   // find GUI states root object
1689   SUIT_DataObject* guiRootObj = 0;
1690   DataObjectList ch;
1691   study->root()->children( ch );
1692   DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1693   for ( ; it != last ; ++it ) {
1694     if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1695       guiRootObj = *it;
1696       break;
1697     }
1698   }
1699   std::vector<int> savePoints = study->getSavePoints();
1700   // case 1: no more save points but they existed in study's tree
1701   if ( savePoints.empty() && guiRootObj ) {
1702     //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1703     //    : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1704     const bool isAutoUpdate = ob->autoUpdate();
1705     selMgr->clearSelected();
1706     ob->setAutoUpdate(true);
1707     DataObjectList ch = guiRootObj->children();
1708     for( int i = 0; i < ch.size(); i++ )
1709       delete ch[i];
1710     delete guiRootObj;
1711     ob->setAutoUpdate(isAutoUpdate);
1712     return;
1713   }
1714   // case 2: no more save points but root does not exist either
1715   if ( savePoints.empty() && !guiRootObj )
1716     return;
1717   // case 3: save points but no root for them - create it
1718   if ( !savePoints.empty() && !guiRootObj )
1719     guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1720   // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1721   // to be always the last one in the tree.  Here we check - if it is not the last one - remove and
1722   // re-create it.
1723   if ( guiRootObj->nextBrother() ) {
1724     study->root()->removeChild(guiRootObj);
1725     study->root()->appendChild(guiRootObj);
1726     //study->root()->dump();
1727   }
1728
1729   // store data objects in a map id-to-DataObject
1730   QMap<int,SalomeApp_SavePointObject*> mapDO;
1731   ch.clear();
1732   guiRootObj->children( ch );
1733   for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1734     SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1735     if ( dobj )
1736       mapDO[dobj->getId()] = dobj;
1737   }
1738
1739   // iterate new save points.  if DataObject with such ID not found in map - create DataObject
1740   // if in the map - remove it from map.
1741   for ( int i = 0; i < savePoints.size(); i++ )
1742     if ( !mapDO.contains( savePoints[i] ) )
1743       new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1744     else
1745       mapDO.remove( savePoints[i] );
1746
1747   // delete DataObjects that are still in the map -- their IDs were not found in data model
1748   if( mapDO.size() > 0) {
1749     //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1750     //    : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1751     selMgr->clearSelected();
1752     const bool isAutoUpdate = ob->autoUpdate();
1753     ob->setAutoUpdate(true);
1754     for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1755       delete it.value();
1756     ob->setAutoUpdate(isAutoUpdate);
1757   }
1758 }
1759
1760 /*! Check data object */
1761 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1762 {
1763   if (theObj)
1764     return true;
1765
1766   return false;
1767 }
1768
1769 /*!
1770   Opens other study into active Study. If Study is empty - creates it.
1771   \param theName - name of study
1772 */
1773 bool SalomeApp_Application::useStudy( const QString& theName )
1774 {
1775   createEmptyStudy();
1776   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1777   bool res = false;
1778   if (aStudy)
1779     res = aStudy->loadDocument( theName );
1780   updateDesktopTitle();
1781   updateCommandsStatus();
1782   return res;
1783 }
1784
1785 /*! Show/hide object browser colums according to preferences */
1786 void SalomeApp_Application::objectBrowserColumnsVisibility()
1787 {
1788   if ( objectBrowser() )
1789     for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1790     {
1791       bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1792       objectBrowser()->treeView()->setColumnHidden( i, !shown );
1793     }
1794 }
1795
1796 #ifndef DISABLE_PYCONSOLE
1797 /*! Set SalomeApp_NoteBook pointer */
1798 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1799 {
1800   myNoteBook = theNoteBook;
1801 }
1802
1803 /*! Return SalomeApp_NoteBook pointer */
1804 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1805 {
1806   return myNoteBook;
1807 }
1808 #endif
1809
1810 /*!
1811  * Define extra actions defined in module definition XML file.
1812  * Additional popup items sections can be defined by parameter "popupitems".
1813  * Supported attributes:
1814  * title - title of menu item,
1815  * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1816  * method - method which has to be called when menu item is selected
1817  * Example:
1818  * <section name="MODULENAME">
1819  *   <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1820  * </section>
1821  * <section name="importmed">
1822  *   <parameter name="title" value="My menu"/>
1823  *   <parameter name="objectid" value="VISU.Result"/>
1824  *   <parameter name="method" value="nameOfModuleMethod"/>
1825  * </section>
1826  */
1827 void SalomeApp_Application::createExtraActions()
1828 {
1829   myExtActions.clear();
1830   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1831
1832   QStringList aModules;
1833   modules(aModules, false);
1834   foreach(QString aModile, aModules) {
1835     QString aModName = moduleName(aModile);
1836     QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1837     if (!aSectionStr.isNull()) {
1838       QStringList aSections = aSectionStr.split(':');
1839       foreach(QString aSection, aSections) {
1840         QString aTitle = resMgr->stringValue(aSection, "title",    QString());
1841         QString aId    = resMgr->stringValue(aSection, "objectid", QString());
1842         QString aSlot  = resMgr->stringValue(aSection, "method",   QString());
1843         if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1844           continue;
1845
1846         QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1847         if (aModuleName.isNull())
1848           aModuleName = aModName;
1849
1850         QAction* aAction = new QAction(aTitle, this);
1851         QStringList aData;
1852         aData<<aModuleName<<aSlot;
1853         aAction->setData(aData);
1854         connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1855         myExtActions[aId] = aAction;
1856       }
1857     }
1858   }
1859 }
1860
1861 /*!
1862  * Called when extra action is selected
1863  */
1864 void SalomeApp_Application::onExtAction()
1865 {
1866   QAction* aAction = ::qobject_cast<QAction*>(sender());
1867   if (!aAction)
1868     return;
1869
1870   QVariant aData = aAction->data();
1871   QStringList aDataList = aData.value<QStringList>();
1872   if (aDataList.size() != 2)
1873     return;
1874
1875   LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1876   SALOME_ListIO aListIO;
1877   aSelectionMgr->selectedObjects(aListIO);
1878   const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1879   if (aListIO.Extent() < 1)
1880     return;
1881   if (!anIO->hasEntry())
1882     return;
1883
1884   QString aEntry(anIO->getEntry());
1885
1886   QApplication::setOverrideCursor( Qt::WaitCursor );
1887   QString aModuleTitle = moduleTitle(aDataList[0]);
1888   activateModule(aModuleTitle);
1889   QApplication::restoreOverrideCursor();
1890
1891   QCoreApplication::processEvents();
1892
1893   CAM_Module* aModule = activeModule();
1894   if (!aModule)
1895     return;
1896
1897   if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1898     printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1899 }
1900
1901 /*!
1902   Checks that an object can be renamed.
1903   \param entry entry of the object
1904   \brief Return \c true if object can be renamed
1905 */
1906 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1907 {
1908   return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1909 }
1910
1911 /*!
1912   Rename object by entry.
1913   \param entry entry of the object
1914   \param name new name of the object
1915   \brief Return \c true if rename operation finished successfully, \c false otherwise.
1916 */
1917 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1918 {
1919   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1920
1921   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1922
1923   if(!aStudy || savePoint == -1)
1924     return false;
1925
1926   if ( !name.isNull() && !name.isEmpty() ) {
1927     aStudy->setNameOfSavePoint( savePoint, name );
1928     updateSavePointDataObjects( aStudy );
1929
1930     //Mark study as modified
1931     aStudy->Modified();
1932     return true;
1933   }
1934   return false;
1935 }
1936
1937 #ifndef DISABLE_PYCONSOLE
1938 //============================================================================
1939 /*! Function : onUpdateStudy
1940  *  Purpose  : Slot to update the study.
1941  */
1942 //============================================================================
1943 void SalomeApp_Application::onUpdateStudy()
1944 {
1945   QApplication::setOverrideCursor( Qt::WaitCursor );
1946
1947   if( !updateStudy() )
1948     SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1949
1950   QApplication::restoreOverrideCursor();
1951 }
1952
1953 //============================================================================
1954 /*! Function : updateStudy
1955  *  Purpose  : Update study by dumping the study to Python script and loading it.
1956  *             It is used to apply variable modifications done in NoteBook to created objects.
1957  */
1958 //============================================================================
1959 bool SalomeApp_Application::updateStudy()
1960 {
1961   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1962   if ( !study || !myNoteBook )
1963     return false;
1964
1965   myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1966   myNoteBook->setDumpedStudyName( study->studyName() );
1967
1968   _PTR(Study) studyDS = study->studyDS();
1969
1970   // get unique temporary directory name
1971   QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1972   if( aTmpDir.isEmpty() )
1973     return false;
1974
1975   if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1976     aTmpDir.remove( aTmpDir.length() - 1, 1 );
1977
1978   // dump study to the temporary directory
1979   QString aScriptName( "notebook" );
1980   bool toPublish = true;
1981   bool isMultiFile = false;
1982   bool toSaveGUI = true;
1983
1984   int savePoint;
1985   _PTR(AttributeParameter) ap;
1986   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1987   if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1988   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1989     ip->setDumpPython(studyDS);
1990     savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1991   }
1992   bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1993   if ( toSaveGUI )
1994     study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1995
1996   if( ok )
1997     myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1998   else
1999     return false;
2000
2001   QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
2002   int anIndex = aList.indexOf( this );
2003
2004   // Disconnect dialog from application desktop in case if:
2005   // 1) Application is not the first application in the session
2006   // 2) Application is the first application in session but not the only.
2007   bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
2008   if( changeDesktop ) {
2009
2010     SalomeApp_Application* app = this;
2011     if( anIndex > 0 && anIndex < aList.count() )
2012       app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
2013     else if(anIndex == 0 && aList.count() > 1)
2014       app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
2015
2016     if( !app )
2017       return false;
2018
2019     // creation a new study and restoring will be done in another application
2020     connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
2021              app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
2022   }
2023
2024   QString aDumpScript = myNoteBook->getDumpedStudyScript();
2025   QString aStudyName = myNoteBook->getDumpedStudyName();
2026   bool isStudySaved = myNoteBook->isDumpedStudySaved();
2027   // clear a study (delete all objects)
2028   onCloseDoc( false );
2029
2030   if( !changeDesktop ) {
2031     ok = onRestoreStudy( aDumpScript,
2032                          aStudyName,
2033                          isStudySaved );
2034   }
2035
2036   return ok;
2037 }
2038 #endif
2039
2040 //============================================================================
2041 /*! Function : onRestoreStudy
2042  *  Purpose  : Load the dumped study from Python script
2043  */
2044 //============================================================================
2045 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2046                                             const QString& theStudyName,
2047                                             bool theIsStudySaved )
2048 {
2049   bool ok = true;
2050
2051   // create a new study
2052   onNewDoc();
2053
2054   // get active application
2055   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2056
2057   // load study from the temporary directory
2058   QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
2059
2060 #ifndef DISABLE_PYCONSOLE
2061   PyConsole_Console* pyConsole = app->pythonConsole();
2062   if ( pyConsole )
2063     pyConsole->execAndWait( command );
2064 #endif
2065
2066   // remove temporary directory
2067   QFileInfo aScriptInfo = QFileInfo( theDumpScript );
2068   QString aStudyName = aScriptInfo.baseName();
2069   QDir aDir = aScriptInfo.absoluteDir();
2070   QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2071   for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2072     ok = aDir.remove( *it ) && ok;
2073   if( ok )
2074     ok = aDir.rmdir( aDir.absolutePath() );
2075
2076   if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2077   {
2078 #ifndef DISABLE_PYCONSOLE
2079     _PTR(Study) aStudyDS = newStudy->studyDS();
2080     app->getNoteBook()->Init( aStudyDS );
2081     newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2082     newStudy->Modified();
2083     updateDesktopTitle();
2084     updateActions();
2085 #endif
2086   }
2087   else
2088     ok = false;
2089
2090   return ok;
2091 }
2092
2093 /*!
2094   Close the Application
2095 */
2096 void SalomeApp_Application::afterCloseDoc()
2097 {
2098 #ifndef DISABLE_PYCONSOLE
2099   // emit signal to restore study from Python script
2100   if ( myNoteBook ) {
2101     emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2102                             myNoteBook->getDumpedStudyName(),
2103                             myNoteBook->isDumpedStudySaved() );
2104   }
2105 #endif
2106   LightApp_Application::afterCloseDoc();
2107 }
2108
2109 /*
2110   Asks to close existing document.
2111 */
2112 bool SalomeApp_Application::checkExistingDoc()
2113 {
2114   bool result = LightApp_Application::checkExistingDoc();
2115   if ( result && !activeStudy() ) {
2116     SALOMEDSClient_StudyManager* aMgr = studyMgr();
2117     if ( aMgr ) {
2118       std::vector<std::string> List = studyMgr()->GetOpenStudies();
2119       if( List.size() > 0 ) {
2120         SUIT_MessageBox::critical( desktop(), tr( "WRN_WARNING" ), tr( "ERR_ACTIVEDOC_LOAD" ));
2121         result = false;
2122       }
2123     }
2124   }
2125   return result;
2126 }
2127
2128
2129 #ifndef DISABLE_PYCONSOLE
2130
2131 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2132 {
2133   return new SalomeApp_PyInterp();
2134 }
2135
2136 #endif // DISABLE_PYCONSOLE