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