Salome HOME
Merge from V6_main 01/04/2013
[modules/gui.git] / src / SalomeApp / SalomeApp_Study.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #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   
561   //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
562   //     mark study as "not saved" after call openDocument( ... ) method.
563   setIsSaved(false);
564   emit opened( this );
565
566   bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
567   if ( restore ) {
568     std::vector<int> savePoints = getSavePoints();
569     if ( savePoints.size() > 0 )
570       SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
571   }
572
573   //SRN: BugID IPAL9021: End
574   return res;
575 }
576
577 /*!
578   Saves document
579   \param theFileName - name of file
580 */
581 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
582 {
583   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
584   if ( store )
585     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
586
587   ModelList list; dataModels( list );
588
589   QListIterator<CAM_DataModel*> it( list );
590   QStringList listOfFiles;
591   while ( it.hasNext() ) {
592     // Cast to LightApp class in order to give a chance
593     // to light modules to save their data
594     if ( LightApp_DataModel* aModel = 
595          dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
596       listOfFiles.clear();
597       aModel->saveAs( theFileName, this, listOfFiles );
598       if ( !listOfFiles.isEmpty() )
599         saveModuleData(aModel->module()->name(), listOfFiles);
600     }
601   }
602
603   // save SALOMEDS document
604   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
605   if( !resMgr )
606     return false;
607
608   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
609   bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
610   bool res = (isAscii ?
611     SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
612     SalomeApp_Application::studyMgr()->SaveAs     ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
613     && CAM_Study::saveDocumentAs( theFileName );
614
615   res = res && saveStudyData(theFileName);
616
617   if ( res )
618     emit saved( this );
619
620   return res;
621 }
622
623 /*!
624   Saves previously opened document
625 */
626 bool SalomeApp_Study::saveDocument()
627 {
628   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
629   if ( store )
630     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
631
632   ModelList list; dataModels( list );
633
634   QListIterator<CAM_DataModel*> it( list );
635   QStringList listOfFiles;
636   while ( it.hasNext() ) {
637     // Cast to LightApp class in order to give a chance
638     // to light modules to save their data
639     if ( LightApp_DataModel* aModel = 
640          dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
641       listOfFiles.clear();
642       aModel->save(listOfFiles);
643       if ( !listOfFiles.isEmpty() )
644         saveModuleData(aModel->module()->name(), listOfFiles);
645     }
646   }
647
648   // save SALOMEDS document
649   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
650   if( !resMgr )
651     return false;
652
653   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
654   bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
655   bool res = (isAscii ?
656     SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
657     SalomeApp_Application::studyMgr()->Save     ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
658
659   res = res && saveStudyData(studyName());
660   if ( res )
661     emit saved( this );
662
663   return res;
664 }
665
666 /*!
667   Closes document
668 */
669 void SalomeApp_Study::closeDocument(bool permanently)
670 {
671   LightApp_Study::closeDocument(permanently);
672
673   // close SALOMEDS document
674   _PTR(Study) studyPtr = studyDS();
675   if ( studyPtr )
676   {
677     if(permanently) {
678       SalomeApp_Application::studyMgr()->Close( studyPtr );
679     }
680     SALOMEDSClient_Study* aStudy = 0;
681     setStudyDS( _PTR(Study)(aStudy) );
682   }
683 }
684
685 /*!
686   Dump study operation. Writes a Python dump file using
687   SALOMEDS services. Additionally, gives a chance to light modules
688   to participate in dump study operation.
689
690   \param theFileName - full path to the output Python file
691   \param toPublish - if true, all objects are published in a study 
692   by the output script, including those not orignally present 
693   in the current study.
694   \param isMultiFile - if true, each module's dump is written into 
695   a separate Python file, otherwise a single output file is written
696   \param toSaveGUI - if true, the GUI state is written
697
698   \return - true if the operation succeeds, and false otherwise.
699 */
700 bool SalomeApp_Study::dump( const QString& theFileName, 
701                             bool toPublish, 
702                             bool isMultiFile,
703                             bool toSaveGUI )
704 {
705   int savePoint;
706   _PTR(AttributeParameter) ap;
707   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
708   _PTR(Study) aStudy = studyDS();
709
710   if( ip->isDumpPython( aStudy ) ) 
711     ip->setDumpPython( aStudy ); //Unset DumpPython flag.
712
713   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
714     ip->setDumpPython( aStudy );
715     //SRN: create a temporary save point
716     savePoint = SalomeApp_VisualState( 
717       dynamic_cast<SalomeApp_Application*>( application() ) ).storeState(); 
718   }
719
720   // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
721   // This is an optional but important step, it gives a chance to light modules
722   // to dump their data as a part of common dump study operation
723   ModelList list; 
724   dataModels( list );
725
726   QListIterator<CAM_DataModel*> it( list );
727   QStringList listOfFiles;
728   while ( it.hasNext() ) {
729     if ( LightApp_DataModel* aModel = 
730          dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
731       listOfFiles.clear();
732       if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) && 
733            !listOfFiles.isEmpty() )
734         // This call simply passes the data model's dump output to SalomeApp_Engine servant.
735         // This code is shared with persistence mechanism.
736         // NOTE: this should be revised if behavior of saveModuleData() changes!
737         saveModuleData(aModel->module()->name(), listOfFiles);
738     }
739   }
740
741   // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if 
742   // any light module is present in the current configuration
743   QFileInfo aFileInfo( theFileName );
744   bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
745                                 aFileInfo.baseName().toUtf8().data(),
746                                 toPublish,
747                                 isMultiFile);
748   if ( toSaveGUI )
749     removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
750
751   // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
752   // This code is shared with persistence mechanism.
753   // NOTE: this should be revised if behavior of saveStudyData() changes!
754   saveStudyData( theFileName );
755
756   return res;
757 }
758
759 /*!
760   \return true, if study is modified in comparison with last open/save
761 */
762 bool SalomeApp_Study::isModified() const
763 {
764   bool isAnyChanged = studyDS() && studyDS()->IsModified();
765   if (!isAnyChanged)
766     isAnyChanged = LightApp_Study::isModified();
767
768   return isAnyChanged;
769 }
770
771 /*!
772   Set study modified to \a on.
773  */
774 void SalomeApp_Study::Modified()
775 {
776   if(_PTR(Study) aStudy = studyDS())
777     aStudy->Modified();
778   LightApp_Study::Modified();
779 }
780
781 /*!
782   \return if data model is saved
783 */
784 bool SalomeApp_Study::isSaved() const
785 {
786   bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
787   if (!isAllSaved)
788     isAllSaved = LightApp_Study::isSaved();
789
790   return isAllSaved;
791 }
792
793 /*!
794   Saves data of module
795   \param theModuleName - name of module
796   \param theListOfFiles - list of files to be saved
797 */
798 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
799 {
800   int aNb = theListOfFiles.count();
801   if ( aNb == 0 )
802     return;
803
804   std::vector<std::string> aListOfFiles ( aNb );
805   int anIndex = 0;
806   for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
807     if ( (*it).isEmpty() )
808       continue;
809     aListOfFiles[anIndex] = (*it).toUtf8().data();
810     anIndex++;
811   }
812   SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
813 }
814
815 /*!
816   Loads data of module
817   \param theModuleName - name of module
818   \param theListOfFiles - list of files to be loaded
819 */
820 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
821 {
822   std::vector<std::string> aListOfFiles =  GetListOfFiles( theModuleName.toStdString().c_str() );
823
824   int i, aLength = aListOfFiles.size() - 1;
825   if ( aLength < 0 )
826     return;
827
828   //Get a temporary directory for saved a file
829   theListOfFiles.append(aListOfFiles[0].c_str());
830
831   for(i = 0; i < aLength; i++)
832     theListOfFiles.append(aListOfFiles[i+1].c_str());
833 }
834
835 /*!
836   Re-implemented from LightApp_Study, actually does not save anything but
837   simply cleans up light modules' data
838 */
839 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
840 {
841   ModelList list; dataModels( list );
842   QListIterator<CAM_DataModel*> it( list );
843   std::vector<std::string> listOfFiles(0);
844   while ( it.hasNext() ){
845     LightApp_DataModel* aLModel = 
846       dynamic_cast<LightApp_DataModel*>( it.next() );
847     // It is safe to call SetListOfFiles() for any kind of module
848     // because SetListOfFiles() does nothing for full modules :)
849     if ( aLModel )
850       SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
851   }
852   return true;
853 }
854
855 /*!
856   Loads data for study
857 */
858 bool SalomeApp_Study::openStudyData( const QString& theFileName )
859 {
860  return true;
861 }
862
863 /*!
864   Set studyDS.
865 */
866 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
867 {
868   myStudyDS = s;
869 }
870
871 /*!
872   Virtual method re-implemented from LightApp_Study in order to create
873   the module object connected to SALOMEDS - SalomeApp_ModuleObject.
874
875   \param theDataModel - data model instance to create a module object for
876   \param theParent - the module object's parent (normally it's the study root)
877   \return the module object instance
878   \sa LightApp_Study class, LightApp_DataModel class
879 */
880 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel, 
881                                                        SUIT_DataObject* theParent ) const
882 {
883   SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
884   
885   // Ensure that SComponent instance is published in the study for the given module
886   // This line causes automatic creation of SalomeApp_ModuleObject in case if
887   // WITH_SALOMEDS_OBSERVER is defined
888   that->addComponent( theDataModel );
889   
890   // SalomeApp_ModuleObject might have been created by SALOMEDS observer
891   // or by someone else so check if it exists first of all
892   CAM_ModuleObject* res = 0;
893
894   DataObjectList children = root()->children();
895   DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
896   for( ; !res && anIt!=aLast; anIt++ )
897   {
898     SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
899     if ( obj && obj->componentDataType() == theDataModel->module()->name() )
900       res = obj;
901   }
902
903   if ( !res ){
904     _PTR(Study) aStudy = studyDS();
905     if ( !aStudy )
906       return res;
907
908     _PTR(SComponent) aComp = aStudy->FindComponent( 
909       theDataModel->module()->name().toStdString() );
910     if ( !aComp )
911       return res;
912
913     res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
914   }
915
916   return res;
917 }
918
919 /*!
920   Insert data model.
921 */
922 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
923 {
924   MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
925
926   CAM_Study::dataModelInserted(dm);
927
928   //  addComponent(dm);
929 }
930
931 /*!
932   Create SComponent for module, using default engine (CORBAless)
933 */
934 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
935 {
936   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
937   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
938   if (!aModule) {
939     // Check SComponent existance
940     _PTR(Study) aStudy = studyDS();
941     if (!aStudy)
942       return;
943
944     std::string aCompDataType = dm->module()->name().toStdString();
945
946     _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
947     if (!aComp) {
948       // Create SComponent
949       _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
950       aComp = aBuilder->NewComponent(aCompDataType);
951       aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
952       QString anIconName = dm->module()->iconName();
953       if (!anIconName.isEmpty()) {
954         _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
955         if (anAttr)
956           anAttr->SetPixMap(anIconName.toStdString());
957       }
958
959       // Set default engine IOR
960       // Issue 21377 - using separate engine for each type of light module
961       std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
962                                                                            true );
963       aBuilder->DefineComponentInstance(aComp, anEngineIOR);
964       //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
965       SalomeApp_DataModel::synchronize( aComp, this );
966     }
967     else {
968       _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
969       aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
970       QString anIconName = dm->module()->iconName();
971       if (!anIconName.isEmpty()) {
972         _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
973         if (anAttr)
974           anAttr->SetPixMap(anIconName.toStdString());
975       }
976       // Set default engine IOR
977     }
978   }
979 }
980
981 /*!
982   Open data model
983 */
984 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
985 {
986   if (!dm)
987     return false;
988
989   //  SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
990   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
991   _PTR(Study)       aStudy = studyDS(); // shared_ptr cannot be used here
992   _PTR(SComponent)  aSComp;
993   QString anEngine;
994   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
995   if (!aModule) {
996     // Issue 21377 - using separate engine for each type of light module
997     std::string aCompDataType = dm->module()->name().toStdString();
998     anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
999     aSComp = aStudy->FindComponent( aCompDataType );
1000   }
1001   else {
1002     SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1003     if ( aDM ) {
1004       QString anId = aDM->getRootEntry( this );
1005       if ( anId.isEmpty() )
1006         return true; // Probably nothing to load
1007       anEngine = aDM->getModule()->engineIOR();
1008       if ( anEngine.isEmpty() )
1009         return false;
1010       aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1011     }
1012   }
1013   if ( aSComp ) {
1014     _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1015     if ( aBuilder ) {
1016       try {
1017         aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1018       }
1019       catch( const SALOME::SALOME_Exception& ) {
1020         // Oops, something went wrong while loading -> return an error
1021         return false;
1022       }
1023       // Something has been read -> create data model tree
1024       //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1025       // aDM->buildTree( aSComp, 0, this );
1026     }
1027   } else {
1028     // Don't return false here, for there might be no data
1029     // for a given component in the study yet
1030   }
1031   QStringList listOfFiles;
1032   openModuleData(dm->module()->name(), listOfFiles);
1033   if (dm && dm->open(studyName, this, listOfFiles)) {
1034     // Remove the files and temporary directory, created
1035     // for this module by LightApp_Engine_i::Load()
1036     bool isMultiFile = false; // TODO: decide, how to access this parameter
1037     RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1038
1039     // Something has been read -> create data model tree
1040     LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1041     if ( aDM )
1042       aDM->update(NULL, this);
1043     return true;
1044   }
1045   return false;
1046 }
1047
1048 /*!
1049   Create new study name.
1050 */
1051 QString SalomeApp_Study::newStudyName() const
1052 {
1053   std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1054   QString prefix( "Study%1" ), newName, curName;
1055   int i = 1, j, n = studies.size();
1056   while ( newName.isEmpty() ){
1057     curName = prefix.arg( i );
1058     for ( j = 0 ; j < n; j++ ){
1059       if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1060         break;
1061     }
1062     if ( j == n )
1063       newName = curName;
1064     else
1065       i++;
1066   }
1067   return newName;
1068 }
1069
1070 /*!
1071   Note that this method does not create or activate SalomeApp_Engine_i instance,
1072   therefore it can be called safely for any kind of module, but for full
1073   modules it returns an empty list.
1074   \return list of files used by module: to be used by CORBAless modules
1075   \param theModuleName - name of module
1076 */
1077 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName  ) const
1078 {
1079   // Issue 21377 - using separate engine for each type of light module
1080   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1081   if (aDefaultEngine)
1082     return aDefaultEngine->GetListOfFiles(id());
1083
1084   std::vector<std::string> aListOfFiles;
1085   return aListOfFiles;
1086 }
1087
1088 /*!
1089   Sets list of files used by module: to be used by CORBAless modules.
1090   Note that this method does not create or activate SalomeApp_Engine_i instance,
1091   therefore it can be called safely for any kind of module, but for full
1092   modules it simply does nothing.
1093   \param theModuleName - name of module
1094   \param theListOfFiles - list of files
1095 */
1096 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1097                                        const std::vector<std::string> theListOfFiles )
1098 {
1099   // Issue 21377 - using separate engine for each type of light module
1100   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1101   if (aDefaultEngine)
1102     aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1103 }
1104
1105 /*!
1106   \return temporary directory for saving files of modules
1107 */
1108 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool  isMultiFile )
1109 {
1110   std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1111   std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1112   return aTmpDir;
1113 }
1114
1115 /*!
1116   Removes temporary files
1117 */
1118 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1119 {
1120   if (isMultiFile)
1121     return;
1122
1123   std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1124   if (aListOfFiles.size() > 0) {
1125     std::string aTmpDir = aListOfFiles[0];
1126
1127     const int n = aListOfFiles.size() - 1;
1128     SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1129     aSeq->length(n);
1130     for (int i = 0; i < n; i++)
1131       aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1132
1133     SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1134   }
1135 }
1136
1137 /*!
1138   Mark the study as saved in the file
1139   \param theFileName - the name of file
1140 */
1141 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1142 {
1143   setStudyName(theFileName);
1144   studyDS()->Name(theFileName.toStdString());
1145   setIsSaved( isSaved );
1146 }
1147
1148 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1149 {
1150   LightApp_DataObject* o = dynamic_cast<LightApp_DataObject*>( myObserver ? myObserver->findObject( theEntry.toLatin1().constData() ) : 0 );
1151   return o;
1152 }
1153
1154 /*!
1155   Deletes all references to object
1156   \param obj - object
1157 */
1158 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1159 {
1160   _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1161   std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1162   for( int i=0, n=aRefs.size(); i<n; i++ )
1163   {
1164     _PTR( SObject ) o = aRefs[i];
1165     if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1166     {
1167       sb->RemoveReference( o );
1168       sb->RemoveObjectWithChildren( o );
1169     }
1170   }
1171 }
1172
1173 /*!
1174   \return real entry by entry of reference
1175   \param entry - entry of reference object
1176 */
1177 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1178 {
1179   _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1180   _PTR(SObject) refobj;
1181
1182   if( obj && obj->ReferencedObject( refobj ) )
1183     return refobj->GetID().c_str();
1184   return LightApp_Study::referencedToEntry( entry );
1185 }
1186
1187 /*!
1188   \return component data type for entry
1189 */
1190 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1191 {
1192   _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1193   if ( !obj )
1194     return LightApp_Study::componentDataType( entry );
1195   return obj->GetFatherComponent()->ComponentDataType().c_str();
1196 }
1197
1198 /*!
1199   \return true if entry corresponds to component
1200 */
1201 bool SalomeApp_Study::isComponent( const QString& entry ) const
1202 {
1203   _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1204   return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1205 }
1206
1207 /*!
1208   \return entries of object children
1209 */
1210 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1211 {
1212   _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1213   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1214   anIter->InitEx( true );
1215   while( anIter->More() )
1216   {
1217     _PTR(SObject) val( anIter->Value() );
1218     child_entries.append( val->GetID().c_str() );
1219     anIter->Next();
1220   }
1221 }
1222
1223 /*!
1224   Fills list with components names
1225   \param comp - list to be filled
1226 */
1227 void SalomeApp_Study::components( QStringList& comps ) const
1228 {
1229   for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1230   {
1231     _PTR(SComponent) aComponent ( it->Value() );
1232     // skip the magic "Interface Applicative" component
1233     if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1234       comps.append( aComponent->ComponentDataType().c_str() );
1235   }
1236 }
1237
1238 /*!
1239   Get the entry for the given module
1240   \param comp - list to be filled
1241   \return module root's entry
1242 */
1243 QString SalomeApp_Study::centry( const QString& comp ) const
1244 {
1245   QString e;
1246   for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1247   {
1248     _PTR(SComponent) aComponent ( it->Value() );
1249     if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1250       e = aComponent->GetID().c_str();
1251   }
1252   return e;
1253 }
1254
1255 /*!
1256   \return a list of saved points' IDs
1257 */
1258 std::vector<int> SalomeApp_Study::getSavePoints()
1259 {
1260   std::vector<int> v;
1261
1262   _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1263   if(!so) return v;
1264
1265   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1266   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1267   for(; anIter->More(); anIter->Next())
1268   {
1269     _PTR(SObject) val( anIter->Value() );
1270     _PTR(GenericAttribute) genAttr;
1271     if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1272   }
1273
1274   return v;
1275 }
1276
1277 /*!
1278   Removes a given save point
1279 */
1280 void SalomeApp_Study::removeSavePoint(int savePoint)
1281 {
1282   if(savePoint <= 0) return;
1283  _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1284   _PTR(SObject) so = AP->GetSObject();
1285   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1286   builder->RemoveObjectWithChildren(so);
1287 }
1288
1289 /*!
1290   \return a name of save point
1291 */
1292 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1293 {
1294   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1295   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1296   return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1297 }
1298
1299 /*!
1300   Sets a name of save point
1301 */
1302 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1303 {
1304   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1305   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1306   ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1307 }
1308
1309 /*!
1310  * \brief Restores the study state
1311  */
1312 void SalomeApp_Study::restoreState(int savePoint)
1313 {
1314   SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1315 }
1316
1317
1318 /*!
1319   Slot: called on change of a root of a data model. Redefined from CAM_Study
1320 */
1321 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1322 {
1323   LightApp_Study::updateModelRoot( dm );
1324
1325   // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1326   // it must always be the last one.
1327   ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );
1328 }