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