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