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