1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "SalomeApp_Study.h"
25 #include "SalomeApp_Module.h"
26 #include "SalomeApp_DataObject.h"
27 #include "SalomeApp_DataModel.h"
28 #include "SalomeApp_Application.h"
29 #include "SalomeApp_Engine_i.h"
30 #include "SalomeApp_VisualState.h"
32 // temporary commented
33 //#include <OB_Browser.h>
35 #include <QCoreApplication>
38 #include "SALOME_Event.h"
39 #include "Basics_Utils.hxx"
41 #include <SUIT_ResourceMgr.h>
42 #include <SUIT_TreeModel.h>
43 #include <SUIT_DataBrowser.h>
44 #include <SUIT_MessageBox.h>
45 #include <SUIT_Session.h>
46 #include <SUIT_Desktop.h>
48 #include <LightApp_Displayer.h>
50 #ifndef DISABLE_PYCONSOLE
51 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
52 #include <PyConsole_Console.h>
55 #include "utilities.h"
57 #include "SALOMEDS_Tool.hxx"
59 #include "SALOMEDSClient_ClientFactory.hxx"
61 #include <SALOMEconfig.h>
62 #include CORBA_SERVER_HEADER(SALOME_Exception)
64 //#define NOTIFY_BY_EVENT
66 class ObserverEvent : public QEvent
69 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
79 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
81 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
82 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
86 Observer_i(_PTR(Study) aStudyDS, SalomeApp_Study* aStudy):QObject(aStudy)
93 SUIT_DataObject* findObject( const char* theID ) const
95 EntryMap::const_iterator it = entry2SuitObject.find( theID );
96 return it != entry2SuitObject.end() ? it->second : 0;
99 virtual void notifyObserverID(const char* theID, CORBA::Long event)
101 #ifdef NOTIFY_BY_EVENT
102 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
104 notifyObserverID_real(theID,event);
108 virtual bool event(QEvent *event)
110 if (event->type() == QEvent::User )
112 //START_TIMING(notify);
113 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
114 //END_TIMING(notify,100);
119 void notifyObserverID_real(const std::string& theID, long event)
121 SalomeApp_DataObject* suit_obj = 0;
126 _PTR(SObject) aSObj = myStudyDS->FindObjectID(theID);
127 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
129 if (!aSComp || aSComp->IsNull()) {
130 MESSAGE("Entry " << theID << " has not father component. Problem ??");
134 // Mantis issue 0020136: Drag&Drop in OB
135 _PTR(UseCaseBuilder) aUseCaseBuilder = myStudyDS->GetUseCaseBuilder();
136 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
137 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
138 // tree node is not yet set, it is a normal situation
142 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
143 if (!aFatherSO || aFatherSO->IsNull()) {
144 MESSAGE("Father SObject is not found. Problem ??");
148 std::string parent_id = aFatherSO->GetID();
149 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
151 if (it == entry2SuitObject.end()) {
152 MESSAGE("Father data object is not found. Problem ??");
156 SalomeApp_DataObject* aFatherDO = it->second;
158 it = entry2SuitObject.find(theID);
159 if (it != entry2SuitObject.end()) { // this SOobject is already added somethere
160 suit_obj = it->second;
161 SUIT_DataObject* oldFather = suit_obj->parent();
163 oldFather->removeChild(suit_obj, false);
164 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
165 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
166 model->forgetObject( suit_obj );
168 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
169 oldFatherSA->updateItem();
174 suit_obj = new SalomeApp_DataObject(aSObj);
175 entry2SuitObject[theID] = suit_obj;
178 suit_obj->updateItem();
179 // define position in the data tree (in aFatherDO) to insert the aSObj
181 //int childDataObjCount = aFatherDO->childCount();
182 _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
183 for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
184 if (aUseCaseIter->Value()->GetID() == theID) {
190 aFatherDO->insertChildAtPos(suit_obj, pos);
191 //aFatherDO->insertChild(suit_obj, pos);
192 aFatherDO->updateItem();
194 /* Define visibility state */
195 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
196 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
197 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
198 if (!moduleTitle.isEmpty()) {
199 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
201 if(aDisplayer->canBeDisplayed(theID.c_str())) {
202 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState ); //hide the just added object
203 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
206 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
210 } // END: work with tree nodes structure
211 else { // BEGIN: work with study structure
212 EntryMapIter it = entry2SuitObject.find( theID );
213 if ( it != entry2SuitObject.end() ) {
214 MESSAGE("Entry " << theID << " is already added. Problem ??");
218 int last2Pnt_pos = theID.rfind( ":" );
219 std::string parent_id = theID.substr( 0, last2Pnt_pos );
220 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
222 if ( parent_id.length() == 3 ) // "0:1" - root item?
224 // It's probably a SComponent
225 if ( theID == aSComp->GetID() )
226 suit_obj = new SalomeApp_ModuleObject( aSComp );
228 suit_obj = new SalomeApp_DataObject( aSObj );
232 suit_obj = new SalomeApp_DataObject( aSObj );
235 it = entry2SuitObject.find( parent_id );
236 if ( it != entry2SuitObject.end() ) {
237 SalomeApp_DataObject* father = it->second;
238 father->insertChildAtTag( suit_obj, tag );
241 if ( parent_id.length() == 3 ) // "0:1" - root item?
243 // This should be for a module
244 SUIT_DataObject* father=myStudy->root();
245 father->appendChild(suit_obj);
249 MESSAGE("SHOULD NEVER GET HERE!!!");
251 //Try to find the SalomeApp_DataObject object parent
252 std::string root_id = parent_id.substr( 0, 4 );
253 std::string obj_id = parent_id.substr( 4 );
256 std::string::size_type debut = 0;
257 std::string::size_type fin;
258 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
260 fin = obj_id.find_first_of( ':', debut );
261 if ( fin == std::string::npos ) {
263 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
264 entry2SuitObject[parent_id] = anObj;
267 anID = root_id + obj_id.substr( 0, fin );
268 EntryMapIter it2 = entry2SuitObject.find( anID );
269 if ( it2 == entry2SuitObject.end() ) {
270 //the ID is not known in entry2SuitObject
271 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
272 entry2SuitObject[anID] = anObj;
278 anObj->insertChildAtTag( suit_obj, tag );
281 entry2SuitObject[theID] = suit_obj;
282 } // END: work with study structure
287 EntryMapIter it = entry2SuitObject.find( theID );
288 if ( it != entry2SuitObject.end() )
290 suit_obj = it->second;
291 // VSR: object is not removed, since SALOMEDS::SObject is not actually removed,
292 // only its attributes are cleared;
293 // thus, the object can be later reused
294 suit_obj->updateItem();
295 //SUIT_DataObject* father=suit_obj->parent();
297 // father->removeChild(suit_obj);
298 //entry2SuitObject.erase(it);
302 MESSAGE("Want to remove an unknown object" << theID);
308 //MESSAGE("Want to modify an object " << theID);
309 EntryMapIter it = entry2SuitObject.find( theID );
310 if ( it != entry2SuitObject.end() )
312 suit_obj = it->second;
313 suit_obj->updateItem();
317 MESSAGE("Want to modify an unknown object" << theID);
321 case 5: //IOR of the object modified
323 EntryMapIter it = entry2SuitObject.find( theID );
324 if ( it != entry2SuitObject.end() )
325 suit_obj = it->second;
327 /* Define visibility state */
328 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
329 if ( suit_obj && !isComponent ) {
330 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
331 if (!moduleTitle.isEmpty()) {
332 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
334 if(aDisplayer->canBeDisplayed(theID.c_str())) {
335 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
336 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
339 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
345 #ifndef DISABLE_PYCONSOLE
346 case 6: //NoteBook variables were modified
348 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
352 default:MESSAGE("Unknown event: " << event);break;
354 } //notifyObserverID_real
359 entry2SuitObject.clear();
360 SUIT_DataObject* o = myStudy->root();
362 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
364 std::string entry = so->entry().toLatin1().constData();
366 entry2SuitObject[entry] = so;
368 if ( o->childCount() > 0 ) {
369 // parse the children
372 else if ( o->nextBrother() > 0 ) {
373 o = o->nextBrother();
376 // step to the next appropriate parent
379 if ( o->nextBrother() ) {
380 o = o->nextBrother();
390 _PTR(Study) myStudyDS;
391 SalomeApp_Study* myStudy;
392 EntryMap entry2SuitObject;
399 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
400 : LightApp_Study( app ), myObserver( 0 )
407 SalomeApp_Study::~SalomeApp_Study()
410 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
411 myObserver->_default_POA()->deactivate_object( oid.in() );
415 #ifndef DISABLE_PYCONSOLE
416 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
418 emit notebookVarUpdated( theVarName );
425 int SalomeApp_Study::id() const
429 id = studyDS()->StudyId();
436 QString SalomeApp_Study::studyName() const
438 // redefined from SUIT_Study to update study name properly since
439 // it can be changed outside of GUI
440 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
442 QString newName = QString::fromUtf8(studyDS()->Name().c_str());
443 if ( LightApp_Study::studyName() != newName ) {
444 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
445 that->setStudyName( newName );
446 ((SalomeApp_Application*)application())->updateDesktopTitle();
449 return LightApp_Study::studyName();
453 Gets studyDS pointer.
455 _PTR(Study) SalomeApp_Study::studyDS() const
463 bool SalomeApp_Study::createDocument( const QString& theStr )
465 MESSAGE( "createDocument" );
467 // initialize myStudyDS, read HDF file
468 QString aName = newStudyName();
472 study = _PTR(Study)( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
474 catch(const SALOME_Exception& ex) {
475 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
476 tr("ERR_ERROR"), tr(ex.what()));
480 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
481 tr("ERR_ERROR"), tr("CREATE_DOCUMENT_PROBLEM"));
489 setStudyName( aName );
492 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
493 #ifdef WITH_SALOMEDS_OBSERVER
494 aRoot->setToSynchronize(false);
498 bool aRet = CAM_Study::createDocument( theStr );
500 #ifdef WITH_SALOMEDS_OBSERVER
501 myObserver = new Observer_i(myStudyDS,this);
502 //attach an observer to the study with notification of modifications
503 myStudyDS->attach(myObserver->_this(),true);
506 emit created( this );
513 \param theFileName - name of file
515 bool SalomeApp_Study::openDocument( const QString& theFileName )
517 MESSAGE( "openDocument" );
519 // initialize myStudyDS, read HDF file
522 study = _PTR(Study) ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
524 catch(const SALOME_Exception& ex) {
525 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
526 tr("ERR_ERROR"), tr(ex.what()));
530 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
531 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
540 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
542 // update loaded data models: call open() and update() on them.
545 QListIterator<CAM_DataModel*> it( dm_s );
546 while ( it.hasNext() )
547 openDataModel( studyName(), it.next() );
549 // this will build a SUIT_DataObject-s tree under myRoot member field
550 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
551 // but tree that corresponds to not-loaded data models will be updated any way.
552 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
554 #ifdef WITH_SALOMEDS_OBSERVER
555 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
556 myObserver = new Observer_i(myStudyDS,this);
557 //attach an observer to the study with notification of modifications
558 myStudyDS->attach(myObserver->_this(),true);
561 bool res = CAM_Study::openDocument( theFileName );
564 study->IsSaved(true);
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 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
578 Connects GUI study to SALOMEDS one already loaded into StudyManager
579 \param theStudyName - name of study
581 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
583 MESSAGE( "loadDocument" );
585 // obtain myStudyDS from StudyManager
586 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
592 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
594 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
596 // update loaded data models: call open() and update() on them.
600 QListIterator<CAM_DataModel*> it( dm_s );
601 while ( it.hasNext() )
602 openDataModel( studyName(), it.next() );
604 // this will build a SUIT_DataObject-s tree under myRoot member field
605 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
606 // but tree that corresponds to not-loaded data models will be updated any way.
607 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
609 #ifdef WITH_SALOMEDS_OBSERVER
610 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
611 myObserver = new Observer_i(myStudyDS,this);
612 //attach an observer to the study with notification of modifications
613 myStudyDS->attach(myObserver->_this(),true);
616 bool res = CAM_Study::openDocument( theStudyName );
618 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
619 // mark study as "not saved" after call openDocument( ... ) method.
623 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
625 std::vector<int> savePoints = getSavePoints();
626 if ( savePoints.size() > 0 )
627 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
630 //SRN: BugID IPAL9021: End
636 \param theFileName - name of file
638 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
640 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
642 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
644 ModelList list; dataModels( list );
646 QListIterator<CAM_DataModel*> it( list );
647 QStringList listOfFiles;
648 while ( it.hasNext() ) {
649 // Cast to LightApp class in order to give a chance
650 // to light modules to save their data
651 if ( LightApp_DataModel* aModel =
652 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
654 aModel->saveAs( theFileName, this, listOfFiles );
655 if ( !listOfFiles.isEmpty() )
656 saveModuleData(aModel->module()->name(), listOfFiles);
660 // save SALOMEDS document
661 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
665 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
666 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
667 bool res = (isAscii ?
668 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
669 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
670 && CAM_Study::saveDocumentAs( theFileName );
672 res = res && saveStudyData(theFileName);
681 Saves previously opened document
683 bool SalomeApp_Study::saveDocument()
685 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
687 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
689 ModelList list; dataModels( list );
691 QListIterator<CAM_DataModel*> it( list );
692 QStringList listOfFiles;
693 while ( it.hasNext() ) {
694 // Cast to LightApp class in order to give a chance
695 // to light modules to save their data
696 if ( LightApp_DataModel* aModel =
697 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
699 aModel->save(listOfFiles);
700 if ( !listOfFiles.isEmpty() )
701 saveModuleData(aModel->module()->name(), listOfFiles);
705 // save SALOMEDS document
706 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
710 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
711 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
712 bool res = (isAscii ?
713 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
714 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
716 res = res && saveStudyData(studyName());
726 void SalomeApp_Study::closeDocument(bool permanently)
728 LightApp_Study::closeDocument(permanently);
730 // close SALOMEDS document
731 _PTR(Study) studyPtr = studyDS();
735 myStudyDS->detach( myObserver->_this() );
737 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
738 bool isBlocked = desk->signalsBlocked();
739 desk->blockSignals( true );
740 SalomeApp_Application::studyMgr()->Close( studyPtr );
741 desk->blockSignals( isBlocked );
742 #ifndef DISABLE_PYCONSOLE
743 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
744 if( app->pythonConsole() )
745 app->pythonConsole()->getInterp()->destroy();
748 SALOMEDSClient_Study* aStudy = 0;
749 setStudyDS( _PTR(Study)(aStudy) );
754 Dump study operation. Writes a Python dump file using
755 SALOMEDS services. Additionally, gives a chance to light modules
756 to participate in dump study operation.
758 \param theFileName - full path to the output Python file
759 \param toPublish - if true, all objects are published in a study
760 by the output script, including those not orignally present
761 in the current study.
762 \param isMultiFile - if true, each module's dump is written into
763 a separate Python file, otherwise a single output file is written
764 \param toSaveGUI - if true, the GUI state is written
766 \return - true if the operation succeeds, and false otherwise.
768 bool SalomeApp_Study::dump( const QString& theFileName,
774 _PTR(AttributeParameter) ap;
775 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
776 _PTR(Study) aStudy = studyDS();
778 if( ip->isDumpPython( aStudy ) )
779 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
781 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
782 ip->setDumpPython( aStudy );
783 //SRN: create a temporary save point
784 savePoint = SalomeApp_VisualState(
785 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
788 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
789 // This is an optional but important step, it gives a chance to light modules
790 // to dump their data as a part of common dump study operation
794 QListIterator<CAM_DataModel*> it( list );
795 QStringList listOfFiles;
796 while ( it.hasNext() ) {
797 if ( LightApp_DataModel* aModel =
798 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
800 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
801 !listOfFiles.isEmpty() )
802 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
803 // This code is shared with persistence mechanism.
804 // NOTE: this should be revised if behavior of saveModuleData() changes!
805 saveModuleData(aModel->module()->name(), listOfFiles);
809 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
810 // any light module is present in the current configuration
811 QFileInfo aFileInfo( theFileName );
812 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
813 aFileInfo.baseName().toUtf8().data(),
817 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
819 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
820 // This code is shared with persistence mechanism.
821 // NOTE: this should be revised if behavior of saveStudyData() changes!
822 saveStudyData( theFileName );
828 \return true, if study is modified in comparison with last open/save
830 bool SalomeApp_Study::isModified() const
832 bool isAnyChanged = studyDS() && studyDS()->IsModified();
834 isAnyChanged = LightApp_Study::isModified();
840 Set study modified to \a on.
842 void SalomeApp_Study::Modified()
844 if(_PTR(Study) aStudy = studyDS())
846 LightApp_Study::Modified();
850 \return if data model is saved
852 bool SalomeApp_Study::isSaved() const
854 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
856 isAllSaved = LightApp_Study::isSaved();
863 \param theModuleName - name of module
864 \param theListOfFiles - list of files to be saved
866 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
868 int aNb = theListOfFiles.count();
872 std::vector<std::string> aListOfFiles ( aNb );
874 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
875 if ( (*it).isEmpty() )
877 aListOfFiles[anIndex] = (*it).toUtf8().data();
880 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
885 \param theModuleName - name of module
886 \param theListOfFiles - list of files to be loaded
888 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
890 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
892 int i, aLength = aListOfFiles.size() - 1;
896 //Get a temporary directory for saved a file
897 theListOfFiles.append(aListOfFiles[0].c_str());
899 for(i = 0; i < aLength; i++)
900 theListOfFiles.append(aListOfFiles[i+1].c_str());
904 Re-implemented from LightApp_Study, actually does not save anything but
905 simply cleans up light modules' data
907 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
909 ModelList list; dataModels( list );
910 QListIterator<CAM_DataModel*> it( list );
911 std::vector<std::string> listOfFiles(0);
912 while ( it.hasNext() ){
913 LightApp_DataModel* aLModel =
914 dynamic_cast<LightApp_DataModel*>( it.next() );
915 // It is safe to call SetListOfFiles() for any kind of module
916 // because SetListOfFiles() does nothing for full modules :)
918 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
926 bool SalomeApp_Study::openStudyData( const QString& theFileName )
934 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
940 Virtual method re-implemented from LightApp_Study in order to create
941 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
943 \param theDataModel - data model instance to create a module object for
944 \param theParent - the module object's parent (normally it's the study root)
945 \return the module object instance
946 \sa LightApp_Study class, LightApp_DataModel class
948 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
949 SUIT_DataObject* theParent ) const
951 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
953 // Ensure that SComponent instance is published in the study for the given module
954 // This line causes automatic creation of SalomeApp_ModuleObject in case if
955 // WITH_SALOMEDS_OBSERVER is defined
956 that->addComponent( theDataModel );
958 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
959 // or by someone else so check if it exists first of all
960 CAM_ModuleObject* res = 0;
962 DataObjectList children = root()->children();
963 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
964 for( ; !res && anIt!=aLast; anIt++ )
966 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
967 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
972 _PTR(Study) aStudy = studyDS();
976 _PTR(SComponent) aComp = aStudy->FindComponent(
977 theDataModel->module()->name().toStdString() );
981 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
990 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
992 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
994 CAM_Study::dataModelInserted(dm);
1000 Create SComponent for module, using default engine (CORBAless)
1002 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
1004 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1005 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1007 // Check SComponent existance
1008 _PTR(Study) aStudy = studyDS();
1012 std::string aCompDataType = dm->module()->name().toStdString();
1014 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
1016 // Create SComponent
1017 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1018 aComp = aBuilder->NewComponent(aCompDataType);
1019 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1020 QString anIconName = dm->module()->iconName();
1021 if (!anIconName.isEmpty()) {
1022 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1024 anAttr->SetPixMap(anIconName.toStdString());
1027 // Set default engine IOR
1028 // Issue 21377 - using separate engine for each type of light module
1029 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
1031 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
1032 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
1033 SalomeApp_DataModel::synchronize( aComp, this );
1036 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1037 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1038 QString anIconName = dm->module()->iconName();
1039 if (!anIconName.isEmpty()) {
1040 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1042 anAttr->SetPixMap(anIconName.toStdString());
1044 // Set default engine IOR
1052 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1057 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1058 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1059 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
1060 _PTR(SComponent) aSComp;
1062 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1064 // Issue 21377 - using separate engine for each type of light module
1065 std::string aCompDataType = dm->module()->name().toStdString();
1066 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1067 aSComp = aStudy->FindComponent( aCompDataType );
1070 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1072 QString anId = aDM->getRootEntry( this );
1073 if ( anId.isEmpty() )
1074 return true; // Probably nothing to load
1075 anEngine = aDM->getModule()->engineIOR();
1076 if ( anEngine.isEmpty() )
1078 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1082 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1085 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1087 catch( const SALOME::SALOME_Exception& ) {
1088 // Oops, something went wrong while loading -> return an error
1091 // Something has been read -> create data model tree
1092 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1093 // aDM->buildTree( aSComp, 0, this );
1096 // Don't return false here, for there might be no data
1097 // for a given component in the study yet
1099 QStringList listOfFiles;
1100 openModuleData(dm->module()->name(), listOfFiles);
1101 if (dm && dm->open(studyName, this, listOfFiles)) {
1102 // Remove the files and temporary directory, created
1103 // for this module by LightApp_Engine_i::Load()
1104 bool isMultiFile = false; // TODO: decide, how to access this parameter
1105 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1107 // Something has been read -> create data model tree
1108 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1110 aDM->update(NULL, this);
1117 Create new study name.
1119 QString SalomeApp_Study::newStudyName() const
1121 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1122 QString prefix( "Study%1" ), newName, curName;
1123 int i = 1, j, n = studies.size();
1124 while ( newName.isEmpty() ){
1125 curName = prefix.arg( i );
1126 for ( j = 0 ; j < n; j++ ){
1127 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1139 Note that this method does not create or activate SalomeApp_Engine_i instance,
1140 therefore it can be called safely for any kind of module, but for full
1141 modules it returns an empty list.
1142 \return list of files used by module: to be used by CORBAless modules
1143 \param theModuleName - name of module
1145 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1147 // Issue 21377 - using separate engine for each type of light module
1148 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1150 return aDefaultEngine->GetListOfFiles(id());
1152 std::vector<std::string> aListOfFiles;
1153 return aListOfFiles;
1157 Sets list of files used by module: to be used by CORBAless modules.
1158 Note that this method does not create or activate SalomeApp_Engine_i instance,
1159 therefore it can be called safely for any kind of module, but for full
1160 modules it simply does nothing.
1161 \param theModuleName - name of module
1162 \param theListOfFiles - list of files
1164 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1165 const std::vector<std::string> theListOfFiles )
1167 // Issue 21377 - using separate engine for each type of light module
1168 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1170 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1174 \return temporary directory for saving files of modules
1176 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1178 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1179 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1184 Removes temporary files
1186 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1191 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1192 if (aListOfFiles.size() > 0) {
1193 std::string aTmpDir = aListOfFiles[0];
1195 const int n = aListOfFiles.size() - 1;
1196 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1198 for (int i = 0; i < n; i++)
1199 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1201 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1205 #ifndef DISABLE_PYCONSOLE
1207 Mark the study as saved in the file
1208 \param theFileName - the name of file
1210 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1212 setStudyName(theFileName);
1213 studyDS()->Name(theFileName.toStdString());
1214 setIsSaved( isSaved );
1218 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1220 LightApp_DataObject* o = 0;
1222 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toLatin1().constData() ) );
1225 o = LightApp_Study::findObjectByEntry( theEntry );
1231 Deletes all references to object
1234 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1236 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1237 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1238 for( int i=0, n=aRefs.size(); i<n; i++ )
1240 _PTR( SObject ) o = aRefs[i];
1241 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1243 sb->RemoveReference( o );
1244 sb->RemoveObjectWithChildren( o );
1250 \return real entry by entry of reference
1251 \param entry - entry of reference object
1253 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1255 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1256 _PTR(SObject) refobj;
1258 if( obj && obj->ReferencedObject( refobj ) )
1259 return refobj->GetID().c_str();
1260 return LightApp_Study::referencedToEntry( entry );
1264 \return component data type for entry
1266 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1268 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1270 return LightApp_Study::componentDataType( entry );
1271 return obj->GetFatherComponent()->ComponentDataType().c_str();
1275 \return true if entry corresponds to component
1277 bool SalomeApp_Study::isComponent( const QString& entry ) const
1279 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1280 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1284 \return entries of object children
1286 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1288 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1289 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1290 anIter->InitEx( true );
1291 while( anIter->More() )
1293 _PTR(SObject) val( anIter->Value() );
1294 child_entries.append( val->GetID().c_str() );
1300 Fills list with components names
1301 \param comp - list to be filled
1303 void SalomeApp_Study::components( QStringList& comps ) const
1305 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1307 _PTR(SComponent) aComponent ( it->Value() );
1308 // skip the magic "Interface Applicative" component
1309 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1310 comps.append( aComponent->ComponentDataType().c_str() );
1315 Get the entry for the given module
1316 \param comp - list to be filled
1317 \return module root's entry
1319 QString SalomeApp_Study::centry( const QString& comp ) const
1322 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1324 _PTR(SComponent) aComponent ( it->Value() );
1325 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1326 e = aComponent->GetID().c_str();
1332 \return a list of saved points' IDs
1334 std::vector<int> SalomeApp_Study::getSavePoints()
1338 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1341 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1342 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1343 for(; anIter->More(); anIter->Next())
1345 _PTR(SObject) val( anIter->Value() );
1346 _PTR(GenericAttribute) genAttr;
1347 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1354 Removes a given save point
1356 void SalomeApp_Study::removeSavePoint(int savePoint)
1358 if(savePoint <= 0) return;
1359 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1360 _PTR(SObject) so = AP->GetSObject();
1361 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1362 builder->RemoveObjectWithChildren(so);
1366 \return a name of save point
1368 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1370 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1371 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1372 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1376 Sets a name of save point
1378 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1380 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1381 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1382 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1386 * \brief Restores the study state
1388 void SalomeApp_Study::restoreState(int savePoint)
1390 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1395 Slot: called on change of a root of a data model. Redefined from CAM_Study
1397 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1399 LightApp_Study::updateModelRoot( dm );
1401 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1402 // it must always be the last one.
1403 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );