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