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