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