Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / SalomeApp / SalomeApp_Study.cxx
1 //  Copyright (C) 2007-2008  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 #include "SalomeApp_Study.h"
23
24 #include "SalomeApp_Module.h"
25 #include "SalomeApp_DataObject.h"
26 #include "SalomeApp_DataModel.h"
27 #include "SalomeApp_Application.h"
28 #include "SalomeApp_Engine_i.hxx"
29 #include "SalomeApp_VisualState.h"
30
31 // temporary commented
32 //#include <OB_Browser.h>
33
34 #include <SUIT_ResourceMgr.h>
35
36 #include "utilities.h"
37
38 #include "SALOMEDS_Tool.hxx"
39
40 #include "SALOMEDSClient_ClientFactory.hxx"
41
42 #include <SALOMEconfig.h>
43 #include CORBA_SERVER_HEADER(SALOME_Exception)
44
45 using namespace std;
46
47 /*!
48   Constructor.
49 */
50 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
51 : LightApp_Study( app )
52 {
53 }  
54
55 /*!
56   Destructor.
57 */
58 SalomeApp_Study::~SalomeApp_Study()
59 {
60 }
61
62 /*!
63   Gets study id.
64 */
65 int SalomeApp_Study::id() const
66 {
67   int id = -1;
68   if ( myStudyDS )
69     id = studyDS()->StudyId();
70   return id;
71 }
72
73 /*!
74   Gets studyDS pointer.
75 */
76 _PTR(Study) SalomeApp_Study::studyDS() const
77 {
78   return myStudyDS;
79 }
80
81 /*!
82   Create document.
83 */
84 bool SalomeApp_Study::createDocument( const QString& theStr )
85 {
86   MESSAGE( "openDocument" );
87
88   // initialize myStudyDS, read HDF file
89   QString aName = newStudyName();
90   _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.toStdString() ) );
91   if ( !study )
92     return false;
93
94   setStudyDS( study );
95   setStudyName( aName );
96
97   // create myRoot
98   setRoot( new SalomeApp_RootObject( this ) );
99
100   bool aRet = CAM_Study::createDocument( theStr );
101   emit created( this );
102
103   return aRet;
104 }
105
106 /*!
107   Opens document
108   \param theFileName - name of file
109 */
110 bool SalomeApp_Study::openDocument( const QString& theFileName )
111 {
112   MESSAGE( "openDocument" );
113
114   // initialize myStudyDS, read HDF file
115   _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( (char*) theFileName.toStdString().c_str() ) );
116   if ( !study )
117     return false;
118
119   setStudyDS( study );
120
121   setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
122
123   // update loaded data models: call open() and update() on them.
124   ModelList dm_s;
125   dataModels( dm_s );
126   QListIterator<CAM_DataModel*> it( dm_s );
127   while ( it.hasNext() ) 
128     openDataModel( studyName(), it.next() );
129   
130   // this will build a SUIT_DataObject-s tree under myRoot member field
131   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
132   // but tree that corresponds to not-loaded data models will be updated any way. 
133   ((SalomeApp_Application*)application())->updateObjectBrowser( false ); 
134
135   bool res = CAM_Study::openDocument( theFileName );
136   
137   emit opened( this );
138   study->IsSaved(true);
139
140   bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
141   if ( restore ) {
142     std::vector<int> savePoints = getSavePoints();
143     if ( savePoints.size() > 0 )
144       SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
145   }
146
147   ((SalomeApp_Application*)application())->updateObjectBrowser( true ); 
148   return res;
149 }
150
151 /*!
152   Connects GUI study to SALOMEDS one already loaded into StudyManager
153   \param theStudyName - name of study
154 */
155 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
156 {
157   MESSAGE( "loadDocument" );
158
159   // obtain myStudyDS from StudyManager
160   _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( (char*) theStudyName.toStdString().c_str() ) );
161   if ( !study )
162     return false;
163
164   setStudyDS( study );
165
166   setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
167
168   //SRN: BugID IPAL9021, put there the same code as in a method openDocument
169
170   // update loaded data models: call open() and update() on them.
171   ModelList dm_s;
172   dataModels( dm_s );
173
174   QListIterator<CAM_DataModel*> it( dm_s );
175   while ( it.hasNext() )
176     openDataModel( studyName(), it.next() );
177
178   // this will build a SUIT_DataObject-s tree under myRoot member field
179   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
180   // but tree that corresponds to not-loaded data models will be updated any way. 
181   ((SalomeApp_Application*)application())->updateObjectBrowser( false ); 
182
183   bool res = CAM_Study::openDocument( theStudyName );
184   emit opened( this );
185
186   bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
187   if ( restore ) {
188     std::vector<int> savePoints = getSavePoints();
189     if ( savePoints.size() > 0 )
190       SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
191   }
192
193   //SRN: BugID IPAL9021: End
194   return res;
195 }
196
197 /*!
198   Saves document
199   \param theFileName - name of file
200 */
201 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
202 {
203   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
204   if ( store )
205     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
206   
207   ModelList list; dataModels( list );
208
209   QListIterator<CAM_DataModel*> it( list );
210   QStringList listOfFiles;
211   while ( it.hasNext() ) {
212     if ( SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)it.next() ) {
213       listOfFiles.clear();
214       aModel->saveAs( theFileName, this, listOfFiles );
215       if ( !listOfFiles.isEmpty() )
216         saveModuleData(aModel->module()->name(), listOfFiles);
217     }
218   }
219
220   // save SALOMEDS document
221   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
222   if( !resMgr )
223     return false;
224
225   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
226   bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
227   bool res = (isAscii ? 
228     SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toStdString(), studyDS(), isMultiFile ) :
229     SalomeApp_Application::studyMgr()->SaveAs     ( theFileName.toStdString(), studyDS(), isMultiFile ))
230     && CAM_Study::saveDocumentAs( theFileName );
231   
232   res = res && saveStudyData(theFileName);
233
234   if ( res )
235     emit saved( this );
236
237   return res;
238 }
239
240 /*!
241   Saves previously opened document
242 */
243 bool SalomeApp_Study::saveDocument()
244 {
245   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
246   if ( store )
247     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
248
249   ModelList list; dataModels( list );
250
251   QListIterator<CAM_DataModel*> it( list );
252   QStringList listOfFiles;
253   while ( it.hasNext() ) {
254     if ( SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)it.next() ) {
255       listOfFiles.clear();
256       aModel->save(listOfFiles);
257       if ( !listOfFiles.isEmpty() ) 
258         saveModuleData(aModel->module()->name(), listOfFiles);
259     }
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).toStdString();
350     anIndex++;
351   }
352   SetListOfFiles(theModuleName.toStdString().c_str(), 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.toStdString().c_str() );
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   QListIterator<CAM_DataModel*> it( list );
382   std::vector<std::string> listOfFiles(0);
383   while ( it.hasNext() )
384     if ( SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)it.next() )
385       SetListOfFiles(aModel->module()->name().toStdString().c_str(), listOfFiles);
386   return true;
387 }
388
389 /*!
390   Loads data for study
391 */
392 bool SalomeApp_Study::openStudyData( const QString& theFileName )
393 {
394  return true;
395 }
396
397 /*!
398   Set studyDS.
399 */
400 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
401 {
402   myStudyDS = s;
403 }
404
405 /*!
406   Insert data model.
407 */
408 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
409 {
410   MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
411
412   CAM_Study::dataModelInserted(dm);
413
414   //  addComponent(dm);
415 }
416
417 /*!
418   Create SComponent for module, using default engine (CORBAless)
419 */
420 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
421 {
422   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
423   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
424   if (!aModule) {
425     // Check SComponent existance
426     _PTR(Study) aStudy = studyDS();
427     if (!aStudy) 
428       return;
429     _PTR(SComponent) aComp = aStudy->FindComponent(dm->module()->name().toStdString());
430     if (!aComp) {
431       // Create SComponent
432       _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
433       aComp = aBuilder->NewComponent(dm->module()->name().toStdString());
434       aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
435       QString anIconName = dm->module()->iconName();
436       if (!anIconName.isEmpty()) {
437         _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
438         if (anAttr)
439           anAttr->SetPixMap(anIconName.toStdString());
440       }
441       // Set default engine IOR
442       aBuilder->DefineComponentInstance(aComp, SalomeApp_Application::defaultEngineIOR().toStdString());
443       //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
444       SalomeApp_DataModel::synchronize( aComp, this );
445     }
446   }
447 }
448
449 /*!
450   Open data model
451 */
452 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
453 {
454   if (!dm)
455     return false;
456
457   //  SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
458   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
459   _PTR(Study)       aStudy = studyDS(); // shared_ptr cannot be used here
460   _PTR(SComponent)  aSComp;
461   QString anEngine;
462   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
463   if (!aModule) {
464     anEngine = SalomeApp_Application::defaultEngineIOR();
465     aSComp = aStudy->FindComponent(dm->module()->name().toStdString());
466   }
467   else {
468     SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
469     if ( aDM ) {
470       QString anId = aDM->getRootEntry( this );
471       if ( anId.isEmpty() )
472         return true; // Probably nothing to load
473       anEngine = aDM->getModule()->engineIOR();
474       if ( anEngine.isEmpty() )
475         return false;
476       aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
477     }
478   }
479   if ( aSComp ) {
480     _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
481     if ( aBuilder ) {
482       try {
483         aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
484       }
485       catch( const SALOME::SALOME_Exception& ) {
486         // Oops, something went wrong while loading -> return an error
487         return false;
488       }
489       // Something has been read -> create data model tree
490       //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
491       // aDM->buildTree( aSComp, 0, this );
492     }
493   } else {
494     // Don't return false here, for there might be no data
495     // for a given component in the study yet
496   }
497   QStringList listOfFiles;
498   openModuleData(dm->module()->name(), listOfFiles);
499   if (dm && dm->open(studyName, this, listOfFiles)) {
500     // Remove the files and temporary directory, created
501     // for this module by LightApp_Engine_i::Load()
502     bool isMultiFile = false; // TODO: decide, how to access this parameter
503     RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
504
505     // Something has been read -> create data model tree
506     LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
507     if ( aDM )
508       aDM->update(NULL, this);
509     return true;
510   }
511   return false;
512 }
513
514 /*!
515   Create new study name.
516 */
517 QString SalomeApp_Study::newStudyName() const
518 {
519   std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
520   QString prefix( "Study%1" ), newName, curName;
521   int i = 1, j, n = studies.size();
522   while ( newName.isEmpty() ){
523     curName = prefix.arg( i );
524     for ( j = 0 ; j < n; j++ ){
525       if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
526         break;
527     }
528     if ( j == n )
529       newName = curName;
530     else
531       i++;
532   }
533   return newName;
534 }
535
536 /*!
537   \return list of files used by module: to be used by CORBAless modules
538   \param theModuleName - name of module
539 */
540 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName  ) const
541 {
542   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance();
543   if (aDefaultEngine)
544     return aDefaultEngine->GetListOfFiles(id(), theModuleName);
545
546   std::vector<std::string> aListOfFiles;
547   return aListOfFiles;
548 }
549
550 /*!
551   Sets list of files used by module: to be used by CORBAless modules
552   \param theModuleName - name of module
553   \param theListOfFiles - list of files
554 */
555 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
556                                        const std::vector<std::string> theListOfFiles )
557 {
558   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance();
559   if (aDefaultEngine)
560     aDefaultEngine->SetListOfFiles(theListOfFiles, id(), theModuleName);
561 }
562
563 /*!
564   \return temporary directory for saving files of modules
565 */
566 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool  isMultiFile )
567 {
568   std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
569   std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
570   return aTmpDir;
571 }
572
573 /*!
574   Removes temporary files
575 */
576 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
577 {
578   if (isMultiFile)
579     return;
580
581   std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
582   if (aListOfFiles.size() > 0) {
583     std::string aTmpDir = aListOfFiles[0];
584
585     const int n = aListOfFiles.size() - 1;
586     SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
587     aSeq->length(n);
588     for (int i = 0; i < n; i++)
589       aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
590
591     SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
592   }
593 }
594
595 /*!
596   Mark the study as saved in the file
597   \param theFileName - the name of file
598 */
599 void SalomeApp_Study::markAsSavedIn(QString theFileName)
600 {
601   setStudyName(theFileName);
602   setIsSaved(true);
603 }
604
605 /*!
606   Deletes all references to object
607   \param obj - object
608 */
609 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
610 {
611   _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
612   std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
613   for( int i=0, n=aRefs.size(); i<n; i++ )
614   {
615     _PTR( SObject ) o = aRefs[i];
616     if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
617     {
618       sb->RemoveReference( o );
619       sb->RemoveObjectWithChildren( o );
620     }
621   }
622 }
623
624 /*!
625   \return real entry by entry of reference
626   \param entry - entry of reference object
627 */
628 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
629 {
630   _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
631   _PTR(SObject) refobj;
632
633   if( obj && obj->ReferencedObject( refobj ) )
634     return refobj->GetID().c_str();
635   return LightApp_Study::referencedToEntry( entry );
636 }
637
638 /*!
639   \return component data type for entry
640 */
641 QString SalomeApp_Study::componentDataType( const QString& entry ) const
642 {
643   _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
644   if ( !obj )
645     return LightApp_Study::componentDataType( entry );
646   return obj->GetFatherComponent()->ComponentDataType().c_str();
647 }
648
649 /*!
650   \return true if entry corresponds to component
651 */
652 bool SalomeApp_Study::isComponent( const QString& entry ) const
653 {
654   _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
655   return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
656 }
657
658 /*!
659   \return entries of object children
660 */
661 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
662 {
663   _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
664   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
665   anIter->InitEx( true );
666   while( anIter->More() )
667   {
668     _PTR(SObject) val( anIter->Value() );
669     child_entries.append( val->GetID().c_str() );
670     anIter->Next();
671   }
672 }
673
674 /*!
675   Fills list with components names
676   \param comp - list to be filled
677 */
678 void SalomeApp_Study::components( QStringList& comps ) const
679 {
680   for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() ) 
681   {
682     _PTR(SComponent) aComponent ( it->Value() );
683     if( aComponent && aComponent->ComponentDataType() == "Interface Applicative" )
684       continue; // skip the magic "Interface Applicative" component
685     comps.append( aComponent->ComponentDataType().c_str() );
686   }
687 }
688
689 /*!
690   \return a list of saved points' IDs
691 */
692 std::vector<int> SalomeApp_Study::getSavePoints()
693 {
694   std::vector<int> v;
695
696   _PTR(SObject) so = studyDS()->FindComponent("Interface Applicative");
697   if(!so) return v;
698
699   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
700   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
701   for(; anIter->More(); anIter->Next())
702   {
703     _PTR(SObject) val( anIter->Value() );
704     _PTR(GenericAttribute) genAttr;
705     if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
706   }
707
708   return v;
709 }
710
711 /*!
712   Removes a given save point
713 */
714 void SalomeApp_Study::removeSavePoint(int savePoint)
715 {
716   if(savePoint <= 0) return;
717  _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName(), savePoint);
718   _PTR(SObject) so = AP->GetSObject();
719   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
720   builder->RemoveObjectWithChildren(so);
721 }
722
723 /*!
724   \return a name of save point
725 */
726 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
727 {
728   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName(), savePoint);
729   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
730   return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
731 }
732
733 /*!
734   Sets a name of save point
735 */
736 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
737 {
738   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName(), savePoint);
739   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
740   ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
741 }
742
743 /*!
744   \return a name of the component where visual parameters are stored
745 */
746 std::string SalomeApp_Study::getVisualComponentName()
747 {
748   return "Interface Applicative";
749 }
750
751 /*!
752  * \brief Restores the study state
753  */
754 void SalomeApp_Study::restoreState(int savePoint)
755 {
756   SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
757 }
758
759
760 /*!
761   Slot: called on change of a root of a data model. Redefined from CAM_Study
762 */
763 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
764 {
765   LightApp_Study::updateModelRoot( dm );
766
767   // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
768   // it must always be the last one.
769   ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );
770 }