]> SALOME platform Git repositories - modules/gui.git/blob - src/SalomeApp/SalomeApp_Study.cxx
Salome HOME
7e3659945ceba819cb032c2db2cc5d0ac2335cc6
[modules/gui.git] / src / SalomeApp / SalomeApp_Study.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "SalomeApp_Study.h"
24
25 #include "SalomeApp_Module.h"
26 #include "SalomeApp_DataObject.h"
27 #include "SalomeApp_DataModel.h"
28 #include "SalomeApp_Application.h"
29 #include "SalomeApp_Engine_i.h"
30 #include "SalomeApp_VisualState.h"
31
32 // temporary commented
33 //#include <OB_Browser.h>
34
35 #include <QCoreApplication>
36 #include <QEvent>
37 #include <QFileInfo>
38 #include "SALOME_Event.h"
39 #include "Basics_Utils.hxx"
40
41 #include <SUIT_ResourceMgr.h>
42 #include <SUIT_TreeModel.h>
43 #include <SUIT_DataBrowser.h>
44
45 #include <LightApp_Displayer.h>
46
47 #include "utilities.h"
48
49 #include "SALOMEDS_Tool.hxx"
50
51 #include "SALOMEDSClient_ClientFactory.hxx"
52
53 #include <SALOMEconfig.h>
54 #include CORBA_SERVER_HEADER(SALOME_Exception)
55
56 //#define NOTIFY_BY_EVENT
57
58 class ObserverEvent : public QEvent
59 {
60 public:
61   ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
62   {
63     _anID=theID;
64     _event=event;
65   }
66
67   std::string _anID;
68   CORBA::Long _event;
69 };
70
71 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
72 {
73   typedef std::map<std::string, SalomeApp_DataObject*>           EntryMap;
74   typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
75
76 public:
77
78   Observer_i(_PTR(Study) aStudyDS, SalomeApp_Study* aStudy):QObject(aStudy)
79   {
80     myStudyDS=aStudyDS;
81     myStudy=aStudy;
82     fillEntryMap();
83   }
84
85   SUIT_DataObject* findObject( const char* theID ) const
86   {
87     EntryMap::const_iterator it = entry2SuitObject.find( theID );
88     return it != entry2SuitObject.end() ? it->second : 0;
89   }
90
91   virtual void notifyObserverID(const char* theID, CORBA::Long event)
92   {
93 #ifdef NOTIFY_BY_EVENT
94     QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
95 #else
96     notifyObserverID_real(theID,event);
97 #endif
98   }
99
100   virtual bool event(QEvent *event)
101   {
102     if (event->type() == QEvent::User )
103     {
104       //START_TIMING(notify);
105       notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
106       //END_TIMING(notify,100);
107     }
108     return true;
109   }
110
111   void notifyObserverID_real(const std::string& theID, long event)
112   {
113     SalomeApp_DataObject* suit_obj = 0;
114
115     switch(event) {
116     case 1:
117       { //Add sobject
118         _PTR(SObject) aSObj = myStudyDS->FindObjectID(theID);
119         _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
120
121         if (!aSComp || aSComp->IsNull()) {
122           MESSAGE("Entry " << theID << " has not father component. Problem ??");
123           return;
124         }
125
126         // Mantis issue 0020136: Drag&Drop in OB
127         _PTR(UseCaseBuilder) aUseCaseBuilder = myStudyDS->GetUseCaseBuilder();
128         if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
129           if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
130             // tree node is not yet set, it is a normal situation
131             return;
132           }
133
134           _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
135           if (!aFatherSO || aFatherSO->IsNull()) {
136             MESSAGE("Father SObject is not found. Problem ??");
137             return;
138           }
139
140           std::string parent_id = aFatherSO->GetID();
141           EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
142
143           if (it == entry2SuitObject.end()) {
144             MESSAGE("Father data object is not found. Problem ??");
145             return;
146           }
147
148           SalomeApp_DataObject* aFatherDO = it->second;
149
150           it = entry2SuitObject.find(theID);
151           if (it != entry2SuitObject.end()) { // this SOobject is already added somethere
152             suit_obj = it->second;
153             SUIT_DataObject* oldFather = suit_obj->parent();
154             if (oldFather) {
155               oldFather->removeChild(suit_obj, false);
156               SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
157               SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
158               model->forgetObject( suit_obj );
159                 
160               if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
161                 oldFatherSA->updateItem();
162               }
163             }
164           }
165           else {
166             suit_obj = new SalomeApp_DataObject(aSObj);
167             entry2SuitObject[theID] = suit_obj;
168           }
169
170           suit_obj->updateItem();
171           // define position in the data tree (in aFatherDO) to insert the aSObj
172           int pos = -1;
173           //int childDataObjCount = aFatherDO->childCount();
174           _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
175           for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
176             if (aUseCaseIter->Value()->GetID() == theID) {
177               pos = cur;
178               break;
179             }
180           }
181
182           aFatherDO->insertChildAtPos(suit_obj, pos);
183           //aFatherDO->insertChild(suit_obj, pos);
184           aFatherDO->updateItem();
185
186         } // END: work with tree nodes structure
187         else { // BEGIN: work with study structure
188           EntryMapIter it = entry2SuitObject.find( theID );
189           if ( it != entry2SuitObject.end() ) {
190             MESSAGE("Entry " << theID << " is already added. Problem ??");
191             return;
192           }
193
194           int last2Pnt_pos = theID.rfind( ":" );
195           std::string parent_id = theID.substr( 0, last2Pnt_pos );
196           int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
197
198           if ( parent_id.length() == 3 ) // "0:1" - root item?
199           {
200             // It's probably a SComponent
201             if ( theID == aSComp->GetID() )
202               suit_obj = new SalomeApp_ModuleObject( aSComp );
203             else
204               suit_obj = new SalomeApp_DataObject( aSObj );
205           }
206           else
207           {
208             suit_obj = new SalomeApp_DataObject( aSObj );
209           }
210
211           it = entry2SuitObject.find( parent_id );
212           if ( it != entry2SuitObject.end() ) {
213             SalomeApp_DataObject* father = it->second;
214             father->insertChildAtTag( suit_obj, tag );
215           }
216           else {
217             if ( parent_id.length() == 3 ) // "0:1" - root item?
218             {
219               // This should be for a module
220               SUIT_DataObject* father=myStudy->root();
221               father->appendChild(suit_obj);
222             }
223             else
224             {
225               MESSAGE("SHOULD NEVER GET HERE!!!");
226
227               //Try to find the SalomeApp_DataObject object parent
228               std::string root_id = parent_id.substr( 0, 4 );
229               std::string obj_id = parent_id.substr( 4 );
230
231               std::string anID;
232               std::string::size_type debut = 0;
233               std::string::size_type fin;
234               SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
235               while ( 1 ) {
236                 fin = obj_id.find_first_of( ':', debut );
237                 if ( fin == std::string::npos ) {
238                   //last id
239                   anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
240                   entry2SuitObject[parent_id] = anObj;
241                   break;
242                 }
243                 anID = root_id + obj_id.substr( 0, fin );
244                 EntryMapIter it2 = entry2SuitObject.find( anID );
245                 if ( it2 == entry2SuitObject.end() ) {
246                   //the ID is not known in entry2SuitObject
247                   anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
248                   entry2SuitObject[anID] = anObj;
249                 }
250                 else
251                   anObj = it2->second;
252                 debut = fin+1;
253               }
254               anObj->insertChildAtTag( suit_obj, tag );
255             }
256           }
257           entry2SuitObject[theID] = suit_obj;
258         } // END: work with study structure
259         break;
260       }
261     case 2:
262       { // Remove sobject
263         EntryMapIter it = entry2SuitObject.find( theID );
264         if ( it != entry2SuitObject.end() )
265         {
266           suit_obj = it->second;
267           // VSR: object is not removed, since SALOMEDS::SObject is not actually removed,
268           //      only its attributes are cleared;
269           //      thus, the object can be later reused
270           suit_obj->updateItem();
271           //SUIT_DataObject* father=suit_obj->parent();
272           //if(father)
273           //  father->removeChild(suit_obj);
274           //entry2SuitObject.erase(it);
275         }
276         else
277         {
278           MESSAGE("Want to remove an unknown object" << theID);
279         }
280         break;
281       }
282     case 0:
283       { //modify sobject
284         //MESSAGE("Want to modify an object "  << theID);
285         EntryMapIter it = entry2SuitObject.find( theID );
286         if ( it != entry2SuitObject.end() )
287         {
288           suit_obj = it->second;
289           suit_obj->updateItem();
290         }
291         else
292         {
293           MESSAGE("Want to modify an unknown object"  << theID);
294         }
295         break;
296       }
297     case 5: //IOR of the object modified
298       {
299         EntryMapIter it = entry2SuitObject.find( theID );
300         if ( it != entry2SuitObject.end() )
301           suit_obj = it->second;
302
303         /* Define visibility state */
304         bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
305         if ( suit_obj && !isComponent ) {
306           QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
307           if (!moduleTitle.isEmpty()) {
308             LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
309             if (aDisplayer) {
310               if(aDisplayer->canBeDisplayed(theID.c_str())) {
311                 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
312                 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
313               }
314               else
315                 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
316             }
317           }
318         }
319         break;
320       }
321     case 6: //NoteBook variables were modified
322       {
323         myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
324         break;
325       }
326     default:MESSAGE("Unknown event: "  << event);break;
327     } //switch
328   } //notifyObserverID_real
329
330 private:
331   void fillEntryMap()
332   {
333     entry2SuitObject.clear();
334     SUIT_DataObject* o = myStudy->root();
335     while (o) {
336       SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
337       if ( so ) {
338         std::string entry = so->entry().toLatin1().constData();
339         if ( entry.size() )
340           entry2SuitObject[entry] = so;
341       }
342       if ( o->childCount() > 0 ) {
343         // parse the children
344         o = o->firstChild();
345       }
346       else if ( o->nextBrother() > 0 ) {
347         o = o->nextBrother();
348       }
349       else {
350         // step to the next appropriate parent
351         o = o->parent();
352         while ( o ) {
353           if ( o->nextBrother() ) {
354             o = o->nextBrother();
355             break;
356           }
357           o = o->parent();
358         }
359       }
360     }
361   }
362
363 private:
364   _PTR(Study)      myStudyDS;
365   SalomeApp_Study* myStudy;
366   EntryMap         entry2SuitObject;
367 };
368
369
370 /*!
371   Constructor.
372 */
373 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
374 : LightApp_Study( app ), myObserver( 0 )
375 {
376 }
377
378 /*!
379   Destructor.
380 */
381 SalomeApp_Study::~SalomeApp_Study()
382 {
383   if ( myObserver ) {
384     PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
385     myObserver->_default_POA()->deactivate_object( oid.in() );
386   }
387 }
388
389 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
390 {
391   emit notebookVarUpdated( theVarName );
392 }
393
394 /*!
395   Gets study id.
396 */
397 int SalomeApp_Study::id() const
398 {
399   int id = -1;
400   if ( studyDS() )
401     id = studyDS()->StudyId();
402   return id;
403 }
404
405 /*!
406   Get study name.
407 */
408 QString SalomeApp_Study::studyName() const
409 {
410   // redefined from SUIT_Study to update study name properly since
411   // it can be changed outside of GUI
412   // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
413   if ( studyDS() ) {
414     QString newName = studyDS()->Name().c_str();
415     if ( LightApp_Study::studyName() != newName ) {
416       SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
417       that->setStudyName( newName );
418       ((SalomeApp_Application*)application())->updateDesktopTitle();
419     }
420   }
421   return LightApp_Study::studyName();
422 }
423
424 /*!
425   Gets studyDS pointer.
426 */
427 _PTR(Study) SalomeApp_Study::studyDS() const
428 {
429   return myStudyDS;
430 }
431
432 /*!
433   Create document.
434 */
435 bool SalomeApp_Study::createDocument( const QString& theStr )
436 {
437   MESSAGE( "createDocument" );
438
439   // initialize myStudyDS, read HDF file
440   QString aName = newStudyName();
441   _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
442   if ( !study )
443     return false;
444
445   setStudyDS( study );
446   setStudyName( aName );
447
448   // create myRoot
449   SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
450 #ifdef WITH_SALOMEDS_OBSERVER
451   aRoot->setToSynchronize(false);
452 #endif
453   setRoot( aRoot );
454
455   bool aRet = CAM_Study::createDocument( theStr );
456
457 #ifdef WITH_SALOMEDS_OBSERVER
458   myObserver = new Observer_i(myStudyDS,this);
459   //attach an observer to the study with notification of modifications
460   myStudyDS->attach(myObserver->_this(),true);
461 #endif
462
463   emit created( this );
464
465   return aRet;
466 }
467
468 /*!
469   Opens document
470   \param theFileName - name of file
471 */
472 bool SalomeApp_Study::openDocument( const QString& theFileName )
473 {
474   MESSAGE( "openDocument" );
475
476   // initialize myStudyDS, read HDF file
477   _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
478   if ( !study )
479     return false;
480
481   setStudyDS( study );
482
483   setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
484
485   // update loaded data models: call open() and update() on them.
486   ModelList dm_s;
487   dataModels( dm_s );
488   QListIterator<CAM_DataModel*> it( dm_s );
489   while ( it.hasNext() )
490     openDataModel( studyName(), it.next() );
491
492   // this will build a SUIT_DataObject-s tree under myRoot member field
493   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
494   // but tree that corresponds to not-loaded data models will be updated any way.
495   ((SalomeApp_Application*)application())->updateObjectBrowser( false );
496
497 #ifdef WITH_SALOMEDS_OBSERVER
498   dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
499   myObserver = new Observer_i(myStudyDS,this);
500   //attach an observer to the study with notification of modifications
501   myStudyDS->attach(myObserver->_this(),true);
502 #endif
503
504   bool res = CAM_Study::openDocument( theFileName );
505
506   emit opened( this );
507   study->IsSaved(true);
508
509   bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
510   if ( restore ) {
511     std::vector<int> savePoints = getSavePoints();
512     if ( savePoints.size() > 0 )
513       SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
514   }
515
516   ((SalomeApp_Application*)application())->updateObjectBrowser( true );
517   return res;
518 }
519
520 /*!
521   Connects GUI study to SALOMEDS one already loaded into StudyManager
522   \param theStudyName - name of study
523 */
524 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
525 {
526   MESSAGE( "loadDocument" );
527
528   // obtain myStudyDS from StudyManager
529   _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
530   if ( !study )
531     return false;
532
533   setStudyDS( study );
534
535   setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
536
537   //SRN: BugID IPAL9021, put there the same code as in a method openDocument
538
539   // update loaded data models: call open() and update() on them.
540   ModelList dm_s;
541   dataModels( dm_s );
542
543   QListIterator<CAM_DataModel*> it( dm_s );
544   while ( it.hasNext() )
545     openDataModel( studyName(), it.next() );
546
547   // this will build a SUIT_DataObject-s tree under myRoot member field
548   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
549   // but tree that corresponds to not-loaded data models will be updated any way.
550   ((SalomeApp_Application*)application())->updateObjectBrowser( false );
551
552 #ifdef WITH_SALOMEDS_OBSERVER
553   dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
554   myObserver = new Observer_i(myStudyDS,this);
555   //attach an observer to the study with notification of modifications
556   myStudyDS->attach(myObserver->_this(),true);
557 #endif
558
559   bool res = CAM_Study::openDocument( theStudyName );
560   emit opened( this );
561
562   bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
563   if ( restore ) {
564     std::vector<int> savePoints = getSavePoints();
565     if ( savePoints.size() > 0 )
566       SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
567   }
568
569   //SRN: BugID IPAL9021: End
570   return res;
571 }
572
573 /*!
574   Saves document
575   \param theFileName - name of file
576 */
577 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
578 {
579   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
580   if ( store )
581     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
582
583   ModelList list; dataModels( list );
584
585   QListIterator<CAM_DataModel*> it( list );
586   QStringList listOfFiles;
587   while ( it.hasNext() ) {
588     // Cast to LightApp class in order to give a chance
589     // to light modules to save their data
590     if ( LightApp_DataModel* aModel = 
591          dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
592       listOfFiles.clear();
593       aModel->saveAs( theFileName, this, listOfFiles );
594       if ( !listOfFiles.isEmpty() )
595         saveModuleData(aModel->module()->name(), listOfFiles);
596     }
597   }
598
599   // save SALOMEDS document
600   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
601   if( !resMgr )
602     return false;
603
604   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
605   bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
606   bool res = (isAscii ?
607     SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
608     SalomeApp_Application::studyMgr()->SaveAs     ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
609     && CAM_Study::saveDocumentAs( theFileName );
610
611   res = res && saveStudyData(theFileName);
612
613   if ( res )
614     emit saved( this );
615
616   return res;
617 }
618
619 /*!
620   Saves previously opened document
621 */
622 bool SalomeApp_Study::saveDocument()
623 {
624   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
625   if ( store )
626     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
627
628   ModelList list; dataModels( list );
629
630   QListIterator<CAM_DataModel*> it( list );
631   QStringList listOfFiles;
632   while ( it.hasNext() ) {
633     // Cast to LightApp class in order to give a chance
634     // to light modules to save their data
635     if ( LightApp_DataModel* aModel = 
636          dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
637       listOfFiles.clear();
638       aModel->save(listOfFiles);
639       if ( !listOfFiles.isEmpty() )
640         saveModuleData(aModel->module()->name(), listOfFiles);
641     }
642   }
643
644   // save SALOMEDS document
645   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
646   if( !resMgr )
647     return false;
648
649   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
650   bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
651   bool res = (isAscii ?
652     SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
653     SalomeApp_Application::studyMgr()->Save     ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
654
655   res = res && saveStudyData(studyName());
656   if ( res )
657     emit saved( this );
658
659   return res;
660 }
661
662 /*!
663   Closes document
664 */
665 void SalomeApp_Study::closeDocument(bool permanently)
666 {
667   LightApp_Study::closeDocument(permanently);
668
669   // close SALOMEDS document
670   _PTR(Study) studyPtr = studyDS();
671   if ( studyPtr )
672   {
673     if(permanently) {
674       SalomeApp_Application::studyMgr()->Close( studyPtr );
675     }
676     SALOMEDSClient_Study* aStudy = 0;
677     setStudyDS( _PTR(Study)(aStudy) );
678   }
679 }
680
681 /*!
682   Dump study operation. Writes a Python dump file using
683   SALOMEDS services. Additionally, gives a chance to light modules
684   to participate in dump study operation.
685
686   \param theFileName - full path to the output Python file
687   \param toPublish - if true, all objects are published in a study 
688   by the output script, including those not orignally present 
689   in the current study.
690   \param isMultiFile - if true, each module's dump is written into 
691   a separate Python file, otherwise a single output file is written
692   \param toSaveGUI - if true, the GUI state is written
693
694   \return - true if the operation succeeds, and false otherwise.
695 */
696 bool SalomeApp_Study::dump( const QString& theFileName, 
697                             bool toPublish, 
698                             bool isMultiFile,
699                             bool toSaveGUI )
700 {
701   int savePoint;
702   _PTR(AttributeParameter) ap;
703   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
704   _PTR(Study) aStudy = studyDS();
705
706   if( ip->isDumpPython( aStudy ) ) 
707     ip->setDumpPython( aStudy ); //Unset DumpPython flag.
708
709   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
710     ip->setDumpPython( aStudy );
711     //SRN: create a temporary save point
712     savePoint = SalomeApp_VisualState( 
713       dynamic_cast<SalomeApp_Application*>( application() ) ).storeState(); 
714   }
715
716   // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
717   // This is an optional but important step, it gives a chance to light modules
718   // to dump their data as a part of common dump study operation
719   ModelList list; 
720   dataModels( list );
721
722   QListIterator<CAM_DataModel*> it( list );
723   QStringList listOfFiles;
724   while ( it.hasNext() ) {
725     if ( LightApp_DataModel* aModel = 
726          dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
727       listOfFiles.clear();
728       if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) && 
729            !listOfFiles.isEmpty() )
730         // This call simply passes the data model's dump output to SalomeApp_Engine servant.
731         // This code is shared with persistence mechanism.
732         // NOTE: this should be revised if behavior of saveModuleData() changes!
733         saveModuleData(aModel->module()->name(), listOfFiles);
734     }
735   }
736
737   // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if 
738   // any light module is present in the current configuration
739   QFileInfo aFileInfo( theFileName );
740   bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
741                                 aFileInfo.baseName().toUtf8().data(),
742                                 toPublish,
743                                 isMultiFile);
744   if ( toSaveGUI )
745     removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
746
747   // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
748   // This code is shared with persistence mechanism.
749   // NOTE: this should be revised if behavior of saveStudyData() changes!
750   saveStudyData( theFileName );
751
752   return res;
753 }
754
755 /*!
756   \return true, if study is modified in comparison with last open/save
757 */
758 bool SalomeApp_Study::isModified() const
759 {
760   bool isAnyChanged = studyDS() && studyDS()->IsModified();
761   if (!isAnyChanged)
762     isAnyChanged = LightApp_Study::isModified();
763
764   return isAnyChanged;
765 }
766
767 /*!
768   Set study modified to \a on.
769  */
770 void SalomeApp_Study::Modified()
771 {
772   if(_PTR(Study) aStudy = studyDS())
773     aStudy->Modified();
774   LightApp_Study::Modified();
775 }
776
777 /*!
778   \return if data model is saved
779 */
780 bool SalomeApp_Study::isSaved() const
781 {
782   bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
783   if (!isAllSaved)
784     isAllSaved = LightApp_Study::isSaved();
785
786   return isAllSaved;
787 }
788
789 /*!
790   Saves data of module
791   \param theModuleName - name of module
792   \param theListOfFiles - list of files to be saved
793 */
794 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
795 {
796   int aNb = theListOfFiles.count();
797   if ( aNb == 0 )
798     return;
799
800   std::vector<std::string> aListOfFiles ( aNb );
801   int anIndex = 0;
802   for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
803     if ( (*it).isEmpty() )
804       continue;
805     aListOfFiles[anIndex] = (*it).toUtf8().data();
806     anIndex++;
807   }
808   SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
809 }
810
811 /*!
812   Loads data of module
813   \param theModuleName - name of module
814   \param theListOfFiles - list of files to be loaded
815 */
816 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
817 {
818   std::vector<std::string> aListOfFiles =  GetListOfFiles( theModuleName.toStdString().c_str() );
819
820   int i, aLength = aListOfFiles.size() - 1;
821   if ( aLength < 0 )
822     return;
823
824   //Get a temporary directory for saved a file
825   theListOfFiles.append(aListOfFiles[0].c_str());
826
827   for(i = 0; i < aLength; i++)
828     theListOfFiles.append(aListOfFiles[i+1].c_str());
829 }
830
831 /*!
832   Re-implemented from LightApp_Study, actually does not save anything but
833   simply cleans up light modules' data
834 */
835 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
836 {
837   ModelList list; dataModels( list );
838   QListIterator<CAM_DataModel*> it( list );
839   std::vector<std::string> listOfFiles(0);
840   while ( it.hasNext() ){
841     LightApp_DataModel* aLModel = 
842       dynamic_cast<LightApp_DataModel*>( it.next() );
843     // It is safe to call SetListOfFiles() for any kind of module
844     // because SetListOfFiles() does nothing for full modules :)
845     if ( aLModel )
846       SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
847   }
848   return true;
849 }
850
851 /*!
852   Loads data for study
853 */
854 bool SalomeApp_Study::openStudyData( const QString& theFileName )
855 {
856  return true;
857 }
858
859 /*!
860   Set studyDS.
861 */
862 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
863 {
864   myStudyDS = s;
865 }
866
867 /*!
868   Virtual method re-implemented from LightApp_Study in order to create
869   the module object connected to SALOMEDS - SalomeApp_ModuleObject.
870
871   \param theDataModel - data model instance to create a module object for
872   \param theParent - the module object's parent (normally it's the study root)
873   \return the module object instance
874   \sa LightApp_Study class, LightApp_DataModel class
875 */
876 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel, 
877                                                        SUIT_DataObject* theParent ) const
878 {
879   SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
880   
881   // Ensure that SComponent instance is published in the study for the given module
882   // This line causes automatic creation of SalomeApp_ModuleObject in case if
883   // WITH_SALOMEDS_OBSERVER is defined
884   that->addComponent( theDataModel );
885   
886   // SalomeApp_ModuleObject might have been created by SALOMEDS observer
887   // or by someone else so check if it exists first of all
888   CAM_ModuleObject* res = 0;
889
890   DataObjectList children = root()->children();
891   DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
892   for( ; !res && anIt!=aLast; anIt++ )
893   {
894     SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
895     if ( obj && obj->componentDataType() == theDataModel->module()->name() )
896       res = obj;
897   }
898
899   if ( !res ){
900     _PTR(Study) aStudy = studyDS();
901     if ( !aStudy )
902       return res;
903
904     _PTR(SComponent) aComp = aStudy->FindComponent( 
905       theDataModel->module()->name().toStdString() );
906     if ( !aComp )
907       return res;
908
909     res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
910   }
911
912   return res;
913 }
914
915 /*!
916   Insert data model.
917 */
918 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
919 {
920   MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
921
922   CAM_Study::dataModelInserted(dm);
923
924   //  addComponent(dm);
925 }
926
927 /*!
928   Create SComponent for module, using default engine (CORBAless)
929 */
930 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
931 {
932   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
933   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
934   if (!aModule) {
935     // Check SComponent existance
936     _PTR(Study) aStudy = studyDS();
937     if (!aStudy)
938       return;
939
940     std::string aCompDataType = dm->module()->name().toStdString();
941
942     _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
943     if (!aComp) {
944       // Create SComponent
945       _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
946       aComp = aBuilder->NewComponent(aCompDataType);
947       aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
948       QString anIconName = dm->module()->iconName();
949       if (!anIconName.isEmpty()) {
950         _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
951         if (anAttr)
952           anAttr->SetPixMap(anIconName.toStdString());
953       }
954
955       // Set default engine IOR
956       // Issue 21377 - using separate engine for each type of light module
957       std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
958                                                                            true );
959       aBuilder->DefineComponentInstance(aComp, anEngineIOR);
960       //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
961       SalomeApp_DataModel::synchronize( aComp, this );
962     }
963     else {
964       _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
965       aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
966       QString anIconName = dm->module()->iconName();
967       if (!anIconName.isEmpty()) {
968         _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
969         if (anAttr)
970           anAttr->SetPixMap(anIconName.toStdString());
971       }
972       // Set default engine IOR
973     }
974   }
975 }
976
977 /*!
978   Open data model
979 */
980 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
981 {
982   if (!dm)
983     return false;
984
985   //  SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
986   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
987   _PTR(Study)       aStudy = studyDS(); // shared_ptr cannot be used here
988   _PTR(SComponent)  aSComp;
989   QString anEngine;
990   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
991   if (!aModule) {
992     // Issue 21377 - using separate engine for each type of light module
993     std::string aCompDataType = dm->module()->name().toStdString();
994     anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
995     aSComp = aStudy->FindComponent( aCompDataType );
996   }
997   else {
998     SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
999     if ( aDM ) {
1000       QString anId = aDM->getRootEntry( this );
1001       if ( anId.isEmpty() )
1002         return true; // Probably nothing to load
1003       anEngine = aDM->getModule()->engineIOR();
1004       if ( anEngine.isEmpty() )
1005         return false;
1006       aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1007     }
1008   }
1009   if ( aSComp ) {
1010     _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1011     if ( aBuilder ) {
1012       try {
1013         aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1014       }
1015       catch( const SALOME::SALOME_Exception& ) {
1016         // Oops, something went wrong while loading -> return an error
1017         return false;
1018       }
1019       // Something has been read -> create data model tree
1020       //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1021       // aDM->buildTree( aSComp, 0, this );
1022     }
1023   } else {
1024     // Don't return false here, for there might be no data
1025     // for a given component in the study yet
1026   }
1027   QStringList listOfFiles;
1028   openModuleData(dm->module()->name(), listOfFiles);
1029   if (dm && dm->open(studyName, this, listOfFiles)) {
1030     // Remove the files and temporary directory, created
1031     // for this module by LightApp_Engine_i::Load()
1032     bool isMultiFile = false; // TODO: decide, how to access this parameter
1033     RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1034
1035     // Something has been read -> create data model tree
1036     LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1037     if ( aDM )
1038       aDM->update(NULL, this);
1039     return true;
1040   }
1041   return false;
1042 }
1043
1044 /*!
1045   Create new study name.
1046 */
1047 QString SalomeApp_Study::newStudyName() const
1048 {
1049   std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1050   QString prefix( "Study%1" ), newName, curName;
1051   int i = 1, j, n = studies.size();
1052   while ( newName.isEmpty() ){
1053     curName = prefix.arg( i );
1054     for ( j = 0 ; j < n; j++ ){
1055       if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1056         break;
1057     }
1058     if ( j == n )
1059       newName = curName;
1060     else
1061       i++;
1062   }
1063   return newName;
1064 }
1065
1066 /*!
1067   Note that this method does not create or activate SalomeApp_Engine_i instance,
1068   therefore it can be called safely for any kind of module, but for full
1069   modules it returns an empty list.
1070   \return list of files used by module: to be used by CORBAless modules
1071   \param theModuleName - name of module
1072 */
1073 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName  ) const
1074 {
1075   // Issue 21377 - using separate engine for each type of light module
1076   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1077   if (aDefaultEngine)
1078     return aDefaultEngine->GetListOfFiles(id());
1079
1080   std::vector<std::string> aListOfFiles;
1081   return aListOfFiles;
1082 }
1083
1084 /*!
1085   Sets list of files used by module: to be used by CORBAless modules.
1086   Note that this method does not create or activate SalomeApp_Engine_i instance,
1087   therefore it can be called safely for any kind of module, but for full
1088   modules it simply does nothing.
1089   \param theModuleName - name of module
1090   \param theListOfFiles - list of files
1091 */
1092 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1093                                        const std::vector<std::string> theListOfFiles )
1094 {
1095   // Issue 21377 - using separate engine for each type of light module
1096   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1097   if (aDefaultEngine)
1098     aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1099 }
1100
1101 /*!
1102   \return temporary directory for saving files of modules
1103 */
1104 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool  isMultiFile )
1105 {
1106   std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1107   std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1108   return aTmpDir;
1109 }
1110
1111 /*!
1112   Removes temporary files
1113 */
1114 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1115 {
1116   if (isMultiFile)
1117     return;
1118
1119   std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1120   if (aListOfFiles.size() > 0) {
1121     std::string aTmpDir = aListOfFiles[0];
1122
1123     const int n = aListOfFiles.size() - 1;
1124     SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1125     aSeq->length(n);
1126     for (int i = 0; i < n; i++)
1127       aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1128
1129     SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1130   }
1131 }
1132
1133 /*!
1134   Mark the study as saved in the file
1135   \param theFileName - the name of file
1136 */
1137 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1138 {
1139   setStudyName(theFileName);
1140   studyDS()->Name(theFileName.toStdString());
1141   setIsSaved( isSaved );
1142 }
1143
1144 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1145 {
1146   LightApp_DataObject* o = dynamic_cast<LightApp_DataObject*>( myObserver ? myObserver->findObject( theEntry.toLatin1().constData() ) : 0 );
1147   return o;
1148 }
1149
1150 /*!
1151   Deletes all references to object
1152   \param obj - object
1153 */
1154 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1155 {
1156   _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1157   std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1158   for( int i=0, n=aRefs.size(); i<n; i++ )
1159   {
1160     _PTR( SObject ) o = aRefs[i];
1161     if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1162     {
1163       sb->RemoveReference( o );
1164       sb->RemoveObjectWithChildren( o );
1165     }
1166   }
1167 }
1168
1169 /*!
1170   \return real entry by entry of reference
1171   \param entry - entry of reference object
1172 */
1173 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1174 {
1175   _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1176   _PTR(SObject) refobj;
1177
1178   if( obj && obj->ReferencedObject( refobj ) )
1179     return refobj->GetID().c_str();
1180   return LightApp_Study::referencedToEntry( entry );
1181 }
1182
1183 /*!
1184   \return component data type for entry
1185 */
1186 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1187 {
1188   _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1189   if ( !obj )
1190     return LightApp_Study::componentDataType( entry );
1191   return obj->GetFatherComponent()->ComponentDataType().c_str();
1192 }
1193
1194 /*!
1195   \return true if entry corresponds to component
1196 */
1197 bool SalomeApp_Study::isComponent( const QString& entry ) const
1198 {
1199   _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1200   return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1201 }
1202
1203 /*!
1204   \return entries of object children
1205 */
1206 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1207 {
1208   _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1209   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1210   anIter->InitEx( true );
1211   while( anIter->More() )
1212   {
1213     _PTR(SObject) val( anIter->Value() );
1214     child_entries.append( val->GetID().c_str() );
1215     anIter->Next();
1216   }
1217 }
1218
1219 /*!
1220   Fills list with components names
1221   \param comp - list to be filled
1222 */
1223 void SalomeApp_Study::components( QStringList& comps ) const
1224 {
1225   for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1226   {
1227     _PTR(SComponent) aComponent ( it->Value() );
1228     // skip the magic "Interface Applicative" component
1229     if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1230       comps.append( aComponent->ComponentDataType().c_str() );
1231   }
1232 }
1233
1234 /*!
1235   Get the entry for the given module
1236   \param comp - list to be filled
1237   \return module root's entry
1238 */
1239 QString SalomeApp_Study::centry( const QString& comp ) const
1240 {
1241   QString e;
1242   for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1243   {
1244     _PTR(SComponent) aComponent ( it->Value() );
1245     if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1246       e = aComponent->GetID().c_str();
1247   }
1248   return e;
1249 }
1250
1251 /*!
1252   \return a list of saved points' IDs
1253 */
1254 std::vector<int> SalomeApp_Study::getSavePoints()
1255 {
1256   std::vector<int> v;
1257
1258   _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1259   if(!so) return v;
1260
1261   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1262   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1263   for(; anIter->More(); anIter->Next())
1264   {
1265     _PTR(SObject) val( anIter->Value() );
1266     _PTR(GenericAttribute) genAttr;
1267     if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1268   }
1269
1270   return v;
1271 }
1272
1273 /*!
1274   Removes a given save point
1275 */
1276 void SalomeApp_Study::removeSavePoint(int savePoint)
1277 {
1278   if(savePoint <= 0) return;
1279  _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1280   _PTR(SObject) so = AP->GetSObject();
1281   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1282   builder->RemoveObjectWithChildren(so);
1283 }
1284
1285 /*!
1286   \return a name of save point
1287 */
1288 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1289 {
1290   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1291   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1292   return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1293 }
1294
1295 /*!
1296   Sets a name of save point
1297 */
1298 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1299 {
1300   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1301   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1302   ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1303 }
1304
1305 /*!
1306  * \brief Restores the study state
1307  */
1308 void SalomeApp_Study::restoreState(int savePoint)
1309 {
1310   SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1311 }
1312
1313
1314 /*!
1315   Slot: called on change of a root of a data model. Redefined from CAM_Study
1316 */
1317 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1318 {
1319   LightApp_Study::updateModelRoot( dm );
1320
1321   // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1322   // it must always be the last one.
1323   ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );
1324 }