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