1 // Copyright (C) 2007-2013 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):QObject(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 case 6: //NoteBook variables were modified
323 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
326 default:MESSAGE("Unknown event: " << event);break;
328 } //notifyObserverID_real
333 entry2SuitObject.clear();
334 SUIT_DataObject* o = myStudy->root();
336 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
338 std::string entry = so->entry().toLatin1().constData();
340 entry2SuitObject[entry] = so;
342 if ( o->childCount() > 0 ) {
343 // parse the children
346 else if ( o->nextBrother() > 0 ) {
347 o = o->nextBrother();
350 // step to the next appropriate parent
353 if ( o->nextBrother() ) {
354 o = o->nextBrother();
364 _PTR(Study) myStudyDS;
365 SalomeApp_Study* myStudy;
366 EntryMap entry2SuitObject;
373 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
374 : LightApp_Study( app ), myObserver( 0 )
381 SalomeApp_Study::~SalomeApp_Study()
384 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
385 myObserver->_default_POA()->deactivate_object( oid.in() );
389 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
391 emit notebookVarUpdated( theVarName );
397 int SalomeApp_Study::id() const
401 id = studyDS()->StudyId();
408 QString SalomeApp_Study::studyName() const
410 // redefined from SUIT_Study to update study name properly since
411 // it can be changed outside of GUI
412 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
414 QString newName = studyDS()->Name().c_str();
415 if ( LightApp_Study::studyName() != newName ) {
416 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
417 that->setStudyName( newName );
418 ((SalomeApp_Application*)application())->updateDesktopTitle();
421 return LightApp_Study::studyName();
425 Gets studyDS pointer.
427 _PTR(Study) SalomeApp_Study::studyDS() const
435 bool SalomeApp_Study::createDocument( const QString& theStr )
437 MESSAGE( "createDocument" );
439 // initialize myStudyDS, read HDF file
440 QString aName = newStudyName();
441 _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
446 setStudyName( aName );
449 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
450 #ifdef WITH_SALOMEDS_OBSERVER
451 aRoot->setToSynchronize(false);
455 bool aRet = CAM_Study::createDocument( theStr );
457 #ifdef WITH_SALOMEDS_OBSERVER
458 myObserver = new Observer_i(myStudyDS,this);
459 //attach an observer to the study with notification of modifications
460 myStudyDS->attach(myObserver->_this(),true);
463 emit created( this );
470 \param theFileName - name of file
472 bool SalomeApp_Study::openDocument( const QString& theFileName )
474 MESSAGE( "openDocument" );
476 // initialize myStudyDS, read HDF file
477 _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
483 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
485 // update loaded data models: call open() and update() on them.
488 QListIterator<CAM_DataModel*> it( dm_s );
489 while ( it.hasNext() )
490 openDataModel( studyName(), it.next() );
492 // this will build a SUIT_DataObject-s tree under myRoot member field
493 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
494 // but tree that corresponds to not-loaded data models will be updated any way.
495 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
497 #ifdef WITH_SALOMEDS_OBSERVER
498 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
499 myObserver = new Observer_i(myStudyDS,this);
500 //attach an observer to the study with notification of modifications
501 myStudyDS->attach(myObserver->_this(),true);
504 bool res = CAM_Study::openDocument( theFileName );
507 study->IsSaved(true);
509 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
511 std::vector<int> savePoints = getSavePoints();
512 if ( savePoints.size() > 0 )
513 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
516 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
521 Connects GUI study to SALOMEDS one already loaded into StudyManager
522 \param theStudyName - name of study
524 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
526 MESSAGE( "loadDocument" );
528 // obtain myStudyDS from StudyManager
529 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
535 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
537 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
539 // update loaded data models: call open() and update() on them.
543 QListIterator<CAM_DataModel*> it( dm_s );
544 while ( it.hasNext() )
545 openDataModel( studyName(), it.next() );
547 // this will build a SUIT_DataObject-s tree under myRoot member field
548 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
549 // but tree that corresponds to not-loaded data models will be updated any way.
550 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
552 #ifdef WITH_SALOMEDS_OBSERVER
553 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
554 myObserver = new Observer_i(myStudyDS,this);
555 //attach an observer to the study with notification of modifications
556 myStudyDS->attach(myObserver->_this(),true);
559 bool res = CAM_Study::openDocument( theStudyName );
561 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
562 // mark study as "not saved" after call openDocument( ... ) method.
566 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
568 std::vector<int> savePoints = getSavePoints();
569 if ( savePoints.size() > 0 )
570 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
573 //SRN: BugID IPAL9021: End
579 \param theFileName - name of file
581 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
583 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
585 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
587 ModelList list; dataModels( list );
589 QListIterator<CAM_DataModel*> it( list );
590 QStringList listOfFiles;
591 while ( it.hasNext() ) {
592 // Cast to LightApp class in order to give a chance
593 // to light modules to save their data
594 if ( LightApp_DataModel* aModel =
595 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
597 aModel->saveAs( theFileName, this, listOfFiles );
598 if ( !listOfFiles.isEmpty() )
599 saveModuleData(aModel->module()->name(), listOfFiles);
603 // save SALOMEDS document
604 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
608 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
609 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
610 bool res = (isAscii ?
611 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
612 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
613 && CAM_Study::saveDocumentAs( theFileName );
615 res = res && saveStudyData(theFileName);
624 Saves previously opened document
626 bool SalomeApp_Study::saveDocument()
628 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
630 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
632 ModelList list; dataModels( list );
634 QListIterator<CAM_DataModel*> it( list );
635 QStringList listOfFiles;
636 while ( it.hasNext() ) {
637 // Cast to LightApp class in order to give a chance
638 // to light modules to save their data
639 if ( LightApp_DataModel* aModel =
640 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
642 aModel->save(listOfFiles);
643 if ( !listOfFiles.isEmpty() )
644 saveModuleData(aModel->module()->name(), listOfFiles);
648 // save SALOMEDS document
649 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
653 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
654 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
655 bool res = (isAscii ?
656 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
657 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
659 res = res && saveStudyData(studyName());
669 void SalomeApp_Study::closeDocument(bool permanently)
671 LightApp_Study::closeDocument(permanently);
673 // close SALOMEDS document
674 _PTR(Study) studyPtr = studyDS();
678 SalomeApp_Application::studyMgr()->Close( studyPtr );
680 SALOMEDSClient_Study* aStudy = 0;
681 setStudyDS( _PTR(Study)(aStudy) );
686 Dump study operation. Writes a Python dump file using
687 SALOMEDS services. Additionally, gives a chance to light modules
688 to participate in dump study operation.
690 \param theFileName - full path to the output Python file
691 \param toPublish - if true, all objects are published in a study
692 by the output script, including those not orignally present
693 in the current study.
694 \param isMultiFile - if true, each module's dump is written into
695 a separate Python file, otherwise a single output file is written
696 \param toSaveGUI - if true, the GUI state is written
698 \return - true if the operation succeeds, and false otherwise.
700 bool SalomeApp_Study::dump( const QString& theFileName,
706 _PTR(AttributeParameter) ap;
707 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
708 _PTR(Study) aStudy = studyDS();
710 if( ip->isDumpPython( aStudy ) )
711 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
713 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
714 ip->setDumpPython( aStudy );
715 //SRN: create a temporary save point
716 savePoint = SalomeApp_VisualState(
717 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
720 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
721 // This is an optional but important step, it gives a chance to light modules
722 // to dump their data as a part of common dump study operation
726 QListIterator<CAM_DataModel*> it( list );
727 QStringList listOfFiles;
728 while ( it.hasNext() ) {
729 if ( LightApp_DataModel* aModel =
730 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
732 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
733 !listOfFiles.isEmpty() )
734 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
735 // This code is shared with persistence mechanism.
736 // NOTE: this should be revised if behavior of saveModuleData() changes!
737 saveModuleData(aModel->module()->name(), listOfFiles);
741 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
742 // any light module is present in the current configuration
743 QFileInfo aFileInfo( theFileName );
744 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
745 aFileInfo.baseName().toUtf8().data(),
749 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
751 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
752 // This code is shared with persistence mechanism.
753 // NOTE: this should be revised if behavior of saveStudyData() changes!
754 saveStudyData( theFileName );
760 \return true, if study is modified in comparison with last open/save
762 bool SalomeApp_Study::isModified() const
764 bool isAnyChanged = studyDS() && studyDS()->IsModified();
766 isAnyChanged = LightApp_Study::isModified();
772 Set study modified to \a on.
774 void SalomeApp_Study::Modified()
776 if(_PTR(Study) aStudy = studyDS())
778 LightApp_Study::Modified();
782 \return if data model is saved
784 bool SalomeApp_Study::isSaved() const
786 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
788 isAllSaved = LightApp_Study::isSaved();
795 \param theModuleName - name of module
796 \param theListOfFiles - list of files to be saved
798 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
800 int aNb = theListOfFiles.count();
804 std::vector<std::string> aListOfFiles ( aNb );
806 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
807 if ( (*it).isEmpty() )
809 aListOfFiles[anIndex] = (*it).toUtf8().data();
812 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
817 \param theModuleName - name of module
818 \param theListOfFiles - list of files to be loaded
820 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
822 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
824 int i, aLength = aListOfFiles.size() - 1;
828 //Get a temporary directory for saved a file
829 theListOfFiles.append(aListOfFiles[0].c_str());
831 for(i = 0; i < aLength; i++)
832 theListOfFiles.append(aListOfFiles[i+1].c_str());
836 Re-implemented from LightApp_Study, actually does not save anything but
837 simply cleans up light modules' data
839 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
841 ModelList list; dataModels( list );
842 QListIterator<CAM_DataModel*> it( list );
843 std::vector<std::string> listOfFiles(0);
844 while ( it.hasNext() ){
845 LightApp_DataModel* aLModel =
846 dynamic_cast<LightApp_DataModel*>( it.next() );
847 // It is safe to call SetListOfFiles() for any kind of module
848 // because SetListOfFiles() does nothing for full modules :)
850 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
858 bool SalomeApp_Study::openStudyData( const QString& theFileName )
866 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
872 Virtual method re-implemented from LightApp_Study in order to create
873 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
875 \param theDataModel - data model instance to create a module object for
876 \param theParent - the module object's parent (normally it's the study root)
877 \return the module object instance
878 \sa LightApp_Study class, LightApp_DataModel class
880 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
881 SUIT_DataObject* theParent ) const
883 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
885 // Ensure that SComponent instance is published in the study for the given module
886 // This line causes automatic creation of SalomeApp_ModuleObject in case if
887 // WITH_SALOMEDS_OBSERVER is defined
888 that->addComponent( theDataModel );
890 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
891 // or by someone else so check if it exists first of all
892 CAM_ModuleObject* res = 0;
894 DataObjectList children = root()->children();
895 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
896 for( ; !res && anIt!=aLast; anIt++ )
898 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
899 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
904 _PTR(Study) aStudy = studyDS();
908 _PTR(SComponent) aComp = aStudy->FindComponent(
909 theDataModel->module()->name().toStdString() );
913 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
922 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
924 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
926 CAM_Study::dataModelInserted(dm);
932 Create SComponent for module, using default engine (CORBAless)
934 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
936 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
937 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
939 // Check SComponent existance
940 _PTR(Study) aStudy = studyDS();
944 std::string aCompDataType = dm->module()->name().toStdString();
946 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
949 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
950 aComp = aBuilder->NewComponent(aCompDataType);
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());
959 // Set default engine IOR
960 // Issue 21377 - using separate engine for each type of light module
961 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
963 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
964 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
965 SalomeApp_DataModel::synchronize( aComp, this );
968 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
969 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
970 QString anIconName = dm->module()->iconName();
971 if (!anIconName.isEmpty()) {
972 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
974 anAttr->SetPixMap(anIconName.toStdString());
976 // Set default engine IOR
984 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
989 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
990 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
991 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
992 _PTR(SComponent) aSComp;
994 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
996 // Issue 21377 - using separate engine for each type of light module
997 std::string aCompDataType = dm->module()->name().toStdString();
998 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
999 aSComp = aStudy->FindComponent( aCompDataType );
1002 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1004 QString anId = aDM->getRootEntry( this );
1005 if ( anId.isEmpty() )
1006 return true; // Probably nothing to load
1007 anEngine = aDM->getModule()->engineIOR();
1008 if ( anEngine.isEmpty() )
1010 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1014 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1017 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1019 catch( const SALOME::SALOME_Exception& ) {
1020 // Oops, something went wrong while loading -> return an error
1023 // Something has been read -> create data model tree
1024 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1025 // aDM->buildTree( aSComp, 0, this );
1028 // Don't return false here, for there might be no data
1029 // for a given component in the study yet
1031 QStringList listOfFiles;
1032 openModuleData(dm->module()->name(), listOfFiles);
1033 if (dm && dm->open(studyName, this, listOfFiles)) {
1034 // Remove the files and temporary directory, created
1035 // for this module by LightApp_Engine_i::Load()
1036 bool isMultiFile = false; // TODO: decide, how to access this parameter
1037 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1039 // Something has been read -> create data model tree
1040 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1042 aDM->update(NULL, this);
1049 Create new study name.
1051 QString SalomeApp_Study::newStudyName() const
1053 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1054 QString prefix( "Study%1" ), newName, curName;
1055 int i = 1, j, n = studies.size();
1056 while ( newName.isEmpty() ){
1057 curName = prefix.arg( i );
1058 for ( j = 0 ; j < n; j++ ){
1059 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1071 Note that this method does not create or activate SalomeApp_Engine_i instance,
1072 therefore it can be called safely for any kind of module, but for full
1073 modules it returns an empty list.
1074 \return list of files used by module: to be used by CORBAless modules
1075 \param theModuleName - name of module
1077 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1079 // Issue 21377 - using separate engine for each type of light module
1080 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1082 return aDefaultEngine->GetListOfFiles(id());
1084 std::vector<std::string> aListOfFiles;
1085 return aListOfFiles;
1089 Sets list of files used by module: to be used by CORBAless modules.
1090 Note that this method does not create or activate SalomeApp_Engine_i instance,
1091 therefore it can be called safely for any kind of module, but for full
1092 modules it simply does nothing.
1093 \param theModuleName - name of module
1094 \param theListOfFiles - list of files
1096 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1097 const std::vector<std::string> theListOfFiles )
1099 // Issue 21377 - using separate engine for each type of light module
1100 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1102 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1106 \return temporary directory for saving files of modules
1108 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1110 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1111 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1116 Removes temporary files
1118 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1123 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1124 if (aListOfFiles.size() > 0) {
1125 std::string aTmpDir = aListOfFiles[0];
1127 const int n = aListOfFiles.size() - 1;
1128 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1130 for (int i = 0; i < n; i++)
1131 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1133 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1138 Mark the study as saved in the file
1139 \param theFileName - the name of file
1141 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1143 setStudyName(theFileName);
1144 studyDS()->Name(theFileName.toStdString());
1145 setIsSaved( isSaved );
1148 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1150 LightApp_DataObject* o = dynamic_cast<LightApp_DataObject*>( myObserver ? myObserver->findObject( theEntry.toLatin1().constData() ) : 0 );
1155 Deletes all references to object
1158 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1160 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1161 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1162 for( int i=0, n=aRefs.size(); i<n; i++ )
1164 _PTR( SObject ) o = aRefs[i];
1165 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1167 sb->RemoveReference( o );
1168 sb->RemoveObjectWithChildren( o );
1174 \return real entry by entry of reference
1175 \param entry - entry of reference object
1177 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1179 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1180 _PTR(SObject) refobj;
1182 if( obj && obj->ReferencedObject( refobj ) )
1183 return refobj->GetID().c_str();
1184 return LightApp_Study::referencedToEntry( entry );
1188 \return component data type for entry
1190 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1192 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1194 return LightApp_Study::componentDataType( entry );
1195 return obj->GetFatherComponent()->ComponentDataType().c_str();
1199 \return true if entry corresponds to component
1201 bool SalomeApp_Study::isComponent( const QString& entry ) const
1203 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1204 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1208 \return entries of object children
1210 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1212 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1213 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1214 anIter->InitEx( true );
1215 while( anIter->More() )
1217 _PTR(SObject) val( anIter->Value() );
1218 child_entries.append( val->GetID().c_str() );
1224 Fills list with components names
1225 \param comp - list to be filled
1227 void SalomeApp_Study::components( QStringList& comps ) const
1229 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1231 _PTR(SComponent) aComponent ( it->Value() );
1232 // skip the magic "Interface Applicative" component
1233 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1234 comps.append( aComponent->ComponentDataType().c_str() );
1239 Get the entry for the given module
1240 \param comp - list to be filled
1241 \return module root's entry
1243 QString SalomeApp_Study::centry( const QString& comp ) const
1246 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1248 _PTR(SComponent) aComponent ( it->Value() );
1249 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1250 e = aComponent->GetID().c_str();
1256 \return a list of saved points' IDs
1258 std::vector<int> SalomeApp_Study::getSavePoints()
1262 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1265 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1266 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1267 for(; anIter->More(); anIter->Next())
1269 _PTR(SObject) val( anIter->Value() );
1270 _PTR(GenericAttribute) genAttr;
1271 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1278 Removes a given save point
1280 void SalomeApp_Study::removeSavePoint(int savePoint)
1282 if(savePoint <= 0) return;
1283 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1284 _PTR(SObject) so = AP->GetSObject();
1285 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1286 builder->RemoveObjectWithChildren(so);
1290 \return a name of save point
1292 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1294 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1295 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1296 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1300 Sets a name of save point
1302 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1304 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1305 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1306 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1310 * \brief Restores the study state
1312 void SalomeApp_Study::restoreState(int savePoint)
1314 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1319 Slot: called on change of a root of a data model. Redefined from CAM_Study
1321 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1323 LightApp_Study::updateModelRoot( dm );
1325 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1326 // it must always be the last one.
1327 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );