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