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