1 // Copyright (C) 2007-2023 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 #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 //#define NOTIFY_BY_EVENT
65 class ObserverEvent : public QEvent
68 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
78 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
80 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
81 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
85 Observer_i( SalomeApp_Study* aStudy):QObject(aStudy)
91 SUIT_DataObject* findObject( const char* theID ) const
93 EntryMap::const_iterator it = entry2SuitObject.find( theID );
94 return it != entry2SuitObject.end() ? it->second : 0;
97 virtual void notifyObserverID(const char* theID, CORBA::Long event)
99 #ifdef NOTIFY_BY_EVENT
100 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
102 notifyObserverID_real(theID,event);
106 virtual bool event(QEvent *event)
108 if (event->type() == QEvent::User )
110 //START_TIMING(notify);
111 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
112 //END_TIMING(notify,100);
117 void notifyObserverID_real(const std::string& theID, long event)
119 SalomeApp_DataObject* suit_obj = 0;
124 _PTR(SObject) aSObj = SalomeApp_Application::getStudy()->FindObjectID(theID);
125 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
127 if (!aSComp || aSComp->IsNull()) {
128 MESSAGE("Entry " << theID << " has not father component. Problem ??");
132 // Mantis issue 0020136: Drag&Drop in OB
133 _PTR(UseCaseBuilder) aUseCaseBuilder = SalomeApp_Application::getStudy()->GetUseCaseBuilder();
134 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
135 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
136 // tree node is not yet set, it is a normal situation
140 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
141 if (!aFatherSO || aFatherSO->IsNull()) {
142 MESSAGE("Father SObject is not found. Problem ??");
146 std::string parent_id = aFatherSO->GetID();
147 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
149 if (it == entry2SuitObject.end()) {
150 MESSAGE("Father data object is not found. Problem ??");
154 SalomeApp_DataObject* aFatherDO = it->second;
156 it = entry2SuitObject.find(theID);
157 if (it != entry2SuitObject.end()) { // this SOobject is already added somewhere
158 suit_obj = it->second;
159 SUIT_DataObject* oldFather = suit_obj->parent();
161 oldFather->removeChild(suit_obj, false);
162 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
163 // MESSAGE("myStudy: " << myStudy->id() << " app " << app);
164 // MESSAGE("objectBrowser: "<< app->objectBrowser());
165 if (!app->objectBrowser()) {
166 MESSAGE("Object Browser not found. Problem ??");
169 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
170 model->forgetObject( suit_obj );
172 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
173 oldFatherSA->updateItem();
178 suit_obj = new SalomeApp_DataObject(aSObj);
179 entry2SuitObject[theID] = suit_obj;
182 suit_obj->updateItem();
183 // define position in the data tree (in aFatherDO) to insert the aSObj
184 int pos = aUseCaseBuilder->GetIndexInFather(aFatherSO, aSObj);
186 aFatherDO->insertChildAtPos(suit_obj, pos);
187 //aFatherDO->insertChild(suit_obj, pos);
188 aFatherDO->updateItem();
190 /* Define visibility state */
191 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
192 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
193 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer
194 (suit_obj->componentDataType(),false);
196 if (aDisplayer->canBeDisplayed(theID.c_str())) {
197 //hide the just added object
198 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
199 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
202 // 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 = (int)theID.rfind( ":" ); //!< TODO: conversion from size_t to int
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));
260 entry2SuitObject[parent_id] = anObj;
263 anID = root_id + obj_id.substr( 0, fin );
264 EntryMapIter it2 = entry2SuitObject.find( anID );
265 if ( it2 == entry2SuitObject.end() ) {
266 //the ID is not known in entry2SuitObject
267 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
269 entry2SuitObject[anID] = anObj;
276 anObj->insertChildAtTag( suit_obj, tag );
279 entry2SuitObject[theID] = suit_obj;
280 } // END: work with study structure
285 EntryMapIter it = entry2SuitObject.find( theID );
286 if ( it != entry2SuitObject.end() )
288 suit_obj = it->second;
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 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer
326 (suit_obj->componentDataType(),false);
328 if (aDisplayer->canBeDisplayed(theID.c_str())) {
329 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
330 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
333 // MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
338 #ifndef DISABLE_PYCONSOLE
339 case 6: //NoteBook variables were modified
341 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
345 default:MESSAGE("Unknown event: " << event);break;
347 } //notifyObserverID_real
352 entry2SuitObject.clear();
353 SUIT_DataObject* o = myStudy->root();
355 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
357 std::string entry = so->entry().toUtf8().constData();
359 entry2SuitObject[entry] = so;
361 if ( o->childCount() > 0 ) {
362 // parse the children
365 else if ( o->nextBrother() ) {
366 o = o->nextBrother();
369 // step to the next appropriate parent
372 if ( o->nextBrother() ) {
373 o = o->nextBrother();
383 SalomeApp_Study* myStudy;
384 EntryMap entry2SuitObject;
391 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
392 : LightApp_Study( app ), myObserver( 0 )
394 myStudyDS = SalomeApp_Application::getStudy();
400 SalomeApp_Study::~SalomeApp_Study()
403 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
404 myObserver->_default_POA()->deactivate_object( oid.in() );
409 #ifndef DISABLE_PYCONSOLE
410 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
412 emit notebookVarUpdated( theVarName );
419 QString SalomeApp_Study::studyName() const
421 // redefined from SUIT_Study to update study name properly since
422 // it can be changed outside of GUI
423 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
425 QString newName = QString::fromUtf8(studyDS()->URL().c_str());
426 if ( newName.isEmpty() )
427 newName = QString::fromUtf8(studyDS()->Name().c_str());
428 if ( LightApp_Study::studyName() != newName ) {
429 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
430 that->setStudyName( newName );
431 ((SalomeApp_Application*)application())->updateDesktopTitle();
434 return LightApp_Study::studyName();
438 Gets studyDS pointer.
440 _PTR(Study) SalomeApp_Study::studyDS() const
448 bool SalomeApp_Study::createDocument( const QString& theStr )
450 MESSAGE( "createDocument" );
452 setStudyName( QString::fromUtf8(myStudyDS->URL().c_str()) );
455 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
456 #ifdef WITH_SALOMEDS_OBSERVER
457 aRoot->setToSynchronize(false);
461 bool aRet = CAM_Study::createDocument( theStr );
463 #ifdef WITH_SALOMEDS_OBSERVER
464 myObserver = new Observer_i(this);
465 //attach an observer to the study with notification of modifications
466 myStudyDS->attach(myObserver->_this(),true);
469 emit created( this );
476 \param theFileName - name of file
478 bool SalomeApp_Study::openDocument( const QString& theFileName )
480 MESSAGE( "openDocument" );
484 bool showError = !application()->property("open_study_from_command_line").isValid() ||
485 !application()->property("open_study_from_command_line").toBool();
487 res = myStudyDS->Open( theFileName.toUtf8().data() );
489 catch(const SALOME_Exception& ex) {
490 application()->putInfo(tr(ex.what()));
492 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
493 tr("ERR_ERROR"), tr(ex.what()));
497 application()->putInfo(tr("OPEN_DOCUMENT_PROBLEM"));
499 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
500 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
507 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
509 // update loaded data models: call open() and update() on them.
512 QListIterator<CAM_DataModel*> it( dm_s );
513 while ( it.hasNext() )
514 openDataModel( studyName(), it.next() );
516 // this will build a SUIT_DataObject-s tree under myRoot member field
517 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
518 // but tree that corresponds to not-loaded data models will be updated any way.
519 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
521 #ifdef WITH_SALOMEDS_OBSERVER
522 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
523 myObserver = new Observer_i(this);
524 //attach an observer to the study with notification of modifications
525 myStudyDS->attach(myObserver->_this(),true);
528 res = CAM_Study::openDocument( theFileName );
531 myStudyDS->IsSaved(true);
533 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
535 std::vector<int> savePoints = getSavePoints();
536 if ( savePoints.size() > 0 )
537 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
540 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
545 Connects GUI study to SALOMEDS one
546 \param theStudyName - name of study
548 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
550 MESSAGE( "loadDocument" );
552 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
554 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
556 // update loaded data models: call open() and update() on them.
560 QListIterator<CAM_DataModel*> it( dm_s );
561 while ( it.hasNext() )
562 openDataModel( studyName(), it.next() );
564 bool res = CAM_Study::openDocument( theStudyName );
566 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
567 // mark study as "not saved" after call openDocument( ... ) method.
569 emit opened( this ); // myRoot is set to Object Browser here
571 // this will build a SUIT_DataObject-s tree under myRoot member field
572 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
573 // but tree that corresponds to not-loaded data models will be updated any way.
574 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
576 #ifdef WITH_SALOMEDS_OBSERVER
577 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
578 myObserver = new Observer_i(this);
579 //attach an observer to the study with notification of modifications
580 myStudyDS->attach(myObserver->_this(),true);
583 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
585 std::vector<int> savePoints = getSavePoints();
586 if ( savePoints.size() > 0 )
587 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
590 //SRN: BugID IPAL9021: End
596 \param theFileName - name of file
598 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
600 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
602 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
604 ModelList list; dataModels( list );
606 QListIterator<CAM_DataModel*> it( list );
607 QStringList listOfFiles;
608 while ( it.hasNext() ) {
609 // Cast to LightApp class in order to give a chance
610 // to light modules to save their data
611 if ( LightApp_DataModel* aModel =
612 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
614 aModel->saveAs( theFileName, this, listOfFiles );
615 if ( !listOfFiles.isEmpty() )
616 saveModuleData(aModel->module()->name(), 0, // 0 means persistence file
621 // save SALOMEDS document
622 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
626 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
627 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
628 bool res = studyDS()->SaveAs( theFileName.toUtf8().data(), isMultiFile, isAscii )
629 && CAM_Study::saveDocumentAs( theFileName );
631 res = res && saveStudyData(theFileName, 0); // 0 means persistence file
640 Saves previously opened document
642 bool SalomeApp_Study::saveDocument()
644 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
646 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
648 ModelList list; dataModels( list );
650 QListIterator<CAM_DataModel*> it( list );
651 QStringList listOfFiles;
652 while ( it.hasNext() ) {
653 // Cast to LightApp class in order to give a chance
654 // to light modules to save their data
655 if ( LightApp_DataModel* aModel =
656 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
658 aModel->save(listOfFiles);
659 if ( !listOfFiles.isEmpty() )
660 saveModuleData(aModel->module()->name(), 0, // 0 means persistence file
665 // save SALOMEDS document
666 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
670 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
671 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
672 bool res = studyDS()->Save( isMultiFile, isAscii ) && CAM_Study::saveDocument();
674 res = res && saveStudyData(studyName(), 0); // 0 means persistence file
684 void SalomeApp_Study::closeDocument(bool permanently)
686 LightApp_Study::closeDocument(permanently);
688 // close SALOMEDS document
690 myStudyDS->detach( myObserver->_this() );
692 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
693 bool isBlocked = desk->signalsBlocked();
694 desk->blockSignals( true );
696 desk->blockSignals( isBlocked );
697 #ifndef DISABLE_PYCONSOLE
698 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
699 app->getPyInterp()->destroy();
705 Dump study operation. Writes a Python dump file using
706 SALOMEDS services. Additionally, gives a chance to light modules
707 to participate in dump study operation.
709 \param theFileName - full path to the output Python file
710 \param toPublish - if true, all objects are published in a study
711 by the output script, including those not orignally present
712 in the current study.
713 \param isMultiFile - if true, each module's dump is written into
714 a separate Python file, otherwise a single output file is written
715 \param toSaveGUI - if true, the GUI state is written
717 \return - true if the operation succeeds, and false otherwise.
719 bool SalomeApp_Study::dump( const QString& theFileName,
725 _PTR(AttributeParameter) ap;
726 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
728 if( ip->isDumpPython() )
729 ip->setDumpPython(); //Unset DumpPython flag.
731 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
733 //SRN: create a temporary save point
734 savePoint = SalomeApp_VisualState(
735 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
738 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
739 // This is an optional but important step, it gives a chance to light modules
740 // to dump their data as a part of common dump study operation
744 QListIterator<CAM_DataModel*> it( list );
745 QStringList listOfFiles;
746 while ( it.hasNext() ) {
747 if ( LightApp_DataModel* aModel =
748 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
750 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
751 !listOfFiles.isEmpty() )
752 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
753 // This code is shared with persistence mechanism.
754 // NOTE: this should be revised if behavior of saveModuleData() changes!
755 saveModuleData(aModel->module()->name(), 1, // 1 means dump file
760 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
761 // any light module is present in the current configuration
762 QFileInfo aFileInfo( theFileName );
763 bool res = myStudyDS->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
764 aFileInfo.baseName().toUtf8().data(),
768 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
770 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
771 // This code is shared with persistence mechanism.
772 // NOTE: this should be revised if behavior of saveStudyData() changes!
773 saveStudyData( theFileName, 1 ); // 0 means persistence file
779 \return true, if study is modified in comparison with last open/save
781 bool SalomeApp_Study::isModified() const
783 bool isAnyChanged = studyDS() && studyDS()->IsModified();
785 isAnyChanged = LightApp_Study::isModified();
791 Set study modified to \a on.
793 void SalomeApp_Study::Modified()
795 myStudyDS->Modified();
796 LightApp_Study::Modified();
800 \return if data model is saved
802 bool SalomeApp_Study::isSaved() const
804 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
806 isAllSaved = LightApp_Study::isSaved();
813 \param theModuleName - name of module
814 \param theListOfFiles - list of files to be saved
816 void SalomeApp_Study::saveModuleData( QString theModuleName, int type, QStringList theListOfFiles )
818 int aNb = theListOfFiles.count();
822 std::vector<std::string> aListOfFiles ( aNb );
824 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
825 if ( (*it).isEmpty() )
827 aListOfFiles[anIndex] = (*it).toUtf8().data();
830 SetListOfFiles(theModuleName.toStdString().c_str(), type, aListOfFiles);
835 \param theModuleName - name of module
836 \param theListOfFiles - list of files to be loaded
838 void SalomeApp_Study::openModuleData( QString theModuleName, int type, QStringList& theListOfFiles )
840 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str(), type );
842 int i, aLength = (int)aListOfFiles.size() - 1; //!< TODO: conversion from size_t to int
846 //Get a temporary directory for saved a file
847 theListOfFiles.append(aListOfFiles[0].c_str());
849 for(i = 0; i < aLength; i++)
850 theListOfFiles.append(aListOfFiles[i+1].c_str());
854 Re-implemented from LightApp_Study, actually does not save anything but
855 simply cleans up light modules' data
857 bool SalomeApp_Study::saveStudyData( const QString& /*theFileName*/, int type )
859 ModelList list; dataModels( list );
860 QListIterator<CAM_DataModel*> it( list );
861 while ( it.hasNext() ){
862 LightApp_DataModel* aLModel =
863 dynamic_cast<LightApp_DataModel*>( it.next() );
864 // It is safe to call SetListOfFiles() for any kind of module
865 // because SetListOfFiles() does nothing for full modules :)
867 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), type, std::vector<std::string>());
875 bool SalomeApp_Study::openStudyData( const QString& /*theFileName*/, int /*type*/ )
881 Virtual method re-implemented from LightApp_Study in order to create
882 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
884 \param theDataModel - data model instance to create a module object for
885 \param theParent - the module object's parent (normally it's the study root)
886 \return the module object instance
887 \sa LightApp_Study class, LightApp_DataModel class
889 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
890 SUIT_DataObject* theParent ) const
892 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
894 // Ensure that SComponent instance is published in the study for the given module
895 // This line causes automatic creation of SalomeApp_ModuleObject in case if
896 // WITH_SALOMEDS_OBSERVER is defined
897 that->addComponent( theDataModel );
899 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
900 // or by someone else so check if it exists first of all
901 CAM_ModuleObject* res = 0;
903 DataObjectList children = root()->children();
904 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
905 for( ; !res && anIt!=aLast; anIt++ )
907 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
908 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
913 _PTR(SComponent) aComp = myStudyDS->FindComponent(
914 theDataModel->module()->name().toStdString() );
918 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
927 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
929 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
931 CAM_Study::dataModelInserted(dm);
937 Create SComponent for module, using default engine (CORBAless)
939 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
941 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
942 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
944 // Check SComponent existance
946 std::string aCompDataType = dm->module()->name().toStdString();
948 _PTR(SComponent) aComp = myStudyDS->FindComponent(aCompDataType);
951 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
952 aComp = aBuilder->NewComponent(aCompDataType);
953 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
954 QString anIconName = dm->module()->iconName();
955 if (!anIconName.isEmpty()) {
956 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
958 anAttr->SetPixMap(anIconName.toStdString());
961 // Set default engine IOR
962 // Issue 21377 - using separate engine for each type of light module
963 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
965 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
966 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
967 SalomeApp_DataModel::synchronize( aComp, this );
970 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
971 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
972 QString anIconName = dm->module()->iconName();
973 if (!anIconName.isEmpty()) {
974 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
976 anAttr->SetPixMap(anIconName.toStdString());
978 // Set default engine IOR
986 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
991 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
992 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
993 _PTR(SComponent) aSComp;
995 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
997 // Issue 21377 - using separate engine for each type of light module
998 std::string aCompDataType = dm->module()->name().toStdString();
999 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1000 aSComp = myStudyDS->FindComponent( aCompDataType );
1003 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1005 QString anId = aDM->getRootEntry( this );
1006 if ( anId.isEmpty() )
1007 return true; // Probably nothing to load
1008 anEngine = aDM->getModule()->engineIOR();
1009 if ( anEngine.isEmpty() )
1011 aSComp = myStudyDS->FindComponentID( std::string( anId.toLatin1() ) );
1015 _PTR(StudyBuilder) aBuilder( myStudyDS->NewBuilder() );
1018 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1020 catch( const SALOME::SALOME_Exception& ) {
1021 // Oops, something went wrong while loading -> return an error
1024 // Something has been read -> create data model tree
1025 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1026 // aDM->buildTree( aSComp, 0, this );
1029 // Don't return false here, for there might be no data
1030 // for a given component in the study yet
1032 QStringList listOfFiles;
1033 openModuleData(dm->module()->name(), 0, // 0 means persistence file
1035 if (dm && dm->open(studyName, this, listOfFiles)) {
1036 // Remove the files and temporary directory, created
1037 // for this module by LightApp_Engine_i::Load()
1038 bool isMultiFile = false; // TODO: decide, how to access this parameter
1039 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile, true );
1040 SetListOfFiles( dm->module()->name().toStdString().c_str(), 0, // 0 means persistence file
1041 std::vector<std::string>() );
1043 // Something has been read -> create data model tree
1044 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1046 aDM->update(NULL, this);
1053 Note that this method does not create or activate SalomeApp_Engine_i instance,
1054 therefore it can be called safely for any kind of module, but for full
1055 modules it returns an empty list.
1056 \return list of files used by module: to be used by CORBAless modules
1057 \param theModuleName - name of module
1059 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName, int type ) const
1061 // Issue 21377 - using separate engine for each type of light module
1062 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1064 return aDefaultEngine->GetListOfFiles( type );
1066 return std::vector<std::string>();
1070 Sets list of files used by module: to be used by CORBAless modules.
1071 Note that this method does not create or activate SalomeApp_Engine_i instance,
1072 therefore it can be called safely for any kind of module, but for full
1073 modules it simply does nothing.
1074 \param theModuleName - name of module
1075 \param theListOfFiles - list of files
1077 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName, int type,
1078 const std::vector<std::string> theListOfFiles )
1080 // Issue 21377 - using separate engine for each type of light module
1081 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1083 aDefaultEngine->SetListOfFiles(type, theListOfFiles);
1087 \return temporary directory for saving files of modules
1089 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1091 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1092 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1097 Removes temporary files
1099 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, bool isMultiFile, bool force )
1104 SALOMEDS_Tool::ListOfFiles aListOfFiles = GetListOfFiles( theModuleName, 0 );
1105 if (aListOfFiles.size() > 0) {
1106 std::string aTmpDir = aListOfFiles[0];
1108 const int n = (int)aListOfFiles.size() - 1; //!< TODO: conversion from size_t to int
1109 std::vector<std::string> aSeq;
1111 for (int i = 0; i < n; i++)
1112 aSeq.push_back(CORBA::string_dup(aListOfFiles[i + 1].c_str()));
1114 SalomeApp_Engine_i* engine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1115 bool toRemove = force || ( engine && !engine->keepFiles() );
1118 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq, true);
1119 engine->keepFiles( false );
1124 #ifndef DISABLE_PYCONSOLE
1126 Mark the study as saved in the file
1127 \param theFileName - the name of file
1129 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1131 setStudyName(theFileName);
1132 studyDS()->URL(theFileName.toStdString());
1133 setIsSaved( isSaved );
1137 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1139 LightApp_DataObject* o = 0;
1141 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toUtf8().constData() ) );
1144 o = LightApp_Study::findObjectByEntry( theEntry );
1150 Deletes all references to object
1153 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1155 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1156 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1157 for( size_t i=0, n=aRefs.size(); i<n; i++ )
1159 _PTR( SObject ) o = aRefs[i];
1160 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1162 sb->RemoveReference( o );
1163 sb->RemoveObjectWithChildren( o );
1169 \return real entry by entry of reference
1170 \param entry - entry of reference object
1172 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1174 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1175 _PTR(SObject) refobj;
1177 if( obj && obj->ReferencedObject( refobj ) )
1178 return refobj->GetID().c_str();
1179 return LightApp_Study::referencedToEntry( entry );
1183 \return component data type for entry
1185 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1187 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1189 return LightApp_Study::componentDataType( entry );
1190 return obj->GetFatherComponent()->ComponentDataType().c_str();
1194 \return true if entry corresponds to component
1196 bool SalomeApp_Study::isComponent( const QString& entry ) const
1198 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1199 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1203 \return entries of object children
1205 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1207 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1208 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1209 anIter->InitEx( true );
1210 while( anIter->More() )
1212 _PTR(SObject) val( anIter->Value() );
1213 child_entries.append( val->GetID().c_str() );
1219 Fills list with components names
1220 \param comp - list to be filled
1222 void SalomeApp_Study::components( QStringList& comps ) const
1224 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1226 _PTR(SComponent) aComponent ( it->Value() );
1227 // skip the magic "Interface Applicative" component
1228 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1229 comps.append( aComponent->ComponentDataType().c_str() );
1234 Get the entry for the given module
1235 \param comp - list to be filled
1236 \return module root's entry
1238 QString SalomeApp_Study::centry( const QString& comp ) const
1241 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1243 _PTR(SComponent) aComponent ( it->Value() );
1244 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1245 e = aComponent->GetID().c_str();
1251 \return a list of saved points' IDs
1253 std::vector<int> SalomeApp_Study::getSavePoints()
1257 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1260 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1261 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1262 for(; anIter->More(); anIter->Next())
1264 _PTR(SObject) val( anIter->Value() );
1265 _PTR(GenericAttribute) genAttr;
1266 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1273 Removes a given save point
1275 void SalomeApp_Study::removeSavePoint(int savePoint)
1277 if(savePoint <= 0) return;
1278 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1279 _PTR(SObject) so = AP->GetSObject();
1280 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1281 builder->RemoveObjectWithChildren(so);
1285 \return a name of save point
1287 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1289 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1290 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1291 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1295 Sets a name of save point
1297 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1299 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1300 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1301 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1305 * \brief Restores the study state
1307 void SalomeApp_Study::restoreState(int savePoint)
1309 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1314 Slot: called on change of a root of a data model. Redefined from CAM_Study
1316 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1318 LightApp_Study::updateModelRoot( dm );
1320 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1321 // it must always be the last one.
1322 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );