1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "SalomeApp_Study.h"
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"
32 // temporary commented
33 //#include <OB_Browser.h>
35 #include <QCoreApplication>
38 #include "SALOME_Event.h"
39 #include "Basics_Utils.hxx"
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>
48 #include <LightApp_Displayer.h>
50 #ifndef DISABLE_PYCONSOLE
51 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
54 #include "utilities.h"
56 #include "SALOMEDS_Tool.hxx"
58 #include "SALOMEDSClient_ClientFactory.hxx"
60 #include <SALOMEconfig.h>
61 #include CORBA_SERVER_HEADER(SALOME_Exception)
63 //#define NOTIFY_BY_EVENT
65 class ObserverEvent : public QEvent
68 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
78 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
80 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
81 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
85 Observer_i(_PTR(Study) aStudyDS, SalomeApp_Study* aStudy):QObject(aStudy)
92 SUIT_DataObject* findObject( const char* theID ) const
94 EntryMap::const_iterator it = entry2SuitObject.find( theID );
95 return it != entry2SuitObject.end() ? it->second : 0;
98 virtual void notifyObserverID(const char* theID, CORBA::Long event)
100 #ifdef NOTIFY_BY_EVENT
101 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
103 notifyObserverID_real(theID,event);
107 virtual bool event(QEvent *event)
109 if (event->type() == QEvent::User )
111 //START_TIMING(notify);
112 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
113 //END_TIMING(notify,100);
118 void notifyObserverID_real(const std::string& theID, long event)
120 SalomeApp_DataObject* suit_obj = 0;
125 _PTR(SObject) aSObj = myStudyDS->FindObjectID(theID);
126 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
128 if (!aSComp || aSComp->IsNull()) {
129 MESSAGE("Entry " << theID << " has not father component. Problem ??");
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
141 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
142 if (!aFatherSO || aFatherSO->IsNull()) {
143 MESSAGE("Father SObject is not found. Problem ??");
147 std::string parent_id = aFatherSO->GetID();
148 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
150 if (it == entry2SuitObject.end()) {
151 MESSAGE("Father data object is not found. Problem ??");
155 SalomeApp_DataObject* aFatherDO = it->second;
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();
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 );
167 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
168 oldFatherSA->updateItem();
173 suit_obj = new SalomeApp_DataObject(aSObj);
174 entry2SuitObject[theID] = suit_obj;
177 suit_obj->updateItem();
178 // define position in the data tree (in aFatherDO) to insert the aSObj
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) {
189 aFatherDO->insertChildAtPos(suit_obj, pos);
190 //aFatherDO->insertChild(suit_obj, pos);
191 aFatherDO->updateItem();
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);
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 !!!");
205 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
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 ??");
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() );
221 if ( parent_id.length() == 3 ) // "0:1" - root item?
223 // It's probably a SComponent
224 if ( theID == aSComp->GetID() )
225 suit_obj = new SalomeApp_ModuleObject( aSComp );
227 suit_obj = new SalomeApp_DataObject( aSObj );
231 suit_obj = new SalomeApp_DataObject( aSObj );
234 it = entry2SuitObject.find( parent_id );
235 if ( it != entry2SuitObject.end() ) {
236 SalomeApp_DataObject* father = it->second;
237 father->insertChildAtTag( suit_obj, tag );
240 if ( parent_id.length() == 3 ) // "0:1" - root item?
242 // This should be for a module
243 SUIT_DataObject* father=myStudy->root();
244 father->appendChild(suit_obj);
248 MESSAGE("SHOULD NEVER GET HERE!!!");
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 );
255 std::string::size_type debut = 0;
256 std::string::size_type fin;
257 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
259 fin = obj_id.find_first_of( ':', debut );
260 if ( fin == std::string::npos ) {
262 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
263 entry2SuitObject[parent_id] = anObj;
266 anID = root_id + obj_id.substr( 0, fin );
267 EntryMapIter it2 = entry2SuitObject.find( anID );
268 if ( it2 == entry2SuitObject.end() ) {
269 //the ID is not known in entry2SuitObject
270 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
271 entry2SuitObject[anID] = anObj;
277 anObj->insertChildAtTag( suit_obj, tag );
280 entry2SuitObject[theID] = suit_obj;
281 } // END: work with study structure
286 EntryMapIter it = entry2SuitObject.find( theID );
287 if ( it != entry2SuitObject.end() )
289 suit_obj = it->second;
290 suit_obj->updateItem();
291 SUIT_DataObject* father=suit_obj->parent();
293 father->removeChild(suit_obj);
294 entry2SuitObject.erase(it);
298 MESSAGE("Want to remove an unknown object" << theID);
304 //MESSAGE("Want to modify an object " << theID);
305 EntryMapIter it = entry2SuitObject.find( theID );
306 if ( it != entry2SuitObject.end() )
308 suit_obj = it->second;
309 suit_obj->updateItem();
313 MESSAGE("Want to modify an unknown object" << theID);
317 case 5: //IOR of the object modified
319 EntryMapIter it = entry2SuitObject.find( theID );
320 if ( it != entry2SuitObject.end() )
321 suit_obj = it->second;
323 /* Define visibility state */
324 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
325 if ( suit_obj && !isComponent ) {
326 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
327 if (!moduleTitle.isEmpty()) {
328 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
330 if(aDisplayer->canBeDisplayed(theID.c_str())) {
331 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
332 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
335 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
341 #ifndef DISABLE_PYCONSOLE
342 case 6: //NoteBook variables were modified
344 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
348 default:MESSAGE("Unknown event: " << event);break;
350 } //notifyObserverID_real
355 entry2SuitObject.clear();
356 SUIT_DataObject* o = myStudy->root();
358 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
360 std::string entry = so->entry().toLatin1().constData();
362 entry2SuitObject[entry] = so;
364 if ( o->childCount() > 0 ) {
365 // parse the children
368 else if ( o->nextBrother() > 0 ) {
369 o = o->nextBrother();
372 // step to the next appropriate parent
375 if ( o->nextBrother() ) {
376 o = o->nextBrother();
386 _PTR(Study) myStudyDS;
387 SalomeApp_Study* myStudy;
388 EntryMap entry2SuitObject;
395 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
396 : LightApp_Study( app ), myObserver( 0 )
403 SalomeApp_Study::~SalomeApp_Study()
406 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
407 myObserver->_default_POA()->deactivate_object( oid.in() );
411 #ifndef DISABLE_PYCONSOLE
412 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
414 emit notebookVarUpdated( theVarName );
421 int SalomeApp_Study::id() const
425 id = studyDS()->StudyId();
432 QString SalomeApp_Study::studyName() const
434 // redefined from SUIT_Study to update study name properly since
435 // it can be changed outside of GUI
436 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
438 QString newName = QString::fromUtf8(studyDS()->Name().c_str());
439 if ( LightApp_Study::studyName() != newName ) {
440 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
441 that->setStudyName( newName );
442 ((SalomeApp_Application*)application())->updateDesktopTitle();
445 return LightApp_Study::studyName();
449 Gets studyDS pointer.
451 _PTR(Study) SalomeApp_Study::studyDS() const
459 bool SalomeApp_Study::createDocument( const QString& theStr )
461 MESSAGE( "createDocument" );
463 // initialize myStudyDS, read HDF file
464 QString aName = newStudyName();
468 study = _PTR(Study)( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
470 catch(const SALOME_Exception& ex) {
471 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
472 tr("ERR_ERROR"), tr(ex.what()));
476 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
477 tr("ERR_ERROR"), tr("CREATE_DOCUMENT_PROBLEM"));
485 setStudyName( aName );
488 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
489 #ifdef WITH_SALOMEDS_OBSERVER
490 aRoot->setToSynchronize(false);
494 bool aRet = CAM_Study::createDocument( theStr );
496 #ifdef WITH_SALOMEDS_OBSERVER
497 myObserver = new Observer_i(myStudyDS,this);
498 //attach an observer to the study with notification of modifications
499 myStudyDS->attach(myObserver->_this(),true);
502 emit created( this );
509 \param theFileName - name of file
511 bool SalomeApp_Study::openDocument( const QString& theFileName )
513 MESSAGE( "openDocument" );
515 // initialize myStudyDS, read HDF file
518 study = _PTR(Study) ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
520 catch(const SALOME_Exception& ex) {
521 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
522 tr("ERR_ERROR"), tr(ex.what()));
526 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
527 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
536 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
538 // update loaded data models: call open() and update() on them.
541 QListIterator<CAM_DataModel*> it( dm_s );
542 while ( it.hasNext() )
543 openDataModel( studyName(), it.next() );
545 // this will build a SUIT_DataObject-s tree under myRoot member field
546 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
547 // but tree that corresponds to not-loaded data models will be updated any way.
548 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
550 #ifdef WITH_SALOMEDS_OBSERVER
551 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
552 myObserver = new Observer_i(myStudyDS,this);
553 //attach an observer to the study with notification of modifications
554 myStudyDS->attach(myObserver->_this(),true);
557 bool res = CAM_Study::openDocument( theFileName );
560 study->IsSaved(true);
562 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
564 std::vector<int> savePoints = getSavePoints();
565 if ( savePoints.size() > 0 )
566 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
569 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
574 Connects GUI study to SALOMEDS one already loaded into StudyManager
575 \param theStudyName - name of study
577 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
579 MESSAGE( "loadDocument" );
581 // obtain myStudyDS from StudyManager
582 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
588 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
590 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
592 // update loaded data models: call open() and update() on them.
596 QListIterator<CAM_DataModel*> it( dm_s );
597 while ( it.hasNext() )
598 openDataModel( studyName(), it.next() );
600 // this will build a SUIT_DataObject-s tree under myRoot member field
601 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
602 // but tree that corresponds to not-loaded data models will be updated any way.
603 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
605 #ifdef WITH_SALOMEDS_OBSERVER
606 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
607 myObserver = new Observer_i(myStudyDS,this);
608 //attach an observer to the study with notification of modifications
609 myStudyDS->attach(myObserver->_this(),true);
612 bool res = CAM_Study::openDocument( theStudyName );
614 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
615 // mark study as "not saved" after call openDocument( ... ) method.
619 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
621 std::vector<int> savePoints = getSavePoints();
622 if ( savePoints.size() > 0 )
623 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
626 //SRN: BugID IPAL9021: End
632 \param theFileName - name of file
634 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
636 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
638 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
640 ModelList list; dataModels( list );
642 QListIterator<CAM_DataModel*> it( list );
643 QStringList listOfFiles;
644 while ( it.hasNext() ) {
645 // Cast to LightApp class in order to give a chance
646 // to light modules to save their data
647 if ( LightApp_DataModel* aModel =
648 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
650 aModel->saveAs( theFileName, this, listOfFiles );
651 if ( !listOfFiles.isEmpty() )
652 saveModuleData(aModel->module()->name(), listOfFiles);
656 // save SALOMEDS document
657 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
661 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
662 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
663 bool res = (isAscii ?
664 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
665 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
666 && CAM_Study::saveDocumentAs( theFileName );
668 res = res && saveStudyData(theFileName);
677 Saves previously opened document
679 bool SalomeApp_Study::saveDocument()
681 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
683 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
685 ModelList list; dataModels( list );
687 QListIterator<CAM_DataModel*> it( list );
688 QStringList listOfFiles;
689 while ( it.hasNext() ) {
690 // Cast to LightApp class in order to give a chance
691 // to light modules to save their data
692 if ( LightApp_DataModel* aModel =
693 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
695 aModel->save(listOfFiles);
696 if ( !listOfFiles.isEmpty() )
697 saveModuleData(aModel->module()->name(), listOfFiles);
701 // save SALOMEDS document
702 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
706 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
707 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
708 bool res = (isAscii ?
709 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
710 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
712 res = res && saveStudyData(studyName());
722 void SalomeApp_Study::closeDocument(bool permanently)
724 LightApp_Study::closeDocument(permanently);
726 // close SALOMEDS document
727 _PTR(Study) studyPtr = studyDS();
731 myStudyDS->detach( myObserver->_this() );
733 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
734 bool isBlocked = desk->signalsBlocked();
735 desk->blockSignals( true );
736 SalomeApp_Application::studyMgr()->Close( studyPtr );
737 desk->blockSignals( isBlocked );
738 #ifndef DISABLE_PYCONSOLE
739 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
740 app->getPyInterp()->destroy();
743 SALOMEDSClient_Study* aStudy = 0;
744 setStudyDS( _PTR(Study)(aStudy) );
749 Dump study operation. Writes a Python dump file using
750 SALOMEDS services. Additionally, gives a chance to light modules
751 to participate in dump study operation.
753 \param theFileName - full path to the output Python file
754 \param toPublish - if true, all objects are published in a study
755 by the output script, including those not orignally present
756 in the current study.
757 \param isMultiFile - if true, each module's dump is written into
758 a separate Python file, otherwise a single output file is written
759 \param toSaveGUI - if true, the GUI state is written
761 \return - true if the operation succeeds, and false otherwise.
763 bool SalomeApp_Study::dump( const QString& theFileName,
769 _PTR(AttributeParameter) ap;
770 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
771 _PTR(Study) aStudy = studyDS();
773 if( ip->isDumpPython( aStudy ) )
774 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
776 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
777 ip->setDumpPython( aStudy );
778 //SRN: create a temporary save point
779 savePoint = SalomeApp_VisualState(
780 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
783 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
784 // This is an optional but important step, it gives a chance to light modules
785 // to dump their data as a part of common dump study operation
789 QListIterator<CAM_DataModel*> it( list );
790 QStringList listOfFiles;
791 while ( it.hasNext() ) {
792 if ( LightApp_DataModel* aModel =
793 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
795 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
796 !listOfFiles.isEmpty() )
797 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
798 // This code is shared with persistence mechanism.
799 // NOTE: this should be revised if behavior of saveModuleData() changes!
800 saveModuleData(aModel->module()->name(), listOfFiles);
804 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
805 // any light module is present in the current configuration
806 QFileInfo aFileInfo( theFileName );
807 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
808 aFileInfo.baseName().toUtf8().data(),
812 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
814 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
815 // This code is shared with persistence mechanism.
816 // NOTE: this should be revised if behavior of saveStudyData() changes!
817 saveStudyData( theFileName );
823 \return true, if study is modified in comparison with last open/save
825 bool SalomeApp_Study::isModified() const
827 bool isAnyChanged = studyDS() && studyDS()->IsModified();
829 isAnyChanged = LightApp_Study::isModified();
835 Set study modified to \a on.
837 void SalomeApp_Study::Modified()
839 if(_PTR(Study) aStudy = studyDS())
841 LightApp_Study::Modified();
845 \return if data model is saved
847 bool SalomeApp_Study::isSaved() const
849 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
851 isAllSaved = LightApp_Study::isSaved();
858 \param theModuleName - name of module
859 \param theListOfFiles - list of files to be saved
861 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
863 int aNb = theListOfFiles.count();
867 std::vector<std::string> aListOfFiles ( aNb );
869 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
870 if ( (*it).isEmpty() )
872 aListOfFiles[anIndex] = (*it).toUtf8().data();
875 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
880 \param theModuleName - name of module
881 \param theListOfFiles - list of files to be loaded
883 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
885 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
887 int i, aLength = aListOfFiles.size() - 1;
891 //Get a temporary directory for saved a file
892 theListOfFiles.append(aListOfFiles[0].c_str());
894 for(i = 0; i < aLength; i++)
895 theListOfFiles.append(aListOfFiles[i+1].c_str());
899 Re-implemented from LightApp_Study, actually does not save anything but
900 simply cleans up light modules' data
902 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
904 ModelList list; dataModels( list );
905 QListIterator<CAM_DataModel*> it( list );
906 std::vector<std::string> listOfFiles(0);
907 while ( it.hasNext() ){
908 LightApp_DataModel* aLModel =
909 dynamic_cast<LightApp_DataModel*>( it.next() );
910 // It is safe to call SetListOfFiles() for any kind of module
911 // because SetListOfFiles() does nothing for full modules :)
913 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
921 bool SalomeApp_Study::openStudyData( const QString& theFileName )
929 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
935 Virtual method re-implemented from LightApp_Study in order to create
936 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
938 \param theDataModel - data model instance to create a module object for
939 \param theParent - the module object's parent (normally it's the study root)
940 \return the module object instance
941 \sa LightApp_Study class, LightApp_DataModel class
943 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
944 SUIT_DataObject* theParent ) const
946 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
948 // Ensure that SComponent instance is published in the study for the given module
949 // This line causes automatic creation of SalomeApp_ModuleObject in case if
950 // WITH_SALOMEDS_OBSERVER is defined
951 that->addComponent( theDataModel );
953 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
954 // or by someone else so check if it exists first of all
955 CAM_ModuleObject* res = 0;
957 DataObjectList children = root()->children();
958 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
959 for( ; !res && anIt!=aLast; anIt++ )
961 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
962 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
967 _PTR(Study) aStudy = studyDS();
971 _PTR(SComponent) aComp = aStudy->FindComponent(
972 theDataModel->module()->name().toStdString() );
976 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
985 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
987 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
989 CAM_Study::dataModelInserted(dm);
995 Create SComponent for module, using default engine (CORBAless)
997 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
999 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1000 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1002 // Check SComponent existance
1003 _PTR(Study) aStudy = studyDS();
1007 std::string aCompDataType = dm->module()->name().toStdString();
1009 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
1011 // Create SComponent
1012 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1013 aComp = aBuilder->NewComponent(aCompDataType);
1014 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1015 QString anIconName = dm->module()->iconName();
1016 if (!anIconName.isEmpty()) {
1017 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1019 anAttr->SetPixMap(anIconName.toStdString());
1022 // Set default engine IOR
1023 // Issue 21377 - using separate engine for each type of light module
1024 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
1026 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
1027 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
1028 SalomeApp_DataModel::synchronize( aComp, this );
1031 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1032 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1033 QString anIconName = dm->module()->iconName();
1034 if (!anIconName.isEmpty()) {
1035 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1037 anAttr->SetPixMap(anIconName.toStdString());
1039 // Set default engine IOR
1047 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1052 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1053 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1054 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
1055 _PTR(SComponent) aSComp;
1057 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1059 // Issue 21377 - using separate engine for each type of light module
1060 std::string aCompDataType = dm->module()->name().toStdString();
1061 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1062 aSComp = aStudy->FindComponent( aCompDataType );
1065 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1067 QString anId = aDM->getRootEntry( this );
1068 if ( anId.isEmpty() )
1069 return true; // Probably nothing to load
1070 anEngine = aDM->getModule()->engineIOR();
1071 if ( anEngine.isEmpty() )
1073 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1077 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1080 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1082 catch( const SALOME::SALOME_Exception& ) {
1083 // Oops, something went wrong while loading -> return an error
1086 // Something has been read -> create data model tree
1087 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1088 // aDM->buildTree( aSComp, 0, this );
1091 // Don't return false here, for there might be no data
1092 // for a given component in the study yet
1094 QStringList listOfFiles;
1095 openModuleData(dm->module()->name(), listOfFiles);
1096 if (dm && dm->open(studyName, this, listOfFiles)) {
1097 // Remove the files and temporary directory, created
1098 // for this module by LightApp_Engine_i::Load()
1099 bool isMultiFile = false; // TODO: decide, how to access this parameter
1100 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1102 // Something has been read -> create data model tree
1103 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1105 aDM->update(NULL, this);
1112 Create new study name.
1114 QString SalomeApp_Study::newStudyName() const
1116 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1117 QString prefix( "Study%1" ), newName, curName;
1118 int i = 1, j, n = studies.size();
1119 while ( newName.isEmpty() ){
1120 curName = prefix.arg( i );
1121 for ( j = 0 ; j < n; j++ ){
1122 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1134 Note that this method does not create or activate SalomeApp_Engine_i instance,
1135 therefore it can be called safely for any kind of module, but for full
1136 modules it returns an empty list.
1137 \return list of files used by module: to be used by CORBAless modules
1138 \param theModuleName - name of module
1140 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1142 // Issue 21377 - using separate engine for each type of light module
1143 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1145 return aDefaultEngine->GetListOfFiles(id());
1147 std::vector<std::string> aListOfFiles;
1148 return aListOfFiles;
1152 Sets list of files used by module: to be used by CORBAless modules.
1153 Note that this method does not create or activate SalomeApp_Engine_i instance,
1154 therefore it can be called safely for any kind of module, but for full
1155 modules it simply does nothing.
1156 \param theModuleName - name of module
1157 \param theListOfFiles - list of files
1159 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1160 const std::vector<std::string> theListOfFiles )
1162 // Issue 21377 - using separate engine for each type of light module
1163 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1165 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1169 \return temporary directory for saving files of modules
1171 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1173 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1174 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1179 Removes temporary files
1181 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1186 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1187 if (aListOfFiles.size() > 0) {
1188 std::string aTmpDir = aListOfFiles[0];
1190 const int n = aListOfFiles.size() - 1;
1191 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1193 for (int i = 0; i < n; i++)
1194 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1196 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1200 #ifndef DISABLE_PYCONSOLE
1202 Mark the study as saved in the file
1203 \param theFileName - the name of file
1205 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1207 setStudyName(theFileName);
1208 studyDS()->Name(theFileName.toStdString());
1209 setIsSaved( isSaved );
1213 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1215 LightApp_DataObject* o = 0;
1217 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toLatin1().constData() ) );
1220 o = LightApp_Study::findObjectByEntry( theEntry );
1226 Deletes all references to object
1229 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1231 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1232 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1233 for( int i=0, n=aRefs.size(); i<n; i++ )
1235 _PTR( SObject ) o = aRefs[i];
1236 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1238 sb->RemoveReference( o );
1239 sb->RemoveObjectWithChildren( o );
1245 \return real entry by entry of reference
1246 \param entry - entry of reference object
1248 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1250 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1251 _PTR(SObject) refobj;
1253 if( obj && obj->ReferencedObject( refobj ) )
1254 return refobj->GetID().c_str();
1255 return LightApp_Study::referencedToEntry( entry );
1259 \return component data type for entry
1261 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1263 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1265 return LightApp_Study::componentDataType( entry );
1266 return obj->GetFatherComponent()->ComponentDataType().c_str();
1270 \return true if entry corresponds to component
1272 bool SalomeApp_Study::isComponent( const QString& entry ) const
1274 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1275 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1279 \return entries of object children
1281 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1283 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1284 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1285 anIter->InitEx( true );
1286 while( anIter->More() )
1288 _PTR(SObject) val( anIter->Value() );
1289 child_entries.append( val->GetID().c_str() );
1295 Fills list with components names
1296 \param comp - list to be filled
1298 void SalomeApp_Study::components( QStringList& comps ) const
1300 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1302 _PTR(SComponent) aComponent ( it->Value() );
1303 // skip the magic "Interface Applicative" component
1304 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1305 comps.append( aComponent->ComponentDataType().c_str() );
1310 Get the entry for the given module
1311 \param comp - list to be filled
1312 \return module root's entry
1314 QString SalomeApp_Study::centry( const QString& comp ) const
1317 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1319 _PTR(SComponent) aComponent ( it->Value() );
1320 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1321 e = aComponent->GetID().c_str();
1327 \return a list of saved points' IDs
1329 std::vector<int> SalomeApp_Study::getSavePoints()
1333 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1336 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1337 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1338 for(; anIter->More(); anIter->Next())
1340 _PTR(SObject) val( anIter->Value() );
1341 _PTR(GenericAttribute) genAttr;
1342 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1349 Removes a given save point
1351 void SalomeApp_Study::removeSavePoint(int savePoint)
1353 if(savePoint <= 0) return;
1354 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1355 _PTR(SObject) so = AP->GetSObject();
1356 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1357 builder->RemoveObjectWithChildren(so);
1361 \return a name of save point
1363 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1365 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1366 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1367 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1371 Sets a name of save point
1373 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1375 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1376 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1377 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1381 * \brief Restores the study state
1383 void SalomeApp_Study::restoreState(int savePoint)
1385 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1390 Slot: called on change of a root of a data model. Redefined from CAM_Study
1392 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1394 LightApp_Study::updateModelRoot( dm );
1396 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1397 // it must always be the last one.
1398 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );