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