1 // Copyright (C) 2007-2023 CEA, EDF, 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 #ifndef DISABLE_PYCONSOLE
24 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
27 #include "SalomeApp_Study.h"
29 #include "SalomeApp_Module.h"
30 #include "SalomeApp_DataObject.h"
31 #include "SalomeApp_DataModel.h"
32 #include "SalomeApp_Application.h"
33 #include "SalomeApp_Engine_i.h"
34 #include "SalomeApp_VisualState.h"
36 // temporary commented
37 //#include <OB_Browser.h>
39 #include <QCoreApplication>
42 #include "SALOME_Event.h"
43 #include "Basics_Utils.hxx"
45 #include <SUIT_ResourceMgr.h>
46 #include <SUIT_TreeModel.h>
47 #include <SUIT_DataBrowser.h>
48 #include <SUIT_MessageBox.h>
49 #include <SUIT_Session.h>
50 #include <SUIT_Desktop.h>
52 #include <LightApp_Displayer.h>
54 #include "utilities.h"
56 #include "SALOMEDS_Tool.hxx"
58 #include "SALOMEDSClient_ClientFactory.hxx"
60 #include <SALOMEconfig.h>
61 #include CORBA_SERVER_HEADER(SALOME_Exception)
63 //---------------------------------------------------------
65 //#define MB_IGNORE_QT
66 //#define MB_FULL_DUMP
67 #define MBCLASSNAME "SalomeApp_Study"
69 // <-- insert includes for addtional debug headers here!
70 //---------------------------------------------------------
72 //#define NOTIFY_BY_EVENT
74 class ObserverEvent : public QEvent
77 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
87 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
89 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
90 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
94 Observer_i( SalomeApp_Study* aStudy):QObject(aStudy)
100 SUIT_DataObject* findObject( const char* theID ) const
102 EntryMap::const_iterator it = entry2SuitObject.find( theID );
103 return it != entry2SuitObject.end() ? it->second : 0;
106 virtual void notifyObserverID(const char* theID, CORBA::Long event)
108 #ifdef NOTIFY_BY_EVENT
109 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
111 notifyObserverID_real(theID,event);
115 virtual bool event(QEvent *event)
117 if (event->type() == QEvent::User )
119 //START_TIMING(notify);
120 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
121 //END_TIMING(notify,100);
126 void notifyObserverID_real(const std::string& theID, long event)
128 SalomeApp_DataObject* suit_obj = 0;
133 _PTR(SObject) aSObj = SalomeApp_Application::getStudy()->FindObjectID(theID);
134 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
136 if (!aSComp || aSComp->IsNull()) {
137 MESSAGE("Entry " << theID << " has not father component. Problem ??");
141 // Mantis issue 0020136: Drag&Drop in OB
142 _PTR(UseCaseBuilder) aUseCaseBuilder = SalomeApp_Application::getStudy()->GetUseCaseBuilder();
143 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
144 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
145 // tree node is not yet set, it is a normal situation
149 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
150 if (!aFatherSO || aFatherSO->IsNull()) {
151 MESSAGE("Father SObject is not found. Problem ??");
155 std::string parent_id = aFatherSO->GetID();
156 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
158 if (it == entry2SuitObject.end()) {
159 MESSAGE("Father data object is not found. Problem ??");
163 SalomeApp_DataObject* aFatherDO = it->second;
165 it = entry2SuitObject.find(theID);
166 if (it != entry2SuitObject.end()) { // this SOobject is already added somewhere
167 suit_obj = it->second;
168 SUIT_DataObject* oldFather = suit_obj->parent();
170 oldFather->removeChild(suit_obj, false);
171 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
172 // MESSAGE("myStudy: " << myStudy->id() << " app " << app);
173 // MESSAGE("objectBrowser: "<< app->objectBrowser());
174 if (!app->objectBrowser()) {
175 MESSAGE("Object Browser not found. Problem ??");
178 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
179 model->forgetObject( suit_obj );
181 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
182 oldFatherSA->updateItem();
187 suit_obj = new SalomeApp_DataObject(aSObj);
188 entry2SuitObject[theID] = suit_obj;
191 suit_obj->updateItem();
192 // define position in the data tree (in aFatherDO) to insert the aSObj
193 int pos = aUseCaseBuilder->GetIndexInFather(aFatherSO, aSObj);
195 aFatherDO->insertChildAtPos(suit_obj, pos);
196 //aFatherDO->insertChild(suit_obj, pos);
197 aFatherDO->updateItem();
199 /* Define visibility state */
200 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
201 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
202 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer
203 (suit_obj->componentDataType(),false);
205 if (aDisplayer->canBeDisplayed(theID.c_str())) {
206 //hide the just added object
207 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
208 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
211 // MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
214 } // END: work with tree nodes structure
215 else { // BEGIN: work with study structure
216 EntryMapIter it = entry2SuitObject.find( theID );
217 if ( it != entry2SuitObject.end() ) {
218 MESSAGE("Entry " << theID << " is already added. Problem ??");
222 int last2Pnt_pos = (int)theID.rfind( ":" ); //!< TODO: conversion from size_t to int
223 std::string parent_id = theID.substr( 0, last2Pnt_pos );
224 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
226 if ( parent_id.length() == 3 ) // "0:1" - root item?
228 // It's probably a SComponent
229 if ( theID == aSComp->GetID() )
230 suit_obj = new SalomeApp_ModuleObject( aSComp );
232 suit_obj = new SalomeApp_DataObject( aSObj );
236 suit_obj = new SalomeApp_DataObject( aSObj );
239 it = entry2SuitObject.find( parent_id );
240 if ( it != entry2SuitObject.end() ) {
241 SalomeApp_DataObject* father = it->second;
242 father->insertChildAtTag( suit_obj, tag );
245 if ( parent_id.length() == 3 ) // "0:1" - root item?
247 // This should be for a module
248 SUIT_DataObject* father=myStudy->root();
249 father->appendChild(suit_obj);
253 MESSAGE("SHOULD NEVER GET HERE!!!");
255 //Try to find the SalomeApp_DataObject object parent
256 std::string root_id = parent_id.substr( 0, 4 );
257 std::string obj_id = parent_id.substr( 4 );
260 std::string::size_type debut = 0;
261 std::string::size_type fin;
262 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
264 fin = obj_id.find_first_of( ':', debut );
265 if ( fin == std::string::npos ) {
267 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
269 entry2SuitObject[parent_id] = anObj;
272 anID = root_id + obj_id.substr( 0, fin );
273 EntryMapIter it2 = entry2SuitObject.find( anID );
274 if ( it2 == entry2SuitObject.end() ) {
275 //the ID is not known in entry2SuitObject
276 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
278 entry2SuitObject[anID] = anObj;
285 anObj->insertChildAtTag( suit_obj, tag );
288 entry2SuitObject[theID] = suit_obj;
289 } // END: work with study structure
294 EntryMapIter it = entry2SuitObject.find( theID );
295 if ( it != entry2SuitObject.end() )
297 suit_obj = it->second;
298 suit_obj->updateItem();
299 SUIT_DataObject* father=suit_obj->parent();
301 father->removeChild(suit_obj);
302 entry2SuitObject.erase(it);
306 MESSAGE("Want to remove an unknown object" << theID);
312 //MESSAGE("Want to modify an object " << theID);
313 EntryMapIter it = entry2SuitObject.find( theID );
314 if ( it != entry2SuitObject.end() )
316 suit_obj = it->second;
317 suit_obj->updateItem();
321 MESSAGE("Want to modify an unknown object" << theID);
325 case 5: //IOR of the object modified
327 EntryMapIter it = entry2SuitObject.find( theID );
328 if ( it != entry2SuitObject.end() )
329 suit_obj = it->second;
331 /* Define visibility state */
332 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
333 if ( suit_obj && !isComponent ) {
334 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer
335 (suit_obj->componentDataType(),false);
337 if (aDisplayer->canBeDisplayed(theID.c_str())) {
338 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
339 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
342 // MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
347 #ifndef DISABLE_PYCONSOLE
348 case 6: //NoteBook variables were modified
350 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
354 default:MESSAGE("Unknown event: " << event);break;
356 } //notifyObserverID_real
361 entry2SuitObject.clear();
362 SUIT_DataObject* o = myStudy->root();
364 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
366 std::string entry = so->entry().toUtf8().constData();
368 entry2SuitObject[entry] = so;
370 if ( o->childCount() > 0 ) {
371 // parse the children
374 else if ( o->nextBrother() ) {
375 o = o->nextBrother();
378 // step to the next appropriate parent
381 if ( o->nextBrother() ) {
382 o = o->nextBrother();
392 SalomeApp_Study* myStudy;
393 EntryMap entry2SuitObject;
400 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
401 : LightApp_Study( app ), myObserver( 0 )
404 myStudyDS = SalomeApp_Application::getStudy();
410 SalomeApp_Study::~SalomeApp_Study()
414 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
415 myObserver->_default_POA()->deactivate_object( oid.in() );
420 #ifndef DISABLE_PYCONSOLE
421 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
423 emit notebookVarUpdated( theVarName );
430 QString SalomeApp_Study::studyName() const
432 // redefined from SUIT_Study to update study name properly since
433 // it can be changed outside of GUI
434 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
436 QString newName = QString::fromUtf8(studyDS()->URL().c_str());
437 if ( newName.isEmpty() )
438 newName = QString::fromUtf8(studyDS()->Name().c_str());
439 if ( LightApp_Study::studyName() != newName ) {
440 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
441 that->setStudyName( newName );
442 ((SalomeApp_Application*)application())->updateDesktopTitle();
445 return LightApp_Study::studyName();
449 Gets studyDS pointer.
451 _PTR(Study) SalomeApp_Study::studyDS() const
459 bool SalomeApp_Study::createDocument( const QString& theStr )
463 MESSAGE( "createDocument" );
465 setStudyName( QString::fromUtf8(myStudyDS->URL().c_str()) );
468 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
469 #ifdef WITH_SALOMEDS_OBSERVER
470 aRoot->setToSynchronize(false);
474 bool aRet = CAM_Study::createDocument( theStr );
476 #ifdef WITH_SALOMEDS_OBSERVER
477 myObserver = new Observer_i(this);
478 //attach an observer to the study with notification of modifications
479 myStudyDS->attach(myObserver->_this(),true);
482 emit created( this );
489 \param theFileName - name of file
491 bool SalomeApp_Study::openDocument( const QString& theFileName )
495 MESSAGE( "openDocument" );
499 bool showError = !application()->property("open_study_from_command_line").isValid() ||
500 !application()->property("open_study_from_command_line").toBool();
502 res = myStudyDS->Open( theFileName.toUtf8().data() );
504 catch(const SALOME_Exception& ex) {
505 application()->putInfo(tr(ex.what()));
507 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
508 tr("ERR_ERROR"), tr(ex.what()));
512 application()->putInfo(tr("OPEN_DOCUMENT_PROBLEM"));
514 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
515 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
522 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
524 // update loaded data models: call open() and update() on them.
527 QListIterator<CAM_DataModel*> it( dm_s );
528 while ( it.hasNext() )
529 openDataModel( studyName(), it.next() );
531 // this will build a SUIT_DataObject-s tree under myRoot member field
532 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
533 // but tree that corresponds to not-loaded data models will be updated any way.
534 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
536 #ifdef WITH_SALOMEDS_OBSERVER
537 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
538 myObserver = new Observer_i(this);
539 //attach an observer to the study with notification of modifications
540 myStudyDS->attach(myObserver->_this(),true);
543 res = CAM_Study::openDocument( theFileName );
546 myStudyDS->IsSaved(true);
548 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
550 std::vector<int> savePoints = getSavePoints();
551 if ( savePoints.size() > 0 )
552 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
555 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
560 Connects GUI study to SALOMEDS one
561 \param theStudyName - name of study
563 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
567 MESSAGE( "loadDocument" );
569 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
571 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
573 // update loaded data models: call open() and update() on them.
577 QListIterator<CAM_DataModel*> it( dm_s );
578 while ( it.hasNext() )
579 openDataModel( studyName(), it.next() );
581 bool res = CAM_Study::openDocument( theStudyName );
583 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
584 // mark study as "not saved" after call openDocument( ... ) method.
586 emit opened( this ); // myRoot is set to Object Browser here
588 // this will build a SUIT_DataObject-s tree under myRoot member field
589 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
590 // but tree that corresponds to not-loaded data models will be updated any way.
591 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
593 #ifdef WITH_SALOMEDS_OBSERVER
594 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
595 myObserver = new Observer_i(this);
596 //attach an observer to the study with notification of modifications
597 myStudyDS->attach(myObserver->_this(),true);
600 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
602 std::vector<int> savePoints = getSavePoints();
603 if ( savePoints.size() > 0 )
604 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
607 //SRN: BugID IPAL9021: End
613 \param theFileName - name of file
615 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName, bool isBackup/*=false*/ )
621 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
622 if ( store && !isBackup )
623 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
625 ModelList list; dataModels( list );
627 QListIterator<CAM_DataModel*> it( list );
628 QStringList listOfFiles;
629 while ( it.hasNext() ) {
630 // Cast to LightApp class in order to give a chance
631 // to light modules to save their data
632 if ( LightApp_DataModel* aModel =
633 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
635 aModel->saveAs( theFileName, this, listOfFiles, isBackup );
636 if ( !listOfFiles.isEmpty() )
637 saveModuleData(aModel->module()->name(), 0, // 0 means persistence file
642 // save SALOMEDS document
643 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
647 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
648 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
649 bool res = studyDS()->SaveAs( theFileName.toUtf8().data(), isMultiFile, isAscii )
650 && CAM_Study::saveDocumentAs( theFileName );
652 res = res && saveStudyData(theFileName, 0); // 0 means persistence file
654 if ( res && !isBackup)
661 Saves previously opened document
663 bool SalomeApp_Study::saveDocument()
666 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
668 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
670 ModelList list; dataModels( list );
672 QListIterator<CAM_DataModel*> it( list );
673 QStringList listOfFiles;
674 while ( it.hasNext() ) {
675 // Cast to LightApp class in order to give a chance
676 // to light modules to save their data
677 if ( LightApp_DataModel* aModel =
678 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
680 aModel->save(listOfFiles);
681 if ( !listOfFiles.isEmpty() )
682 saveModuleData(aModel->module()->name(), 0, // 0 means persistence file
687 // save SALOMEDS document
688 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
692 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
693 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
694 bool res = studyDS()->Save( isMultiFile, isAscii ) && CAM_Study::saveDocument();
696 res = res && saveStudyData(studyName(), 0); // 0 means persistence file
706 void SalomeApp_Study::closeDocument(bool permanently)
709 LightApp_Study::closeDocument(permanently);
711 // close SALOMEDS document
713 myStudyDS->detach( myObserver->_this() );
715 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
716 bool isBlocked = desk->signalsBlocked();
717 desk->blockSignals( true );
719 desk->blockSignals( isBlocked );
720 #ifndef DISABLE_PYCONSOLE
721 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
722 app->getPyInterp()->destroy();
728 Dump study operation. Writes a Python dump file using
729 SALOMEDS services. Additionally, gives a chance to light modules
730 to participate in dump study operation.
732 \param theFileName - full path to the output Python file
733 \param toPublish - if true, all objects are published in a study
734 by the output script, including those not orignally present
735 in the current study.
736 \param isMultiFile - if true, each module's dump is written into
737 a separate Python file, otherwise a single output file is written
738 \param toSaveGUI - if true, the GUI state is written
740 \return - true if the operation succeeds, and false otherwise.
742 bool SalomeApp_Study::dump( const QString& theFileName,
753 _PTR(AttributeParameter) ap;
754 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
756 if( ip->isDumpPython() )
757 ip->setDumpPython(); //Unset DumpPython flag.
759 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
761 //SRN: create a temporary save point
762 savePoint = SalomeApp_VisualState(
763 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
766 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
767 // This is an optional but important step, it gives a chance to light modules
768 // to dump their data as a part of common dump study operation
772 QListIterator<CAM_DataModel*> it( list );
773 QStringList listOfFiles;
774 while ( it.hasNext() ) {
775 if ( LightApp_DataModel* aModel =
776 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
778 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
779 !listOfFiles.isEmpty() )
780 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
781 // This code is shared with persistence mechanism.
782 // NOTE: this should be revised if behavior of saveModuleData() changes!
783 saveModuleData(aModel->module()->name(), 1, // 1 means dump file
788 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
789 // any light module is present in the current configuration
790 QFileInfo aFileInfo( theFileName );
791 bool res = myStudyDS->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
792 aFileInfo.baseName().toUtf8().data(),
796 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
798 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
799 // This code is shared with persistence mechanism.
800 // NOTE: this should be revised if behavior of saveStudyData() changes!
801 saveStudyData( theFileName, 1 ); // 0 means persistence file
807 \return true, if study is modified in comparison with last open/save
809 bool SalomeApp_Study::isModified() const
811 bool isAnyChanged = studyDS() && studyDS()->IsModified();
813 isAnyChanged = LightApp_Study::isModified();
819 Set study modified to \a on.
821 void SalomeApp_Study::Modified()
823 myStudyDS->Modified();
824 LightApp_Study::Modified();
828 \return if data model is saved
830 bool SalomeApp_Study::isSaved() const
832 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
834 isAllSaved = LightApp_Study::isSaved();
841 \param theModuleName - name of module
842 \param theListOfFiles - list of files to be saved
844 void SalomeApp_Study::saveModuleData( QString theModuleName, int type, QStringList theListOfFiles )
846 int aNb = theListOfFiles.count();
850 std::vector<std::string> aListOfFiles ( aNb );
852 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
853 if ( (*it).isEmpty() )
855 aListOfFiles[anIndex] = (*it).toUtf8().data();
858 SetListOfFiles(theModuleName.toStdString().c_str(), type, aListOfFiles);
863 \param theModuleName - name of module
864 \param theListOfFiles - list of files to be loaded
866 void SalomeApp_Study::openModuleData( QString theModuleName, int type, QStringList& theListOfFiles )
868 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str(), type );
870 int i, aLength = (int)aListOfFiles.size() - 1; //!< TODO: conversion from size_t to int
874 //Get a temporary directory for saved a file
875 theListOfFiles.append(aListOfFiles[0].c_str());
877 for(i = 0; i < aLength; i++)
878 theListOfFiles.append(aListOfFiles[i+1].c_str());
882 Re-implemented from LightApp_Study, actually does not save anything but
883 simply cleans up light modules' data
885 bool SalomeApp_Study::saveStudyData( const QString& /*theFileName*/, int type )
887 ModelList list; dataModels( list );
888 QListIterator<CAM_DataModel*> it( list );
889 while ( it.hasNext() ){
890 LightApp_DataModel* aLModel =
891 dynamic_cast<LightApp_DataModel*>( it.next() );
892 // It is safe to call SetListOfFiles() for any kind of module
893 // because SetListOfFiles() does nothing for full modules :)
895 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), type, std::vector<std::string>());
903 bool SalomeApp_Study::openStudyData( const QString& /*theFileName*/, int /*type*/ )
909 Virtual method re-implemented from LightApp_Study in order to create
910 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
912 \param theDataModel - data model instance to create a module object for
913 \param theParent - the module object's parent (normally it's the study root)
914 \return the module object instance
915 \sa LightApp_Study class, LightApp_DataModel class
917 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
918 SUIT_DataObject* theParent ) const
920 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
922 // Ensure that SComponent instance is published in the study for the given module
923 // This line causes automatic creation of SalomeApp_ModuleObject in case if
924 // WITH_SALOMEDS_OBSERVER is defined
925 that->addComponent( theDataModel );
927 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
928 // or by someone else so check if it exists first of all
929 CAM_ModuleObject* res = 0;
931 DataObjectList children = root()->children();
932 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
933 for( ; !res && anIt!=aLast; anIt++ )
935 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
936 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
941 _PTR(SComponent) aComp = myStudyDS->FindComponent(
942 theDataModel->module()->name().toStdString() );
946 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
955 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
957 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
959 CAM_Study::dataModelInserted(dm);
965 Create SComponent for module, using default engine (CORBAless)
967 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
969 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
970 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
972 // Check SComponent existance
974 std::string aCompDataType = dm->module()->name().toStdString();
976 _PTR(SComponent) aComp = myStudyDS->FindComponent(aCompDataType);
979 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
980 aComp = aBuilder->NewComponent(aCompDataType);
981 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
982 QString anIconName = dm->module()->iconName();
983 if (!anIconName.isEmpty()) {
984 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
986 anAttr->SetPixMap(anIconName.toStdString());
989 // Set default engine IOR
990 // Issue 21377 - using separate engine for each type of light module
991 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
993 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
994 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
995 SalomeApp_DataModel::synchronize( aComp, this );
998 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
999 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1000 QString anIconName = dm->module()->iconName();
1001 if (!anIconName.isEmpty()) {
1002 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1004 anAttr->SetPixMap(anIconName.toStdString());
1006 // Set default engine IOR
1014 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1019 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1020 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1021 _PTR(SComponent) aSComp;
1023 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1025 // Issue 21377 - using separate engine for each type of light module
1026 std::string aCompDataType = dm->module()->name().toStdString();
1027 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1028 aSComp = myStudyDS->FindComponent( aCompDataType );
1031 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1033 QString anId = aDM->getRootEntry( this );
1034 if ( anId.isEmpty() )
1035 return true; // Probably nothing to load
1036 anEngine = aDM->getModule()->engineIOR();
1037 if ( anEngine.isEmpty() )
1039 aSComp = myStudyDS->FindComponentID( std::string( anId.toLatin1() ) );
1043 _PTR(StudyBuilder) aBuilder( myStudyDS->NewBuilder() );
1046 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1048 catch( const SALOME::SALOME_Exception& ) {
1049 // Oops, something went wrong while loading -> return an error
1052 // Something has been read -> create data model tree
1053 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1054 // aDM->buildTree( aSComp, 0, this );
1057 // Don't return false here, for there might be no data
1058 // for a given component in the study yet
1060 QStringList listOfFiles;
1061 openModuleData(dm->module()->name(), 0, // 0 means persistence file
1063 if (dm && dm->open(studyName, this, listOfFiles)) {
1064 // Remove the files and temporary directory, created
1065 // for this module by LightApp_Engine_i::Load()
1066 bool isMultiFile = false; // TODO: decide, how to access this parameter
1067 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile, true );
1068 SetListOfFiles( dm->module()->name().toStdString().c_str(), 0, // 0 means persistence file
1069 std::vector<std::string>() );
1071 // Something has been read -> create data model tree
1072 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1074 aDM->update(NULL, this);
1081 Note that this method does not create or activate SalomeApp_Engine_i instance,
1082 therefore it can be called safely for any kind of module, but for full
1083 modules it returns an empty list.
1084 \return list of files used by module: to be used by CORBAless modules
1085 \param theModuleName - name of module
1087 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName, int type ) const
1089 // Issue 21377 - using separate engine for each type of light module
1090 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1092 return aDefaultEngine->GetListOfFiles( type );
1094 return std::vector<std::string>();
1098 Sets list of files used by module: to be used by CORBAless modules.
1099 Note that this method does not create or activate SalomeApp_Engine_i instance,
1100 therefore it can be called safely for any kind of module, but for full
1101 modules it simply does nothing.
1102 \param theModuleName - name of module
1103 \param theListOfFiles - list of files
1105 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName, int type,
1106 const std::vector<std::string> theListOfFiles )
1108 // Issue 21377 - using separate engine for each type of light module
1109 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1111 aDefaultEngine->SetListOfFiles(type, theListOfFiles);
1115 \return temporary directory for saving files of modules
1117 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1119 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1120 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1125 Removes temporary files
1127 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, bool isMultiFile, bool force )
1132 SALOMEDS_Tool::ListOfFiles aListOfFiles = GetListOfFiles( theModuleName, 0 );
1133 if (aListOfFiles.size() > 0) {
1134 std::string aTmpDir = aListOfFiles[0];
1136 const int n = (int)aListOfFiles.size() - 1; //!< TODO: conversion from size_t to int
1137 std::vector<std::string> aSeq;
1139 for (int i = 0; i < n; i++)
1140 aSeq.push_back(CORBA::string_dup(aListOfFiles[i + 1].c_str()));
1142 SalomeApp_Engine_i* engine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1143 bool toRemove = force || ( engine && !engine->keepFiles() );
1146 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq, true);
1147 engine->keepFiles( false );
1152 #ifndef DISABLE_PYCONSOLE
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()->URL(theFileName.toStdString());
1161 setIsSaved( isSaved );
1165 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1167 LightApp_DataObject* o = 0;
1169 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toUtf8().constData() ) );
1172 o = LightApp_Study::findObjectByEntry( theEntry );
1178 Deletes all references to object
1181 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1183 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1184 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1185 for( size_t i=0, n=aRefs.size(); i<n; i++ )
1187 _PTR( SObject ) o = aRefs[i];
1188 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1190 sb->RemoveReference( o );
1191 sb->RemoveObjectWithChildren( o );
1197 \return real entry by entry of reference
1198 \param entry - entry of reference object
1200 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1202 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1203 _PTR(SObject) refobj;
1205 if( obj && obj->ReferencedObject( refobj ) )
1206 return refobj->GetID().c_str();
1207 return LightApp_Study::referencedToEntry( entry );
1211 \return component data type for entry
1213 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1215 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1217 return LightApp_Study::componentDataType( entry );
1218 return obj->GetFatherComponent()->ComponentDataType().c_str();
1222 \return true if entry corresponds to component
1224 bool SalomeApp_Study::isComponent( const QString& entry ) const
1226 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1227 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1231 \return entries of object children
1233 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1235 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1236 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1237 anIter->InitEx( true );
1238 while( anIter->More() )
1240 _PTR(SObject) val( anIter->Value() );
1241 child_entries.append( val->GetID().c_str() );
1247 Fills list with components names
1248 \param comp - list to be filled
1250 void SalomeApp_Study::components( QStringList& comps ) const
1252 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1254 _PTR(SComponent) aComponent ( it->Value() );
1255 // skip the magic "Interface Applicative" component
1256 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1257 comps.append( aComponent->ComponentDataType().c_str() );
1262 Get the entry for the given module
1263 \param comp - list to be filled
1264 \return module root's entry
1266 QString SalomeApp_Study::centry( const QString& comp ) const
1269 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1271 _PTR(SComponent) aComponent ( it->Value() );
1272 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1273 e = aComponent->GetID().c_str();
1279 \return a list of saved points' IDs
1281 std::vector<int> SalomeApp_Study::getSavePoints()
1285 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1288 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1289 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1290 for(; anIter->More(); anIter->Next())
1292 _PTR(SObject) val( anIter->Value() );
1293 _PTR(GenericAttribute) genAttr;
1294 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1301 Removes a given save point
1303 void SalomeApp_Study::removeSavePoint(int savePoint)
1305 if(savePoint <= 0) return;
1306 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1307 _PTR(SObject) so = AP->GetSObject();
1308 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1309 builder->RemoveObjectWithChildren(so);
1313 \return a name of save point
1315 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1317 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1318 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1319 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1323 Sets a name of save point
1325 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1327 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1328 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1329 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1333 * \brief Restores the study state
1335 void SalomeApp_Study::restoreState(int savePoint)
1337 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1342 Slot: called on change of a root of a data model. Redefined from CAM_Study
1344 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1346 LightApp_Study::updateModelRoot( dm );
1348 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1349 // it must always be the last one.
1350 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );