Salome HOME
Merge from V6_main 01/04/2013
[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
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()
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   myNoteBook = theNoteBook;
1612 }
1613
1614 /*! Return SalomeApp_NoteBook pointer */
1615 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1616 {
1617   return myNoteBook;
1618 }
1619
1620 /*!
1621  * Define extra actions defined in module definition XML file.
1622  * Additional popup items sections can be defined by parameter "popupitems".
1623  * Supported attributes:
1624  * title - title of menu item,
1625  * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1626  * method - method which has to be called when menu item is selected
1627  * Example:
1628  * <section name="MODULENAME">
1629  *   <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1630  * </section>
1631  * <section name="importmed">
1632  *   <parameter name="title" value="My menu"/>
1633  *   <parameter name="objectid" value="VISU.Result"/>
1634  *   <parameter name="method" value="nameOfModuleMethod"/>
1635  * </section>
1636  */
1637 void SalomeApp_Application::createExtraActions()
1638 {
1639   myExtActions.clear();
1640   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1641
1642   QStringList aModules;
1643   modules(aModules, false);
1644   foreach(QString aModile, aModules) {
1645     QString aModName = moduleName(aModile);
1646     QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1647     if (!aSectionStr.isNull()) {
1648       QStringList aSections = aSectionStr.split(':');
1649       foreach(QString aSection, aSections) {
1650         QString aTitle = resMgr->stringValue(aSection, "title",    QString());
1651         QString aId    = resMgr->stringValue(aSection, "objectid", QString());
1652         QString aSlot  = resMgr->stringValue(aSection, "method",   QString());
1653         if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1654           continue;
1655
1656         QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1657         if (aModuleName.isNull())
1658           aModuleName = aModName;
1659
1660         QAction* aAction = new QAction(aTitle, this);
1661         QStringList aData;
1662         aData<<aModuleName<<aSlot;
1663         aAction->setData(aData);
1664         connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1665         myExtActions[aId] = aAction;
1666       }
1667     }
1668   }
1669 }
1670
1671 /*!
1672  * Called when extra action is selected
1673  */
1674 void SalomeApp_Application::onExtAction()
1675 {
1676   QAction* aAction = ::qobject_cast<QAction*>(sender());
1677   if (!aAction)
1678     return;
1679
1680   QVariant aData = aAction->data();
1681   QStringList aDataList = aData.value<QStringList>();
1682   if (aDataList.size() != 2)
1683     return;
1684
1685   LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1686   SALOME_ListIO aListIO;
1687   aSelectionMgr->selectedObjects(aListIO);
1688   const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1689   if (aListIO.Extent() < 1)
1690     return;
1691   if (!anIO->hasEntry())
1692     return;
1693
1694   QString aEntry(anIO->getEntry());
1695
1696   QApplication::setOverrideCursor( Qt::WaitCursor );
1697   QString aModuleTitle = moduleTitle(aDataList[0]);
1698   activateModule(aModuleTitle);
1699   QApplication::restoreOverrideCursor();
1700
1701   QCoreApplication::processEvents();
1702
1703   CAM_Module* aModule = activeModule();
1704   if (!aModule)
1705     return;
1706
1707   if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1708     printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1709 }
1710
1711 /*!
1712  * Called when window activated
1713  */
1714 void SalomeApp_Application::onWindowActivated( SUIT_ViewWindow* theViewWindow )
1715 {
1716   SUIT_DataBrowser* anOB = objectBrowser();
1717   if( !anOB )
1718     return;
1719   SUIT_DataObject* rootObj = anOB->root();
1720   if( !rootObj )
1721     return;
1722
1723   DataObjectList listObj = rootObj->children( true );
1724
1725   SUIT_ViewModel* vmod = 0;
1726   if ( SUIT_ViewManager* vman = theViewWindow->getViewManager() )
1727     vmod = vman->getViewModel();
1728   updateVisibilityState( listObj, vmod );
1729 }
1730
1731 /*!
1732   Update visibility state of given objects
1733  */
1734 void SalomeApp_Application::updateVisibilityState( DataObjectList& theList,
1735                                                    SUIT_ViewModel*  theViewModel )
1736 {
1737   LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1738
1739   if(!theViewModel)
1740     return;
1741
1742   SALOME_View* aView = dynamic_cast<SALOME_View*>( theViewModel );
1743
1744   if (theList.isEmpty() || !aView || !aStudy)
1745     return;
1746
1747   for ( DataObjectList::iterator itr = theList.begin(); itr != theList.end(); ++itr ) {
1748     LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>(*itr);
1749
1750     if (!obj || aStudy->isComponent(obj->entry()))
1751       continue;
1752
1753     LightApp_Module* anObjModule = dynamic_cast<LightApp_Module*>(obj->module());
1754     Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
1755
1756     if(anObjModule) {
1757       LightApp_Displayer* aDisplayer = anObjModule->displayer();
1758       if(aDisplayer) {
1759         if( aDisplayer->canBeDisplayed(obj->entry(), theViewModel->getType()) ) {
1760           if(aDisplayer->IsDisplayed(obj->entry(),aView))
1761             anObjState = Qtx::ShownState;
1762           else
1763             anObjState = Qtx::HiddenState;
1764         }
1765       }
1766       aStudy->setVisibilityState( obj->entry(), anObjState );
1767     }
1768   }
1769 }
1770
1771 /*!
1772   Called then view manager removed
1773 */
1774 void SalomeApp_Application::onViewManagerRemoved( SUIT_ViewManager* )
1775 {
1776   ViewManagerList lst;
1777   viewManagers(lst);
1778   if( lst.count() == 1) { // in case if closed last view window
1779     LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1780     if(aStudy)
1781       aStudy->setVisibilityStateForAll(Qtx::UnpresentableState);
1782   }
1783 }
1784
1785 /*!
1786   Checks that an object can be renamed.
1787   \param entry entry of the object
1788   \brief Return \c true if object can be renamed
1789 */
1790 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1791 {
1792   return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1793 }
1794
1795 /*!
1796   Rename object by entry.
1797   \param entry entry of the object
1798   \param name new name of the object
1799   \brief Return \c true if rename operation finished successfully, \c false otherwise.
1800 */
1801 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1802 {
1803   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1804
1805   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1806
1807   if(!aStudy || savePoint == -1)
1808     return false;
1809
1810   if ( !name.isNull() && !name.isEmpty() ) {
1811     aStudy->setNameOfSavePoint( savePoint, name );
1812     updateSavePointDataObjects( aStudy );
1813
1814     //Mark study as modified
1815     aStudy->Modified();
1816     return true;
1817   }
1818   return false;
1819 }
1820
1821 /*!
1822   \return default windows( Object Browser, Python Console )
1823   Adds to map \a aMap.
1824 */
1825 void SalomeApp_Application::defaultWindows( QMap<int, int>& aMap ) const
1826 {
1827   LightApp_Application::defaultWindows(aMap);
1828   if ( !aMap.contains( WT_NoteBook ) ) { 
1829     if ( !myNoteBook ) {
1830       aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1831     }
1832   }
1833 }
1834
1835 /*!
1836   Gets current windows.
1837   \param winMap - output current windows map.
1838 */
1839 void SalomeApp_Application::currentWindows(QMap<int, int>& aMap) const
1840 {
1841   LightApp_Application::currentWindows( aMap );
1842   if ( !aMap.contains( WT_NoteBook) && myNoteBook )
1843     aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1844 }
1845
1846 //============================================================================
1847 /*! Function : onUpdateStudy
1848  *  Purpose  : Slot to update the study.
1849  */
1850 //============================================================================
1851 void SalomeApp_Application::onUpdateStudy()
1852 {
1853   QApplication::setOverrideCursor( Qt::WaitCursor );
1854
1855   if( !updateStudy() )
1856     SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1857     
1858   QApplication::restoreOverrideCursor();
1859 }
1860
1861 //============================================================================
1862 /*! Function : updateStudy
1863  *  Purpose  : Update study by dumping the study to Python script and loading it.
1864  *             It is used to apply variable modifications done in NoteBook to created objects.
1865  */
1866 //============================================================================
1867 bool SalomeApp_Application::updateStudy()
1868 {
1869   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1870   if ( !study || !myNoteBook )
1871     return false;
1872
1873   myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1874   myNoteBook->setDumpedStudyName( study->studyName() );
1875
1876   _PTR(Study) studyDS = study->studyDS();
1877
1878   // get unique temporary directory name
1879   QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1880   if( aTmpDir.isEmpty() )
1881     return false;
1882
1883   if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1884     aTmpDir.remove( aTmpDir.length() - 1, 1 );
1885
1886   // dump study to the temporary directory
1887   QString aScriptName( "notebook" );
1888   bool toPublish = true;
1889   bool isMultiFile = false;
1890   bool toSaveGUI = true;
1891
1892   int savePoint;
1893   _PTR(AttributeParameter) ap;
1894   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1895   if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1896   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1897     ip->setDumpPython(studyDS);
1898     savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1899   }
1900   bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1901   if ( toSaveGUI )
1902     study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1903
1904   if( ok )
1905     myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1906   else
1907     return false;
1908
1909   QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1910   int anIndex = aList.indexOf( this );
1911
1912   // Disconnect dialog from application desktop in case if:
1913   // 1) Application is not the first application in the session 
1914   // 2) Application is the first application in session but not the only.
1915   bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1916
1917   SalomeApp_Application* app;
1918   if( anIndex > 0 && anIndex < aList.count() )
1919     app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1920   else if(anIndex == 0 && aList.count() > 1)
1921     app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1922
1923   if( !app )
1924     return false;
1925
1926   if( changeDesktop ) {
1927     // creation a new study and restoring will be done in another application
1928     connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1929              app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1930   }
1931
1932   QString aDumpScript = myNoteBook->getDumpedStudyScript();
1933   QString aStudyName = myNoteBook->getDumpedStudyName();
1934   bool isStudySaved = myNoteBook->isDumpedStudySaved();
1935   // clear a study (delete all objects)
1936   onCloseDoc( false );
1937
1938   if( !changeDesktop ) {
1939     ok = onRestoreStudy( aDumpScript, 
1940                          aStudyName, 
1941                          isStudySaved );
1942   }
1943
1944   return ok;
1945 }
1946
1947 //============================================================================
1948 /*! Function : onRestoreStudy
1949  *  Purpose  : Load the dumped study from Python script
1950  */
1951 //============================================================================
1952 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript, 
1953                                             const QString& theStudyName, 
1954                                             bool theIsStudySaved )
1955 {
1956   bool ok = true;
1957
1958   // create a new study
1959   onNewDoc();
1960
1961   // get active application
1962   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1963
1964   // load study from the temporary directory
1965   QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
1966
1967   PyConsole_Console* pyConsole = app->pythonConsole();
1968   if ( pyConsole )
1969     pyConsole->execAndWait( command );
1970
1971   // remove temporary directory
1972   QFileInfo aScriptInfo = QFileInfo( theDumpScript );
1973   QString aStudyName = aScriptInfo.baseName();
1974   QDir aDir = aScriptInfo.absoluteDir();
1975   QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
1976   for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
1977     ok = aDir.remove( *it ) && ok;
1978   if( ok )
1979     ok = aDir.rmdir( aDir.absolutePath() );
1980
1981   if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
1982   {
1983     _PTR(Study) aStudyDS = newStudy->studyDS();
1984     app->getNoteBook()->Init( aStudyDS );
1985     newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
1986     newStudy->Modified();
1987     updateDesktopTitle();
1988     updateActions();
1989   }
1990   else
1991     ok = false;
1992
1993   return ok;
1994 }
1995
1996 /*!
1997   Close the Application
1998 */
1999 void SalomeApp_Application::closeApplication()
2000 {
2001   // emit signal to restore study from Python script
2002   if ( myNoteBook ) {
2003     emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(), 
2004                             myNoteBook->getDumpedStudyName(), 
2005                             myNoteBook->isDumpedStudySaved() );
2006   }
2007   LightApp_Application::closeApplication();
2008 }