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