]> SALOME platform Git repositories - modules/gui.git/blob - src/SalomeApp/SalomeApp_Application.cxx
Salome HOME
802d7d7b0fd5ea10fc7d4ff3161750f9ff73592f
[modules/gui.git] / src / SalomeApp / SalomeApp_Application.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // File:      SalomeApp_Application.cxx
20 // Created:   10/22/2004 3:23:45 PM
21 // Author:    Sergey LITONIN
22 // Copyright (C) CEA 2004
23
24 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
25
26 #include "SalomeApp_Application.h"
27
28 #include "SalomeApp_Study.h"
29 #include "SalomeApp_DataModel.h"
30 #include "SalomeApp_DataObject.h"
31 #include "SalomeApp_EventFilter.h"
32 #include "SalomeApp_VisualState.h"
33 #include "SalomeApp_ExitDlg.h"
34
35 #include "SalomeApp_StudyPropertiesDlg.h"
36
37 #include "LightApp_Application.h"
38 #include "LightApp_Preferences.h"
39 #include "LightApp_WidgetContainer.h"
40 #include "LightApp_SelectionMgr.h"
41 #include "LightApp_NameDlg.h"
42
43 #include "STD_LoadStudiesDlg.h"
44
45 #include <SUIT_Tools.h>
46 #include <SUIT_Session.h>
47 #include <SUIT_MsgDlg.h>
48
49 #include <QtxMRUAction.h>
50
51 #include <OB_Browser.h>
52 #include <OB_ListItem.h>
53
54 #include <PythonConsole_PyConsole.h>
55
56 #include <SUIT_FileDlg.h>
57 #include <SUIT_MessageBox.h>
58 #include <SUIT_ResourceMgr.h>
59 #include <SUIT_ActionOperation.h>
60
61 #include <Utils_ORB_INIT.hxx>
62 #include <Utils_SINGLETON.hxx>
63 #include <SALOME_ModuleCatalog_impl.hxx>
64 #include <SALOME_LifeCycleCORBA.hxx>
65
66 #include <qaction.h>
67 #include <qcombobox.h>
68 #include <qlistbox.h>
69 #include <qregexp.h>
70 #include <qcheckbox.h>
71 #include <qpushbutton.h>
72 #include <qlabel.h>
73 #include <qmessagebox.h>
74
75 #include "SALOMEDSClient_ClientFactory.hxx"
76 #include "SALOMEDSClient_IParameters.hxx"
77
78 #include "SALOME_ListIteratorOfListIO.hxx"
79 #include "SALOME_ListIO.hxx"
80
81 #include "ToolsGUI_CatalogGeneratorDlg.h"
82 #include "ToolsGUI_RegWidget.h"
83
84 #include <SALOMEDSClient_ClientFactory.hxx>
85
86 #include <vector>
87 /*!Internal class that updates object browser item properties */
88 class SalomeApp_Updater : public OB_Updater
89 {
90 public:
91   SalomeApp_Updater() : OB_Updater(){};
92   virtual ~SalomeApp_Updater(){};
93   virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
94 };
95
96 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
97 {
98   if( !theObj || !theItem )
99     return;
100
101   SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
102   if( !SAObj )
103     return;
104   
105   _PTR(SObject) SObj = SAObj->object();
106   if( !SObj )
107     return;
108   _PTR( GenericAttribute ) anAttr;
109
110   // Selectable
111   if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
112   {
113     _PTR(AttributeSelectable) aAttrSel = anAttr;
114     theItem->setSelectable( aAttrSel->IsSelectable() );
115   }
116   // Expandable
117   if ( SObj->FindAttribute(anAttr, "AttributeExpandable") ) 
118   {
119     _PTR(AttributeExpandable) aAttrExpand = anAttr;
120     theItem->setExpandable( aAttrExpand->IsExpandable() );
121   }
122   // Opened
123   //this attribute is not supported in the version of SALOME 3.x
124   //if ( SObj->FindAttribute(anAttr, "AttributeOpened") ) 
125   //{
126   //  _PTR(AttributeOpened) aAttrOpen = anAttr;
127   //  theItem->setOpen( aAttrOpen->IsOpened() );
128   //}
129 }
130
131 /*!Create new instance of SalomeApp_Application.*/
132 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
133 {
134   return new SalomeApp_Application();
135 }
136
137 /*!Constructor.*/
138 SalomeApp_Application::SalomeApp_Application()
139 : LightApp_Application()
140 {
141   connect( desktop(), SIGNAL( message( const QString& ) ), 
142            this,      SLOT( onDesktopMessage( const QString& ) ) );
143 }
144
145 /*!Destructor.
146  *\li Destroy event filter.
147  */
148 SalomeApp_Application::~SalomeApp_Application()
149 {
150   // Do not destroy. It's a singleton !
151   //SalomeApp_EventFilter::Destroy();
152 }
153
154 /*!Start application.*/
155 void SalomeApp_Application::start()
156 {
157   LightApp_Application::start();
158
159   SalomeApp_EventFilter::Init();
160
161   static bool isFirst = true;
162   if ( isFirst ) {
163     isFirst = false;
164
165     QString hdffile;
166     QStringList pyfiles;
167
168     for (int i = 1; i < qApp->argc(); i++) {
169       QRegExp rxs ("--study-hdf=(.+)");
170       if ( rxs.search( QString(qApp->argv()[i]) ) >= 0 && rxs.capturedTexts().count() > 1 ) {
171         QString file = rxs.capturedTexts()[1];
172         QFileInfo fi ( file );
173         QString extension = fi.extension( false ).lower();
174         if ( extension == "hdf" && fi.exists() )
175           hdffile = fi.absFilePath();
176       }
177       else {
178         QRegExp rxp ("--pyscript=(.+)");
179         if ( rxp.search( QString(qApp->argv()[i]) ) >= 0 && rxp.capturedTexts().count() > 1 ) {
180           QStringList files = QStringList::split(",",rxp.capturedTexts()[1],false);
181           pyfiles += files;
182         }
183       }
184     }
185
186     if ( !hdffile.isEmpty() )       // open hdf file given as parameter
187       onOpenDoc( hdffile );
188     else if ( pyfiles.count() > 0 ) // create new study
189       onNewDoc();
190
191     // import/execute python scripts
192     if ( pyfiles.count() > 0 && activeStudy() ) {
193       SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
194       if ( appStudy ) {
195         _PTR(Study) aStudy = appStudy->studyDS();
196         if ( !aStudy->GetProperties()->IsLocked() ) {
197           for (uint j = 0; j < pyfiles.count(); j++ ) {
198             QFileInfo fi ( pyfiles[j] );
199             PythonConsole* pyConsole = pythonConsole();
200             if ( pyConsole ) {
201               QString extension = fi.extension( false ).lower();
202               if ( fi.exists() ) {
203                 // execute python script
204                 QString command = QString( "execfile(\"%1\")" ).arg( fi.absFilePath() );
205                 pyConsole->exec( command );
206               }
207               else {
208                 // import python module
209                 QString command = QString( "import %1" ).arg( pyfiles[j] );
210                 if ( extension == "py" )
211                   command = QString( "import %1" ).arg( fi.baseName( true ) );
212                 pyConsole->exec( command );
213               }
214             }
215           }
216         }
217       }
218     }
219   }
220 }
221
222 /*!Create actions:*/
223 void SalomeApp_Application::createActions()
224 {
225   LightApp_Application::createActions();
226
227   SUIT_Desktop* desk = desktop();
228   
229   //! Save GUI state
230   // "Save GUI State" command is moved to VISU module
231   //  createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIconSet(),
232   //            tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
233   //            0, desk, false, this, SLOT( onSaveGUIState() ) );
234   
235   //! Dump study
236   createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIconSet(),
237                 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
238                 CTRL+Key_D, desk, false, this, SLOT( onDumpStudy() ) );
239     
240   //! Load script
241   createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIconSet(),
242                 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
243                 CTRL+Key_T, desk, false, this, SLOT( onLoadScript() ) );
244
245   //! Properties
246   createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIconSet(),
247                 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
248                 CTRL+Key_P, desk, false, this, SLOT( onProperties() ) );
249
250   //! Catalog Generator
251   createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ),  QIconSet(),
252                 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
253                 SHIFT+Key_G, desk, false, this, SLOT( onCatalogGen() ) );
254
255   //! Registry Display
256   createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ),  QIconSet(),
257                 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
258                 /*SHIFT+Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
259
260   //SRN: BugID IPAL9021, add an action "Load"
261   createAction( FileLoadId, tr( "TOT_DESK_FILE_LOAD" ),
262                 resourceMgr()->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
263                 tr( "MEN_DESK_FILE_LOAD" ), tr( "PRP_DESK_FILE_LOAD" ),
264                 CTRL+Key_L, desk, false, this, SLOT( onLoadDoc() ) );
265   //SRN: BugID IPAL9021: End
266
267
268   int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
269
270   // "Save GUI State" command is renamed to "Save VISU State" and 
271   // creation of menu item is moved to VISU
272   //  createMenu( SaveGUIStateId, fileMenu, 10, -1 ); 
273
274   createMenu( FileLoadId,   fileMenu, 0 );  //SRN: BugID IPAL9021, add a menu item "Load"
275
276   createMenu( DumpStudyId, fileMenu, 10, -1 );
277   createMenu( separator(), fileMenu, -1, 15, -1 );
278   createMenu( LoadScriptId, fileMenu, 10, -1 );
279   createMenu( separator(), fileMenu, -1, 15, -1 );
280   createMenu( PropertiesId, fileMenu, 10, -1 );
281   createMenu( separator(), fileMenu, -1, 15, -1 );
282
283   int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
284   createMenu( CatalogGenId, toolsMenu, 10, -1 );
285   createMenu( RegDisplayId, toolsMenu, 10, -1 );
286   createMenu( separator(), toolsMenu, -1, 15, -1 );
287 }
288
289 /*! Purpose : SLOT. Open new document with \a aName.*/
290 bool SalomeApp_Application::onOpenDoc( const QString& aName )
291 {
292   bool res = false, toOpen = true, isAlreadyOpen = false;
293
294   // Look among opened studies
295   if (activeStudy()) { // at least one study is opened
296     SUIT_Session* aSession = SUIT_Session::session();
297     QPtrList<SUIT_Application> aAppList = aSession->applications();
298     QPtrListIterator<SUIT_Application> it (aAppList);
299     SUIT_Application* aApp = 0;
300     // iterate on all applications
301     for (; (aApp = it.current()) && !isAlreadyOpen; ++it) {
302       if (aApp->activeStudy()->studyName() == aName) {
303         isAlreadyOpen = true; // Already opened, ask user what to do
304
305         // The document ... is already open.
306         // Do you want to reload it?
307         int aAnswer = SUIT_MessageBox::warn2(desktop(), tr("WRN_WARNING"),
308                                              tr("QUE_DOC_ALREADYOPEN").arg(aName),
309                                              tr("BUT_YES"), tr("BUT_NO"), 1, 2, 2);
310         if (aAnswer == 1) { // reload
311           if (activeStudy()->studyName() == aName && aAppList.count() > 1) {
312             // Opened in THIS (active) application.
313             STD_Application* app1 = (STD_Application*)aAppList.at(0);
314             STD_Application* app2 = (STD_Application*)aAppList.at(1);
315             if (!app1 || !app2) {
316               // Error
317               return false;
318             }
319             if (app1->activeStudy()->studyName() == aName) {
320               // app1 is this application, we need another one
321               app1 = app2;
322             }
323             // Close document of this application. This application will be destroyed.
324             onCloseDoc(/*ask = */false);
325             // Open the file with another application, as this one will be destroyed.
326             return app1->onOpenDoc(aName);
327           } else {
328             // Opened in another application.
329             STD_Application* app = (STD_Application*)aApp;
330             if (app)
331               app->onCloseDoc(/*ask = */false);
332           }
333         } else { // do not reload
334           // OK, the study will not be reloaded, but we call
335           // CAM_Application::onOpenDoc( aName ) all the same.
336           // It will activate a desktop of the study <aName>.
337         }
338       }
339     }
340   }
341
342   // Look among unloaded studies
343   if (!isAlreadyOpen) {
344     std::vector<std::string> List = studyMgr()->GetOpenStudies();
345
346     QString studyName;
347     for (unsigned int ind = 0; ind < List.size() && !isAlreadyOpen; ind++) {
348       studyName = List[ind].c_str();
349       if (aName == studyName) {
350         // Already exists unloaded, ask user what to do
351         isAlreadyOpen = true;
352
353         // The document ... already exists in the study manager.
354         // Do you want to reload it?
355         int aAnswer = SUIT_MessageBox::warn2(desktop(), tr("WRN_WARNING"),
356                                              tr("QUE_DOC_ALREADYEXIST").arg(aName),
357                                              tr("BUT_YES"), tr("BUT_NO"), 1, 2, 2);
358         if (aAnswer == 1) {
359           _PTR(Study) aStudy = studyMgr()->GetStudyByName(aName.latin1());
360           if (aStudy)
361             studyMgr()->Close(aStudy);
362         } else {
363           toOpen = false;
364         }
365       }
366     }
367   }
368
369   if (toOpen)
370     res = CAM_Application::onOpenDoc( aName );
371
372   QAction* a = action( MRUId );
373   if ( a && a->inherits( "QtxMRUAction" ) )
374   {
375     QtxMRUAction* mru = (QtxMRUAction*)a;
376     if ( res )
377       mru->insert( aName );
378     else
379       mru->remove( aName );
380   }
381   return res;
382 }
383
384 /*!SLOT. Load document.*/
385 void SalomeApp_Application::onLoadDoc()
386 {
387   QString name, studyname, ext;
388
389   STD_LoadStudiesDlg aDlg( desktop(), TRUE);
390
391   std::vector<std::string> List = studyMgr()->GetOpenStudies();
392
393   SUIT_Session* aSession = SUIT_Session::session();
394   QPtrList<SUIT_Application> aAppList = aSession->applications();
395   SUIT_Application* aApp = 0;
396
397   for (unsigned int ind = 0; ind < List.size(); ind++) {
398      studyname = List[ind].c_str();
399      //Add to list only unloaded studies
400      bool isAlreadyOpen = false;
401      for ( QPtrListIterator<SUIT_Application> it( aAppList ); it.current() && !isAlreadyOpen; ++it )
402        {
403          aApp = it.current();
404          if(!aApp || !aApp->activeStudy()) continue;
405          if ( aApp->activeStudy()->studyName() == studyname ) isAlreadyOpen = true;
406        }
407
408      if ( !isAlreadyOpen ) aDlg.ListComponent->insertItem( studyname );
409   }
410
411   int retVal = aDlg.exec();
412   studyname = aDlg.ListComponent->currentText();
413
414   if (retVal == QDialog::Rejected)
415     return;
416
417   if ( studyname.isNull() || studyname.isEmpty() )
418     return;
419
420   name = studyname;
421 #ifndef WNT
422   //this code replace marker of windows drive and path become invalid therefore 
423   // defines placed there
424   name.replace( QRegExp(":"), "/" );
425 #endif
426
427   if( LightApp_Application::onLoadDoc( name ) )
428   {
429      updateWindows();
430      updateViewManagers();
431      updateObjectBrowser(true);
432   }
433 }
434
435 /*!
436   \brief Close application.
437 */
438 void SalomeApp_Application::onExit()
439 {
440   bool killServers = false;
441   bool result = true;
442
443   if ( exitConfirmation() ) {
444     SalomeApp_ExitDlg dlg( desktop() );
445     result = dlg.exec() == QDialog::Accepted;
446     killServers = dlg.isServersShutdown();
447   }
448   
449   if ( result )
450     SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
451 }
452
453 /*!SLOT. Load document with \a aName.*/
454 bool SalomeApp_Application::onLoadDoc( const QString& aName )
455 {
456   return LightApp_Application::onLoadDoc( aName );
457 }
458
459 /*!SLOT. Copy objects to study maneger from selection maneger..*/
460 void SalomeApp_Application::onCopy()
461 {
462   SALOME_ListIO list;
463   LightApp_SelectionMgr* mgr = selectionMgr();
464   mgr->selectedObjects(list);
465   
466   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
467   if(study == NULL) return;
468   
469   _PTR(Study) stdDS = study->studyDS();
470   if(!stdDS) return;
471
472   SALOME_ListIteratorOfListIO it( list );
473   if(it.More())
474     {
475       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
476       try {
477         studyMgr()->Copy(so);
478         onSelectionChanged();
479       }
480       catch(...) {
481       }
482     }
483 }
484
485 /*!SLOT. Paste objects to study maneger from selection manager.*/
486 void SalomeApp_Application::onPaste()
487 {
488   SALOME_ListIO list;
489   LightApp_SelectionMgr* mgr = selectionMgr();
490   mgr->selectedObjects(list);
491
492   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
493   if(study == NULL) return;
494
495   _PTR(Study) stdDS = study->studyDS();
496   if(!stdDS) return;
497
498   if ( stdDS->GetProperties()->IsLocked() ) {
499     SUIT_MessageBox::warn1 ( desktop(),
500                              QObject::tr("WRN_WARNING"),
501                              QObject::tr("WRN_STUDY_LOCKED"),
502                              QObject::tr("BUT_OK") );
503     return;
504   }
505
506   SALOME_ListIteratorOfListIO it( list );
507   if(it.More())
508     {
509       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
510       try {
511         studyMgr()->Paste(so);
512         updateObjectBrowser( true );
513         updateActions(); //SRN: BugID IPAL9377, case 3
514       }
515       catch(...) {
516       }
517     }
518 }
519
520 /*! Check if the study is locked */
521 void SalomeApp_Application::onCloseDoc( bool ask )
522 {
523   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
524
525   if (study != NULL) {
526     _PTR(Study) stdDS = study->studyDS(); 
527     if(stdDS && stdDS->IsStudyLocked()) {
528       if ( SUIT_MessageBox::warn2( desktop(),
529                                    QObject::tr( "WRN_WARNING" ),
530                                    QObject::tr( "CLOSE_LOCKED_STUDY" ),
531                                    QObject::tr( "BUT_YES" ), 
532                                    QObject::tr( "BUT_NO" ),
533                                    SUIT_YES, 
534                                    SUIT_NO, 
535                                    SUIT_NO ) == SUIT_NO ) return;
536         
537     }
538   }
539
540   LightApp_Application::onCloseDoc( ask );
541 }
542
543 /*!Sets enable or disable some actions on selection changed.*/
544 void SalomeApp_Application::onSelectionChanged()
545 {
546    SALOME_ListIO list;
547    LightApp_SelectionMgr* mgr = selectionMgr();
548    mgr->selectedObjects(list);
549
550    bool canCopy  = false;
551    bool canPaste = false;
552
553    SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
554    if (study != NULL) {
555      _PTR(Study) stdDS = study->studyDS();
556
557      if (stdDS) {
558        SALOME_ListIteratorOfListIO it ( list );
559
560        if (it.More() && list.Extent() == 1) {
561          _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
562
563          if ( so ) {
564              canCopy = studyMgr()->CanCopy(so);
565              canPaste = studyMgr()->CanPaste(so);
566          }
567        }
568      }
569    }
570
571    action(EditCopyId)->setEnabled(canCopy);
572    action(EditPasteId)->setEnabled(canPaste);
573 }
574
575 /*!Delete references.*/
576 void SalomeApp_Application::onDeleteInvalidReferences()
577 {
578   SALOME_ListIO aList;
579   LightApp_SelectionMgr* mgr = selectionMgr();
580   mgr->selectedObjects( aList, QString::null, false );
581
582   if( aList.IsEmpty() )
583     return;
584
585   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
586   _PTR(Study) aStudyDS = aStudy->studyDS();
587   _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
588   _PTR(SObject) anObj;
589
590   for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
591     if ( it.Value()->hasEntry() )
592     {
593       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
594       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
595         aRefObj = anObj;
596
597       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
598          aStudyBuilder->RemoveReference( aSObject );
599     }
600   updateObjectBrowser();
601 }
602
603 /*!Private SLOT. */
604 void SalomeApp_Application::onOpenWith()
605 {
606   QApplication::setOverrideCursor( Qt::waitCursor );
607   SALOME_ListIO aList;
608   LightApp_SelectionMgr* mgr = selectionMgr();
609   mgr->selectedObjects(aList);
610   if (aList.Extent() != 1)
611     {
612       QApplication::restoreOverrideCursor();
613       return;
614     }
615   Handle(SALOME_InteractiveObject) aIObj = aList.First();
616   QString aModuleName(aIObj->getComponentDataType());
617   QString aModuleTitle = moduleTitle(aModuleName);
618   activateModule(aModuleTitle);
619   QApplication::restoreOverrideCursor();
620 }
621
622 /*!
623   Creates new study
624 */
625 SUIT_Study* SalomeApp_Application::createNewStudy()
626 {
627   SalomeApp_Study* aStudy = new SalomeApp_Study( this );
628
629   // Set up processing of major study-related events
630   connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
631   connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
632   connect( aStudy, SIGNAL( saved  ( SUIT_Study* ) ), this, SLOT( onStudySaved  ( SUIT_Study* ) ) );
633   connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
634
635   return aStudy;
636 }
637
638 /*!
639   Enable/Disable menu items and toolbar buttons. Rebuild menu
640 */
641 void SalomeApp_Application::updateCommandsStatus()
642 {
643   LightApp_Application::updateCommandsStatus();
644
645   // Dump study menu
646   QAction* a = action( DumpStudyId );
647   if ( a )
648     a->setEnabled( activeStudy() );
649
650   // Load script menu
651   a = action( LoadScriptId );
652   if ( a )
653     a->setEnabled( activeStudy() );
654
655   // Properties menu
656   a = action( PropertiesId );
657   if( a )
658     a->setEnabled( activeStudy() );
659
660   // Save GUI state menu
661   a = action( SaveGUIStateId );
662   if( a )
663     a->setEnabled( activeStudy() );
664
665   // update state of Copy/Paste menu items
666   onSelectionChanged();
667 }
668
669 /*!
670   \class DumpStudyFileDlg
671   Private class used in Dump Study operation.  Consists 2 check boxes: 
672   "Publish in study" and "Save GUI parameters"
673 */
674 class DumpStudyFileDlg : public SUIT_FileDlg
675 {
676 public:
677   DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true ) 
678   {
679     QHBox* hB = new QHBox( this );
680     myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY"), hB );
681     mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE"), hB );
682     QPushButton* pb = new QPushButton(this);      
683     addWidgets( new QLabel("", this), hB, pb );
684     pb->hide();    
685   }
686   QCheckBox* myPublishChk;
687   QCheckBox* mySaveGUIChk;
688 };
689
690 /*!Private SLOT. On dump study.*/
691 void SalomeApp_Application::onDumpStudy( )
692 {
693   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
694   if ( !appStudy ) return;
695   _PTR(Study) aStudy = appStudy->studyDS();
696
697   QStringList aFilters;
698   aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
699
700   DumpStudyFileDlg* fd = new DumpStudyFileDlg( desktop() );
701   fd->setCaption( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
702   fd->setFilters( aFilters );
703   fd->myPublishChk->setChecked( true );
704   fd->mySaveGUIChk->setChecked( true );
705   QString aFileName;
706   while (1) {
707     fd->exec();
708     fd->raise();
709     aFileName = fd->selectedFile();
710     if (!aFileName.isEmpty()) {
711       if ( (aFileName.find('-', 0) == -1) && (aFileName.find('!', 0) == -1) && (aFileName.find('?', 0) == -1) &&
712            (aFileName.find('#', 0) == -1) && (aFileName.find('*', 0) == -1) && (aFileName.find('&', 0) == -1)) {
713         break;
714       }
715       else {
716       SUIT_MessageBox::warn1 ( desktop(),
717                                QObject::tr("WRN_WARNING"),
718                                tr("WRN_FILE_NAME_BAD"),
719                                QObject::tr("BUT_OK") );
720       }
721     }
722     else {
723       break;
724     }
725   }
726   bool toPublish = fd->myPublishChk->isChecked();
727   bool toSaveGUI = fd->mySaveGUIChk->isChecked();
728   delete fd;
729
730   if ( !aFileName.isEmpty() ) {
731     QFileInfo aFileInfo(aFileName);
732     int savePoint;
733     _PTR(AttributeParameter) ap;
734     _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
735     if(ip->isDumpPython(appStudy->studyDS())) ip->setDumpPython(appStudy->studyDS()); //Unset DumpPython flag.
736     if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
737       ip->setDumpPython(appStudy->studyDS());
738       savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point      
739     }
740     bool res = aStudy->DumpStudy( aFileInfo.dirPath( true ).latin1(), aFileInfo.baseName().latin1(), toPublish);
741     if ( toSaveGUI ) 
742       appStudy->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
743     if ( !res )
744       SUIT_MessageBox::warn1 ( desktop(),
745                                QObject::tr("WRN_WARNING"),
746                                tr("WRN_DUMP_STUDY_FAILED"),
747                                QObject::tr("BUT_OK") );
748   }
749 }
750
751 /*!Private SLOT. On load script.*/
752 void SalomeApp_Application::onLoadScript( )
753 {
754   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
755   if ( !appStudy ) return;
756   _PTR(Study) aStudy = appStudy->studyDS();
757
758   if ( aStudy->GetProperties()->IsLocked() ) {
759     SUIT_MessageBox::warn1 ( desktop(),
760                              QObject::tr("WRN_WARNING"),
761                              QObject::tr("WRN_STUDY_LOCKED"),
762                              QObject::tr("BUT_OK") );
763     return;
764   }
765
766   QStringList filtersList;
767   filtersList.append(tr("PYTHON_FILES_FILTER"));
768   filtersList.append(tr("ALL_FILES_FILTER"));
769
770   QString aFile = SUIT_FileDlg::getFileName( desktop(), "", filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
771
772   if ( !aFile.isEmpty() )
773   {
774     QString command = QString("execfile(\"%1\")").arg(aFile);
775
776     PythonConsole* pyConsole = pythonConsole();
777
778     if ( pyConsole )
779       pyConsole->exec( command );
780   }
781 }
782
783 /*!Private SLOT. On save GUI state.*/
784 void SalomeApp_Application::onSaveGUIState()
785 {
786   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
787   if ( study ) {
788     SalomeApp_VisualState( this ).storeState();
789     updateSavePointDataObjects( study );
790     objectBrowser()->updateTree( study->root() );
791   }
792   updateActions();
793 }
794
795 /*!Gets file filter.
796  *\retval QString "(*.hdf)"
797  */
798 QString SalomeApp_Application::getFileFilter() const
799 {
800   return "(*.hdf)";
801 }
802
803 /*!Create window.*/
804 QWidget* SalomeApp_Application::createWindow( const int flag )
805 {
806   QWidget* wid = 0;
807   if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
808
809   SUIT_ResourceMgr* resMgr = resourceMgr();
810
811   if ( flag == WT_ObjectBrowser )
812   {
813     OB_Browser* ob = (OB_Browser*)wid;
814     ob->setUpdater( new SalomeApp_Updater() );
815     connect( ob->listView(), SIGNAL( doubleClicked( QListViewItem* ) ), this, SLOT( onDblClick( QListViewItem* ) ) );
816     bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false ),
817          autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
818     for ( int i = SalomeApp_DataObject::CT_Value; i <= SalomeApp_DataObject::CT_RefEntry; i++ )
819     {
820       ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
821       ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
822                                                    QString().sprintf( "visibility_column_%d", i ), true ) );
823     }
824     ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
825     ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
826     ob->resize( desktop()->width()/3, ob->height() );
827   }
828   else if ( flag == WT_PyConsole )
829   {
830     PythonConsole* pyCons = new PythonConsole( desktop(), new SalomeApp_PyInterp() );
831     pyCons->setCaption( tr( "PYTHON_CONSOLE" ) );
832     wid = pyCons;
833     pyCons->resize( pyCons->width(), desktop()->height()/4 );
834     //pyCons->connectPopupRequest(this, SLOT(onConnectPopupRequest(SUIT_PopupClient*, QContextMenuEvent*)));
835   }
836   return wid;
837 }
838
839 /*!Create preferences.*/
840 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
841 {
842   LightApp_Application::createPreferences(pref);
843
844   if ( !pref )
845     return;
846
847   int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
848   int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
849   int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
850   for ( int i = SalomeApp_DataObject::CT_Value; i <= SalomeApp_DataObject::CT_RefEntry; i++ )
851   {
852     pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), defCols,
853                          LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_%d", i ) );
854   }
855   pref->setItemProperty( defCols, "columns", 1 );
856
857   // adding preference to LightApp_Application handled preferences..  a bit of hacking with resources..
858   int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
859   int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
860   pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
861 }
862
863 /*!Update desktop title.*/
864 void SalomeApp_Application::updateDesktopTitle() {
865   QString aTitle = applicationName();
866   QString aVer = applicationVersion();
867   if ( !aVer.isEmpty() )
868     aTitle += QString( " " ) + aVer;
869
870   if ( activeStudy() )
871   {
872     QString sName = SUIT_Tools::file( activeStudy()->studyName().stripWhiteSpace(), false );
873     if ( !sName.isEmpty() ) {
874       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
875       if ( study ) {
876         _PTR(Study) stdDS = study->studyDS();
877         if(stdDS) {
878           if ( stdDS->GetProperties()->IsLocked() ) {
879             aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
880           } else {
881             aTitle += QString( " - [%1]" ).arg( sName );
882           }
883         }
884       }
885     }
886   }
887
888   desktop()->setCaption( aTitle );
889 }
890
891 /*!
892   \brief Show dialog box to propose possible user actions when study is closed.
893   \param docName study name
894   \return chosen action ID
895   \sa closeAction()
896 */
897 int SalomeApp_Application::closeChoice( const QString& docName )
898 {
899   SUIT_MsgDlg dlg( desktop(), tr( "APPCLOSE_CAPTION" ), tr ( "APPCLOSE_DESCRIPTION" ),
900                    QMessageBox::standardIcon( QMessageBox::Information ) );
901   dlg.addButton( tr ( "APPCLOSE_SAVE" ),   CloseSave );
902   dlg.addButton( tr ( "APPCLOSE_CLOSE" ),  CloseDiscard );
903   dlg.addButton( tr ( "APPCLOSE_UNLOAD" ), CloseUnload );
904
905   return dlg.exec();
906 }
907
908 /*!
909   \brief Process user actions selected from the dialog box when study is closed.
910   \param choice chosen action ID
911   \param closePermanently "forced study closing" flag
912   \return operation status
913   \sa closeChoice()
914 */
915 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
916 {
917   bool res = true;
918   switch( choice )
919   {
920   case CloseSave:
921     if ( activeStudy()->isSaved() )
922       onSaveDoc();
923     else if ( !onSaveAsDoc() )
924       res = false;
925     break;
926   case CloseDiscard:
927     break;
928   case CloseUnload:
929     closePermanently = false;
930     break;
931   case CloseCancel:
932   default:
933     res = false;
934   }
935   return res;
936 }
937
938 /*!
939   \brief Get module activation actions
940   \return map <action_id><action_name> where
941   - action_id is unique non-zero action identifier
942   - action_name is action title
943   \sa moduleActionSelected()
944 */
945 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
946 {
947   QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
948   opmap.insert( LoadStudyId,  tr( "ACTIVATE_MODULE_OP_LOAD" ) );
949   return opmap;
950 }
951
952 /*!
953   \brief Process module activation action.
954   \param id action identifier
955   \sa activateModuleActions()
956 */
957 void SalomeApp_Application::moduleActionSelected( const int id )
958 {
959   if ( id == LoadStudyId )
960     onLoadDoc();
961   else
962     LightApp_Application::moduleActionSelected( id );
963 }
964
965 /*!Gets CORBA::ORB_var*/
966 CORBA::ORB_var SalomeApp_Application::orb()
967 {
968   ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
969   static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
970   return _orb;
971 }
972
973 /*!Create and return SALOMEDS_StudyManager.*/
974 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
975 {
976   static _PTR(StudyManager) _sm;
977   if(!_sm) _sm = ClientFactory::StudyManager();
978   return _sm.get();
979 }
980
981 /*!Create and return SALOME_NamingService.*/
982 SALOME_NamingService* SalomeApp_Application::namingService()
983 {
984   static SALOME_NamingService* _ns = new SALOME_NamingService( orb() );
985   return _ns;
986 }
987
988 /*!Create and return SALOME_LifeCycleCORBA.*/
989 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
990 {
991   static SALOME_LifeCycleCORBA* _lcc = new SALOME_LifeCycleCORBA( namingService() );
992   return _lcc;
993 }
994
995 /*!Return default engine IOR for light modules*/
996 QString SalomeApp_Application::defaultEngineIOR()
997 {
998   /// Look for a default module engine (needed for CORBAless modules to use SALOMEDS persistence)
999   QString anIOR( "" );
1000   CORBA::Object_ptr anEngine = namingService()->Resolve( "/SalomeAppEngine" );
1001   if ( !CORBA::is_nil( anEngine ) )
1002   {
1003     CORBA::String_var objStr = orb()->object_to_string( anEngine );
1004     anIOR = QString( objStr.in() );
1005   }
1006   return anIOR;
1007 }
1008
1009 /*!Private SLOT. On preferences.*/
1010 void SalomeApp_Application::onProperties()
1011 {
1012   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1013   if( !study )
1014     return;
1015
1016   _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1017   SB->NewCommand();
1018
1019   SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1020   int res = aDlg.exec();
1021   if( res==QDialog::Accepted && aDlg.isChanged() )
1022     SB->CommitCommand();
1023   else
1024     SB->AbortCommand();
1025
1026   //study->updateCaptions();
1027   updateDesktopTitle();
1028   updateActions();
1029 }
1030
1031 /*!Insert items in popup, which necessary for current application*/
1032 void SalomeApp_Application::contextMenuPopup( const QString& type, QPopupMenu* thePopup, QString& title )
1033 {
1034   LightApp_Application::contextMenuPopup( type, thePopup, title );
1035
1036   OB_Browser* ob = objectBrowser();
1037   if ( !ob || type != ob->popupClientType() )
1038     return;
1039
1040   // Get selected objects
1041   SALOME_ListIO aList;
1042   LightApp_SelectionMgr* mgr = selectionMgr();
1043   mgr->selectedObjects( aList, QString::null, false );
1044
1045   // add GUI state commands: restore, rename
1046   if ( aList.Extent() == 1 && aList.First()->hasEntry() && 
1047        QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1048     thePopup->insertSeparator();
1049     thePopup->insertItem( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1050     thePopup->insertItem( tr( "MEN_RENAME_VS" ),  this, SLOT( onRenameGUIState() ) );
1051     thePopup->insertItem( tr( "MEN_DELETE_VS" ),  this, SLOT( onDeleteGUIState() ) );
1052   }
1053
1054   // "Delete reference" item should appear only for invalid references
1055
1056   // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1057   bool isInvalidRefs = false;
1058   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1059   _PTR(Study) aStudyDS = aStudy->studyDS();
1060   _PTR(SObject) anObj;
1061
1062   for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1063     if( it.Value()->hasEntry() )
1064     {
1065       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1066       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1067         aRefObj = anObj;
1068
1069       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1070         isInvalidRefs = true;
1071     }
1072
1073   // Add "Delete reference" item to popup
1074   if ( isInvalidRefs )
1075   {
1076     thePopup->insertSeparator();
1077     thePopup->insertItem( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1078     return;
1079   }
1080
1081   aList.Clear();
1082   mgr->selectedObjects( aList );
1083
1084   // "Activate module" item should appear only if it's necessary
1085   if (aList.Extent() != 1)
1086     return;
1087   Handle(SALOME_InteractiveObject) aIObj = aList.First();
1088   // check if item is a "GUI state" item (also a first level object)
1089   QString entry( aIObj->getEntry() );
1090   if ( entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) )
1091     return;
1092   QString aModuleName(aIObj->getComponentDataType());
1093   QString aModuleTitle = moduleTitle(aModuleName);
1094   CAM_Module* currentModule = activeModule();
1095   if (currentModule && currentModule->moduleName() == aModuleTitle)
1096     return;
1097   if ( !aModuleTitle.isEmpty() )
1098     thePopup->insertItem( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1099 }
1100
1101 /*!Update obect browser:
1102  1.if 'updateModels' true, update existing data models;
1103  2. update "non-existing" (not loaded yet) data models;
1104  3. update object browser if it exists */
1105 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1106 {
1107   // update "non-existing" (not loaded yet) data models
1108   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1109   if ( study )
1110   {
1111     _PTR(Study) stdDS = study->studyDS();
1112     if( stdDS )
1113     {
1114       for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() ) 
1115       {
1116         _PTR(SComponent) aComponent ( it->Value() );
1117
1118         if ( aComponent->ComponentDataType() == "Interface Applicative" )
1119           continue; // skip the magic "Interface Applicative" component
1120
1121         OB_Browser* ob = static_cast<OB_Browser*>( getWindow( WT_ObjectBrowser ));
1122         const bool isAutoUpdate = ob->isAutoUpdate();
1123         ob->setAutoUpdate( false );
1124         SalomeApp_DataModel::synchronize( aComponent, study );
1125         ob->setAutoUpdate( isAutoUpdate );
1126         //SalomeApp_DataModel::BuildTree( aComponent, study->root(), study, /*skipExisitng=*/true );
1127       }
1128     }
1129   }
1130
1131   // create data objects that correspond to GUI state save points
1132   if ( study ) updateSavePointDataObjects( study );
1133
1134   // update existing data models (already loaded SComponents)
1135   LightApp_Application::updateObjectBrowser( updateModels );
1136 }
1137
1138 /*!Display Catalog Genenerator dialog */
1139 void SalomeApp_Application::onCatalogGen()
1140 {
1141   ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1142   aDlg.exec();
1143 }
1144
1145 /*!Display Registry Display dialog */
1146 void SalomeApp_Application::onRegDisplay()
1147 {
1148   CORBA::ORB_var anOrb = orb();
1149   ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop(), "Registry" );
1150   regWnd->show();
1151   regWnd->raise();
1152   regWnd->setActiveWindow();
1153 }
1154
1155 /*!find original object by double click on item */
1156 void SalomeApp_Application::onDblClick( QListViewItem* it )
1157 {
1158   OB_ListItem* item = dynamic_cast<OB_ListItem*>( it );
1159   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1160
1161   if( study && item )
1162   {
1163     SalomeApp_DataObject* obj = dynamic_cast<SalomeApp_DataObject*>( item->dataObject() );
1164     if( !obj )
1165       return;
1166
1167     QString entry = obj->entry();
1168     _PTR(SObject) sobj = study->studyDS()->FindObjectID( entry.latin1() ), ref;
1169
1170     if( sobj && sobj->ReferencedObject( ref ) )
1171     {
1172       entry = ref->GetID().c_str();
1173       QListViewItemIterator anIt( item->listView() );
1174       for( ; anIt.current(); anIt++ )
1175       {
1176         OB_ListItem* item = dynamic_cast<OB_ListItem*>( anIt.current() );
1177         if( !item )
1178           continue;
1179
1180         SalomeApp_DataObject* original = dynamic_cast<SalomeApp_DataObject*>( item->dataObject() );
1181         if( original->entry()!=entry )
1182           continue;
1183
1184         OB_Browser* br = objectBrowser();
1185         br->setSelected( original );
1186         SUIT_DataObject* p = original->parent();
1187         while( p )
1188         {
1189           br->setOpen( p );
1190           p = p->parent();
1191         }
1192         break;
1193       }
1194     }
1195   }
1196 }
1197
1198 /*!
1199   Creates new view manager
1200   \param type - type of view manager
1201 */
1202 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1203 {
1204   return createViewManager(type);
1205 }
1206
1207
1208 /*!Global utility funciton, returns selected GUI Save point object's ID */
1209 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1210 {
1211   SALOME_ListIO aList;
1212   selMgr->selectedObjects( aList );
1213   Handle(SALOME_InteractiveObject) aIObj = aList.First();
1214   QString entry( aIObj->getEntry() );
1215   QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1216   if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1217     return -1;
1218   bool ok; // conversion to integer is ok?
1219   int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1220   return ok ? savePoint : -1;
1221 }
1222
1223 /*!Called on Restore GUI State popup command*/
1224 void SalomeApp_Application::onRestoreGUIState()
1225 {
1226   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1227   if ( savePoint == -1 ) 
1228     return;  
1229   SalomeApp_VisualState( this ).restoreState( savePoint );
1230 }
1231
1232 /*!Called on Rename GUI State popup command*/
1233 void SalomeApp_Application::onRenameGUIState()
1234 {
1235   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1236   if ( savePoint == -1 ) 
1237     return;  
1238   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1239   if ( !study ) 
1240     return;
1241
1242   QString newName = LightApp_NameDlg::getName( desktop(), study->getNameOfSavePoint( savePoint ) );
1243   if ( !newName.isNull() && !newName.isEmpty() ) {
1244     study->setNameOfSavePoint( savePoint, newName );
1245     updateSavePointDataObjects( study );
1246     objectBrowser()->updateTree( study->root() );
1247   }
1248 }
1249
1250
1251 /*!Called on Delete GUI State popup command*/
1252 void SalomeApp_Application::onDeleteGUIState()
1253 {
1254   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1255   if ( savePoint == -1 ) 
1256     return;  
1257   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1258   if ( !study ) 
1259     return;
1260   
1261   study->removeSavePoint( savePoint );
1262   updateSavePointDataObjects( study );
1263 }
1264
1265 /*!Called on Save study operation*/
1266 void SalomeApp_Application::onStudySaved( SUIT_Study* study )
1267 {
1268   LightApp_Application::onStudySaved( study );
1269
1270   if ( objectBrowser() ) {
1271     updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1272     objectBrowser()->updateTree( study->root() );
1273   }
1274 }
1275
1276 /*!Called on Open study operation*/
1277 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1278 {
1279   LightApp_Application::onStudyOpened( study );
1280
1281   if ( objectBrowser() ) {
1282     updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1283     objectBrowser()->updateTree( study->root() );
1284   }
1285 }
1286
1287 /*! utility function.  returns true if list view item that correspond to given SUIT_DataObject is open.
1288  only first level items are traversed */
1289 bool isListViewItemOpen( QListView* lv, const SUIT_DataObject* dobj )
1290 {
1291   if ( !lv || !dobj )
1292     return false;
1293
1294   QListViewItem* item = lv->firstChild();
1295   while ( item ) {
1296     OB_ListItem* ob_item = dynamic_cast<OB_ListItem*>( item );
1297     if ( ob_item && ob_item->dataObject() == dobj )
1298       return ob_item->isOpen();
1299     item = item->nextSibling();
1300   }
1301   return false;
1302 }
1303
1304 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1305 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1306 {
1307   OB_Browser* ob = objectBrowser();
1308
1309   if ( !study || !ob )
1310     return;
1311
1312   // find GUI states root object
1313   SUIT_DataObject* guiRootObj = 0;
1314   DataObjectList ch; 
1315   study->root()->children( ch ); 
1316   DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1317   for ( ; it != last ; ++it ) {
1318     if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1319       guiRootObj = *it;
1320       break;
1321     }
1322   }
1323   std::vector<int> savePoints = study->getSavePoints();
1324   // case 1: no more save points but they existed in study's tree
1325   if ( savePoints.empty() && guiRootObj ) {
1326     delete guiRootObj;
1327     return;
1328   }
1329   // case 2: no more save points but root does not exist either
1330   if ( savePoints.empty() && !guiRootObj )
1331     return;
1332   // case 3: save points but no root for them - create it
1333   if ( !savePoints.empty() && !guiRootObj )
1334     guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1335   // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1336   // to be always the last one in the tree.  Here we check - if it is not the last one - remove and
1337   // re-create it.
1338   if ( guiRootObj->nextBrother() ) {
1339     study->root()->removeChild(guiRootObj);
1340     study->root()->appendChild(guiRootObj);
1341     //study->root()->dump();
1342   }
1343
1344   // store data objects in a map id-to-DataObject
1345   QMap<int,SalomeApp_SavePointObject*> mapDO;
1346   ch.clear(); 
1347   guiRootObj->children( ch ); 
1348   for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1349     SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1350     if ( dobj )
1351       mapDO[dobj->getId()] = dobj;
1352   }
1353
1354   // iterate new save points.  if DataObject with such ID not found in map - create DataObject
1355   // if in the map - remove it from map.  
1356   for ( int i = 0; i < savePoints.size(); i++ )
1357     if ( !mapDO.contains( savePoints[i] ) )
1358       new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1359     else
1360       mapDO.remove( savePoints[i] );
1361
1362   // delete DataObjects that are still in the map -- their IDs were not found in data model
1363   for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1364     delete it.data();
1365 }
1366
1367 /*! Check data object */
1368 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1369 {
1370   if (theObj)
1371     return true;
1372
1373   return false;
1374 }
1375
1376 /*! Process standard messages from desktop */
1377 void SalomeApp_Application::onDesktopMessage( const QString& message )
1378 {
1379   // update object browser
1380   if ( message.lower() == "updateobjectbrowser" || 
1381        message.lower() == "updateobjbrowser" )
1382     updateObjectBrowser();
1383 }
1384