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