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