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>
45 #include <LightApp_Displayer.h>
47 #include "utilities.h"
49 #include "SALOMEDS_Tool.hxx"
51 #include "SALOMEDSClient_ClientFactory.hxx"
53 #include <SALOMEconfig.h>
54 #include CORBA_SERVER_HEADER(SALOME_Exception)
56 //#define NOTIFY_BY_EVENT
58 class ObserverEvent : public QEvent
61 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
71 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
73 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
74 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
78 Observer_i(_PTR(Study) aStudyDS, SalomeApp_Study* aStudy):QObject(aStudy)
85 SUIT_DataObject* findObject( const char* theID ) const
87 EntryMap::const_iterator it = entry2SuitObject.find( theID );
88 return it != entry2SuitObject.end() ? it->second : 0;
91 virtual void notifyObserverID(const char* theID, CORBA::Long event)
93 #ifdef NOTIFY_BY_EVENT
94 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
96 notifyObserverID_real(theID,event);
100 virtual bool event(QEvent *event)
102 if (event->type() == QEvent::User )
104 //START_TIMING(notify);
105 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
106 //END_TIMING(notify,100);
111 void notifyObserverID_real(const std::string& theID, long event)
113 SalomeApp_DataObject* suit_obj = 0;
118 _PTR(SObject) aSObj = myStudyDS->FindObjectID(theID);
119 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
121 if (!aSComp || aSComp->IsNull()) {
122 MESSAGE("Entry " << theID << " has not father component. Problem ??");
126 // Mantis issue 0020136: Drag&Drop in OB
127 _PTR(UseCaseBuilder) aUseCaseBuilder = myStudyDS->GetUseCaseBuilder();
128 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
129 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
130 // tree node is not yet set, it is a normal situation
134 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
135 if (!aFatherSO || aFatherSO->IsNull()) {
136 MESSAGE("Father SObject is not found. Problem ??");
140 std::string parent_id = aFatherSO->GetID();
141 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
143 if (it == entry2SuitObject.end()) {
144 MESSAGE("Father data object is not found. Problem ??");
148 SalomeApp_DataObject* aFatherDO = it->second;
150 it = entry2SuitObject.find(theID);
151 if (it != entry2SuitObject.end()) { // this SOobject is already added somethere
152 suit_obj = it->second;
153 SUIT_DataObject* oldFather = suit_obj->parent();
155 oldFather->removeChild(suit_obj, false);
156 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
157 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
158 model->forgetObject( suit_obj );
160 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
161 oldFatherSA->updateItem();
166 suit_obj = new SalomeApp_DataObject(aSObj);
167 entry2SuitObject[theID] = suit_obj;
170 suit_obj->updateItem();
171 // define position in the data tree (in aFatherDO) to insert the aSObj
173 //int childDataObjCount = aFatherDO->childCount();
174 _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
175 for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
176 if (aUseCaseIter->Value()->GetID() == theID) {
182 aFatherDO->insertChildAtPos(suit_obj, pos);
183 //aFatherDO->insertChild(suit_obj, pos);
184 aFatherDO->updateItem();
186 /* Define visibility state */
187 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
188 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
189 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
190 if (!moduleTitle.isEmpty()) {
191 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
193 if(aDisplayer->canBeDisplayed(theID.c_str())) {
194 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState ); //hide the just added object
195 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
198 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
202 } // END: work with tree nodes structure
203 else { // BEGIN: work with study structure
204 EntryMapIter it = entry2SuitObject.find( theID );
205 if ( it != entry2SuitObject.end() ) {
206 MESSAGE("Entry " << theID << " is already added. Problem ??");
210 int last2Pnt_pos = theID.rfind( ":" );
211 std::string parent_id = theID.substr( 0, last2Pnt_pos );
212 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
214 if ( parent_id.length() == 3 ) // "0:1" - root item?
216 // It's probably a SComponent
217 if ( theID == aSComp->GetID() )
218 suit_obj = new SalomeApp_ModuleObject( aSComp );
220 suit_obj = new SalomeApp_DataObject( aSObj );
224 suit_obj = new SalomeApp_DataObject( aSObj );
227 it = entry2SuitObject.find( parent_id );
228 if ( it != entry2SuitObject.end() ) {
229 SalomeApp_DataObject* father = it->second;
230 father->insertChildAtTag( suit_obj, tag );
233 if ( parent_id.length() == 3 ) // "0:1" - root item?
235 // This should be for a module
236 SUIT_DataObject* father=myStudy->root();
237 father->appendChild(suit_obj);
241 MESSAGE("SHOULD NEVER GET HERE!!!");
243 //Try to find the SalomeApp_DataObject object parent
244 std::string root_id = parent_id.substr( 0, 4 );
245 std::string obj_id = parent_id.substr( 4 );
248 std::string::size_type debut = 0;
249 std::string::size_type fin;
250 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
252 fin = obj_id.find_first_of( ':', debut );
253 if ( fin == std::string::npos ) {
255 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
256 entry2SuitObject[parent_id] = anObj;
259 anID = root_id + obj_id.substr( 0, fin );
260 EntryMapIter it2 = entry2SuitObject.find( anID );
261 if ( it2 == entry2SuitObject.end() ) {
262 //the ID is not known in entry2SuitObject
263 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
264 entry2SuitObject[anID] = anObj;
270 anObj->insertChildAtTag( suit_obj, tag );
273 entry2SuitObject[theID] = suit_obj;
274 } // END: work with study structure
279 EntryMapIter it = entry2SuitObject.find( theID );
280 if ( it != entry2SuitObject.end() )
282 suit_obj = it->second;
283 // VSR: object is not removed, since SALOMEDS::SObject is not actually removed,
284 // only its attributes are cleared;
285 // thus, the object can be later reused
286 suit_obj->updateItem();
287 //SUIT_DataObject* father=suit_obj->parent();
289 // father->removeChild(suit_obj);
290 //entry2SuitObject.erase(it);
294 MESSAGE("Want to remove an unknown object" << theID);
300 //MESSAGE("Want to modify an object " << theID);
301 EntryMapIter it = entry2SuitObject.find( theID );
302 if ( it != entry2SuitObject.end() )
304 suit_obj = it->second;
305 suit_obj->updateItem();
309 MESSAGE("Want to modify an unknown object" << theID);
313 case 5: //IOR of the object modified
315 EntryMapIter it = entry2SuitObject.find( theID );
316 if ( it != entry2SuitObject.end() )
317 suit_obj = it->second;
319 /* Define visibility state */
320 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
321 if ( suit_obj && !isComponent ) {
322 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
323 if (!moduleTitle.isEmpty()) {
324 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
326 if(aDisplayer->canBeDisplayed(theID.c_str())) {
327 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
328 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
331 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
337 #ifndef DISABLE_PYCONSOLE
338 case 6: //NoteBook variables were modified
340 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
344 default:MESSAGE("Unknown event: " << event);break;
346 } //notifyObserverID_real
351 entry2SuitObject.clear();
352 SUIT_DataObject* o = myStudy->root();
354 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
356 std::string entry = so->entry().toLatin1().constData();
358 entry2SuitObject[entry] = so;
360 if ( o->childCount() > 0 ) {
361 // parse the children
364 else if ( o->nextBrother() > 0 ) {
365 o = o->nextBrother();
368 // step to the next appropriate parent
371 if ( o->nextBrother() ) {
372 o = o->nextBrother();
382 _PTR(Study) myStudyDS;
383 SalomeApp_Study* myStudy;
384 EntryMap entry2SuitObject;
391 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
392 : LightApp_Study( app ), myObserver( 0 )
399 SalomeApp_Study::~SalomeApp_Study()
402 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
403 myObserver->_default_POA()->deactivate_object( oid.in() );
407 #ifndef DISABLE_PYCONSOLE
408 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
410 emit notebookVarUpdated( theVarName );
417 int SalomeApp_Study::id() const
421 id = studyDS()->StudyId();
428 QString SalomeApp_Study::studyName() const
430 // redefined from SUIT_Study to update study name properly since
431 // it can be changed outside of GUI
432 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
434 QString newName = QString::fromUtf8(studyDS()->Name().c_str());
435 if ( LightApp_Study::studyName() != newName ) {
436 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
437 that->setStudyName( newName );
438 ((SalomeApp_Application*)application())->updateDesktopTitle();
441 return LightApp_Study::studyName();
445 Gets studyDS pointer.
447 _PTR(Study) SalomeApp_Study::studyDS() const
455 bool SalomeApp_Study::createDocument( const QString& theStr )
457 MESSAGE( "createDocument" );
459 // initialize myStudyDS, read HDF file
460 QString aName = newStudyName();
461 _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
466 setStudyName( aName );
469 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
470 #ifdef WITH_SALOMEDS_OBSERVER
471 aRoot->setToSynchronize(false);
475 bool aRet = CAM_Study::createDocument( theStr );
477 #ifdef WITH_SALOMEDS_OBSERVER
478 myObserver = new Observer_i(myStudyDS,this);
479 //attach an observer to the study with notification of modifications
480 myStudyDS->attach(myObserver->_this(),true);
483 emit created( this );
490 \param theFileName - name of file
492 bool SalomeApp_Study::openDocument( const QString& theFileName )
494 MESSAGE( "openDocument" );
496 // initialize myStudyDS, read HDF file
497 _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
503 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
505 // update loaded data models: call open() and update() on them.
508 QListIterator<CAM_DataModel*> it( dm_s );
509 while ( it.hasNext() )
510 openDataModel( studyName(), it.next() );
512 // this will build a SUIT_DataObject-s tree under myRoot member field
513 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
514 // but tree that corresponds to not-loaded data models will be updated any way.
515 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
517 #ifdef WITH_SALOMEDS_OBSERVER
518 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
519 myObserver = new Observer_i(myStudyDS,this);
520 //attach an observer to the study with notification of modifications
521 myStudyDS->attach(myObserver->_this(),true);
524 bool res = CAM_Study::openDocument( theFileName );
527 study->IsSaved(true);
529 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
531 std::vector<int> savePoints = getSavePoints();
532 if ( savePoints.size() > 0 )
533 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
536 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
541 Connects GUI study to SALOMEDS one already loaded into StudyManager
542 \param theStudyName - name of study
544 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
546 MESSAGE( "loadDocument" );
548 // obtain myStudyDS from StudyManager
549 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
555 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
557 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
559 // update loaded data models: call open() and update() on them.
563 QListIterator<CAM_DataModel*> it( dm_s );
564 while ( it.hasNext() )
565 openDataModel( studyName(), it.next() );
567 // this will build a SUIT_DataObject-s tree under myRoot member field
568 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
569 // but tree that corresponds to not-loaded data models will be updated any way.
570 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
572 #ifdef WITH_SALOMEDS_OBSERVER
573 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
574 myObserver = new Observer_i(myStudyDS,this);
575 //attach an observer to the study with notification of modifications
576 myStudyDS->attach(myObserver->_this(),true);
579 bool res = CAM_Study::openDocument( theStudyName );
581 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
582 // mark study as "not saved" after call openDocument( ... ) method.
586 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
588 std::vector<int> savePoints = getSavePoints();
589 if ( savePoints.size() > 0 )
590 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
593 //SRN: BugID IPAL9021: End
599 \param theFileName - name of file
601 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
603 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
605 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
607 ModelList list; dataModels( list );
609 QListIterator<CAM_DataModel*> it( list );
610 QStringList listOfFiles;
611 while ( it.hasNext() ) {
612 // Cast to LightApp class in order to give a chance
613 // to light modules to save their data
614 if ( LightApp_DataModel* aModel =
615 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
617 aModel->saveAs( theFileName, this, listOfFiles );
618 if ( !listOfFiles.isEmpty() )
619 saveModuleData(aModel->module()->name(), listOfFiles);
623 // save SALOMEDS document
624 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
628 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
629 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
630 bool res = (isAscii ?
631 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
632 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
633 && CAM_Study::saveDocumentAs( theFileName );
635 res = res && saveStudyData(theFileName);
644 Saves previously opened document
646 bool SalomeApp_Study::saveDocument()
648 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
650 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
652 ModelList list; dataModels( list );
654 QListIterator<CAM_DataModel*> it( list );
655 QStringList listOfFiles;
656 while ( it.hasNext() ) {
657 // Cast to LightApp class in order to give a chance
658 // to light modules to save their data
659 if ( LightApp_DataModel* aModel =
660 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
662 aModel->save(listOfFiles);
663 if ( !listOfFiles.isEmpty() )
664 saveModuleData(aModel->module()->name(), listOfFiles);
668 // save SALOMEDS document
669 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
673 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
674 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
675 bool res = (isAscii ?
676 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
677 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
679 res = res && saveStudyData(studyName());
689 void SalomeApp_Study::closeDocument(bool permanently)
691 LightApp_Study::closeDocument(permanently);
693 // close SALOMEDS document
694 _PTR(Study) studyPtr = studyDS();
698 myStudyDS->detach( myObserver->_this() );
700 SalomeApp_Application::studyMgr()->Close( studyPtr );
702 SALOMEDSClient_Study* aStudy = 0;
703 setStudyDS( _PTR(Study)(aStudy) );
708 Dump study operation. Writes a Python dump file using
709 SALOMEDS services. Additionally, gives a chance to light modules
710 to participate in dump study operation.
712 \param theFileName - full path to the output Python file
713 \param toPublish - if true, all objects are published in a study
714 by the output script, including those not orignally present
715 in the current study.
716 \param isMultiFile - if true, each module's dump is written into
717 a separate Python file, otherwise a single output file is written
718 \param toSaveGUI - if true, the GUI state is written
720 \return - true if the operation succeeds, and false otherwise.
722 bool SalomeApp_Study::dump( const QString& theFileName,
728 _PTR(AttributeParameter) ap;
729 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
730 _PTR(Study) aStudy = studyDS();
732 if( ip->isDumpPython( aStudy ) )
733 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
735 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
736 ip->setDumpPython( aStudy );
737 //SRN: create a temporary save point
738 savePoint = SalomeApp_VisualState(
739 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
742 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
743 // This is an optional but important step, it gives a chance to light modules
744 // to dump their data as a part of common dump study operation
748 QListIterator<CAM_DataModel*> it( list );
749 QStringList listOfFiles;
750 while ( it.hasNext() ) {
751 if ( LightApp_DataModel* aModel =
752 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
754 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
755 !listOfFiles.isEmpty() )
756 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
757 // This code is shared with persistence mechanism.
758 // NOTE: this should be revised if behavior of saveModuleData() changes!
759 saveModuleData(aModel->module()->name(), listOfFiles);
763 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
764 // any light module is present in the current configuration
765 QFileInfo aFileInfo( theFileName );
766 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
767 aFileInfo.baseName().toUtf8().data(),
771 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
773 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
774 // This code is shared with persistence mechanism.
775 // NOTE: this should be revised if behavior of saveStudyData() changes!
776 saveStudyData( theFileName );
782 \return true, if study is modified in comparison with last open/save
784 bool SalomeApp_Study::isModified() const
786 bool isAnyChanged = studyDS() && studyDS()->IsModified();
788 isAnyChanged = LightApp_Study::isModified();
794 Set study modified to \a on.
796 void SalomeApp_Study::Modified()
798 if(_PTR(Study) aStudy = studyDS())
800 LightApp_Study::Modified();
804 \return if data model is saved
806 bool SalomeApp_Study::isSaved() const
808 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
810 isAllSaved = LightApp_Study::isSaved();
817 \param theModuleName - name of module
818 \param theListOfFiles - list of files to be saved
820 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
822 int aNb = theListOfFiles.count();
826 std::vector<std::string> aListOfFiles ( aNb );
828 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
829 if ( (*it).isEmpty() )
831 aListOfFiles[anIndex] = (*it).toUtf8().data();
834 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
839 \param theModuleName - name of module
840 \param theListOfFiles - list of files to be loaded
842 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
844 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
846 int i, aLength = aListOfFiles.size() - 1;
850 //Get a temporary directory for saved a file
851 theListOfFiles.append(aListOfFiles[0].c_str());
853 for(i = 0; i < aLength; i++)
854 theListOfFiles.append(aListOfFiles[i+1].c_str());
858 Re-implemented from LightApp_Study, actually does not save anything but
859 simply cleans up light modules' data
861 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
863 ModelList list; dataModels( list );
864 QListIterator<CAM_DataModel*> it( list );
865 std::vector<std::string> listOfFiles(0);
866 while ( it.hasNext() ){
867 LightApp_DataModel* aLModel =
868 dynamic_cast<LightApp_DataModel*>( it.next() );
869 // It is safe to call SetListOfFiles() for any kind of module
870 // because SetListOfFiles() does nothing for full modules :)
872 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
880 bool SalomeApp_Study::openStudyData( const QString& theFileName )
888 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
894 Virtual method re-implemented from LightApp_Study in order to create
895 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
897 \param theDataModel - data model instance to create a module object for
898 \param theParent - the module object's parent (normally it's the study root)
899 \return the module object instance
900 \sa LightApp_Study class, LightApp_DataModel class
902 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
903 SUIT_DataObject* theParent ) const
905 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
907 // Ensure that SComponent instance is published in the study for the given module
908 // This line causes automatic creation of SalomeApp_ModuleObject in case if
909 // WITH_SALOMEDS_OBSERVER is defined
910 that->addComponent( theDataModel );
912 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
913 // or by someone else so check if it exists first of all
914 CAM_ModuleObject* res = 0;
916 DataObjectList children = root()->children();
917 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
918 for( ; !res && anIt!=aLast; anIt++ )
920 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
921 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
926 _PTR(Study) aStudy = studyDS();
930 _PTR(SComponent) aComp = aStudy->FindComponent(
931 theDataModel->module()->name().toStdString() );
935 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
944 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
946 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
948 CAM_Study::dataModelInserted(dm);
954 Create SComponent for module, using default engine (CORBAless)
956 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
958 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
959 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
961 // Check SComponent existance
962 _PTR(Study) aStudy = studyDS();
966 std::string aCompDataType = dm->module()->name().toStdString();
968 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
971 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
972 aComp = aBuilder->NewComponent(aCompDataType);
973 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
974 QString anIconName = dm->module()->iconName();
975 if (!anIconName.isEmpty()) {
976 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
978 anAttr->SetPixMap(anIconName.toStdString());
981 // Set default engine IOR
982 // Issue 21377 - using separate engine for each type of light module
983 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
985 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
986 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
987 SalomeApp_DataModel::synchronize( aComp, this );
990 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
991 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
992 QString anIconName = dm->module()->iconName();
993 if (!anIconName.isEmpty()) {
994 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
996 anAttr->SetPixMap(anIconName.toStdString());
998 // Set default engine IOR
1006 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1011 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1012 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1013 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
1014 _PTR(SComponent) aSComp;
1016 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1018 // Issue 21377 - using separate engine for each type of light module
1019 std::string aCompDataType = dm->module()->name().toStdString();
1020 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1021 aSComp = aStudy->FindComponent( aCompDataType );
1024 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1026 QString anId = aDM->getRootEntry( this );
1027 if ( anId.isEmpty() )
1028 return true; // Probably nothing to load
1029 anEngine = aDM->getModule()->engineIOR();
1030 if ( anEngine.isEmpty() )
1032 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1036 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1039 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1041 catch( const SALOME::SALOME_Exception& ) {
1042 // Oops, something went wrong while loading -> return an error
1045 // Something has been read -> create data model tree
1046 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1047 // aDM->buildTree( aSComp, 0, this );
1050 // Don't return false here, for there might be no data
1051 // for a given component in the study yet
1053 QStringList listOfFiles;
1054 openModuleData(dm->module()->name(), listOfFiles);
1055 if (dm && dm->open(studyName, this, listOfFiles)) {
1056 // Remove the files and temporary directory, created
1057 // for this module by LightApp_Engine_i::Load()
1058 bool isMultiFile = false; // TODO: decide, how to access this parameter
1059 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1061 // Something has been read -> create data model tree
1062 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1064 aDM->update(NULL, this);
1071 Create new study name.
1073 QString SalomeApp_Study::newStudyName() const
1075 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1076 QString prefix( "Study%1" ), newName, curName;
1077 int i = 1, j, n = studies.size();
1078 while ( newName.isEmpty() ){
1079 curName = prefix.arg( i );
1080 for ( j = 0 ; j < n; j++ ){
1081 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1093 Note that this method does not create or activate SalomeApp_Engine_i instance,
1094 therefore it can be called safely for any kind of module, but for full
1095 modules it returns an empty list.
1096 \return list of files used by module: to be used by CORBAless modules
1097 \param theModuleName - name of module
1099 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1101 // Issue 21377 - using separate engine for each type of light module
1102 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1104 return aDefaultEngine->GetListOfFiles(id());
1106 std::vector<std::string> aListOfFiles;
1107 return aListOfFiles;
1111 Sets list of files used by module: to be used by CORBAless modules.
1112 Note that this method does not create or activate SalomeApp_Engine_i instance,
1113 therefore it can be called safely for any kind of module, but for full
1114 modules it simply does nothing.
1115 \param theModuleName - name of module
1116 \param theListOfFiles - list of files
1118 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1119 const std::vector<std::string> theListOfFiles )
1121 // Issue 21377 - using separate engine for each type of light module
1122 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1124 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1128 \return temporary directory for saving files of modules
1130 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1132 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1133 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1138 Removes temporary files
1140 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1145 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1146 if (aListOfFiles.size() > 0) {
1147 std::string aTmpDir = aListOfFiles[0];
1149 const int n = aListOfFiles.size() - 1;
1150 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1152 for (int i = 0; i < n; i++)
1153 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1155 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1159 #ifndef DISABLE_PYCONSOLE
1161 Mark the study as saved in the file
1162 \param theFileName - the name of file
1164 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1166 setStudyName(theFileName);
1167 studyDS()->Name(theFileName.toStdString());
1168 setIsSaved( isSaved );
1172 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1174 LightApp_DataObject* o = 0;
1176 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toLatin1().constData() ) );
1179 o = LightApp_Study::findObjectByEntry( theEntry );
1185 Deletes all references to object
1188 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1190 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1191 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1192 for( int i=0, n=aRefs.size(); i<n; i++ )
1194 _PTR( SObject ) o = aRefs[i];
1195 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1197 sb->RemoveReference( o );
1198 sb->RemoveObjectWithChildren( o );
1204 \return real entry by entry of reference
1205 \param entry - entry of reference object
1207 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1209 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1210 _PTR(SObject) refobj;
1212 if( obj && obj->ReferencedObject( refobj ) )
1213 return refobj->GetID().c_str();
1214 return LightApp_Study::referencedToEntry( entry );
1218 \return component data type for entry
1220 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1222 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1224 return LightApp_Study::componentDataType( entry );
1225 return obj->GetFatherComponent()->ComponentDataType().c_str();
1229 \return true if entry corresponds to component
1231 bool SalomeApp_Study::isComponent( const QString& entry ) const
1233 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1234 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1238 \return entries of object children
1240 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1242 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1243 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1244 anIter->InitEx( true );
1245 while( anIter->More() )
1247 _PTR(SObject) val( anIter->Value() );
1248 child_entries.append( val->GetID().c_str() );
1254 Fills list with components names
1255 \param comp - list to be filled
1257 void SalomeApp_Study::components( QStringList& comps ) const
1259 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1261 _PTR(SComponent) aComponent ( it->Value() );
1262 // skip the magic "Interface Applicative" component
1263 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1264 comps.append( aComponent->ComponentDataType().c_str() );
1269 Get the entry for the given module
1270 \param comp - list to be filled
1271 \return module root's entry
1273 QString SalomeApp_Study::centry( const QString& comp ) const
1276 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1278 _PTR(SComponent) aComponent ( it->Value() );
1279 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1280 e = aComponent->GetID().c_str();
1286 \return a list of saved points' IDs
1288 std::vector<int> SalomeApp_Study::getSavePoints()
1292 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1295 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1296 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1297 for(; anIter->More(); anIter->Next())
1299 _PTR(SObject) val( anIter->Value() );
1300 _PTR(GenericAttribute) genAttr;
1301 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1308 Removes a given save point
1310 void SalomeApp_Study::removeSavePoint(int savePoint)
1312 if(savePoint <= 0) return;
1313 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1314 _PTR(SObject) so = AP->GetSObject();
1315 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1316 builder->RemoveObjectWithChildren(so);
1320 \return a name of save point
1322 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1324 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1325 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1326 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1330 Sets a name of save point
1332 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1334 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1335 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1336 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1340 * \brief Restores the study state
1342 void SalomeApp_Study::restoreState(int savePoint)
1344 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1349 Slot: called on change of a root of a data model. Redefined from CAM_Study
1351 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1353 LightApp_Study::updateModelRoot( dm );
1355 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1356 // it must always be the last one.
1357 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );