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 /* Define visibility state */
187 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
188 if ( suit_obj && !isComponent ) {
189 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
190 if (!moduleTitle.isEmpty()) {
191 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
193 if(aDisplayer->canBeDisplayed(theID.c_str())) {
194 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
195 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
198 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
202 } // END: work with tree nodes structure
203 else { // BEGIN: work with study structure
204 EntryMapIter it = entry2SuitObject.find( theID );
205 if ( it != entry2SuitObject.end() ) {
206 MESSAGE("Entry " << theID << " is already added. Problem ??");
210 int last2Pnt_pos = theID.rfind( ":" );
211 std::string parent_id = theID.substr( 0, last2Pnt_pos );
212 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
214 if ( parent_id.length() == 3 ) // "0:1" - root item?
216 // It's probably a SComponent
217 if ( theID == aSComp->GetID() )
218 suit_obj = new SalomeApp_ModuleObject( aSComp );
220 suit_obj = new SalomeApp_DataObject( aSObj );
224 suit_obj = new SalomeApp_DataObject( aSObj );
227 it = entry2SuitObject.find( parent_id );
228 if ( it != entry2SuitObject.end() ) {
229 SalomeApp_DataObject* father = it->second;
230 father->insertChildAtTag( suit_obj, tag );
233 if ( parent_id.length() == 3 ) // "0:1" - root item?
235 // This should be for a module
236 SUIT_DataObject* father=myStudy->root();
237 father->appendChild(suit_obj);
241 MESSAGE("SHOULD NEVER GET HERE!!!");
243 //Try to find the SalomeApp_DataObject object parent
244 std::string root_id = parent_id.substr( 0, 4 );
245 std::string obj_id = parent_id.substr( 4 );
248 std::string::size_type debut = 0;
249 std::string::size_type fin;
250 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
252 fin = obj_id.find_first_of( ':', debut );
253 if ( fin == std::string::npos ) {
255 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
256 entry2SuitObject[parent_id] = anObj;
259 anID = root_id + obj_id.substr( 0, fin );
260 EntryMapIter it2 = entry2SuitObject.find( anID );
261 if ( it2 == entry2SuitObject.end() ) {
262 //the ID is not known in entry2SuitObject
263 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
264 entry2SuitObject[anID] = anObj;
270 anObj->insertChildAtTag( suit_obj, tag );
273 entry2SuitObject[theID] = suit_obj;
274 } // END: work with study structure
279 EntryMapIter it = entry2SuitObject.find( theID );
280 if ( it != entry2SuitObject.end() )
282 suit_obj = it->second;
283 // VSR: object is not removed, since SALOMEDS::SObject is not actually removed,
284 // only its attributes are cleared;
285 // thus, the object can be later reused
286 suit_obj->updateItem();
287 //SUIT_DataObject* father=suit_obj->parent();
289 // father->removeChild(suit_obj);
290 //entry2SuitObject.erase(it);
294 MESSAGE("Want to remove an unknown object" << theID);
300 //MESSAGE("Want to modify an object " << theID);
301 EntryMapIter it = entry2SuitObject.find( theID );
302 if ( it != entry2SuitObject.end() )
304 suit_obj = it->second;
305 suit_obj->updateItem();
309 MESSAGE("Want to modify an unknown object" << theID);
313 case 5: //IOR of the object modified
315 EntryMapIter it = entry2SuitObject.find( theID );
316 if ( it != entry2SuitObject.end() )
317 suit_obj = it->second;
319 /* Define visibility state */
320 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
321 if ( suit_obj && !isComponent ) {
322 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
323 if (!moduleTitle.isEmpty()) {
324 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
326 if(aDisplayer->canBeDisplayed(theID.c_str())) {
327 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
328 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
331 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
337 case 6: //NoteBook variables were modified
339 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
342 default:MESSAGE("Unknown event: " << event);break;
344 } //notifyObserverID_real
349 entry2SuitObject.clear();
350 SUIT_DataObject* o = myStudy->root();
352 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
354 std::string entry = so->entry().toLatin1().constData();
356 entry2SuitObject[entry] = so;
358 if ( o->childCount() > 0 ) {
359 // parse the children
362 else if ( o->nextBrother() > 0 ) {
363 o = o->nextBrother();
366 // step to the next appropriate parent
369 if ( o->nextBrother() ) {
370 o = o->nextBrother();
380 _PTR(Study) myStudyDS;
381 SalomeApp_Study* myStudy;
382 EntryMap entry2SuitObject;
389 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
390 : LightApp_Study( app ), myObserver( 0 )
397 SalomeApp_Study::~SalomeApp_Study()
400 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
401 myObserver->_default_POA()->deactivate_object( oid.in() );
405 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
407 emit notebookVarUpdated( theVarName );
413 int SalomeApp_Study::id() const
417 id = studyDS()->StudyId();
424 QString SalomeApp_Study::studyName() const
426 // redefined from SUIT_Study to update study name properly since
427 // it can be changed outside of GUI
428 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
430 QString newName = studyDS()->Name().c_str();
431 if ( LightApp_Study::studyName() != newName ) {
432 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
433 that->setStudyName( newName );
434 ((SalomeApp_Application*)application())->updateDesktopTitle();
437 return LightApp_Study::studyName();
441 Gets studyDS pointer.
443 _PTR(Study) SalomeApp_Study::studyDS() const
451 bool SalomeApp_Study::createDocument( const QString& theStr )
453 MESSAGE( "createDocument" );
455 // initialize myStudyDS, read HDF file
456 QString aName = newStudyName();
457 _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
462 setStudyName( aName );
465 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
466 #ifdef WITH_SALOMEDS_OBSERVER
467 aRoot->setToSynchronize(false);
471 bool aRet = CAM_Study::createDocument( theStr );
473 #ifdef WITH_SALOMEDS_OBSERVER
474 myObserver = new Observer_i(myStudyDS,this);
475 //attach an observer to the study with notification of modifications
476 myStudyDS->attach(myObserver->_this(),true);
479 emit created( this );
486 \param theFileName - name of file
488 bool SalomeApp_Study::openDocument( const QString& theFileName )
490 MESSAGE( "openDocument" );
492 // initialize myStudyDS, read HDF file
493 _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
499 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
501 // update loaded data models: call open() and update() on them.
504 QListIterator<CAM_DataModel*> it( dm_s );
505 while ( it.hasNext() )
506 openDataModel( studyName(), it.next() );
508 // this will build a SUIT_DataObject-s tree under myRoot member field
509 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
510 // but tree that corresponds to not-loaded data models will be updated any way.
511 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
513 #ifdef WITH_SALOMEDS_OBSERVER
514 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
515 myObserver = new Observer_i(myStudyDS,this);
516 //attach an observer to the study with notification of modifications
517 myStudyDS->attach(myObserver->_this(),true);
520 bool res = CAM_Study::openDocument( theFileName );
523 study->IsSaved(true);
525 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
527 std::vector<int> savePoints = getSavePoints();
528 if ( savePoints.size() > 0 )
529 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
532 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
537 Connects GUI study to SALOMEDS one already loaded into StudyManager
538 \param theStudyName - name of study
540 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
542 MESSAGE( "loadDocument" );
544 // obtain myStudyDS from StudyManager
545 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
551 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
553 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
555 // update loaded data models: call open() and update() on them.
559 QListIterator<CAM_DataModel*> it( dm_s );
560 while ( it.hasNext() )
561 openDataModel( studyName(), it.next() );
563 // this will build a SUIT_DataObject-s tree under myRoot member field
564 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
565 // but tree that corresponds to not-loaded data models will be updated any way.
566 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
568 #ifdef WITH_SALOMEDS_OBSERVER
569 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
570 myObserver = new Observer_i(myStudyDS,this);
571 //attach an observer to the study with notification of modifications
572 myStudyDS->attach(myObserver->_this(),true);
575 bool res = CAM_Study::openDocument( theStudyName );
577 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
578 // mark study as "not saved" after call openDocument( ... ) method.
582 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
584 std::vector<int> savePoints = getSavePoints();
585 if ( savePoints.size() > 0 )
586 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
589 //SRN: BugID IPAL9021: End
595 \param theFileName - name of file
597 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
599 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
601 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
603 ModelList list; dataModels( list );
605 QListIterator<CAM_DataModel*> it( list );
606 QStringList listOfFiles;
607 while ( it.hasNext() ) {
608 // Cast to LightApp class in order to give a chance
609 // to light modules to save their data
610 if ( LightApp_DataModel* aModel =
611 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
613 aModel->saveAs( theFileName, this, listOfFiles );
614 if ( !listOfFiles.isEmpty() )
615 saveModuleData(aModel->module()->name(), listOfFiles);
619 // save SALOMEDS document
620 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
624 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
625 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
626 bool res = (isAscii ?
627 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
628 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
629 && CAM_Study::saveDocumentAs( theFileName );
631 res = res && saveStudyData(theFileName);
640 Saves previously opened document
642 bool SalomeApp_Study::saveDocument()
644 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
646 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
648 ModelList list; dataModels( list );
650 QListIterator<CAM_DataModel*> it( list );
651 QStringList listOfFiles;
652 while ( it.hasNext() ) {
653 // Cast to LightApp class in order to give a chance
654 // to light modules to save their data
655 if ( LightApp_DataModel* aModel =
656 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
658 aModel->save(listOfFiles);
659 if ( !listOfFiles.isEmpty() )
660 saveModuleData(aModel->module()->name(), listOfFiles);
664 // save SALOMEDS document
665 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
669 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
670 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
671 bool res = (isAscii ?
672 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
673 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
675 res = res && saveStudyData(studyName());
685 void SalomeApp_Study::closeDocument(bool permanently)
687 LightApp_Study::closeDocument(permanently);
689 // close SALOMEDS document
690 _PTR(Study) studyPtr = studyDS();
694 SalomeApp_Application::studyMgr()->Close( studyPtr );
696 SALOMEDSClient_Study* aStudy = 0;
697 setStudyDS( _PTR(Study)(aStudy) );
702 Dump study operation. Writes a Python dump file using
703 SALOMEDS services. Additionally, gives a chance to light modules
704 to participate in dump study operation.
706 \param theFileName - full path to the output Python file
707 \param toPublish - if true, all objects are published in a study
708 by the output script, including those not orignally present
709 in the current study.
710 \param isMultiFile - if true, each module's dump is written into
711 a separate Python file, otherwise a single output file is written
712 \param toSaveGUI - if true, the GUI state is written
714 \return - true if the operation succeeds, and false otherwise.
716 bool SalomeApp_Study::dump( const QString& theFileName,
722 _PTR(AttributeParameter) ap;
723 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
724 _PTR(Study) aStudy = studyDS();
726 if( ip->isDumpPython( aStudy ) )
727 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
729 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
730 ip->setDumpPython( aStudy );
731 //SRN: create a temporary save point
732 savePoint = SalomeApp_VisualState(
733 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
736 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
737 // This is an optional but important step, it gives a chance to light modules
738 // to dump their data as a part of common dump study operation
742 QListIterator<CAM_DataModel*> it( list );
743 QStringList listOfFiles;
744 while ( it.hasNext() ) {
745 if ( LightApp_DataModel* aModel =
746 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
748 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
749 !listOfFiles.isEmpty() )
750 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
751 // This code is shared with persistence mechanism.
752 // NOTE: this should be revised if behavior of saveModuleData() changes!
753 saveModuleData(aModel->module()->name(), listOfFiles);
757 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
758 // any light module is present in the current configuration
759 QFileInfo aFileInfo( theFileName );
760 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
761 aFileInfo.baseName().toUtf8().data(),
765 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
767 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
768 // This code is shared with persistence mechanism.
769 // NOTE: this should be revised if behavior of saveStudyData() changes!
770 saveStudyData( theFileName );
776 \return true, if study is modified in comparison with last open/save
778 bool SalomeApp_Study::isModified() const
780 bool isAnyChanged = studyDS() && studyDS()->IsModified();
782 isAnyChanged = LightApp_Study::isModified();
788 Set study modified to \a on.
790 void SalomeApp_Study::Modified()
792 if(_PTR(Study) aStudy = studyDS())
794 LightApp_Study::Modified();
798 \return if data model is saved
800 bool SalomeApp_Study::isSaved() const
802 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
804 isAllSaved = LightApp_Study::isSaved();
811 \param theModuleName - name of module
812 \param theListOfFiles - list of files to be saved
814 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
816 int aNb = theListOfFiles.count();
820 std::vector<std::string> aListOfFiles ( aNb );
822 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
823 if ( (*it).isEmpty() )
825 aListOfFiles[anIndex] = (*it).toUtf8().data();
828 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
833 \param theModuleName - name of module
834 \param theListOfFiles - list of files to be loaded
836 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
838 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
840 int i, aLength = aListOfFiles.size() - 1;
844 //Get a temporary directory for saved a file
845 theListOfFiles.append(aListOfFiles[0].c_str());
847 for(i = 0; i < aLength; i++)
848 theListOfFiles.append(aListOfFiles[i+1].c_str());
852 Re-implemented from LightApp_Study, actually does not save anything but
853 simply cleans up light modules' data
855 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
857 ModelList list; dataModels( list );
858 QListIterator<CAM_DataModel*> it( list );
859 std::vector<std::string> listOfFiles(0);
860 while ( it.hasNext() ){
861 LightApp_DataModel* aLModel =
862 dynamic_cast<LightApp_DataModel*>( it.next() );
863 // It is safe to call SetListOfFiles() for any kind of module
864 // because SetListOfFiles() does nothing for full modules :)
866 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
874 bool SalomeApp_Study::openStudyData( const QString& theFileName )
882 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
888 Virtual method re-implemented from LightApp_Study in order to create
889 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
891 \param theDataModel - data model instance to create a module object for
892 \param theParent - the module object's parent (normally it's the study root)
893 \return the module object instance
894 \sa LightApp_Study class, LightApp_DataModel class
896 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
897 SUIT_DataObject* theParent ) const
899 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
901 // Ensure that SComponent instance is published in the study for the given module
902 // This line causes automatic creation of SalomeApp_ModuleObject in case if
903 // WITH_SALOMEDS_OBSERVER is defined
904 that->addComponent( theDataModel );
906 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
907 // or by someone else so check if it exists first of all
908 CAM_ModuleObject* res = 0;
910 DataObjectList children = root()->children();
911 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
912 for( ; !res && anIt!=aLast; anIt++ )
914 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
915 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
920 _PTR(Study) aStudy = studyDS();
924 _PTR(SComponent) aComp = aStudy->FindComponent(
925 theDataModel->module()->name().toStdString() );
929 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
938 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
940 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
942 CAM_Study::dataModelInserted(dm);
948 Create SComponent for module, using default engine (CORBAless)
950 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
952 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
953 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
955 // Check SComponent existance
956 _PTR(Study) aStudy = studyDS();
960 std::string aCompDataType = dm->module()->name().toStdString();
962 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
965 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
966 aComp = aBuilder->NewComponent(aCompDataType);
967 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
968 QString anIconName = dm->module()->iconName();
969 if (!anIconName.isEmpty()) {
970 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
972 anAttr->SetPixMap(anIconName.toStdString());
975 // Set default engine IOR
976 // Issue 21377 - using separate engine for each type of light module
977 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
979 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
980 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
981 SalomeApp_DataModel::synchronize( aComp, this );
984 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
985 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
986 QString anIconName = dm->module()->iconName();
987 if (!anIconName.isEmpty()) {
988 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
990 anAttr->SetPixMap(anIconName.toStdString());
992 // Set default engine IOR
1000 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1005 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1006 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1007 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
1008 _PTR(SComponent) aSComp;
1010 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1012 // Issue 21377 - using separate engine for each type of light module
1013 std::string aCompDataType = dm->module()->name().toStdString();
1014 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1015 aSComp = aStudy->FindComponent( aCompDataType );
1018 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1020 QString anId = aDM->getRootEntry( this );
1021 if ( anId.isEmpty() )
1022 return true; // Probably nothing to load
1023 anEngine = aDM->getModule()->engineIOR();
1024 if ( anEngine.isEmpty() )
1026 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1030 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1033 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1035 catch( const SALOME::SALOME_Exception& ) {
1036 // Oops, something went wrong while loading -> return an error
1039 // Something has been read -> create data model tree
1040 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1041 // aDM->buildTree( aSComp, 0, this );
1044 // Don't return false here, for there might be no data
1045 // for a given component in the study yet
1047 QStringList listOfFiles;
1048 openModuleData(dm->module()->name(), listOfFiles);
1049 if (dm && dm->open(studyName, this, listOfFiles)) {
1050 // Remove the files and temporary directory, created
1051 // for this module by LightApp_Engine_i::Load()
1052 bool isMultiFile = false; // TODO: decide, how to access this parameter
1053 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1055 // Something has been read -> create data model tree
1056 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1058 aDM->update(NULL, this);
1065 Create new study name.
1067 QString SalomeApp_Study::newStudyName() const
1069 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1070 QString prefix( "Study%1" ), newName, curName;
1071 int i = 1, j, n = studies.size();
1072 while ( newName.isEmpty() ){
1073 curName = prefix.arg( i );
1074 for ( j = 0 ; j < n; j++ ){
1075 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1087 Note that this method does not create or activate SalomeApp_Engine_i instance,
1088 therefore it can be called safely for any kind of module, but for full
1089 modules it returns an empty list.
1090 \return list of files used by module: to be used by CORBAless modules
1091 \param theModuleName - name of module
1093 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1095 // Issue 21377 - using separate engine for each type of light module
1096 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1098 return aDefaultEngine->GetListOfFiles(id());
1100 std::vector<std::string> aListOfFiles;
1101 return aListOfFiles;
1105 Sets list of files used by module: to be used by CORBAless modules.
1106 Note that this method does not create or activate SalomeApp_Engine_i instance,
1107 therefore it can be called safely for any kind of module, but for full
1108 modules it simply does nothing.
1109 \param theModuleName - name of module
1110 \param theListOfFiles - list of files
1112 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1113 const std::vector<std::string> theListOfFiles )
1115 // Issue 21377 - using separate engine for each type of light module
1116 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1118 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1122 \return temporary directory for saving files of modules
1124 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1126 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1127 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1132 Removes temporary files
1134 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1139 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1140 if (aListOfFiles.size() > 0) {
1141 std::string aTmpDir = aListOfFiles[0];
1143 const int n = aListOfFiles.size() - 1;
1144 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1146 for (int i = 0; i < n; i++)
1147 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1149 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1154 Mark the study as saved in the file
1155 \param theFileName - the name of file
1157 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1159 setStudyName(theFileName);
1160 studyDS()->Name(theFileName.toStdString());
1161 setIsSaved( isSaved );
1164 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1166 LightApp_DataObject* o = dynamic_cast<LightApp_DataObject*>( myObserver ? myObserver->findObject( theEntry.toLatin1().constData() ) : 0 );
1171 Deletes all references to object
1174 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1176 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1177 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1178 for( int i=0, n=aRefs.size(); i<n; i++ )
1180 _PTR( SObject ) o = aRefs[i];
1181 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1183 sb->RemoveReference( o );
1184 sb->RemoveObjectWithChildren( o );
1190 \return real entry by entry of reference
1191 \param entry - entry of reference object
1193 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1195 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1196 _PTR(SObject) refobj;
1198 if( obj && obj->ReferencedObject( refobj ) )
1199 return refobj->GetID().c_str();
1200 return LightApp_Study::referencedToEntry( entry );
1204 \return component data type for entry
1206 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1208 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1210 return LightApp_Study::componentDataType( entry );
1211 return obj->GetFatherComponent()->ComponentDataType().c_str();
1215 \return true if entry corresponds to component
1217 bool SalomeApp_Study::isComponent( const QString& entry ) const
1219 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1220 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1224 \return entries of object children
1226 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1228 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1229 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1230 anIter->InitEx( true );
1231 while( anIter->More() )
1233 _PTR(SObject) val( anIter->Value() );
1234 child_entries.append( val->GetID().c_str() );
1240 Fills list with components names
1241 \param comp - list to be filled
1243 void SalomeApp_Study::components( QStringList& comps ) const
1245 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1247 _PTR(SComponent) aComponent ( it->Value() );
1248 // skip the magic "Interface Applicative" component
1249 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1250 comps.append( aComponent->ComponentDataType().c_str() );
1255 Get the entry for the given module
1256 \param comp - list to be filled
1257 \return module root's entry
1259 QString SalomeApp_Study::centry( const QString& comp ) const
1262 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1264 _PTR(SComponent) aComponent ( it->Value() );
1265 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1266 e = aComponent->GetID().c_str();
1272 \return a list of saved points' IDs
1274 std::vector<int> SalomeApp_Study::getSavePoints()
1278 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1281 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1282 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1283 for(; anIter->More(); anIter->Next())
1285 _PTR(SObject) val( anIter->Value() );
1286 _PTR(GenericAttribute) genAttr;
1287 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1294 Removes a given save point
1296 void SalomeApp_Study::removeSavePoint(int savePoint)
1298 if(savePoint <= 0) return;
1299 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1300 _PTR(SObject) so = AP->GetSObject();
1301 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1302 builder->RemoveObjectWithChildren(so);
1306 \return a name of save point
1308 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1310 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1311 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1312 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1316 Sets a name of save point
1318 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1320 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1321 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1322 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1326 * \brief Restores the study state
1328 void SalomeApp_Study::restoreState(int savePoint)
1330 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1335 Slot: called on change of a root of a data model. Redefined from CAM_Study
1337 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1339 LightApp_Study::updateModelRoot( dm );
1341 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1342 // it must always be the last one.
1343 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );