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