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