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