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