1 // Copyright (C) 2007-2012 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.
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>
45 #include <LightApp_Displayer.h>
47 #include "utilities.h"
49 #include "SALOMEDS_Tool.hxx"
51 #include "SALOMEDSClient_ClientFactory.hxx"
53 #include <SALOMEconfig.h>
54 #include CORBA_SERVER_HEADER(SALOME_Exception)
56 //#define NOTIFY_BY_EVENT
58 class ObserverEvent : public QEvent
61 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
71 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
73 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
74 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
78 Observer_i(_PTR(Study) aStudyDS, SalomeApp_Study* aStudy)
85 SUIT_DataObject* findObject( const char* theID ) const
87 EntryMap::const_iterator it = entry2SuitObject.find( theID );
88 return it != entry2SuitObject.end() ? it->second : 0;
91 virtual void notifyObserverID(const char* theID, CORBA::Long event)
93 #ifdef NOTIFY_BY_EVENT
94 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
96 notifyObserverID_real(theID,event);
100 virtual bool event(QEvent *event)
102 if (event->type() == QEvent::User )
104 //START_TIMING(notify);
105 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
106 //END_TIMING(notify,100);
111 void notifyObserverID_real(const std::string& theID, long event)
113 SalomeApp_DataObject* suit_obj = 0;
118 _PTR(SObject) aSObj = myStudyDS->FindObjectID(theID);
119 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
121 if (!aSComp || aSComp->IsNull()) {
122 MESSAGE("Entry " << theID << " has not father component. Problem ??");
126 // Mantis issue 0020136: Drag&Drop in OB
127 _PTR(UseCaseBuilder) aUseCaseBuilder = myStudyDS->GetUseCaseBuilder();
128 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
129 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
130 // tree node is not yet set, it is a normal situation
134 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
135 if (!aFatherSO || aFatherSO->IsNull()) {
136 MESSAGE("Father SObject is not found. Problem ??");
140 std::string parent_id = aFatherSO->GetID();
141 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
143 if (it == entry2SuitObject.end()) {
144 MESSAGE("Father data object is not found. Problem ??");
148 SalomeApp_DataObject* aFatherDO = it->second;
150 it = entry2SuitObject.find(theID);
151 if (it != entry2SuitObject.end()) { // this SOobject is already added somethere
152 suit_obj = it->second;
153 SUIT_DataObject* oldFather = suit_obj->parent();
155 oldFather->removeChild(suit_obj, false);
156 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
157 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
158 model->forgetObject( suit_obj );
160 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
161 oldFatherSA->updateItem();
166 suit_obj = new SalomeApp_DataObject(aSObj);
167 entry2SuitObject[theID] = suit_obj;
170 suit_obj->updateItem();
171 // define position in the data tree (in aFatherDO) to insert the aSObj
173 //int childDataObjCount = aFatherDO->childCount();
174 _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
175 for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
176 if (aUseCaseIter->Value()->GetID() == theID) {
182 aFatherDO->insertChildAtPos(suit_obj, pos);
183 //aFatherDO->insertChild(suit_obj, pos);
184 aFatherDO->updateItem();
186 } // END: work with tree nodes structure
187 else { // BEGIN: work with study structure
188 EntryMapIter it = entry2SuitObject.find( theID );
189 if ( it != entry2SuitObject.end() ) {
190 MESSAGE("Entry " << theID << " is already added. Problem ??");
194 int last2Pnt_pos = theID.rfind( ":" );
195 std::string parent_id = theID.substr( 0, last2Pnt_pos );
196 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
198 if ( parent_id.length() == 3 ) // "0:1" - root item?
200 // It's probably a SComponent
201 if ( theID == aSComp->GetID() )
202 suit_obj = new SalomeApp_ModuleObject( aSComp );
204 suit_obj = new SalomeApp_DataObject( aSObj );
208 suit_obj = new SalomeApp_DataObject( aSObj );
211 it = entry2SuitObject.find( parent_id );
212 if ( it != entry2SuitObject.end() ) {
213 SalomeApp_DataObject* father = it->second;
214 father->insertChildAtTag( suit_obj, tag );
217 if ( parent_id.length() == 3 ) // "0:1" - root item?
219 // This should be for a module
220 SUIT_DataObject* father=myStudy->root();
221 father->appendChild(suit_obj);
225 MESSAGE("SHOULD NEVER GET HERE!!!");
227 //Try to find the SalomeApp_DataObject object parent
228 std::string root_id = parent_id.substr( 0, 4 );
229 std::string obj_id = parent_id.substr( 4 );
232 std::string::size_type debut = 0;
233 std::string::size_type fin;
234 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
236 fin = obj_id.find_first_of( ':', debut );
237 if ( fin == std::string::npos ) {
239 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
240 entry2SuitObject[parent_id] = anObj;
243 anID = root_id + obj_id.substr( 0, fin );
244 EntryMapIter it2 = entry2SuitObject.find( anID );
245 if ( it2 == entry2SuitObject.end() ) {
246 //the ID is not known in entry2SuitObject
247 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
248 entry2SuitObject[anID] = anObj;
254 anObj->insertChildAtTag( suit_obj, tag );
257 entry2SuitObject[theID] = suit_obj;
258 } // END: work with study structure
263 EntryMapIter it = entry2SuitObject.find( theID );
264 if ( it != entry2SuitObject.end() )
266 suit_obj = it->second;
267 // VSR: object is not removed, since SALOMEDS::SObject is not actually removed,
268 // only its attributes are cleared;
269 // thus, the object can be later reused
270 suit_obj->updateItem();
271 //SUIT_DataObject* father=suit_obj->parent();
273 // father->removeChild(suit_obj);
274 //entry2SuitObject.erase(it);
278 MESSAGE("Want to remove an unknown object" << theID);
284 //MESSAGE("Want to modify an object " << theID);
285 EntryMapIter it = entry2SuitObject.find( theID );
286 if ( it != entry2SuitObject.end() )
288 suit_obj = it->second;
289 suit_obj->updateItem();
293 MESSAGE("Want to modify an unknown object" << theID);
297 case 5: //IOR of the object modified
299 EntryMapIter it = entry2SuitObject.find( theID );
300 if ( it != entry2SuitObject.end() )
301 suit_obj = it->second;
303 /* Define visibility state */
304 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
305 if ( suit_obj && !isComponent ) {
306 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
307 if (!moduleTitle.isEmpty()) {
308 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
310 if(aDisplayer->canBeDisplayed(theID.c_str())) {
311 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
312 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
315 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
321 default:MESSAGE("Unknown event: " << event);break;
323 } //notifyObserverID_real
328 entry2SuitObject.clear();
329 SUIT_DataObject* o = myStudy->root();
331 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
333 std::string entry = so->entry().toLatin1().constData();
335 entry2SuitObject[entry] = so;
337 if ( o->childCount() > 0 ) {
338 // parse the children
341 else if ( o->nextBrother() > 0 ) {
342 o = o->nextBrother();
345 // step to the next appropriate parent
348 if ( o->nextBrother() ) {
349 o = o->nextBrother();
359 _PTR(Study) myStudyDS;
360 SalomeApp_Study* myStudy;
361 EntryMap entry2SuitObject;
368 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
369 : LightApp_Study( app ), myObserver( 0 )
376 SalomeApp_Study::~SalomeApp_Study()
383 int SalomeApp_Study::id() const
387 id = studyDS()->StudyId();
394 QString SalomeApp_Study::studyName() const
396 // redefined from SUIT_Study to update study name properly since
397 // it can be changed outside of GUI
398 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
400 QString newName = studyDS()->Name().c_str();
401 if ( LightApp_Study::studyName() != newName ) {
402 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
403 that->setStudyName( newName );
404 ((SalomeApp_Application*)application())->updateDesktopTitle();
407 return LightApp_Study::studyName();
411 Gets studyDS pointer.
413 _PTR(Study) SalomeApp_Study::studyDS() const
421 bool SalomeApp_Study::createDocument( const QString& theStr )
423 MESSAGE( "createDocument" );
425 // initialize myStudyDS, read HDF file
426 QString aName = newStudyName();
427 _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
432 setStudyName( aName );
435 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
436 #ifdef WITH_SALOMEDS_OBSERVER
437 aRoot->setToSynchronize(false);
441 bool aRet = CAM_Study::createDocument( theStr );
443 #ifdef WITH_SALOMEDS_OBSERVER
444 myObserver = new Observer_i(myStudyDS,this);
445 //attach an observer to the study with notification of modifications
446 myStudyDS->attach(myObserver->_this(),true);
449 emit created( this );
456 \param theFileName - name of file
458 bool SalomeApp_Study::openDocument( const QString& theFileName )
460 MESSAGE( "openDocument" );
462 // initialize myStudyDS, read HDF file
463 _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
469 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
471 // update loaded data models: call open() and update() on them.
474 QListIterator<CAM_DataModel*> it( dm_s );
475 while ( it.hasNext() )
476 openDataModel( studyName(), it.next() );
478 // this will build a SUIT_DataObject-s tree under myRoot member field
479 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
480 // but tree that corresponds to not-loaded data models will be updated any way.
481 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
483 #ifdef WITH_SALOMEDS_OBSERVER
484 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
485 myObserver = new Observer_i(myStudyDS,this);
486 //attach an observer to the study with notification of modifications
487 myStudyDS->attach(myObserver->_this(),true);
490 bool res = CAM_Study::openDocument( theFileName );
493 study->IsSaved(true);
495 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
497 std::vector<int> savePoints = getSavePoints();
498 if ( savePoints.size() > 0 )
499 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
502 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
507 Connects GUI study to SALOMEDS one already loaded into StudyManager
508 \param theStudyName - name of study
510 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
512 MESSAGE( "loadDocument" );
514 // obtain myStudyDS from StudyManager
515 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
521 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
523 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
525 // update loaded data models: call open() and update() on them.
529 QListIterator<CAM_DataModel*> it( dm_s );
530 while ( it.hasNext() )
531 openDataModel( studyName(), it.next() );
533 // this will build a SUIT_DataObject-s tree under myRoot member field
534 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
535 // but tree that corresponds to not-loaded data models will be updated any way.
536 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
538 #ifdef WITH_SALOMEDS_OBSERVER
539 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
540 myObserver = new Observer_i(myStudyDS,this);
541 //attach an observer to the study with notification of modifications
542 myStudyDS->attach(myObserver->_this(),true);
545 bool res = CAM_Study::openDocument( theStudyName );
548 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
550 std::vector<int> savePoints = getSavePoints();
551 if ( savePoints.size() > 0 )
552 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
555 //SRN: BugID IPAL9021: End
561 \param theFileName - name of file
563 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
565 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
567 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
569 ModelList list; dataModels( list );
571 QListIterator<CAM_DataModel*> it( list );
572 QStringList listOfFiles;
573 while ( it.hasNext() ) {
574 // Cast to LightApp class in order to give a chance
575 // to light modules to save their data
576 if ( LightApp_DataModel* aModel =
577 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
579 aModel->saveAs( theFileName, this, listOfFiles );
580 if ( !listOfFiles.isEmpty() )
581 saveModuleData(aModel->module()->name(), listOfFiles);
585 // save SALOMEDS document
586 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
590 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
591 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
592 bool res = (isAscii ?
593 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
594 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
595 && CAM_Study::saveDocumentAs( theFileName );
597 res = res && saveStudyData(theFileName);
606 Saves previously opened document
608 bool SalomeApp_Study::saveDocument()
610 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
612 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
614 ModelList list; dataModels( list );
616 QListIterator<CAM_DataModel*> it( list );
617 QStringList listOfFiles;
618 while ( it.hasNext() ) {
619 // Cast to LightApp class in order to give a chance
620 // to light modules to save their data
621 if ( LightApp_DataModel* aModel =
622 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
624 aModel->save(listOfFiles);
625 if ( !listOfFiles.isEmpty() )
626 saveModuleData(aModel->module()->name(), listOfFiles);
630 // save SALOMEDS document
631 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
635 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
636 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
637 bool res = (isAscii ?
638 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
639 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
641 res = res && saveStudyData(studyName());
651 void SalomeApp_Study::closeDocument(bool permanently)
653 LightApp_Study::closeDocument(permanently);
655 // close SALOMEDS document
656 _PTR(Study) studyPtr = studyDS();
660 SalomeApp_Application::studyMgr()->Close( studyPtr );
662 SALOMEDSClient_Study* aStudy = 0;
663 setStudyDS( _PTR(Study)(aStudy) );
668 Dump study operation. Writes a Python dump file using
669 SALOMEDS services. Additionally, gives a chance to light modules
670 to participate in dump study operation.
672 \param theFileName - full path to the output Python file
673 \param toPublish - if true, all objects are published in a study
674 by the output script, including those not orignally present
675 in the current study.
676 \param isMultiFile - if true, each module's dump is written into
677 a separate Python file, otherwise a single output file is written
678 \param toSaveGUI - if true, the GUI state is written
680 \return - true if the operation succeeds, and false otherwise.
682 bool SalomeApp_Study::dump( const QString& theFileName,
688 _PTR(AttributeParameter) ap;
689 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
690 _PTR(Study) aStudy = studyDS();
692 if( ip->isDumpPython( aStudy ) )
693 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
695 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
696 ip->setDumpPython( aStudy );
697 //SRN: create a temporary save point
698 savePoint = SalomeApp_VisualState(
699 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
702 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
703 // This is an optional but important step, it gives a chance to light modules
704 // to dump their data as a part of common dump study operation
708 QListIterator<CAM_DataModel*> it( list );
709 QStringList listOfFiles;
710 while ( it.hasNext() ) {
711 if ( LightApp_DataModel* aModel =
712 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
714 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
715 !listOfFiles.isEmpty() )
716 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
717 // This code is shared with persistence mechanism.
718 // NOTE: this should be revised if behavior of saveModuleData() changes!
719 saveModuleData(aModel->module()->name(), listOfFiles);
723 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
724 // any light module is present in the current configuration
725 QFileInfo aFileInfo( theFileName );
726 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
727 aFileInfo.baseName().toUtf8().data(),
731 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
733 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
734 // This code is shared with persistence mechanism.
735 // NOTE: this should be revised if behavior of saveStudyData() changes!
736 saveStudyData( theFileName );
742 \return true, if study is modified in comparison with last open/save
744 bool SalomeApp_Study::isModified() const
746 bool isAnyChanged = studyDS() && studyDS()->IsModified();
748 isAnyChanged = LightApp_Study::isModified();
754 Set study modified to \a on.
756 void SalomeApp_Study::Modified()
758 if(_PTR(Study) aStudy = studyDS())
760 LightApp_Study::Modified();
764 \return if data model is saved
766 bool SalomeApp_Study::isSaved() const
768 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
770 isAllSaved = LightApp_Study::isSaved();
777 \param theModuleName - name of module
778 \param theListOfFiles - list of files to be saved
780 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
782 int aNb = theListOfFiles.count();
786 std::vector<std::string> aListOfFiles ( aNb );
788 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
789 if ( (*it).isEmpty() )
791 aListOfFiles[anIndex] = (*it).toUtf8().data();
794 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
799 \param theModuleName - name of module
800 \param theListOfFiles - list of files to be loaded
802 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
804 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
806 int i, aLength = aListOfFiles.size() - 1;
810 //Get a temporary directory for saved a file
811 theListOfFiles.append(aListOfFiles[0].c_str());
813 for(i = 0; i < aLength; i++)
814 theListOfFiles.append(aListOfFiles[i+1].c_str());
818 Re-implemented from LightApp_Study, actually does not save anything but
819 simply cleans up light modules' data
821 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
823 ModelList list; dataModels( list );
824 QListIterator<CAM_DataModel*> it( list );
825 std::vector<std::string> listOfFiles(0);
826 while ( it.hasNext() ){
827 LightApp_DataModel* aLModel =
828 dynamic_cast<LightApp_DataModel*>( it.next() );
829 // It is safe to call SetListOfFiles() for any kind of module
830 // because SetListOfFiles() does nothing for full modules :)
832 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
840 bool SalomeApp_Study::openStudyData( const QString& theFileName )
848 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
854 Virtual method re-implemented from LightApp_Study in order to create
855 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
857 \param theDataModel - data model instance to create a module object for
858 \param theParent - the module object's parent (normally it's the study root)
859 \return the module object instance
860 \sa LightApp_Study class, LightApp_DataModel class
862 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
863 SUIT_DataObject* theParent ) const
865 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
867 // Ensure that SComponent instance is published in the study for the given module
868 // This line causes automatic creation of SalomeApp_ModuleObject in case if
869 // WITH_SALOMEDS_OBSERVER is defined
870 that->addComponent( theDataModel );
872 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
873 // or by someone else so check if it exists first of all
874 CAM_ModuleObject* res = 0;
876 DataObjectList children = root()->children();
877 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
878 for( ; !res && anIt!=aLast; anIt++ )
880 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
881 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
886 _PTR(Study) aStudy = studyDS();
890 _PTR(SComponent) aComp = aStudy->FindComponent(
891 theDataModel->module()->name().toStdString() );
895 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
904 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
906 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
908 CAM_Study::dataModelInserted(dm);
914 Create SComponent for module, using default engine (CORBAless)
916 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
918 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
919 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
921 // Check SComponent existance
922 _PTR(Study) aStudy = studyDS();
926 std::string aCompDataType = dm->module()->name().toStdString();
928 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
931 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
932 aComp = aBuilder->NewComponent(aCompDataType);
933 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
934 QString anIconName = dm->module()->iconName();
935 if (!anIconName.isEmpty()) {
936 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
938 anAttr->SetPixMap(anIconName.toStdString());
941 // Set default engine IOR
942 // Issue 21377 - using separate engine for each type of light module
943 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
945 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
946 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
947 SalomeApp_DataModel::synchronize( aComp, this );
950 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
951 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
952 QString anIconName = dm->module()->iconName();
953 if (!anIconName.isEmpty()) {
954 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
956 anAttr->SetPixMap(anIconName.toStdString());
958 // Set default engine IOR
966 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
971 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
972 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
973 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
974 _PTR(SComponent) aSComp;
976 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
978 // Issue 21377 - using separate engine for each type of light module
979 std::string aCompDataType = dm->module()->name().toStdString();
980 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
981 aSComp = aStudy->FindComponent( aCompDataType );
984 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
986 QString anId = aDM->getRootEntry( this );
987 if ( anId.isEmpty() )
988 return true; // Probably nothing to load
989 anEngine = aDM->getModule()->engineIOR();
990 if ( anEngine.isEmpty() )
992 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
996 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
999 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1001 catch( const SALOME::SALOME_Exception& ) {
1002 // Oops, something went wrong while loading -> return an error
1005 // Something has been read -> create data model tree
1006 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1007 // aDM->buildTree( aSComp, 0, this );
1010 // Don't return false here, for there might be no data
1011 // for a given component in the study yet
1013 QStringList listOfFiles;
1014 openModuleData(dm->module()->name(), listOfFiles);
1015 if (dm && dm->open(studyName, this, listOfFiles)) {
1016 // Remove the files and temporary directory, created
1017 // for this module by LightApp_Engine_i::Load()
1018 bool isMultiFile = false; // TODO: decide, how to access this parameter
1019 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1021 // Something has been read -> create data model tree
1022 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1024 aDM->update(NULL, this);
1031 Create new study name.
1033 QString SalomeApp_Study::newStudyName() const
1035 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1036 QString prefix( "Study%1" ), newName, curName;
1037 int i = 1, j, n = studies.size();
1038 while ( newName.isEmpty() ){
1039 curName = prefix.arg( i );
1040 for ( j = 0 ; j < n; j++ ){
1041 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1053 Note that this method does not create or activate SalomeApp_Engine_i instance,
1054 therefore it can be called safely for any kind of module, but for full
1055 modules it returns an empty list.
1056 \return list of files used by module: to be used by CORBAless modules
1057 \param theModuleName - name of module
1059 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1061 // Issue 21377 - using separate engine for each type of light module
1062 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1064 return aDefaultEngine->GetListOfFiles(id());
1066 std::vector<std::string> aListOfFiles;
1067 return aListOfFiles;
1071 Sets list of files used by module: to be used by CORBAless modules.
1072 Note that this method does not create or activate SalomeApp_Engine_i instance,
1073 therefore it can be called safely for any kind of module, but for full
1074 modules it simply does nothing.
1075 \param theModuleName - name of module
1076 \param theListOfFiles - list of files
1078 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1079 const std::vector<std::string> theListOfFiles )
1081 // Issue 21377 - using separate engine for each type of light module
1082 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1084 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1088 \return temporary directory for saving files of modules
1090 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1092 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1093 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1098 Removes temporary files
1100 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1105 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1106 if (aListOfFiles.size() > 0) {
1107 std::string aTmpDir = aListOfFiles[0];
1109 const int n = aListOfFiles.size() - 1;
1110 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1112 for (int i = 0; i < n; i++)
1113 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1115 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1120 Mark the study as saved in the file
1121 \param theFileName - the name of file
1123 void SalomeApp_Study::markAsSavedIn(QString theFileName)
1125 setStudyName(theFileName);
1129 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1131 LightApp_DataObject* o = dynamic_cast<LightApp_DataObject*>( myObserver ? myObserver->findObject( theEntry.toLatin1().constData() ) : 0 );
1136 Deletes all references to object
1139 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1141 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1142 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1143 for( int i=0, n=aRefs.size(); i<n; i++ )
1145 _PTR( SObject ) o = aRefs[i];
1146 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1148 sb->RemoveReference( o );
1149 sb->RemoveObjectWithChildren( o );
1155 \return real entry by entry of reference
1156 \param entry - entry of reference object
1158 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1160 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1161 _PTR(SObject) refobj;
1163 if( obj && obj->ReferencedObject( refobj ) )
1164 return refobj->GetID().c_str();
1165 return LightApp_Study::referencedToEntry( entry );
1169 \return component data type for entry
1171 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1173 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1175 return LightApp_Study::componentDataType( entry );
1176 return obj->GetFatherComponent()->ComponentDataType().c_str();
1180 \return true if entry corresponds to component
1182 bool SalomeApp_Study::isComponent( const QString& entry ) const
1184 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1185 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1189 \return entries of object children
1191 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1193 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1194 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1195 anIter->InitEx( true );
1196 while( anIter->More() )
1198 _PTR(SObject) val( anIter->Value() );
1199 child_entries.append( val->GetID().c_str() );
1205 Fills list with components names
1206 \param comp - list to be filled
1208 void SalomeApp_Study::components( QStringList& comps ) const
1210 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1212 _PTR(SComponent) aComponent ( it->Value() );
1213 // skip the magic "Interface Applicative" component
1214 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1215 comps.append( aComponent->ComponentDataType().c_str() );
1220 Get the entry for the given module
1221 \param comp - list to be filled
1222 \return module root's entry
1224 QString SalomeApp_Study::centry( const QString& comp ) const
1227 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1229 _PTR(SComponent) aComponent ( it->Value() );
1230 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1231 e = aComponent->GetID().c_str();
1237 \return a list of saved points' IDs
1239 std::vector<int> SalomeApp_Study::getSavePoints()
1243 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1246 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1247 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1248 for(; anIter->More(); anIter->Next())
1250 _PTR(SObject) val( anIter->Value() );
1251 _PTR(GenericAttribute) genAttr;
1252 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1259 Removes a given save point
1261 void SalomeApp_Study::removeSavePoint(int savePoint)
1263 if(savePoint <= 0) return;
1264 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1265 _PTR(SObject) so = AP->GetSObject();
1266 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1267 builder->RemoveObjectWithChildren(so);
1271 \return a name of save point
1273 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1275 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1276 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1277 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1281 Sets a name of save point
1283 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1285 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1286 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1287 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1291 * \brief Restores the study state
1293 void SalomeApp_Study::restoreState(int savePoint)
1295 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1300 Slot: called on change of a root of a data model. Redefined from CAM_Study
1302 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1304 LightApp_Study::updateModelRoot( dm );
1306 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1307 // it must always be the last one.
1308 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );