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