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