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