1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "SalomeApp_Study.h"
25 #include "SalomeApp_Module.h"
26 #include "SalomeApp_DataObject.h"
27 #include "SalomeApp_DataModel.h"
28 #include "SalomeApp_Application.h"
29 #include "SalomeApp_Engine_i.h"
30 #include "SalomeApp_VisualState.h"
32 // temporary commented
33 //#include <OB_Browser.h>
35 #include <QCoreApplication>
38 #include "SALOME_Event.h"
39 #include "Basics_Utils.hxx"
41 #include <SUIT_ResourceMgr.h>
42 #include <SUIT_TreeModel.h>
43 #include <SUIT_DataBrowser.h>
44 #include <SUIT_MessageBox.h>
45 #include <SUIT_Session.h>
46 #include <SUIT_Desktop.h>
48 #include <LightApp_Displayer.h>
50 #include "utilities.h"
52 #include "SALOMEDS_Tool.hxx"
54 #include "SALOMEDSClient_ClientFactory.hxx"
56 #include <SALOMEconfig.h>
57 #include CORBA_SERVER_HEADER(SALOME_Exception)
59 //#define NOTIFY_BY_EVENT
61 class ObserverEvent : public QEvent
64 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
74 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
76 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
77 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
81 Observer_i(_PTR(Study) aStudyDS, SalomeApp_Study* aStudy):QObject(aStudy)
88 SUIT_DataObject* findObject( const char* theID ) const
90 EntryMap::const_iterator it = entry2SuitObject.find( theID );
91 return it != entry2SuitObject.end() ? it->second : 0;
94 virtual void notifyObserverID(const char* theID, CORBA::Long event)
96 #ifdef NOTIFY_BY_EVENT
97 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
99 notifyObserverID_real(theID,event);
103 virtual bool event(QEvent *event)
105 if (event->type() == QEvent::User )
107 //START_TIMING(notify);
108 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
109 //END_TIMING(notify,100);
114 void notifyObserverID_real(const std::string& theID, long event)
116 SalomeApp_DataObject* suit_obj = 0;
121 _PTR(SObject) aSObj = myStudyDS->FindObjectID(theID);
122 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
124 if (!aSComp || aSComp->IsNull()) {
125 MESSAGE("Entry " << theID << " has not father component. Problem ??");
129 // Mantis issue 0020136: Drag&Drop in OB
130 _PTR(UseCaseBuilder) aUseCaseBuilder = myStudyDS->GetUseCaseBuilder();
131 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
132 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
133 // tree node is not yet set, it is a normal situation
137 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
138 if (!aFatherSO || aFatherSO->IsNull()) {
139 MESSAGE("Father SObject is not found. Problem ??");
143 std::string parent_id = aFatherSO->GetID();
144 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
146 if (it == entry2SuitObject.end()) {
147 MESSAGE("Father data object is not found. Problem ??");
151 SalomeApp_DataObject* aFatherDO = it->second;
153 it = entry2SuitObject.find(theID);
154 if (it != entry2SuitObject.end()) { // this SOobject is already added somethere
155 suit_obj = it->second;
156 SUIT_DataObject* oldFather = suit_obj->parent();
158 oldFather->removeChild(suit_obj, false);
159 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
160 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
161 model->forgetObject( suit_obj );
163 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
164 oldFatherSA->updateItem();
169 suit_obj = new SalomeApp_DataObject(aSObj);
170 entry2SuitObject[theID] = suit_obj;
173 suit_obj->updateItem();
174 // define position in the data tree (in aFatherDO) to insert the aSObj
176 //int childDataObjCount = aFatherDO->childCount();
177 _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
178 for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
179 if (aUseCaseIter->Value()->GetID() == theID) {
185 aFatherDO->insertChildAtPos(suit_obj, pos);
186 //aFatherDO->insertChild(suit_obj, pos);
187 aFatherDO->updateItem();
189 /* Define visibility state */
190 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
191 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
192 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
193 if (!moduleTitle.isEmpty()) {
194 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
196 if(aDisplayer->canBeDisplayed(theID.c_str())) {
197 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState ); //hide the just added object
198 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
201 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
205 } // END: work with tree nodes structure
206 else { // BEGIN: work with study structure
207 EntryMapIter it = entry2SuitObject.find( theID );
208 if ( it != entry2SuitObject.end() ) {
209 MESSAGE("Entry " << theID << " is already added. Problem ??");
213 int last2Pnt_pos = theID.rfind( ":" );
214 std::string parent_id = theID.substr( 0, last2Pnt_pos );
215 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
217 if ( parent_id.length() == 3 ) // "0:1" - root item?
219 // It's probably a SComponent
220 if ( theID == aSComp->GetID() )
221 suit_obj = new SalomeApp_ModuleObject( aSComp );
223 suit_obj = new SalomeApp_DataObject( aSObj );
227 suit_obj = new SalomeApp_DataObject( aSObj );
230 it = entry2SuitObject.find( parent_id );
231 if ( it != entry2SuitObject.end() ) {
232 SalomeApp_DataObject* father = it->second;
233 father->insertChildAtTag( suit_obj, tag );
236 if ( parent_id.length() == 3 ) // "0:1" - root item?
238 // This should be for a module
239 SUIT_DataObject* father=myStudy->root();
240 father->appendChild(suit_obj);
244 MESSAGE("SHOULD NEVER GET HERE!!!");
246 //Try to find the SalomeApp_DataObject object parent
247 std::string root_id = parent_id.substr( 0, 4 );
248 std::string obj_id = parent_id.substr( 4 );
251 std::string::size_type debut = 0;
252 std::string::size_type fin;
253 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
255 fin = obj_id.find_first_of( ':', debut );
256 if ( fin == std::string::npos ) {
258 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
259 entry2SuitObject[parent_id] = anObj;
262 anID = root_id + obj_id.substr( 0, fin );
263 EntryMapIter it2 = entry2SuitObject.find( anID );
264 if ( it2 == entry2SuitObject.end() ) {
265 //the ID is not known in entry2SuitObject
266 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
267 entry2SuitObject[anID] = anObj;
273 anObj->insertChildAtTag( suit_obj, tag );
276 entry2SuitObject[theID] = suit_obj;
277 } // END: work with study structure
282 EntryMapIter it = entry2SuitObject.find( theID );
283 if ( it != entry2SuitObject.end() )
285 suit_obj = it->second;
286 // VSR: object is not removed, since SALOMEDS::SObject is not actually removed,
287 // only its attributes are cleared;
288 // thus, the object can be later reused
289 suit_obj->updateItem();
290 //SUIT_DataObject* father=suit_obj->parent();
292 // father->removeChild(suit_obj);
293 //entry2SuitObject.erase(it);
297 MESSAGE("Want to remove an unknown object" << theID);
303 //MESSAGE("Want to modify an object " << theID);
304 EntryMapIter it = entry2SuitObject.find( theID );
305 if ( it != entry2SuitObject.end() )
307 suit_obj = it->second;
308 suit_obj->updateItem();
312 MESSAGE("Want to modify an unknown object" << theID);
316 case 5: //IOR of the object modified
318 EntryMapIter it = entry2SuitObject.find( theID );
319 if ( it != entry2SuitObject.end() )
320 suit_obj = it->second;
322 /* Define visibility state */
323 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
324 if ( suit_obj && !isComponent ) {
325 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
326 if (!moduleTitle.isEmpty()) {
327 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
329 if(aDisplayer->canBeDisplayed(theID.c_str())) {
330 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
331 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
334 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
340 #ifndef DISABLE_PYCONSOLE
341 case 6: //NoteBook variables were modified
343 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
347 default:MESSAGE("Unknown event: " << event);break;
349 } //notifyObserverID_real
354 entry2SuitObject.clear();
355 SUIT_DataObject* o = myStudy->root();
357 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
359 std::string entry = so->entry().toLatin1().constData();
361 entry2SuitObject[entry] = so;
363 if ( o->childCount() > 0 ) {
364 // parse the children
367 else if ( o->nextBrother() > 0 ) {
368 o = o->nextBrother();
371 // step to the next appropriate parent
374 if ( o->nextBrother() ) {
375 o = o->nextBrother();
385 _PTR(Study) myStudyDS;
386 SalomeApp_Study* myStudy;
387 EntryMap entry2SuitObject;
394 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
395 : LightApp_Study( app ), myObserver( 0 )
402 SalomeApp_Study::~SalomeApp_Study()
405 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
406 myObserver->_default_POA()->deactivate_object( oid.in() );
410 #ifndef DISABLE_PYCONSOLE
411 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
413 emit notebookVarUpdated( theVarName );
420 int SalomeApp_Study::id() const
424 id = studyDS()->StudyId();
431 QString SalomeApp_Study::studyName() const
433 // redefined from SUIT_Study to update study name properly since
434 // it can be changed outside of GUI
435 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
437 QString newName = QString::fromUtf8(studyDS()->Name().c_str());
438 if ( LightApp_Study::studyName() != newName ) {
439 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
440 that->setStudyName( newName );
441 ((SalomeApp_Application*)application())->updateDesktopTitle();
444 return LightApp_Study::studyName();
448 Gets studyDS pointer.
450 _PTR(Study) SalomeApp_Study::studyDS() const
458 bool SalomeApp_Study::createDocument( const QString& theStr )
460 MESSAGE( "createDocument" );
462 // initialize myStudyDS, read HDF file
463 QString aName = newStudyName();
467 study = _PTR(Study)( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
469 catch(const SALOME_Exception& ex) {
470 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
471 tr("ERR_ERROR"), tr(ex.what()));
475 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
476 tr("ERR_ERROR"), tr("CREATE_DOCUMENT_PROBLEM"));
484 setStudyName( aName );
487 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
488 #ifdef WITH_SALOMEDS_OBSERVER
489 aRoot->setToSynchronize(false);
493 bool aRet = CAM_Study::createDocument( theStr );
495 #ifdef WITH_SALOMEDS_OBSERVER
496 myObserver = new Observer_i(myStudyDS,this);
497 //attach an observer to the study with notification of modifications
498 myStudyDS->attach(myObserver->_this(),true);
501 emit created( this );
508 \param theFileName - name of file
510 bool SalomeApp_Study::openDocument( const QString& theFileName )
512 MESSAGE( "openDocument" );
514 // initialize myStudyDS, read HDF file
517 study = _PTR(Study) ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
519 catch(const SALOME_Exception& ex) {
520 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
521 tr("ERR_ERROR"), tr(ex.what()));
525 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
526 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
535 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
537 // update loaded data models: call open() and update() on them.
540 QListIterator<CAM_DataModel*> it( dm_s );
541 while ( it.hasNext() )
542 openDataModel( studyName(), it.next() );
544 // this will build a SUIT_DataObject-s tree under myRoot member field
545 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
546 // but tree that corresponds to not-loaded data models will be updated any way.
547 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
549 #ifdef WITH_SALOMEDS_OBSERVER
550 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
551 myObserver = new Observer_i(myStudyDS,this);
552 //attach an observer to the study with notification of modifications
553 myStudyDS->attach(myObserver->_this(),true);
556 bool res = CAM_Study::openDocument( theFileName );
559 study->IsSaved(true);
561 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
563 std::vector<int> savePoints = getSavePoints();
564 if ( savePoints.size() > 0 )
565 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
568 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
573 Connects GUI study to SALOMEDS one already loaded into StudyManager
574 \param theStudyName - name of study
576 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
578 MESSAGE( "loadDocument" );
580 // obtain myStudyDS from StudyManager
581 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
587 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
589 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
591 // update loaded data models: call open() and update() on them.
595 QListIterator<CAM_DataModel*> it( dm_s );
596 while ( it.hasNext() )
597 openDataModel( studyName(), it.next() );
599 // this will build a SUIT_DataObject-s tree under myRoot member field
600 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
601 // but tree that corresponds to not-loaded data models will be updated any way.
602 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
604 #ifdef WITH_SALOMEDS_OBSERVER
605 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
606 myObserver = new Observer_i(myStudyDS,this);
607 //attach an observer to the study with notification of modifications
608 myStudyDS->attach(myObserver->_this(),true);
611 bool res = CAM_Study::openDocument( theStudyName );
613 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
614 // mark study as "not saved" after call openDocument( ... ) method.
618 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
620 std::vector<int> savePoints = getSavePoints();
621 if ( savePoints.size() > 0 )
622 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
625 //SRN: BugID IPAL9021: End
631 \param theFileName - name of file
633 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
635 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
637 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
639 ModelList list; dataModels( list );
641 QListIterator<CAM_DataModel*> it( list );
642 QStringList listOfFiles;
643 while ( it.hasNext() ) {
644 // Cast to LightApp class in order to give a chance
645 // to light modules to save their data
646 if ( LightApp_DataModel* aModel =
647 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
649 aModel->saveAs( theFileName, this, listOfFiles );
650 if ( !listOfFiles.isEmpty() )
651 saveModuleData(aModel->module()->name(), listOfFiles);
655 // save SALOMEDS document
656 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
660 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
661 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
662 bool res = (isAscii ?
663 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
664 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
665 && CAM_Study::saveDocumentAs( theFileName );
667 res = res && saveStudyData(theFileName);
676 Saves previously opened document
678 bool SalomeApp_Study::saveDocument()
680 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
682 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
684 ModelList list; dataModels( list );
686 QListIterator<CAM_DataModel*> it( list );
687 QStringList listOfFiles;
688 while ( it.hasNext() ) {
689 // Cast to LightApp class in order to give a chance
690 // to light modules to save their data
691 if ( LightApp_DataModel* aModel =
692 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
694 aModel->save(listOfFiles);
695 if ( !listOfFiles.isEmpty() )
696 saveModuleData(aModel->module()->name(), listOfFiles);
700 // save SALOMEDS document
701 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
705 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
706 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
707 bool res = (isAscii ?
708 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
709 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
711 res = res && saveStudyData(studyName());
721 void SalomeApp_Study::closeDocument(bool permanently)
723 LightApp_Study::closeDocument(permanently);
725 // close SALOMEDS document
726 _PTR(Study) studyPtr = studyDS();
730 myStudyDS->detach( myObserver->_this() );
732 SalomeApp_Application::studyMgr()->Close( studyPtr );
734 SALOMEDSClient_Study* aStudy = 0;
735 setStudyDS( _PTR(Study)(aStudy) );
740 Dump study operation. Writes a Python dump file using
741 SALOMEDS services. Additionally, gives a chance to light modules
742 to participate in dump study operation.
744 \param theFileName - full path to the output Python file
745 \param toPublish - if true, all objects are published in a study
746 by the output script, including those not orignally present
747 in the current study.
748 \param isMultiFile - if true, each module's dump is written into
749 a separate Python file, otherwise a single output file is written
750 \param toSaveGUI - if true, the GUI state is written
752 \return - true if the operation succeeds, and false otherwise.
754 bool SalomeApp_Study::dump( const QString& theFileName,
760 _PTR(AttributeParameter) ap;
761 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
762 _PTR(Study) aStudy = studyDS();
764 if( ip->isDumpPython( aStudy ) )
765 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
767 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
768 ip->setDumpPython( aStudy );
769 //SRN: create a temporary save point
770 savePoint = SalomeApp_VisualState(
771 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
774 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
775 // This is an optional but important step, it gives a chance to light modules
776 // to dump their data as a part of common dump study operation
780 QListIterator<CAM_DataModel*> it( list );
781 QStringList listOfFiles;
782 while ( it.hasNext() ) {
783 if ( LightApp_DataModel* aModel =
784 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
786 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
787 !listOfFiles.isEmpty() )
788 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
789 // This code is shared with persistence mechanism.
790 // NOTE: this should be revised if behavior of saveModuleData() changes!
791 saveModuleData(aModel->module()->name(), listOfFiles);
795 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
796 // any light module is present in the current configuration
797 QFileInfo aFileInfo( theFileName );
798 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
799 aFileInfo.baseName().toUtf8().data(),
803 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
805 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
806 // This code is shared with persistence mechanism.
807 // NOTE: this should be revised if behavior of saveStudyData() changes!
808 saveStudyData( theFileName );
814 \return true, if study is modified in comparison with last open/save
816 bool SalomeApp_Study::isModified() const
818 bool isAnyChanged = studyDS() && studyDS()->IsModified();
820 isAnyChanged = LightApp_Study::isModified();
826 Set study modified to \a on.
828 void SalomeApp_Study::Modified()
830 if(_PTR(Study) aStudy = studyDS())
832 LightApp_Study::Modified();
836 \return if data model is saved
838 bool SalomeApp_Study::isSaved() const
840 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
842 isAllSaved = LightApp_Study::isSaved();
849 \param theModuleName - name of module
850 \param theListOfFiles - list of files to be saved
852 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
854 int aNb = theListOfFiles.count();
858 std::vector<std::string> aListOfFiles ( aNb );
860 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
861 if ( (*it).isEmpty() )
863 aListOfFiles[anIndex] = (*it).toUtf8().data();
866 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
871 \param theModuleName - name of module
872 \param theListOfFiles - list of files to be loaded
874 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
876 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
878 int i, aLength = aListOfFiles.size() - 1;
882 //Get a temporary directory for saved a file
883 theListOfFiles.append(aListOfFiles[0].c_str());
885 for(i = 0; i < aLength; i++)
886 theListOfFiles.append(aListOfFiles[i+1].c_str());
890 Re-implemented from LightApp_Study, actually does not save anything but
891 simply cleans up light modules' data
893 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
895 ModelList list; dataModels( list );
896 QListIterator<CAM_DataModel*> it( list );
897 std::vector<std::string> listOfFiles(0);
898 while ( it.hasNext() ){
899 LightApp_DataModel* aLModel =
900 dynamic_cast<LightApp_DataModel*>( it.next() );
901 // It is safe to call SetListOfFiles() for any kind of module
902 // because SetListOfFiles() does nothing for full modules :)
904 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
912 bool SalomeApp_Study::openStudyData( const QString& theFileName )
920 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
926 Virtual method re-implemented from LightApp_Study in order to create
927 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
929 \param theDataModel - data model instance to create a module object for
930 \param theParent - the module object's parent (normally it's the study root)
931 \return the module object instance
932 \sa LightApp_Study class, LightApp_DataModel class
934 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
935 SUIT_DataObject* theParent ) const
937 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
939 // Ensure that SComponent instance is published in the study for the given module
940 // This line causes automatic creation of SalomeApp_ModuleObject in case if
941 // WITH_SALOMEDS_OBSERVER is defined
942 that->addComponent( theDataModel );
944 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
945 // or by someone else so check if it exists first of all
946 CAM_ModuleObject* res = 0;
948 DataObjectList children = root()->children();
949 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
950 for( ; !res && anIt!=aLast; anIt++ )
952 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
953 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
958 _PTR(Study) aStudy = studyDS();
962 _PTR(SComponent) aComp = aStudy->FindComponent(
963 theDataModel->module()->name().toStdString() );
967 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
976 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
978 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
980 CAM_Study::dataModelInserted(dm);
986 Create SComponent for module, using default engine (CORBAless)
988 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
990 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
991 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
993 // Check SComponent existance
994 _PTR(Study) aStudy = studyDS();
998 std::string aCompDataType = dm->module()->name().toStdString();
1000 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
1002 // Create SComponent
1003 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1004 aComp = aBuilder->NewComponent(aCompDataType);
1005 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1006 QString anIconName = dm->module()->iconName();
1007 if (!anIconName.isEmpty()) {
1008 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1010 anAttr->SetPixMap(anIconName.toStdString());
1013 // Set default engine IOR
1014 // Issue 21377 - using separate engine for each type of light module
1015 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
1017 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
1018 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
1019 SalomeApp_DataModel::synchronize( aComp, this );
1022 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1023 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1024 QString anIconName = dm->module()->iconName();
1025 if (!anIconName.isEmpty()) {
1026 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1028 anAttr->SetPixMap(anIconName.toStdString());
1030 // Set default engine IOR
1038 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1043 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1044 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1045 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
1046 _PTR(SComponent) aSComp;
1048 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1050 // Issue 21377 - using separate engine for each type of light module
1051 std::string aCompDataType = dm->module()->name().toStdString();
1052 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1053 aSComp = aStudy->FindComponent( aCompDataType );
1056 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1058 QString anId = aDM->getRootEntry( this );
1059 if ( anId.isEmpty() )
1060 return true; // Probably nothing to load
1061 anEngine = aDM->getModule()->engineIOR();
1062 if ( anEngine.isEmpty() )
1064 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1068 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1071 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1073 catch( const SALOME::SALOME_Exception& ) {
1074 // Oops, something went wrong while loading -> return an error
1077 // Something has been read -> create data model tree
1078 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1079 // aDM->buildTree( aSComp, 0, this );
1082 // Don't return false here, for there might be no data
1083 // for a given component in the study yet
1085 QStringList listOfFiles;
1086 openModuleData(dm->module()->name(), listOfFiles);
1087 if (dm && dm->open(studyName, this, listOfFiles)) {
1088 // Remove the files and temporary directory, created
1089 // for this module by LightApp_Engine_i::Load()
1090 bool isMultiFile = false; // TODO: decide, how to access this parameter
1091 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1093 // Something has been read -> create data model tree
1094 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1096 aDM->update(NULL, this);
1103 Create new study name.
1105 QString SalomeApp_Study::newStudyName() const
1107 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1108 QString prefix( "Study%1" ), newName, curName;
1109 int i = 1, j, n = studies.size();
1110 while ( newName.isEmpty() ){
1111 curName = prefix.arg( i );
1112 for ( j = 0 ; j < n; j++ ){
1113 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1125 Note that this method does not create or activate SalomeApp_Engine_i instance,
1126 therefore it can be called safely for any kind of module, but for full
1127 modules it returns an empty list.
1128 \return list of files used by module: to be used by CORBAless modules
1129 \param theModuleName - name of module
1131 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1133 // Issue 21377 - using separate engine for each type of light module
1134 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1136 return aDefaultEngine->GetListOfFiles(id());
1138 std::vector<std::string> aListOfFiles;
1139 return aListOfFiles;
1143 Sets list of files used by module: to be used by CORBAless modules.
1144 Note that this method does not create or activate SalomeApp_Engine_i instance,
1145 therefore it can be called safely for any kind of module, but for full
1146 modules it simply does nothing.
1147 \param theModuleName - name of module
1148 \param theListOfFiles - list of files
1150 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1151 const std::vector<std::string> theListOfFiles )
1153 // Issue 21377 - using separate engine for each type of light module
1154 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1156 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1160 \return temporary directory for saving files of modules
1162 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1164 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1165 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1170 Removes temporary files
1172 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1177 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1178 if (aListOfFiles.size() > 0) {
1179 std::string aTmpDir = aListOfFiles[0];
1181 const int n = aListOfFiles.size() - 1;
1182 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1184 for (int i = 0; i < n; i++)
1185 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1187 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1191 #ifndef DISABLE_PYCONSOLE
1193 Mark the study as saved in the file
1194 \param theFileName - the name of file
1196 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1198 setStudyName(theFileName);
1199 studyDS()->Name(theFileName.toStdString());
1200 setIsSaved( isSaved );
1204 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1206 LightApp_DataObject* o = 0;
1208 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toLatin1().constData() ) );
1211 o = LightApp_Study::findObjectByEntry( theEntry );
1217 Deletes all references to object
1220 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1222 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1223 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1224 for( int i=0, n=aRefs.size(); i<n; i++ )
1226 _PTR( SObject ) o = aRefs[i];
1227 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1229 sb->RemoveReference( o );
1230 sb->RemoveObjectWithChildren( o );
1236 \return real entry by entry of reference
1237 \param entry - entry of reference object
1239 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1241 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1242 _PTR(SObject) refobj;
1244 if( obj && obj->ReferencedObject( refobj ) )
1245 return refobj->GetID().c_str();
1246 return LightApp_Study::referencedToEntry( entry );
1250 \return component data type for entry
1252 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1254 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1256 return LightApp_Study::componentDataType( entry );
1257 return obj->GetFatherComponent()->ComponentDataType().c_str();
1261 \return true if entry corresponds to component
1263 bool SalomeApp_Study::isComponent( const QString& entry ) const
1265 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1266 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1270 \return entries of object children
1272 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1274 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1275 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1276 anIter->InitEx( true );
1277 while( anIter->More() )
1279 _PTR(SObject) val( anIter->Value() );
1280 child_entries.append( val->GetID().c_str() );
1286 Fills list with components names
1287 \param comp - list to be filled
1289 void SalomeApp_Study::components( QStringList& comps ) const
1291 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1293 _PTR(SComponent) aComponent ( it->Value() );
1294 // skip the magic "Interface Applicative" component
1295 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1296 comps.append( aComponent->ComponentDataType().c_str() );
1301 Get the entry for the given module
1302 \param comp - list to be filled
1303 \return module root's entry
1305 QString SalomeApp_Study::centry( const QString& comp ) const
1308 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1310 _PTR(SComponent) aComponent ( it->Value() );
1311 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1312 e = aComponent->GetID().c_str();
1318 \return a list of saved points' IDs
1320 std::vector<int> SalomeApp_Study::getSavePoints()
1324 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1327 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1328 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1329 for(; anIter->More(); anIter->Next())
1331 _PTR(SObject) val( anIter->Value() );
1332 _PTR(GenericAttribute) genAttr;
1333 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1340 Removes a given save point
1342 void SalomeApp_Study::removeSavePoint(int savePoint)
1344 if(savePoint <= 0) return;
1345 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1346 _PTR(SObject) so = AP->GetSObject();
1347 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1348 builder->RemoveObjectWithChildren(so);
1352 \return a name of save point
1354 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1356 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1357 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1358 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1362 Sets a name of save point
1364 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1366 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1367 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1368 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1372 * \brief Restores the study state
1374 void SalomeApp_Study::restoreState(int savePoint)
1376 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1381 Slot: called on change of a root of a data model. Redefined from CAM_Study
1383 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1385 LightApp_Study::updateModelRoot( dm );
1387 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1388 // it must always be the last one.
1389 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );