Salome HOME
0022565: [CEA 1145] Missing WT_NoteBook in python:
[modules/gui.git] / src / SalomeApp / SalomeApp_Application.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File:      SalomeApp_Application.cxx
24 // Created:   10/22/2004 3:23:45 PM
25 // Author:    Sergey LITONIN
26
27 #ifdef WIN32
28   // E.A. : On windows with python 2.6, there is a conflict
29   // E.A. : between pymath.h and Standard_math.h which define
30   // E.A. : some same symbols : acosh, asinh, ...
31   #include <Standard_math.hxx>
32   #ifndef DISABLE_PYCONSOLE
33     #include <pymath.h>
34   #endif
35 #endif
36
37 #ifndef DISABLE_PYCONSOLE
38   #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
39   #include <PyConsole_Console.h>
40   #include "SalomeApp_NoteBook.h"
41 #endif
42 #include "SalomeApp_Application.h"
43 #include "SalomeApp_Study.h"
44 #include "SalomeApp_DataModel.h"
45 #include "SalomeApp_DataObject.h"
46 #include "SalomeApp_VisualState.h"
47 #include "SalomeApp_StudyPropertiesDlg.h"
48 #include "SalomeApp_LoadStudiesDlg.h"
49 #include "SalomeApp_ExitDlg.h"
50
51 #include <LightApp_Application.h>
52 #include <LightApp_Module.h>
53 #include <LightApp_Preferences.h>
54 #include <LightApp_SelectionMgr.h>
55 #include <LightApp_NameDlg.h>
56 #include <LightApp_DataOwner.h>
57
58 #include <CAM_Module.h>
59
60 #include <SUIT_Tools.h>
61 #include <SUIT_Session.h>
62 #include <SUIT_Desktop.h>
63 #include <SUIT_DataBrowser.h>
64 #include <SUIT_FileDlg.h>
65 #include <SUIT_FileValidator.h>
66 #include <SUIT_MessageBox.h>
67 #include <SUIT_ResourceMgr.h>
68 #include <SUIT_TreeModel.h>
69 #include <SUIT_ViewWindow.h>
70 #include <SUIT_ViewManager.h>
71 #include <SUIT_ViewModel.h>
72 #include <SUIT_OverrideCursor.h>
73
74 #include <QtxTreeView.h>
75
76 #include <SALOME_EventFilter.h>
77
78 // temporary commented
79 //#include <OB_ListItem.h>
80
81
82 #include <Utils_ORB_INIT.hxx>
83 #include <Utils_SINGLETON.hxx>
84 #include <SALOME_LifeCycleCORBA.hxx>
85
86 #include <QApplication>
87 #include <QAction>
88 #include <QRegExp>
89 #include <QCheckBox>
90 #include <QPushButton>
91 #include <QLabel>
92 #include <QListWidget>
93 #include <QGridLayout>
94 #include <QMenu>
95 #include <QtDebug>
96
97 #include <SALOMEDSClient_ClientFactory.hxx>
98 #include <Basics_Utils.hxx>
99
100 #include <SALOME_ListIO.hxx>
101 #include <SALOME_ListIteratorOfListIO.hxx>
102 #include <SALOME_Prs.h>
103
104
105 #include <ToolsGUI_CatalogGeneratorDlg.h>
106 #include <ToolsGUI_RegWidget.h>
107
108 #include <vector>
109
110 #include <SALOMEDS_Tool.hxx>
111
112 /*!Internal class that updates object browser item properties */
113 // temporary commented
114 /*class SalomeApp_Updater : public OB_Updater
115 {
116 public:
117   SalomeApp_Updater() : OB_Updater(){};
118   virtual ~SalomeApp_Updater(){};
119   virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
120 };
121
122 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
123 {
124   if( !theObj || !theItem )
125     return;
126
127   SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
128   if( !SAObj )
129     return;
130
131   _PTR(SObject) SObj = SAObj->object();
132   if( !SObj )
133     return;
134   _PTR( GenericAttribute ) anAttr;
135
136   // Selectable
137   if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
138   {
139     _PTR(AttributeSelectable) aAttrSel = anAttr;
140     theItem->setSelectable( aAttrSel->IsSelectable() );
141   }
142   // Expandable
143   if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
144   {
145     _PTR(AttributeExpandable) aAttrExpand = anAttr;
146     theItem->setExpandable( aAttrExpand->IsExpandable() );
147   }
148   // Opened
149   //this attribute is not supported in the version of SALOME 3.x
150   //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
151   //{
152   //  _PTR(AttributeOpened) aAttrOpen = anAttr;
153   //  theItem->setOpen( aAttrOpen->IsOpened() );
154   //}
155 }*/
156
157 /*!Create new instance of SalomeApp_Application.*/
158 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
159 {
160   return new SalomeApp_Application();
161 }
162
163 /*!Constructor.*/
164 SalomeApp_Application::SalomeApp_Application()
165   : LightApp_Application()
166 {
167   connect( desktop(), SIGNAL( message( const QString& ) ),
168            this, SLOT( onLoadDocMessage( const QString& ) ), Qt::UniqueConnection );
169   myIsSiman = false; // default
170 }
171
172 /*!Destructor.
173  *\li Destroy event filter.
174  */
175 SalomeApp_Application::~SalomeApp_Application()
176 {
177   // Do not destroy. It's a singleton !
178   //SALOME_EventFilter::Destroy();
179 }
180
181 /*!Start application.*/
182 void SalomeApp_Application::start()
183 {
184   // process the command line options before start: to createActions in accordance to the options
185   static bool isFirst = true;
186   if ( isFirst ) {
187     isFirst = false;
188
189     QString hdffile;
190     QStringList pyfiles;
191     QString loadStudy;
192
193     for (int i = 1; i < qApp->argc(); i++) {
194       QRegExp rxs ("--study-hdf=(.+)");
195       if ( rxs.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxs.capturedTexts().count() > 1 ) {
196         QString file = rxs.capturedTexts()[1];
197         QFileInfo fi ( file );
198         QString extension = fi.suffix().toLower();
199         if ( extension == "hdf" && fi.exists() )
200           hdffile = fi.absoluteFilePath();
201       }
202       else {
203         QRegExp rxp ("--pyscript=\\[(.+)\\]");
204         QRegExp rxl ("--siman-study=(.+)");
205         if ( rxp.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxp.capturedTexts().count() > 1 ) {
206           // pyscript
207           QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
208           for (int k = 0; k < dictList.count(); ++k) {
209             QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
210             if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
211               for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
212                 pyfiles += rxd.capturedTexts()[m];
213               }
214             }
215           }
216         }
217 #ifdef WITH_SIMANIO
218         if ( rxl.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxl.capturedTexts().count() > 1 ) {
219           // siman
220           loadStudy = rxl.capturedTexts()[1];
221           myIsSiman = true;
222         }
223 #endif
224       }
225     }
226     // Here pyfiles elements are: "script_name": [list_of_"arg"s]
227     // For example: "/absolute/path/to/my_script.py": ["1", "2"]
228
229     LightApp_Application::start();
230     SALOME_EventFilter::Init();
231
232     if ( !hdffile.isEmpty() )       // open hdf file given as parameter
233       onOpenDoc( hdffile );
234     else if ( pyfiles.count() > 0 ) // create new study
235       onNewDoc();
236     else if (!loadStudy.isEmpty()) {// load study by name
237       if (onLoadDoc(loadStudy))
238         updateObjectBrowser(true);
239     }
240
241 #ifndef DISABLE_PYCONSOLE
242     // import/execute python scripts
243     if ( pyfiles.count() > 0 && activeStudy() ) {
244       SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
245       PyConsole_Console* pyConsole = pythonConsole();
246       if ( appStudy && pyConsole ) {
247         _PTR(Study) aStudy = appStudy->studyDS();
248         if ( !aStudy->GetProperties()->IsLocked() ) {
249           // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
250           // Path is absolute, script has .py extension
251           for (uint j = 0; j < pyfiles.count(); j++ ) {
252             // Extract scripts and their arguments, if any
253             QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
254             if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
255               QString script = rxp.capturedTexts()[1];
256               QString args = "";
257               QStringList argList = rxp.capturedTexts()[2].split(",", QString::SkipEmptyParts);
258               for (uint k = 0; k < argList.count(); k++ ) {
259                 QString arg = argList[k].trimmed();
260                 arg.remove( QRegExp("^[\"]") );
261                 arg.remove( QRegExp("[\"]$") );
262                 args += arg+",";
263               }
264               args.remove( QRegExp("[,]$") );
265               if (!args.isEmpty()) {
266                 args = "args:"+args;
267               }
268
269               script.remove( QRegExp("^python.*[\\s]+") );
270               QString cmd = script+" "+args;
271               QString command = QString( "execfile(r\"%1\")" ).arg(cmd.trimmed());
272               pyConsole->exec(command);
273             }
274           } // end for loop on pyfiles QStringList
275         }
276       }
277     }
278 #endif
279   } else {
280     LightApp_Application::start();
281     SALOME_EventFilter::Init();
282   }
283 }
284
285 /*!Create actions:*/
286 void SalomeApp_Application::createActions()
287 {
288   LightApp_Application::createActions();
289
290   SUIT_Desktop* desk = desktop();
291
292   //! Save GUI state
293   // "Save GUI State" command is moved to VISU module
294   //  createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
295   //            tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
296   //            0, desk, false, this, SLOT( onSaveGUIState() ) );
297
298   //! Dump study
299   createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
300                 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
301                 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
302
303   //! Load script
304   createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
305                 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
306                 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
307
308   //! Properties
309   createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
310                 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
311                 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
312
313   //! Catalog Generator
314   createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ),  QIcon(),
315                 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
316                 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
317
318   //! Registry Display
319   createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ),  QIcon(),
320                 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
321                 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
322
323   //SRN: BugID IPAL9021, add an action "Load"
324   createAction( FileLoadId, tr( "TOT_DESK_FILE_LOAD" ),
325                 resourceMgr()->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
326                 tr( "MEN_DESK_FILE_LOAD" ), tr( "PRP_DESK_FILE_LOAD" ),
327                 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
328   //SRN: BugID IPAL9021: End
329
330 #ifdef WITH_SIMANIO
331   if (myIsSiman) {
332     // check-in operations for SIMAN study  
333     createAction( SimanCheckInId, tr( "TOT_SIMAN_CHECK_IN" ), QIcon(),
334                 tr( "MEN_SIMAN_CHECK_IN" ), tr( "PRP_SIMAN_CHECK_IN" ),
335                 0, desk, false, this, SLOT( onCheckIn() ) );
336     createAction( SimanLocalCheckInId, tr( "TOT_SIMAN_LOCAL_CHECK_IN" ), QIcon(),
337                 tr( "MEN_SIMAN_LOCAL_CHECK_IN" ), tr( "PRP_SIMAN_LOCAL_CHECK_IN" ),
338                 0, desk, false, this, SLOT( onLocalCheckIn() ) );
339   }
340 #endif
341
342   int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
343
344   // "Save GUI State" command is renamed to "Save VISU State" and
345   // creation of menu item is moved to VISU
346   //  createMenu( SaveGUIStateId, fileMenu, 10, -1 );
347
348   createMenu( FileLoadId,   fileMenu, 0 );  //SRN: BugID IPAL9021, add a menu item "Load"
349
350 #ifdef WITH_SIMANIO
351   if (myIsSiman) {
352     // check-in operation for SIMAN study
353     // last argument "5" locates this just after "Save As" but certain constant is bad => insert after the separator
354     createMenu( SimanCheckInId, fileMenu, 5);
355     createMenu( SimanLocalCheckInId, fileMenu, 5);
356     createMenu( separator(), fileMenu, 5 );
357   }
358 #endif
359   createMenu( DumpStudyId, fileMenu, 10, -1 );
360   createMenu( separator(), fileMenu, -1, 10, -1 );
361   createMenu( LoadScriptId, fileMenu, 10, -1 );
362   createMenu( separator(), fileMenu, -1, 10, -1 );
363   createMenu( PropertiesId, fileMenu, 10, -1 );
364   createMenu( separator(), fileMenu, -1, 10, -1 );
365
366   int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
367   createMenu( CatalogGenId, toolsMenu, 10, -1 );
368   createMenu( RegDisplayId, toolsMenu, 10, -1 );
369   createMenu( separator(), toolsMenu, -1, 15, -1 );
370
371   createExtraActions();
372
373 #ifndef DISABLE_PYCONSOLE
374 #ifndef DISABLE_SALOMEOBJECT
375   // import Python module that manages SALOME plugins
376   {
377     PyLockWrapper lck; // acquire GIL
378     PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
379     PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_PLUGINS_TOOLS").toStdString().c_str(),tr("MEN_DESK_PLUGINS").toStdString().c_str());
380     if ( !res )
381       PyErr_Print();
382   }
383   // end of SALOME plugins loading
384 #endif
385 #endif
386
387 }
388
389
390 /*!Set desktop:*/
391 void SalomeApp_Application::setDesktop( SUIT_Desktop* desk )
392 {
393   LightApp_Application::setDesktop( desk );
394
395   if ( desk ) {
396     connect( desk, SIGNAL( message( const QString& ) ),
397              this, SLOT( onLoadDocMessage( const QString& ) ), Qt::UniqueConnection );
398   }
399 }
400
401 /*!
402   \brief Close application.
403 */
404 void SalomeApp_Application::onExit()
405 {
406   bool killServers = false;
407   bool result = true;
408
409   if ( exitConfirmation() ) {
410     SalomeApp_ExitDlg dlg( desktop() );
411     result = dlg.exec() == QDialog::Accepted;
412     killServers = dlg.isServersShutdown();
413   }
414
415   if ( result )
416     SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
417 }
418
419 /*!SLOT. Load document.*/
420 void SalomeApp_Application::onLoadDoc()
421 {
422   QString studyName;
423
424   std::vector<std::string> List = studyMgr()->GetOpenStudies();
425
426   SUIT_Session* aSession = SUIT_Session::session();
427   QList<SUIT_Application*> aAppList = aSession->applications();
428
429   QStringList unloadedStudies;
430
431   for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
432      studyName = List[ind].c_str();
433      // Add to list only unloaded studies
434      bool isAlreadyOpen = false;
435      QListIterator<SUIT_Application*> it( aAppList );
436      while ( it.hasNext() && !isAlreadyOpen ) {
437        SUIT_Application* aApp = it.next();
438        if( !aApp || !aApp->activeStudy() )
439          continue;
440        if ( aApp->activeStudy()->studyName() == studyName )
441          isAlreadyOpen = true;
442      }
443
444      if ( !isAlreadyOpen )
445        unloadedStudies << studyName;
446   }
447
448   studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
449   if ( studyName.isEmpty() )
450     return;
451
452 #ifndef WIN32
453   // this code replaces marker of windows drive and path become invalid therefore
454   // defines placed there
455   studyName.replace( QRegExp(":"), "/" );
456 #endif
457
458   if ( onLoadDoc( studyName ) ) {
459     updateWindows();
460     updateViewManagers();
461     updateObjectBrowser( true );
462   }
463 }
464
465 /*!SLOT. Create new study and load script*/
466 void SalomeApp_Application::onNewWithScript()
467 {
468   QStringList filtersList;
469   filtersList.append(tr("PYTHON_FILES_FILTER"));
470   filtersList.append(tr("ALL_FILES_FILTER"));
471
472   QString anInitialPath = "";
473   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
474     anInitialPath = QDir::currentPath();
475
476   QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
477
478   if ( !aFile.isEmpty() )
479   {
480     onNewDoc();
481
482     QString command = QString("execfile(r\"%1\")").arg(aFile);
483
484 #ifndef DISABLE_PYCONSOLE
485     PyConsole_Console* pyConsole = pythonConsole();
486
487     if ( pyConsole )
488       pyConsole->exec( command );
489 #endif
490   }
491 }
492
493
494 /*!SLOT. Load document with \a aName.*/
495 bool SalomeApp_Application::onLoadDoc( const QString& aName )
496 {
497 #ifdef SINGLE_DESKTOP
498   if ( !LightApp_Application::closeDoc() )
499     return false;
500 #endif
501   bool res = true;
502   if ( !activeStudy() ) {
503     // if no study - load in current desktop
504     res = useStudy( aName );
505   }
506   else {
507     // if study exists - load in new desktop. Check: is the same file is loaded?
508     SUIT_Session* aSession = SUIT_Session::session();
509     QList<SUIT_Application*> aAppList = aSession->applications();
510     bool isAlreadyOpen = false;
511     SalomeApp_Application* aApp = 0;
512     for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
513           it != aAppList.end() && !isAlreadyOpen; ++it ) {
514       aApp = dynamic_cast<SalomeApp_Application*>( *it );
515       if ( aApp && aApp->activeStudy()->studyName() == aName )
516         isAlreadyOpen = true;
517     }
518     if ( !isAlreadyOpen ) {
519       aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
520       if ( aApp )
521         res = aApp->useStudy( aName );
522     }
523     else {
524       aApp->desktop()->activateWindow();
525     }
526   }
527
528   return res;
529 }
530
531 /*!SLOT. Load document with a name, specified in \a aMessage.*/
532 void SalomeApp_Application::onLoadDocMessage(const QString& aMessage)
533 {
534   if (aMessage.indexOf("simanCheckoutDone ") == 0) {
535 #ifdef WITH_SIMANIO
536     onLoadDoc(aMessage.section(' ', 1));
537 #else
538     printf( "****************************************************************\n" );
539     printf( "*    Warning: SALOME is built without SIMAN support.\n" );
540     printf( "****************************************************************\n" );
541 #endif
542   }
543 }
544
545 /*!SLOT. Copy objects to study maneger from selection maneger..*/
546 void SalomeApp_Application::onCopy()
547 {
548   SALOME_ListIO list;
549   LightApp_SelectionMgr* mgr = selectionMgr();
550   mgr->selectedObjects(list);
551
552   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
553   if(study == NULL) return;
554
555   _PTR(Study) stdDS = study->studyDS();
556   if(!stdDS) return;
557
558   SALOME_ListIteratorOfListIO it( list );
559   if(it.More())
560     {
561       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
562       try {
563         studyMgr()->Copy(so);
564         onSelectionChanged();
565       }
566       catch(...) {
567       }
568     }
569 }
570
571 /*!SLOT. Paste objects to study maneger from selection manager.*/
572 void SalomeApp_Application::onPaste()
573 {
574   SALOME_ListIO list;
575   LightApp_SelectionMgr* mgr = selectionMgr();
576   mgr->selectedObjects(list);
577
578   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
579   if(study == NULL) return;
580
581   _PTR(Study) stdDS = study->studyDS();
582   if(!stdDS) return;
583
584   if ( stdDS->GetProperties()->IsLocked() ) {
585     SUIT_MessageBox::warning( desktop(),
586                               QObject::tr("WRN_WARNING"),
587                               QObject::tr("WRN_STUDY_LOCKED") );
588     return;
589   }
590
591   SALOME_ListIteratorOfListIO it( list );
592   if(it.More())
593     {
594       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
595       try {
596         studyMgr()->Paste(so);
597         updateObjectBrowser( true );
598         updateActions(); //SRN: BugID IPAL9377, case 3
599       }
600       catch(...) {
601       }
602     }
603 }
604
605 /*!Check the application on closing.
606  * \retval true if possible, else false
607  */
608 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
609 {
610   return LightApp_Application::isPossibleToClose( closePermanently );
611 }
612
613 /*! Check if the study is locked */
614 void SalomeApp_Application::onCloseDoc( bool ask )
615 {
616   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
617
618   if (study != NULL) {
619     _PTR(Study) stdDS = study->studyDS();
620     if(stdDS && stdDS->IsStudyLocked()) {
621       if ( SUIT_MessageBox::question( desktop(),
622                                       QObject::tr( "WRN_WARNING" ),
623                                       QObject::tr( "CLOSE_LOCKED_STUDY" ),
624                                       SUIT_MessageBox::Yes | SUIT_MessageBox::No,
625                                       SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
626
627     }
628   }
629
630   LightApp_Application::onCloseDoc( ask );
631 }
632
633 /*!Sets enable or disable some actions on selection changed.*/
634 void SalomeApp_Application::onSelectionChanged()
635 {
636    SALOME_ListIO list;
637    LightApp_SelectionMgr* mgr = selectionMgr();
638    mgr->selectedObjects(list);
639
640    bool canCopy  = false;
641    bool canPaste = false;
642
643    SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
644    if (study != NULL) {
645      _PTR(Study) stdDS = study->studyDS();
646
647      if (stdDS) {
648        SALOME_ListIteratorOfListIO it ( list );
649
650        if (it.More() && list.Extent() == 1) {
651          _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
652
653          if ( so ) {
654              canCopy = studyMgr()->CanCopy(so);
655              canPaste = studyMgr()->CanPaste(so);
656          }
657        }
658      }
659    }
660
661    action(EditCopyId)->setEnabled(canCopy);
662    action(EditPasteId)->setEnabled(canPaste);
663 }
664
665 /*!Delete references.*/
666 void SalomeApp_Application::onDeleteInvalidReferences()
667 {
668   SALOME_ListIO aList;
669   LightApp_SelectionMgr* mgr = selectionMgr();
670   mgr->selectedObjects( aList, QString(), false );
671
672   if( aList.IsEmpty() )
673     return;
674
675   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
676   _PTR(Study) aStudyDS = aStudy->studyDS();
677   _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
678   _PTR(SObject) anObj;
679
680   for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
681     if ( it.Value()->hasEntry() )
682     {
683       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
684       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
685         aRefObj = anObj;
686
687       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
688          aStudyBuilder->RemoveReference( aSObject );
689     }
690   updateObjectBrowser();
691 }
692
693 /*!Private SLOT. */
694 void SalomeApp_Application::onOpenWith()
695 {
696   QApplication::setOverrideCursor( Qt::WaitCursor );
697   SALOME_ListIO aList;
698   LightApp_SelectionMgr* mgr = selectionMgr();
699   mgr->selectedObjects(aList);
700   if (aList.Extent() != 1)
701     {
702       QApplication::restoreOverrideCursor();
703       return;
704     }
705   Handle(SALOME_InteractiveObject) aIObj = aList.First();
706   QString aModuleName(aIObj->getComponentDataType());
707   QString aModuleTitle = moduleTitle(aModuleName);
708   activateModule(aModuleTitle);
709   QApplication::restoreOverrideCursor();
710 }
711
712 /*!
713   Creates new study
714 */
715 SUIT_Study* SalomeApp_Application::createNewStudy()
716 {
717   SalomeApp_Study* aStudy = new SalomeApp_Study( this );
718
719   // Set up processing of major study-related events
720   connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
721   connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
722   connect( aStudy, SIGNAL( saved  ( SUIT_Study* ) ), this, SLOT( onStudySaved  ( SUIT_Study* ) ) );
723   connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
724
725 #ifndef DISABLE_PYCONSOLE
726   //to receive signal in application that NoteBook's variable was modified
727   connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
728            this, SIGNAL(notebookVarUpdated(QString)) );
729 #endif
730
731   return aStudy;
732 }
733
734 /*!
735   Enable/Disable menu items and toolbar buttons. Rebuild menu
736 */
737 void SalomeApp_Application::updateCommandsStatus()
738 {
739   LightApp_Application::updateCommandsStatus();
740
741   // Dump study menu
742   QAction* a = action( DumpStudyId );
743   if ( a )
744     a->setEnabled( activeStudy() );
745
746   // Load script menu
747   a = action( LoadScriptId );
748   if ( a )
749     a->setEnabled( activeStudy() );
750
751   // Properties menu
752   a = action( PropertiesId );
753   if( a )
754     a->setEnabled( activeStudy() );
755
756   // Save GUI state menu
757   a = action( SaveGUIStateId );
758   if( a )
759     a->setEnabled( activeStudy() );
760
761   // update state of Copy/Paste menu items
762   onSelectionChanged();
763 }
764
765 /*!
766   \class DumpStudyFileDlg
767   Private class used in Dump Study operation.  Consists 2 check boxes:
768   "Publish in study" and "Save GUI parameters"
769 */
770 class DumpStudyFileDlg : public SUIT_FileDlg
771 {
772 public:
773   DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
774   {
775     QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
776     if ( grid )
777     {
778       QWidget *hB = new QWidget( this );
779       myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
780       myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
781       mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
782
783       QHBoxLayout *layout = new QHBoxLayout;
784       layout->addWidget(myPublishChk);
785       layout->addWidget(myMultiFileChk);
786       layout->addWidget(mySaveGUIChk);
787       hB->setLayout(layout);
788
789       QPushButton* pb = new QPushButton(this);
790
791       int row = grid->rowCount();
792       grid->addWidget( new QLabel("", this), row, 0 );
793       grid->addWidget( hB, row, 1, 1, 3 );
794       grid->addWidget( pb, row, 5 );
795
796       pb->hide();
797     }
798   }
799   QCheckBox* myPublishChk;
800   QCheckBox* myMultiFileChk;
801   QCheckBox* mySaveGUIChk;
802 };
803
804 class DumpStudyFileValidator : public SUIT_FileValidator
805 {
806  public:
807   DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
808   virtual ~DumpStudyFileValidator() {};
809   virtual bool canSave( const QString& file, bool permissions );
810 };
811
812 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
813 {
814   QFileInfo fi( file );
815   if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
816     SUIT_MessageBox::critical( parent(),
817                                QObject::tr("WRN_WARNING"),
818                                QObject::tr("WRN_FILE_NAME_BAD") );
819     return false;
820   }
821   return SUIT_FileValidator::canSave( file, permissions);
822 }
823
824 /*!Private SLOT. On dump study.*/
825 void SalomeApp_Application::onDumpStudy( )
826 {
827   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
828   if ( !appStudy ) return;
829   _PTR(Study) aStudy = appStudy->studyDS();
830
831   QStringList aFilters;
832   aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
833
834   bool anIsPublish = true;
835   bool anIsMultiFile = false;
836   bool anIsSaveGUI = true;
837
838   if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
839     anIsPublish   = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
840     anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
841     anIsSaveGUI   = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
842   }
843
844   DumpStudyFileDlg fd( desktop() );
845   fd.setValidator( new DumpStudyFileValidator( &fd ) );
846   fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
847   fd.setFilters( aFilters );
848   fd.myPublishChk->setChecked( anIsPublish );
849   fd.myMultiFileChk->setChecked( anIsMultiFile );
850   fd.mySaveGUIChk->setChecked( anIsSaveGUI );
851   if ( fd.exec() == QDialog::Accepted )
852   {
853     QString aFileName = fd.selectedFile();
854
855     bool toPublish = fd.myPublishChk->isChecked();
856     bool isMultiFile = fd.myMultiFileChk->isChecked();
857     bool toSaveGUI = fd.mySaveGUIChk->isChecked();
858
859     if ( !aFileName.isEmpty() ) {
860       QFileInfo aFileInfo(aFileName);
861       if( aFileInfo.isDir() ) // IPAL19257
862         return;
863
864       // Issue 21377 - dump study implementation moved to SalomeApp_Study class
865       bool res;
866       {
867         SUIT_OverrideCursor wc;
868         res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
869       }
870       if ( !res )
871         SUIT_MessageBox::warning( desktop(),
872                                   QObject::tr("WRN_WARNING"),
873                                   tr("WRN_DUMP_STUDY_FAILED") );
874     }
875   }
876 }
877
878 /*!Private SLOT. On load script.*/
879 void SalomeApp_Application::onLoadScript( )
880 {
881   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
882   if ( !appStudy ) return;
883   _PTR(Study) aStudy = appStudy->studyDS();
884
885   if ( aStudy->GetProperties()->IsLocked() ) {
886     SUIT_MessageBox::warning( desktop(),
887                               QObject::tr("WRN_WARNING"),
888                               QObject::tr("WRN_STUDY_LOCKED") );
889     return;
890   }
891
892   QStringList filtersList;
893   filtersList.append(tr("PYTHON_FILES_FILTER"));
894   filtersList.append(tr("ALL_FILES_FILTER"));
895
896   QString anInitialPath = "";
897   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
898     anInitialPath = QDir::currentPath();
899   
900 #ifdef WITH_SIMANIO
901   // MPV: if it is SIMAN study, make the initial path as the path to the Siman scripts storage
902   if (myIsSiman) {
903     SALOMEDSClient_StudyManager* aMgr = studyMgr();
904     aMgr->GetSimanStudy()->StudyId();
905     anInitialPath = QString(QDir::separator()) + "tmp" + QDir::separator() + "SimanSalome" + QDir::separator() + 
906       aMgr->GetSimanStudy()->StudyId().c_str() + QDir::separator() +
907       aMgr->GetSimanStudy()->ScenarioId().c_str() + QDir::separator() + aMgr->GetSimanStudy()->UserId().c_str();
908   }
909 #endif
910
911   QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
912
913   if ( !aFile.isEmpty() )
914   {
915     QString command = QString("execfile(r\"%1\")").arg(aFile);
916
917 #ifndef DISABLE_PYCONSOLE
918     PyConsole_Console* pyConsole = pythonConsole();
919
920     if ( pyConsole )
921       pyConsole->exec( command );
922 #endif
923   }
924 }
925
926 /*!Private SLOT. On save GUI state.*/
927 void SalomeApp_Application::onSaveGUIState()
928 {
929   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
930   if ( study ) {
931     SalomeApp_VisualState( this ).storeState();
932     updateSavePointDataObjects( study );
933     updateObjectBrowser();
934   }
935   updateActions();
936 }
937
938 /*!Public SLOT. On SIMAN check in operation.*/
939 void SalomeApp_Application::onCheckIn()
940 {
941 #ifdef WITH_SIMANIO
942   setMenuShown(SimanCheckInId, false); // check in may be performed only once
943   setMenuShown(SimanLocalCheckInId, false);
944   SALOMEDSClient_StudyManager* aMgr = studyMgr();
945   aMgr->GetSimanStudy()->CheckIn("");
946 #else
947   printf( "****************************************************************\n" );
948   printf( "*    Warning: SALOME is built without SIMAN support.\n" );
949   printf( "****************************************************************\n" );
950 #endif
951 }
952
953 /*!Public SLOT. On SIMAN local check in operation.*/
954 void SalomeApp_Application::onLocalCheckIn()
955 {
956 #ifdef WITH_SIMANIO
957   // get the active module
958   CAM_Module* aModule = activeModule();
959   if (!aModule) return; // there is no active module
960   
961   setMenuShown(SimanCheckInId, false); // check in may be performed only once
962   setMenuShown(SimanLocalCheckInId, false);
963   SALOMEDSClient_StudyManager* aMgr = studyMgr();
964   aMgr->GetSimanStudy()->CheckIn(aModule->name().toLatin1().data());
965 #else
966   printf( "****************************************************************\n" );
967   printf( "*    Warning: SALOME is built without SIMAN support.\n" );
968   printf( "****************************************************************\n" );
969 #endif
970 }
971
972 /*!Gets file filter.
973  *\retval QString "(*.hdf)"
974  */
975 QString SalomeApp_Application::getFileFilter() const
976 {
977   return "(*.hdf)";
978 }
979
980 /*!Create window.*/
981 QWidget* SalomeApp_Application::createWindow( const int flag )
982 {
983   QWidget* wid = 0;
984 #ifndef DISABLE_PYCONSOLE
985   if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
986 #else
987   wid = LightApp_Application::createWindow(flag);
988 #endif
989
990   SUIT_ResourceMgr* resMgr = resourceMgr();
991
992   if ( flag == WT_ObjectBrowser )
993   {
994     SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
995     if ( ob ) {
996       // temporary commented
997       //ob->setUpdater( new SalomeApp_Updater() );
998
999 #ifdef WITH_SALOMEDS_OBSERVER
1000       //do not activate the automatic update of Qt tree through signal/slot
1001       ob->setAutoUpdate(false);
1002       //activate update of modified objects only
1003       ob->setUpdateModified(true);
1004 #endif
1005
1006       connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1007
1008       QString
1009         ValueCol = QObject::tr( "VALUE_COLUMN" ),
1010         IORCol = QObject::tr( "IOR_COLUMN" ),
1011         RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1012         EntryCol = QObject::tr( "ENTRY_COLUMN" );
1013
1014       SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1015       treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1016       treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1017       treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1018       treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1019       treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1020       treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1021       treeModel->setAppropriate( IORCol, Qtx::Toggled );
1022       treeModel->setAppropriate( RefCol, Qtx::Toggled );
1023
1024       bool autoSize      = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1025       bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1026       bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1027
1028       ob->setAutoSizeFirstColumn(autoSizeFirst);
1029       ob->setAutoSizeColumns(autoSize);
1030       ob->setResizeOnExpandItem(resizeOnExpandItem);
1031       ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
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_EnhConsole( desktop(), new SalomeApp_PyInterp() );
1055     pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1056     pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1057     pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1058     pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1059     wid = pyCons;
1060     //pyCons->resize( pyCons->width(), desktop()->height()/4 );
1061     pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
1062   }
1063   else if ( flag == WT_NoteBook )
1064   {
1065     SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1066     if ( appStudy ) {
1067       _PTR(Study) aStudy = appStudy->studyDS();
1068       setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1069       //to receive signal in NoteBook that it's variable was modified
1070       connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1071                getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1072     }
1073     wid = getNoteBook();
1074   }
1075 #endif
1076   return wid;
1077 }
1078
1079 /*!Create preferences.*/
1080 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1081 {
1082   LightApp_Application::createPreferences(pref);
1083
1084   if ( !pref )
1085     return;
1086
1087   int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1088   int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1089   int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1090   for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1091   {
1092     pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1093                          LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1094   }
1095   pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1096
1097   // adding preference to LightApp_Application handled preferences..  a bit of hacking with resources..
1098   int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1099   int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1100   pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1101   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1102   pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1103   pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1104   pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1105   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1106   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1107 }
1108
1109 /*!Update desktop title.*/
1110 void SalomeApp_Application::updateDesktopTitle() {
1111   QString aTitle = applicationName();
1112   QString aVer = applicationVersion();
1113   if ( !aVer.isEmpty() )
1114     aTitle += QString( " " ) + aVer;
1115
1116   if ( activeStudy() )
1117   {
1118     QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1119     if ( !sName.isEmpty() ) {
1120       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1121       if ( study ) {
1122         _PTR(Study) stdDS = study->studyDS();
1123         if(stdDS) {
1124           if ( stdDS->GetProperties()->IsLocked() ) {
1125             aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1126           } else {
1127             aTitle += QString( " - [%1]" ).arg( sName );
1128           }
1129         }
1130       }
1131     }
1132   }
1133
1134   desktop()->setWindowTitle( aTitle );
1135 }
1136
1137 int SalomeApp_Application::closeChoice( const QString& docName )
1138 {
1139   int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ), tr( "APPCLOSE_DESCRIPTION" ).arg( docName ),
1140                                           tr ("APPCLOSE_SAVE"), tr ("APPCLOSE_CLOSE"),
1141                                           tr ("APPCLOSE_UNLOAD"), tr ("APPCLOSE_CANCEL"), 0 );
1142
1143   int res = CloseCancel;
1144   if ( answer == 0 )
1145     res = CloseSave;
1146   else if ( answer == 1 )
1147     res = CloseDiscard;
1148   else if ( answer == 2 )
1149     res = CloseUnload;
1150
1151   return res;
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 CloseUnload:
1168     closePermanently = false;
1169     break;
1170   case CloseCancel:
1171   default:
1172     res = false;
1173   }
1174
1175   return res;
1176 }
1177
1178 int SalomeApp_Application::openChoice( const QString& aName )
1179 {
1180   int choice = LightApp_Application::openChoice( aName );
1181
1182   if ( QFileInfo( aName ).exists() ) {
1183     if ( choice == OpenNew ) { // The document isn't already open.
1184       bool exist = false;
1185       std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1186       for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1187         if ( aName == QString( lst[i].c_str() ) )
1188           exist = true;
1189       }
1190       // The document already exists in the study manager.
1191       // Do you want to reload it?
1192       if ( exist ) {
1193         int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1194                                                 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1195         if ( answer == SUIT_MessageBox::Yes )
1196           choice = OpenRefresh;
1197         else
1198           choice = OpenCancel;
1199       }
1200     }
1201   } else { // file is not exist on disk
1202     SUIT_MessageBox::warning( desktop(),
1203                               QObject::tr("WRN_WARNING"),
1204                               QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1205     return false;
1206   }
1207
1208   return choice;
1209 }
1210
1211 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1212 {
1213   bool res = false;
1214   int choice = aChoice;
1215   switch ( choice )
1216   {
1217   case OpenRefresh:
1218     {
1219       _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1220       if ( aStudy )
1221       {
1222         studyMgr()->Close( aStudy );
1223         choice = OpenNew;
1224       }
1225     }
1226   default:
1227     res = LightApp_Application::openAction( choice, aName );
1228     break;
1229   }
1230
1231   return res;
1232 }
1233
1234 /*!
1235   \brief Get map of the operations which can be performed
1236   on the module activation.
1237
1238   The method should return the map of the kind \c {<id>:<name>}
1239   where \c <id> is an integer identifier of the operation and
1240   \c <name> is a title for the button to be added to the
1241   dialog box. After user selects the required operation by the
1242   clicking the corresponding button in the dialog box, its identifier
1243   is passed to the moduleActionSelected() method to process
1244   the made choice.
1245
1246   \return map of the operations
1247   \sa moduleActionSelected()
1248 */
1249 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1250 {
1251   QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1252   opmap.insert( LoadStudyId,     tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1253   opmap.insert( NewAndScriptId,  tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1254   return opmap;
1255 }
1256
1257 /*!
1258   \brief Called when the used selectes required operation chosen
1259   from "Activate module" dialog box.
1260
1261   Performs the required operation according to the user choice.
1262
1263   \param id operation identifier
1264   \sa activateModuleActions()
1265 */
1266 void SalomeApp_Application::moduleActionSelected( const int id )
1267 {
1268   switch ( id ) {
1269   case LoadStudyId:
1270     onLoadDoc();
1271     break;
1272   case NewAndScriptId:
1273     onNewWithScript();
1274     break;
1275   default:
1276     LightApp_Application::moduleActionSelected( id );
1277     break;
1278   }
1279 }
1280
1281 /*!Gets CORBA::ORB_var*/
1282 CORBA::ORB_var SalomeApp_Application::orb()
1283 {
1284   ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1285   static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1286   return _orb;
1287 }
1288
1289 /*!Create and return SALOMEDS_StudyManager.*/
1290 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1291 {
1292   static _PTR(StudyManager) _sm;
1293   if(!_sm) _sm = ClientFactory::StudyManager();
1294   return _sm.get();
1295 }
1296
1297 /*!Create and return SALOME_NamingService.*/
1298 SALOME_NamingService* SalomeApp_Application::namingService()
1299 {
1300   static SALOME_NamingService _ns(orb());
1301   return &_ns;
1302 }
1303
1304 /*!Create and return SALOME_LifeCycleCORBA.*/
1305 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1306 {
1307   static SALOME_LifeCycleCORBA _lcc( namingService() );
1308   return &_lcc;
1309 }
1310
1311 /*!Private SLOT. On preferences.*/
1312 void SalomeApp_Application::onProperties()
1313 {
1314   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1315   if( !study )
1316     return;
1317
1318   _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1319   SB->NewCommand();
1320
1321   SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1322   int res = aDlg.exec();
1323   if( res==QDialog::Accepted && aDlg.isChanged() )
1324     SB->CommitCommand();
1325   else
1326     SB->AbortCommand();
1327
1328   //study->updateCaptions();
1329   updateDesktopTitle();
1330   updateActions();
1331 }
1332
1333 /*!Insert items in popup, which necessary for current application*/
1334 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1335 {
1336   LightApp_SelectionMgr* mgr = selectionMgr();
1337   bool cacheIsOn = mgr->isSelectionCacheEnabled();
1338   mgr->setSelectionCacheEnabled( true );
1339
1340   LightApp_Application::contextMenuPopup( type, thePopup, title );
1341
1342   // temporary commented
1343   /*OB_Browser* ob = objectBrowser();
1344   if ( !ob || type != ob->popupClientType() )
1345     return;*/
1346
1347   // Get selected objects
1348   SALOME_ListIO aList;
1349   mgr->selectedObjects( aList, QString(), false );
1350
1351   // add GUI state commands: restore, rename
1352   if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1353        QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1354     thePopup->addSeparator();
1355     thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1356     thePopup->addAction( tr( "MEN_RENAME_VS" ),  objectBrowser(),
1357                          SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1358     thePopup->addAction( tr( "MEN_DELETE_VS" ),  this, SLOT( onDeleteGUIState() ) );
1359   }
1360
1361   // "Delete reference" item should appear only for invalid references
1362
1363   // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1364   bool isInvalidRefs = false;
1365   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1366   _PTR(Study) aStudyDS = aStudy->studyDS();
1367   _PTR(SObject) anObj;
1368
1369   for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1370     if( it.Value()->hasEntry() )
1371     {
1372       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1373       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1374         aRefObj = anObj;
1375
1376       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1377         isInvalidRefs = true;
1378     }
1379
1380   // Add "Delete reference" item to popup
1381   if ( isInvalidRefs )
1382   {
1383     thePopup->addSeparator();
1384     thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1385     return;
1386   }
1387
1388   // "Activate module" item should appear only if it's necessary
1389   if ( aList.Extent() == 1 ) {
1390     aList.Clear();
1391     mgr->selectedObjects( aList );
1392
1393     Handle(SALOME_InteractiveObject) aIObj = aList.First();
1394
1395     // add extra popup menu (defined in XML)
1396     if ( myExtActions.size() > 0 ) {
1397       // Use only first selected object
1398       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1399       if ( study ) {
1400         _PTR(Study) stdDS = study->studyDS();
1401         if ( stdDS ) {
1402           _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1403           if ( aSO ) {
1404             _PTR( GenericAttribute ) anAttr;
1405             std::string auid = "AttributeUserID";
1406             auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1407             if ( aSO->FindAttribute( anAttr, auid ) ) {
1408               _PTR(AttributeUserID) aAttrID = anAttr;
1409               QString aId = aAttrID->Value().c_str();
1410               if ( myExtActions.contains( aId ) ) {
1411                 thePopup->addAction(myExtActions[aId]);
1412               }
1413             }
1414           }
1415         }
1416       }
1417     }
1418
1419     // check if item is a "GUI state" item (also a first level object)
1420     QString entry( aIObj->getEntry() );
1421     if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1422       QString aModuleName( aIObj->getComponentDataType() );
1423       QString aModuleTitle = moduleTitle( aModuleName );
1424       CAM_Module* currentModule = activeModule();
1425       if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1426         thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1427     }
1428   }
1429
1430   mgr->setSelectionCacheEnabled( cacheIsOn );
1431 }
1432
1433 /*!Update obect browser:
1434  1.if 'updateModels' true, update existing data models;
1435  2. update "non-existing" (not loaded yet) data models;
1436  3. update object browser if it exists */
1437 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1438 {
1439   // update "non-existing" (not loaded yet) data models
1440   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1441   if ( study )
1442   {
1443     _PTR(Study) stdDS = study->studyDS();
1444     if( stdDS )
1445     {
1446       for ( _PTR(SComponentIterator) it ( stdDS->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
1465   // create data objects that correspond to GUI state save points
1466   if ( study ) updateSavePointDataObjects( study );
1467
1468   // update existing data models (already loaded SComponents)
1469   LightApp_Application::updateObjectBrowser( updateModels );
1470 }
1471
1472 /*!Display Catalog Genenerator dialog */
1473 void SalomeApp_Application::onCatalogGen()
1474 {
1475   ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1476   aDlg.exec();
1477 }
1478
1479 /*!Display Registry Display dialog */
1480 void SalomeApp_Application::onRegDisplay()
1481 {
1482   CORBA::ORB_var anOrb = orb();
1483   ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1484   regWnd->show();
1485   regWnd->raise();
1486   regWnd->activateWindow();
1487 }
1488
1489 /*!find original object by double click on item */
1490 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1491 {
1492   // Issue 21379: References are supported at LightApp_DataObject level
1493   LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1494
1495   if( obj && obj->isReference() )
1496   {
1497     QString entry = obj->refEntry();
1498
1499     SUIT_DataOwnerPtrList aList;
1500     aList.append( new LightApp_DataOwner( entry ) );
1501     selectionMgr()->setSelected( aList, false );
1502
1503     SUIT_DataBrowser* ob = objectBrowser();
1504
1505     QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1506     if ( !aSelectedIndexes.isEmpty() )
1507       ob->treeView()->scrollTo( aSelectedIndexes.first() );
1508   }
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 ( int 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   _PTR(Study) studyDS = study->studyDS();
1889
1890   // get unique temporary directory name
1891   QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1892   if( aTmpDir.isEmpty() )
1893     return false;
1894
1895   if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1896     aTmpDir.remove( aTmpDir.length() - 1, 1 );
1897
1898   // dump study to the temporary directory
1899   QString aScriptName( "notebook" );
1900   bool toPublish = true;
1901   bool isMultiFile = false;
1902   bool toSaveGUI = true;
1903
1904   int savePoint;
1905   _PTR(AttributeParameter) ap;
1906   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1907   if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1908   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1909     ip->setDumpPython(studyDS);
1910     savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1911   }
1912   bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1913   if ( toSaveGUI )
1914     study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1915
1916   if( ok )
1917     myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1918   else
1919     return false;
1920
1921   QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1922   int anIndex = aList.indexOf( this );
1923
1924   // Disconnect dialog from application desktop in case if:
1925   // 1) Application is not the first application in the session
1926   // 2) Application is the first application in session but not the only.
1927   bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1928   if( changeDesktop ) {
1929
1930     SalomeApp_Application* app = this;
1931     if( anIndex > 0 && anIndex < aList.count() )
1932       app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1933     else if(anIndex == 0 && aList.count() > 1)
1934       app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1935
1936     if( !app )
1937       return false;
1938
1939     // creation a new study and restoring will be done in another application
1940     connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1941              app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1942   }
1943
1944   QString aDumpScript = myNoteBook->getDumpedStudyScript();
1945   QString aStudyName = myNoteBook->getDumpedStudyName();
1946   bool isStudySaved = myNoteBook->isDumpedStudySaved();
1947   // clear a study (delete all objects)
1948   onCloseDoc( false );
1949
1950   if( !changeDesktop ) {
1951     ok = onRestoreStudy( aDumpScript,
1952                          aStudyName,
1953                          isStudySaved );
1954   }
1955
1956   return ok;
1957 }
1958 #endif
1959
1960 //============================================================================
1961 /*! Function : onRestoreStudy
1962  *  Purpose  : Load the dumped study from Python script
1963  */
1964 //============================================================================
1965 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
1966                                             const QString& theStudyName,
1967                                             bool theIsStudySaved )
1968 {
1969   bool ok = true;
1970
1971   // create a new study
1972   onNewDoc();
1973
1974   // get active application
1975   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1976
1977   // load study from the temporary directory
1978   QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
1979
1980 #ifndef DISABLE_PYCONSOLE
1981   PyConsole_Console* pyConsole = app->pythonConsole();
1982   if ( pyConsole )
1983     pyConsole->execAndWait( command );
1984 #endif
1985
1986   // remove temporary directory
1987   QFileInfo aScriptInfo = QFileInfo( theDumpScript );
1988   QString aStudyName = aScriptInfo.baseName();
1989   QDir aDir = aScriptInfo.absoluteDir();
1990   QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
1991   for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
1992     ok = aDir.remove( *it ) && ok;
1993   if( ok )
1994     ok = aDir.rmdir( aDir.absolutePath() );
1995
1996   if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
1997   {
1998 #ifndef DISABLE_PYCONSOLE
1999     _PTR(Study) aStudyDS = newStudy->studyDS();
2000     app->getNoteBook()->Init( aStudyDS );
2001     newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2002     newStudy->Modified();
2003     updateDesktopTitle();
2004     updateActions();
2005 #endif
2006   }
2007   else
2008     ok = false;
2009
2010   return ok;
2011 }
2012
2013 /*!
2014   Close the Application
2015 */
2016 void SalomeApp_Application::afterCloseDoc()
2017 {
2018 #ifndef DISABLE_PYCONSOLE
2019   // emit signal to restore study from Python script
2020   if ( myNoteBook ) {
2021     emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2022                             myNoteBook->getDumpedStudyName(),
2023                             myNoteBook->isDumpedStudySaved() );
2024   }
2025 #endif
2026   LightApp_Application::afterCloseDoc();
2027 }