Salome HOME
aeee814b63b4515a6ba051db89f3559a2dcd25bc
[modules/gui.git] / src / SalomeApp / SalomeApp_Study.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 #include "SalomeApp_Study.h"
20
21 #include "SalomeApp_Module.h"
22 #include "SalomeApp_DataModel.h"
23 #include "SalomeApp_DataObject.h"
24 #include "SalomeApp_Application.h"
25 #include "SalomeApp_Engine_i.hxx"
26 #include "SalomeApp_VisualState.h"
27
28 #include "LightApp_RootObject.h"
29
30 #include <OB_Browser.h>
31
32 #include <SUIT_ResourceMgr.h>
33
34 #include <qptrlist.h>
35 #include <qapplication.h>
36 #include <qdict.h>
37
38 #include "utilities.h"
39 #include <iostream>
40 #include <string>
41 #include <vector>
42
43 #include <SUIT_Session.h>
44
45 #include "SALOMEDS_Tool.hxx"
46
47 #include "SALOMEDSClient_ClientFactory.hxx"
48 #include "SALOMEDSClient_IParameters.hxx"
49
50 #include <SALOMEconfig.h>
51 #include CORBA_SERVER_HEADER(SALOME_Exception)
52
53 using namespace std;
54
55 /*!
56   Constructor.
57 */
58 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
59 : LightApp_Study( app )
60 {
61 }  
62
63 /*!
64   Destructor.
65 */
66 SalomeApp_Study::~SalomeApp_Study()
67 {
68 }
69
70 /*!
71   Gets study id.
72 */
73 int SalomeApp_Study::id() const
74 {
75   int id = -1;
76   if ( myStudyDS )
77     id = studyDS()->StudyId();
78   return id;
79 }
80
81 /*!
82   Gets studyDS pointer.
83 */
84 _PTR(Study) SalomeApp_Study::studyDS() const
85 {
86   return myStudyDS;
87 }
88
89 /*!
90   Create document.
91 */
92 void SalomeApp_Study::createDocument()
93 {
94   MESSAGE( "openDocument" );
95
96   // initialize myStudyDS, read HDF file
97   QString aName = newStudyName();
98   _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.latin1() ) );
99   if ( !study )
100     return;
101
102   setStudyDS( study );
103   setStudyName( aName );
104
105   // create myRoot
106   setRoot( new LightApp_RootObject( this ) );
107
108   CAM_Study::createDocument();
109   emit created( this );
110 }
111
112 /*!
113   Opens document
114   \param theFileName - name of file
115 */
116 bool SalomeApp_Study::openDocument( const QString& theFileName )
117 {
118   MESSAGE( "openDocument" );
119
120   // initialize myStudyDS, read HDF file
121   _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( (char*) theFileName.latin1() ) );
122   if ( !study )
123     return false;
124
125   setStudyDS( study );
126
127   setRoot( new LightApp_RootObject( this ) ); // create myRoot
128
129   // update loaded data models: call open() and update() on them.
130   ModelList dm_s;
131   dataModels( dm_s );
132   for ( ModelListIterator it( dm_s ); it.current(); ++it )
133     openDataModel( studyName(), it.current() );
134
135   // this will build a SUIT_DataObject-s tree under myRoot member field
136   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
137   // but tree that corresponds to not-loaded data models will be updated any way. 
138   ((SalomeApp_Application*)application())->updateObjectBrowser( false ); 
139
140   bool res = CAM_Study::openDocument( theFileName );
141   
142   emit opened( this );
143   study->IsSaved(true);
144
145   bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
146   if ( restore ) {
147     std::vector<int> savePoints = getSavePoints();
148     if ( savePoints.size() > 0 )
149       SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
150   }
151
152   return res;
153 }
154
155 /*!
156   Connects GUI study to SALOMEDS one already loaded into StudyManager
157   \param theStudyName - name of study
158 */
159 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
160 {
161   MESSAGE( "loadDocument" );
162
163   // obtain myStudyDS from StudyManager
164   _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( (char*) theStudyName.latin1() ) );
165   if ( !study )
166     return false;
167
168   setStudyDS( study );
169
170   setRoot( new LightApp_RootObject( this ) ); // create myRoot
171
172   //SRN: BugID IPAL9021, put there the same code as in a method openDocument
173
174   // update loaded data models: call open() and update() on them.
175   ModelList dm_s;
176   dataModels( dm_s );
177
178   for ( ModelListIterator it( dm_s ); it.current(); ++it )
179     openDataModel( studyName(), it.current() );
180
181   // this will build a SUIT_DataObject-s tree under myRoot member field
182   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
183   // but tree that corresponds to not-loaded data models will be updated any way. 
184   ((SalomeApp_Application*)application())->updateObjectBrowser( false ); 
185
186   bool res = CAM_Study::openDocument( theStudyName );
187   emit opened( this );
188
189   bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
190   if ( restore ) {
191     std::vector<int> savePoints = getSavePoints();
192     if ( savePoints.size() > 0 )
193       SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
194   }
195
196   //SRN: BugID IPAL9021: End
197
198   return res;
199 }
200
201 /*!
202   Saves document
203   \param theFileName - name of file
204 */
205 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
206 {
207   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
208   if ( store )
209     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
210   
211   ModelList list; dataModels( list );
212
213   SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
214   QStringList listOfFiles;
215   for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() ) {
216     listOfFiles.clear();
217     aModel->saveAs( theFileName, this, listOfFiles );
218     if ( !listOfFiles.isEmpty() )
219       saveModuleData(aModel->module()->name(), listOfFiles);
220   }
221
222   // save SALOMEDS document
223   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
224   if( !resMgr )
225     return false;
226
227   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
228   bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
229   bool res = (isAscii ? 
230     SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.latin1(), studyDS(), isMultiFile ) :
231     SalomeApp_Application::studyMgr()->SaveAs     ( theFileName.latin1(), studyDS(), isMultiFile ))
232     && CAM_Study::saveDocumentAs( theFileName );
233   
234   res = res && saveStudyData(theFileName);
235
236   if ( res )
237     emit saved( this );
238
239   return res;
240 }
241
242 /*!
243   Saves previously opened document
244 */
245 bool SalomeApp_Study::saveDocument()
246 {
247   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
248   if ( store )
249     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
250
251   ModelList list; dataModels( list );
252
253   SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
254   QStringList listOfFiles;
255   for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() ) {
256     listOfFiles.clear();
257     aModel->save(listOfFiles);
258     if ( !listOfFiles.isEmpty() ) 
259       saveModuleData(aModel->module()->name(), listOfFiles);
260   }
261
262   // save SALOMEDS document
263   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
264   if( !resMgr )
265     return false;
266
267   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
268   bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
269   bool res = (isAscii ? 
270     SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
271     SalomeApp_Application::studyMgr()->Save     ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
272
273   res = res && saveStudyData(studyName());
274   if ( res )
275     emit saved( this );  
276
277   return res;
278 }
279
280 /*!
281   Closes document
282 */
283 void SalomeApp_Study::closeDocument(bool permanently)
284 {
285   LightApp_Study::closeDocument(permanently);
286
287   // close SALOMEDS document
288   _PTR(Study) studyPtr = studyDS();
289   if ( studyPtr )
290   {
291     if(permanently) {
292       SalomeApp_Application::studyMgr()->Close( studyPtr );
293     }
294     SALOMEDSClient_Study* aStudy = 0;
295     setStudyDS( _PTR(Study)(aStudy) );
296   }
297 }
298
299 /*!
300   \return true, if study is modified in comparison with last open/save
301 */
302 bool SalomeApp_Study::isModified() const
303 {
304   bool isAnyChanged = studyDS() && studyDS()->IsModified();
305   if (!isAnyChanged)
306     isAnyChanged = LightApp_Study::isModified();
307
308   return isAnyChanged; 
309 }
310
311 /*!
312   Set study modified to \a on.
313  */
314 void SalomeApp_Study::Modified()
315 {
316   if(_PTR(Study) aStudy = studyDS())
317     aStudy->Modified();
318   LightApp_Study::Modified();
319 }
320
321 /*!
322   \return if data model is saved
323 */
324 bool SalomeApp_Study::isSaved() const
325 {
326   bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
327   if (!isAllSaved)
328     isAllSaved = LightApp_Study::isSaved();
329
330   return isAllSaved; 
331 }
332
333 /*!
334   Saves data of module
335   \param theModuleName - name of module
336   \param theListOfFiles - list of files to be saved
337 */
338 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
339 {
340   int aNb = theListOfFiles.count();
341   if ( aNb == 0 )
342     return;
343
344   std::vector<std::string> aListOfFiles ( aNb );
345   int anIndex = 0;
346   for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
347     if ( (*it).isEmpty() )
348       continue;
349     aListOfFiles[anIndex] = (*it).latin1();
350     anIndex++;
351   }
352   SetListOfFiles(theModuleName, aListOfFiles);
353 }
354
355 /*!
356   Loads data of module
357   \param theModuleName - name of module
358   \param theListOfFiles - list of files to be loaded
359 */
360 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
361 {
362   std::vector<std::string> aListOfFiles =  GetListOfFiles( theModuleName );
363
364   int i, aLength = aListOfFiles.size() - 1;
365   if ( aLength < 0 )
366     return;
367
368   //Get a temporary directory for saved a file
369   theListOfFiles.append(aListOfFiles[0].c_str());
370
371   for(i = 0; i < aLength; i++)
372     theListOfFiles.append(aListOfFiles[i+1].c_str());
373 }
374
375 /*!
376   Saves data from study
377 */
378 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
379 {
380   ModelList list; dataModels( list );
381   SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
382   std::vector<std::string> listOfFiles(0);
383   for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() )
384     SetListOfFiles(aModel->module()->name(), listOfFiles);
385   return true;
386 }
387
388 /*!
389   Loads data for study
390 */
391 bool SalomeApp_Study::openStudyData( const QString& theFileName )
392 {
393  return true;
394 }
395
396 /*!
397   Set studyDS.
398 */
399 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
400 {
401   myStudyDS = s;
402 }
403
404 /*!
405   Insert data model.
406 */
407 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
408 {
409   MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name());
410
411   CAM_Study::dataModelInserted(dm);
412
413   //  addComponent(dm);
414 }
415
416 /*!
417   Create SComponent for module, using default engine (CORBAless)
418 */
419 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
420 {
421   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
422   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
423   if (!aModule) {
424     // Check SComponent existance
425     _PTR(Study) aStudy = studyDS();
426     if (!aStudy) 
427       return;
428     _PTR(SComponent) aComp = aStudy->FindComponent(dm->module()->name());
429     if (!aComp) {
430       // Create SComponent
431       _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
432       aComp = aBuilder->NewComponent(dm->module()->name());
433       aBuilder->SetName(aComp, dm->module()->moduleName().latin1());
434       QString anIconName = dm->module()->iconName();
435       if (!anIconName.isEmpty()) {
436         _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
437         if (anAttr)
438           anAttr->SetPixMap(anIconName.latin1());
439       }
440       // Set default engine IOR
441       aBuilder->DefineComponentInstance(aComp, SalomeApp_Application::defaultEngineIOR().latin1());
442       //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
443       SalomeApp_DataModel::synchronize( aComp, this );
444     }
445   }
446 }
447
448 /*!
449   Open data model
450 */
451 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
452 {
453   if (!dm)
454     return false;
455
456   //  SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
457   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
458   _PTR(Study)       aStudy = studyDS(); // shared_ptr cannot be used here
459   _PTR(SComponent)  aSComp;
460   QString anEngine;
461   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
462   if (!aModule) {
463     anEngine = SalomeApp_Application::defaultEngineIOR();
464     aSComp = aStudy->FindComponent(dm->module()->name());
465   }
466   else {
467     SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
468     if ( aDM ) {
469       QString anId = aDM->getRootEntry( this );
470       if ( anId.isEmpty() )
471         return true; // Probably nothing to load
472       anEngine = aDM->getModule()->engineIOR();
473       if ( anEngine.isEmpty() )
474         return false;
475       aSComp = aStudy->FindComponentID( std::string( anId.latin1() ) );
476     }
477   }
478   if ( aSComp ) {
479     _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
480     if ( aBuilder ) {
481       try {
482         aBuilder->LoadWith( aSComp, std::string( anEngine.latin1() ) );
483       }
484       catch( const SALOME::SALOME_Exception& ) {
485         // Oops, something went wrong while loading -> return an error
486         return false;
487       }
488       // Something has been read -> create data model tree
489       //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
490       // aDM->buildTree( aSComp, 0, this );
491     }
492   } else {
493     // Don't return false here, for there might be no data
494     // for a given component in the study yet
495   }
496   QStringList listOfFiles;
497   openModuleData(dm->module()->name(), listOfFiles);
498   if (dm && dm->open(studyName, this, listOfFiles)) {
499     // Remove the files and temporary directory, created
500     // for this module by LightApp_Engine_i::Load()
501     bool isMultiFile = false; // TODO: decide, how to access this parameter
502     RemoveTemporaryFiles( dm->module()->name(), isMultiFile );
503
504     // Something has been read -> create data model tree
505     LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
506     if ( aDM )
507       aDM->update(NULL, this);
508     return true;
509   }
510   return false;
511 }
512
513 /*!
514   Create new study name.
515 */
516 QString SalomeApp_Study::newStudyName() const
517 {
518   std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
519   QString prefix( "Study%1" ), newName, curName;
520   int i = 1, j, n = studies.size();
521   while ( newName.isEmpty() ){
522     curName = prefix.arg( i );
523     for ( j = 0 ; j < n; j++ ){
524       if ( !strcmp( studies[j].c_str(), curName.latin1() ) )
525         break;
526     }
527     if ( j == n )
528       newName = curName;
529     else
530       i++;
531   }
532   return newName;
533 }
534
535 /*!
536   \return list of files used by module: to be used by CORBAless modules
537   \param theModuleName - name of module
538 */
539 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName  ) const
540 {
541   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance();
542   if (aDefaultEngine)
543     return aDefaultEngine->GetListOfFiles(id(), theModuleName);
544
545   std::vector<std::string> aListOfFiles;
546   return aListOfFiles;
547 }
548
549 /*!
550   Sets list of files used by module: to be used by CORBAless modules
551   \param theModuleName - name of module
552   \param theListOfFiles - list of files
553 */
554 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
555                                        const std::vector<std::string> theListOfFiles )
556 {
557   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance();
558   if (aDefaultEngine)
559     aDefaultEngine->SetListOfFiles(theListOfFiles, id(), theModuleName);
560 }
561
562 /*!
563   \return temporary directory for saving files of modules
564 */
565 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool  isMultiFile )
566 {
567   std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
568   std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
569   return aTmpDir;
570 }
571
572 /*!
573   Removes temporary files
574 */
575 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
576 {
577   if (isMultiFile)
578     return;
579
580   std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
581   if (aListOfFiles.size() > 0) {
582     std::string aTmpDir = aListOfFiles[0];
583
584     const int n = aListOfFiles.size() - 1;
585     SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
586     aSeq->length(n);
587     for (int i = 0; i < n; i++)
588       aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
589
590     SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
591   }
592 }
593
594 /*!
595   Deletes all references to object
596   \param obj - object
597 */
598 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
599 {
600   _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
601   std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
602   for( int i=0, n=aRefs.size(); i<n; i++ )
603   {
604     _PTR( SObject ) o = aRefs[i];
605     if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
606     {
607       sb->RemoveReference( o );
608       sb->RemoveObjectWithChildren( o );
609     }
610   }
611 }
612
613 /*!
614   \return real entry by entry of reference
615   \param entry - entry of reference object
616 */
617 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
618 {
619   _PTR(SObject) obj = studyDS()->FindObjectID( entry.latin1() );
620   _PTR(SObject) refobj;
621
622   if( obj && obj->ReferencedObject( refobj ) )
623     return refobj->GetID().c_str();
624   return LightApp_Study::referencedToEntry( entry );
625 }
626
627 /*!
628   \return component data type for entry
629 */
630 QString SalomeApp_Study::componentDataType( const QString& entry ) const
631 {
632   _PTR(SObject) obj( studyDS()->FindObjectID( entry.latin1() ) );
633   if ( !obj )
634     return LightApp_Study::componentDataType( entry );
635   return obj->GetFatherComponent()->ComponentDataType().c_str();
636 }
637
638 /*!
639   \return true if entry corresponds to component
640 */
641 bool SalomeApp_Study::isComponent( const QString& entry ) const
642 {
643   _PTR(SObject) obj( studyDS()->FindObjectID( entry.latin1() ) );
644   return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
645 }
646
647 /*!
648   \return entries of object children
649 */
650 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
651 {
652   _PTR(SObject) SO = studyDS()->FindObjectID( entry.latin1() );
653   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
654   anIter->InitEx( true );
655   while( anIter->More() )
656   {
657     _PTR(SObject) val( anIter->Value() );
658     child_entries.append( val->GetID().c_str() );
659     anIter->Next();
660   }
661 }
662
663 /*!
664   Fills list with components names
665   \param comp - list to be filled
666 */
667 void SalomeApp_Study::components( QStringList& comps ) const
668 {
669   for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() ) 
670   {
671     _PTR(SComponent) aComponent ( it->Value() );
672     if( aComponent && aComponent->ComponentDataType() == "Interface Applicative" )
673       continue; // skip the magic "Interface Applicative" component
674     comps.append( aComponent->ComponentDataType().c_str() );
675   }
676 }
677
678 /*!
679   \return a list of saved points' IDs
680 */
681 std::vector<int> SalomeApp_Study::getSavePoints()
682 {
683   std::vector<int> v;
684
685   _PTR(SObject) so = studyDS()->FindComponent("Interface Applicative");
686   if(!so) return v;
687
688   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
689   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
690   for(; anIter->More(); anIter->Next())
691   {
692     _PTR(SObject) val( anIter->Value() );
693     _PTR(GenericAttribute) genAttr;
694     if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
695   }
696
697   return v;
698 }
699
700 /*!
701   Removes a given save point
702 */
703 void SalomeApp_Study::removeSavePoint(int savePoint)
704 {
705   if(savePoint <= 0) return;
706  _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName(), savePoint);
707   _PTR(SObject) so = AP->GetSObject();
708   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
709   builder->RemoveObjectWithChildren(so);
710 }
711
712 /*!
713   \return a name of save point
714 */
715 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
716 {
717   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName(), savePoint);
718   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
719   return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
720 }
721
722 /*!
723   Sets a name of save point
724 */
725 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
726 {
727   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName(), savePoint);
728   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
729   ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.latin1());
730 }
731
732 /*!
733   \return a name of the component where visual parameters are stored
734 */
735 std::string SalomeApp_Study::getVisualComponentName()
736 {
737   return "Interface Applicative";
738 }
739
740 /*!
741  * \brief Restores the study state
742  */
743 void SalomeApp_Study::restoreState(int savePoint)
744 {
745   SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
746 }
747
748
749 /*!
750   Slot: called on change of a root of a data model. Redefined from CAM_Study
751 */
752 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
753 {
754   LightApp_Study::updateModelRoot( dm );
755
756   // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
757   // it must always be the last one.
758   ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );
759 }