1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "SalomeApp_Study.h"
25 #include "SalomeApp_Module.h"
26 #include "SalomeApp_DataObject.h"
27 #include "SalomeApp_DataModel.h"
28 #include "SalomeApp_Application.h"
29 #include "SalomeApp_Engine_i.h"
30 #include "SalomeApp_VisualState.h"
32 // temporary commented
33 //#include <OB_Browser.h>
35 #include <QCoreApplication>
38 #include "SALOME_Event.h"
39 #include "Basics_Utils.hxx"
41 #include <SUIT_ResourceMgr.h>
42 #include <SUIT_TreeModel.h>
43 #include <SUIT_DataBrowser.h>
44 #include <SUIT_MessageBox.h>
45 #include <SUIT_Session.h>
46 #include <SUIT_Desktop.h>
48 #include <LightApp_Displayer.h>
50 #ifndef DISABLE_PYCONSOLE
51 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
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(_PTR(Study) aStudyDS, SalomeApp_Study* aStudy):QObject(aStudy)
92 SUIT_DataObject* findObject( const char* theID ) const
94 EntryMap::const_iterator it = entry2SuitObject.find( theID );
95 return it != entry2SuitObject.end() ? it->second : 0;
98 virtual void notifyObserverID(const char* theID, CORBA::Long event)
100 #ifdef NOTIFY_BY_EVENT
101 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
103 notifyObserverID_real(theID,event);
107 virtual bool event(QEvent *event)
109 if (event->type() == QEvent::User )
111 //START_TIMING(notify);
112 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
113 //END_TIMING(notify,100);
118 void notifyObserverID_real(const std::string& theID, long event)
120 SalomeApp_DataObject* suit_obj = 0;
125 _PTR(SObject) aSObj = myStudyDS->FindObjectID(theID);
126 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
128 if (!aSComp || aSComp->IsNull()) {
129 MESSAGE("Entry " << theID << " has not father component. Problem ??");
133 // Mantis issue 0020136: Drag&Drop in OB
134 _PTR(UseCaseBuilder) aUseCaseBuilder = myStudyDS->GetUseCaseBuilder();
135 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
136 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
137 // tree node is not yet set, it is a normal situation
141 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
142 if (!aFatherSO || aFatherSO->IsNull()) {
143 MESSAGE("Father SObject is not found. Problem ??");
147 std::string parent_id = aFatherSO->GetID();
148 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
150 if (it == entry2SuitObject.end()) {
151 MESSAGE("Father data object is not found. Problem ??");
155 SalomeApp_DataObject* aFatherDO = it->second;
157 it = entry2SuitObject.find(theID);
158 if (it != entry2SuitObject.end()) { // this SOobject is already added somethere
159 suit_obj = it->second;
160 SUIT_DataObject* oldFather = suit_obj->parent();
162 oldFather->removeChild(suit_obj, false);
163 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
164 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
165 model->forgetObject( suit_obj );
167 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
168 oldFatherSA->updateItem();
173 suit_obj = new SalomeApp_DataObject(aSObj);
174 entry2SuitObject[theID] = suit_obj;
177 suit_obj->updateItem();
178 // define position in the data tree (in aFatherDO) to insert the aSObj
180 //int childDataObjCount = aFatherDO->childCount();
181 _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
182 for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
183 if (aUseCaseIter->Value()->GetID() == theID) {
189 aFatherDO->insertChildAtPos(suit_obj, pos);
190 //aFatherDO->insertChild(suit_obj, pos);
191 aFatherDO->updateItem();
193 /* Define visibility state */
194 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
195 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
196 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
197 if (!moduleTitle.isEmpty()) {
198 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
200 if(aDisplayer->canBeDisplayed(theID.c_str())) {
201 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState ); //hide the just added object
202 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
205 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
209 } // END: work with tree nodes structure
210 else { // BEGIN: work with study structure
211 EntryMapIter it = entry2SuitObject.find( theID );
212 if ( it != entry2SuitObject.end() ) {
213 MESSAGE("Entry " << theID << " is already added. Problem ??");
217 int last2Pnt_pos = theID.rfind( ":" );
218 std::string parent_id = theID.substr( 0, last2Pnt_pos );
219 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
221 if ( parent_id.length() == 3 ) // "0:1" - root item?
223 // It's probably a SComponent
224 if ( theID == aSComp->GetID() )
225 suit_obj = new SalomeApp_ModuleObject( aSComp );
227 suit_obj = new SalomeApp_DataObject( aSObj );
231 suit_obj = new SalomeApp_DataObject( aSObj );
234 it = entry2SuitObject.find( parent_id );
235 if ( it != entry2SuitObject.end() ) {
236 SalomeApp_DataObject* father = it->second;
237 father->insertChildAtTag( suit_obj, tag );
240 if ( parent_id.length() == 3 ) // "0:1" - root item?
242 // This should be for a module
243 SUIT_DataObject* father=myStudy->root();
244 father->appendChild(suit_obj);
248 MESSAGE("SHOULD NEVER GET HERE!!!");
250 //Try to find the SalomeApp_DataObject object parent
251 std::string root_id = parent_id.substr( 0, 4 );
252 std::string obj_id = parent_id.substr( 4 );
255 std::string::size_type debut = 0;
256 std::string::size_type fin;
257 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
259 fin = obj_id.find_first_of( ':', debut );
260 if ( fin == std::string::npos ) {
262 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
263 entry2SuitObject[parent_id] = anObj;
266 anID = root_id + obj_id.substr( 0, fin );
267 EntryMapIter it2 = entry2SuitObject.find( anID );
268 if ( it2 == entry2SuitObject.end() ) {
269 //the ID is not known in entry2SuitObject
270 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
271 entry2SuitObject[anID] = anObj;
277 anObj->insertChildAtTag( suit_obj, tag );
280 entry2SuitObject[theID] = suit_obj;
281 } // END: work with study structure
286 EntryMapIter it = entry2SuitObject.find( theID );
287 if ( it != entry2SuitObject.end() )
289 suit_obj = it->second;
290 // VSR: object is not removed, since SALOMEDS::SObject is not actually removed,
291 // only its attributes are cleared;
292 // thus, the object can be later reused
293 suit_obj->updateItem();
294 //SUIT_DataObject* father=suit_obj->parent();
296 // father->removeChild(suit_obj);
297 //entry2SuitObject.erase(it);
301 MESSAGE("Want to remove an unknown object" << theID);
307 //MESSAGE("Want to modify an object " << theID);
308 EntryMapIter it = entry2SuitObject.find( theID );
309 if ( it != entry2SuitObject.end() )
311 suit_obj = it->second;
312 suit_obj->updateItem();
316 MESSAGE("Want to modify an unknown object" << theID);
320 case 5: //IOR of the object modified
322 EntryMapIter it = entry2SuitObject.find( theID );
323 if ( it != entry2SuitObject.end() )
324 suit_obj = it->second;
326 /* Define visibility state */
327 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
328 if ( suit_obj && !isComponent ) {
329 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
330 if (!moduleTitle.isEmpty()) {
331 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
333 if(aDisplayer->canBeDisplayed(theID.c_str())) {
334 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
335 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
338 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
344 #ifndef DISABLE_PYCONSOLE
345 case 6: //NoteBook variables were modified
347 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
351 default:MESSAGE("Unknown event: " << event);break;
353 } //notifyObserverID_real
358 entry2SuitObject.clear();
359 SUIT_DataObject* o = myStudy->root();
361 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
363 std::string entry = so->entry().toLatin1().constData();
365 entry2SuitObject[entry] = so;
367 if ( o->childCount() > 0 ) {
368 // parse the children
371 else if ( o->nextBrother() > 0 ) {
372 o = o->nextBrother();
375 // step to the next appropriate parent
378 if ( o->nextBrother() ) {
379 o = o->nextBrother();
389 _PTR(Study) myStudyDS;
390 SalomeApp_Study* myStudy;
391 EntryMap entry2SuitObject;
398 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
399 : LightApp_Study( app ), myObserver( 0 )
406 SalomeApp_Study::~SalomeApp_Study()
409 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
410 myObserver->_default_POA()->deactivate_object( oid.in() );
414 #ifndef DISABLE_PYCONSOLE
415 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
417 emit notebookVarUpdated( theVarName );
424 int SalomeApp_Study::id() const
428 id = studyDS()->StudyId();
435 QString SalomeApp_Study::studyName() const
437 // redefined from SUIT_Study to update study name properly since
438 // it can be changed outside of GUI
439 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
441 QString newName = QString::fromUtf8(studyDS()->Name().c_str());
442 if ( LightApp_Study::studyName() != newName ) {
443 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
444 that->setStudyName( newName );
445 ((SalomeApp_Application*)application())->updateDesktopTitle();
448 return LightApp_Study::studyName();
452 Gets studyDS pointer.
454 _PTR(Study) SalomeApp_Study::studyDS() const
462 bool SalomeApp_Study::createDocument( const QString& theStr )
464 MESSAGE( "createDocument" );
466 // initialize myStudyDS, read HDF file
467 QString aName = newStudyName();
471 study = _PTR(Study)( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
473 catch(const SALOME_Exception& ex) {
474 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
475 tr("ERR_ERROR"), tr(ex.what()));
479 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
480 tr("ERR_ERROR"), tr("CREATE_DOCUMENT_PROBLEM"));
488 setStudyName( aName );
491 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
492 #ifdef WITH_SALOMEDS_OBSERVER
493 aRoot->setToSynchronize(false);
497 bool aRet = CAM_Study::createDocument( theStr );
499 #ifdef WITH_SALOMEDS_OBSERVER
500 myObserver = new Observer_i(myStudyDS,this);
501 //attach an observer to the study with notification of modifications
502 myStudyDS->attach(myObserver->_this(),true);
505 emit created( this );
512 \param theFileName - name of file
514 bool SalomeApp_Study::openDocument( const QString& theFileName )
516 MESSAGE( "openDocument" );
518 // initialize myStudyDS, read HDF file
521 study = _PTR(Study) ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
523 catch(const SALOME_Exception& ex) {
524 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
525 tr("ERR_ERROR"), tr(ex.what()));
529 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
530 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
539 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
541 // update loaded data models: call open() and update() on them.
544 QListIterator<CAM_DataModel*> it( dm_s );
545 while ( it.hasNext() )
546 openDataModel( studyName(), it.next() );
548 // this will build a SUIT_DataObject-s tree under myRoot member field
549 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
550 // but tree that corresponds to not-loaded data models will be updated any way.
551 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
553 #ifdef WITH_SALOMEDS_OBSERVER
554 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
555 myObserver = new Observer_i(myStudyDS,this);
556 //attach an observer to the study with notification of modifications
557 myStudyDS->attach(myObserver->_this(),true);
560 bool res = CAM_Study::openDocument( theFileName );
563 study->IsSaved(true);
565 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
567 std::vector<int> savePoints = getSavePoints();
568 if ( savePoints.size() > 0 )
569 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
572 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
577 Connects GUI study to SALOMEDS one already loaded into StudyManager
578 \param theStudyName - name of study
580 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
582 MESSAGE( "loadDocument" );
584 // obtain myStudyDS from StudyManager
585 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
591 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
593 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
595 // update loaded data models: call open() and update() on them.
599 QListIterator<CAM_DataModel*> it( dm_s );
600 while ( it.hasNext() )
601 openDataModel( studyName(), it.next() );
603 // this will build a SUIT_DataObject-s tree under myRoot member field
604 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
605 // but tree that corresponds to not-loaded data models will be updated any way.
606 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
608 #ifdef WITH_SALOMEDS_OBSERVER
609 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
610 myObserver = new Observer_i(myStudyDS,this);
611 //attach an observer to the study with notification of modifications
612 myStudyDS->attach(myObserver->_this(),true);
615 bool res = CAM_Study::openDocument( theStudyName );
617 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
618 // mark study as "not saved" after call openDocument( ... ) method.
622 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
624 std::vector<int> savePoints = getSavePoints();
625 if ( savePoints.size() > 0 )
626 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
629 //SRN: BugID IPAL9021: End
635 \param theFileName - name of file
637 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
639 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
641 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
643 ModelList list; dataModels( list );
645 QListIterator<CAM_DataModel*> it( list );
646 QStringList listOfFiles;
647 while ( it.hasNext() ) {
648 // Cast to LightApp class in order to give a chance
649 // to light modules to save their data
650 if ( LightApp_DataModel* aModel =
651 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
653 aModel->saveAs( theFileName, this, listOfFiles );
654 if ( !listOfFiles.isEmpty() )
655 saveModuleData(aModel->module()->name(), listOfFiles);
659 // save SALOMEDS document
660 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
664 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
665 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
666 bool res = (isAscii ?
667 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
668 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
669 && CAM_Study::saveDocumentAs( theFileName );
671 res = res && saveStudyData(theFileName);
680 Saves previously opened document
682 bool SalomeApp_Study::saveDocument()
684 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
686 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
688 ModelList list; dataModels( list );
690 QListIterator<CAM_DataModel*> it( list );
691 QStringList listOfFiles;
692 while ( it.hasNext() ) {
693 // Cast to LightApp class in order to give a chance
694 // to light modules to save their data
695 if ( LightApp_DataModel* aModel =
696 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
698 aModel->save(listOfFiles);
699 if ( !listOfFiles.isEmpty() )
700 saveModuleData(aModel->module()->name(), listOfFiles);
704 // save SALOMEDS document
705 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
709 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
710 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
711 bool res = (isAscii ?
712 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
713 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
715 res = res && saveStudyData(studyName());
725 void SalomeApp_Study::closeDocument(bool permanently)
727 LightApp_Study::closeDocument(permanently);
729 // close SALOMEDS document
730 _PTR(Study) studyPtr = studyDS();
734 myStudyDS->detach( myObserver->_this() );
736 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
737 bool isBlocked = desk->signalsBlocked();
738 desk->blockSignals( true );
739 SalomeApp_Application::studyMgr()->Close( studyPtr );
740 desk->blockSignals( isBlocked );
741 #ifndef DISABLE_PYCONSOLE
742 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
743 app->getPyInterp()->destroy();
746 SALOMEDSClient_Study* aStudy = 0;
747 setStudyDS( _PTR(Study)(aStudy) );
752 Dump study operation. Writes a Python dump file using
753 SALOMEDS services. Additionally, gives a chance to light modules
754 to participate in dump study operation.
756 \param theFileName - full path to the output Python file
757 \param toPublish - if true, all objects are published in a study
758 by the output script, including those not orignally present
759 in the current study.
760 \param isMultiFile - if true, each module's dump is written into
761 a separate Python file, otherwise a single output file is written
762 \param toSaveGUI - if true, the GUI state is written
764 \return - true if the operation succeeds, and false otherwise.
766 bool SalomeApp_Study::dump( const QString& theFileName,
772 _PTR(AttributeParameter) ap;
773 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
774 _PTR(Study) aStudy = studyDS();
776 if( ip->isDumpPython( aStudy ) )
777 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
779 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
780 ip->setDumpPython( aStudy );
781 //SRN: create a temporary save point
782 savePoint = SalomeApp_VisualState(
783 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
786 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
787 // This is an optional but important step, it gives a chance to light modules
788 // to dump their data as a part of common dump study operation
792 QListIterator<CAM_DataModel*> it( list );
793 QStringList listOfFiles;
794 while ( it.hasNext() ) {
795 if ( LightApp_DataModel* aModel =
796 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
798 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
799 !listOfFiles.isEmpty() )
800 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
801 // This code is shared with persistence mechanism.
802 // NOTE: this should be revised if behavior of saveModuleData() changes!
803 saveModuleData(aModel->module()->name(), listOfFiles);
807 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
808 // any light module is present in the current configuration
809 QFileInfo aFileInfo( theFileName );
810 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
811 aFileInfo.baseName().toUtf8().data(),
815 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
817 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
818 // This code is shared with persistence mechanism.
819 // NOTE: this should be revised if behavior of saveStudyData() changes!
820 saveStudyData( theFileName );
826 \return true, if study is modified in comparison with last open/save
828 bool SalomeApp_Study::isModified() const
830 bool isAnyChanged = studyDS() && studyDS()->IsModified();
832 isAnyChanged = LightApp_Study::isModified();
838 Set study modified to \a on.
840 void SalomeApp_Study::Modified()
842 if(_PTR(Study) aStudy = studyDS())
844 LightApp_Study::Modified();
848 \return if data model is saved
850 bool SalomeApp_Study::isSaved() const
852 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
854 isAllSaved = LightApp_Study::isSaved();
861 \param theModuleName - name of module
862 \param theListOfFiles - list of files to be saved
864 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
866 int aNb = theListOfFiles.count();
870 std::vector<std::string> aListOfFiles ( aNb );
872 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
873 if ( (*it).isEmpty() )
875 aListOfFiles[anIndex] = (*it).toUtf8().data();
878 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
883 \param theModuleName - name of module
884 \param theListOfFiles - list of files to be loaded
886 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
888 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
890 int i, aLength = aListOfFiles.size() - 1;
894 //Get a temporary directory for saved a file
895 theListOfFiles.append(aListOfFiles[0].c_str());
897 for(i = 0; i < aLength; i++)
898 theListOfFiles.append(aListOfFiles[i+1].c_str());
902 Re-implemented from LightApp_Study, actually does not save anything but
903 simply cleans up light modules' data
905 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
907 ModelList list; dataModels( list );
908 QListIterator<CAM_DataModel*> it( list );
909 std::vector<std::string> listOfFiles(0);
910 while ( it.hasNext() ){
911 LightApp_DataModel* aLModel =
912 dynamic_cast<LightApp_DataModel*>( it.next() );
913 // It is safe to call SetListOfFiles() for any kind of module
914 // because SetListOfFiles() does nothing for full modules :)
916 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
924 bool SalomeApp_Study::openStudyData( const QString& theFileName )
932 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
938 Virtual method re-implemented from LightApp_Study in order to create
939 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
941 \param theDataModel - data model instance to create a module object for
942 \param theParent - the module object's parent (normally it's the study root)
943 \return the module object instance
944 \sa LightApp_Study class, LightApp_DataModel class
946 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
947 SUIT_DataObject* theParent ) const
949 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
951 // Ensure that SComponent instance is published in the study for the given module
952 // This line causes automatic creation of SalomeApp_ModuleObject in case if
953 // WITH_SALOMEDS_OBSERVER is defined
954 that->addComponent( theDataModel );
956 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
957 // or by someone else so check if it exists first of all
958 CAM_ModuleObject* res = 0;
960 DataObjectList children = root()->children();
961 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
962 for( ; !res && anIt!=aLast; anIt++ )
964 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
965 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
970 _PTR(Study) aStudy = studyDS();
974 _PTR(SComponent) aComp = aStudy->FindComponent(
975 theDataModel->module()->name().toStdString() );
979 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
988 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
990 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
992 CAM_Study::dataModelInserted(dm);
998 Create SComponent for module, using default engine (CORBAless)
1000 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
1002 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1003 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1005 // Check SComponent existance
1006 _PTR(Study) aStudy = studyDS();
1010 std::string aCompDataType = dm->module()->name().toStdString();
1012 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
1014 // Create SComponent
1015 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1016 aComp = aBuilder->NewComponent(aCompDataType);
1017 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1018 QString anIconName = dm->module()->iconName();
1019 if (!anIconName.isEmpty()) {
1020 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1022 anAttr->SetPixMap(anIconName.toStdString());
1025 // Set default engine IOR
1026 // Issue 21377 - using separate engine for each type of light module
1027 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
1029 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
1030 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
1031 SalomeApp_DataModel::synchronize( aComp, this );
1034 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1035 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1036 QString anIconName = dm->module()->iconName();
1037 if (!anIconName.isEmpty()) {
1038 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1040 anAttr->SetPixMap(anIconName.toStdString());
1042 // Set default engine IOR
1050 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1055 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1056 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1057 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
1058 _PTR(SComponent) aSComp;
1060 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1062 // Issue 21377 - using separate engine for each type of light module
1063 std::string aCompDataType = dm->module()->name().toStdString();
1064 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1065 aSComp = aStudy->FindComponent( aCompDataType );
1068 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1070 QString anId = aDM->getRootEntry( this );
1071 if ( anId.isEmpty() )
1072 return true; // Probably nothing to load
1073 anEngine = aDM->getModule()->engineIOR();
1074 if ( anEngine.isEmpty() )
1076 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1080 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1083 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1085 catch( const SALOME::SALOME_Exception& ) {
1086 // Oops, something went wrong while loading -> return an error
1089 // Something has been read -> create data model tree
1090 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1091 // aDM->buildTree( aSComp, 0, this );
1094 // Don't return false here, for there might be no data
1095 // for a given component in the study yet
1097 QStringList listOfFiles;
1098 openModuleData(dm->module()->name(), listOfFiles);
1099 if (dm && dm->open(studyName, this, listOfFiles)) {
1100 // Remove the files and temporary directory, created
1101 // for this module by LightApp_Engine_i::Load()
1102 bool isMultiFile = false; // TODO: decide, how to access this parameter
1103 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1105 // Something has been read -> create data model tree
1106 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1108 aDM->update(NULL, this);
1115 Create new study name.
1117 QString SalomeApp_Study::newStudyName() const
1119 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1120 QString prefix( "Study%1" ), newName, curName;
1121 int i = 1, j, n = studies.size();
1122 while ( newName.isEmpty() ){
1123 curName = prefix.arg( i );
1124 for ( j = 0 ; j < n; j++ ){
1125 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1137 Note that this method does not create or activate SalomeApp_Engine_i instance,
1138 therefore it can be called safely for any kind of module, but for full
1139 modules it returns an empty list.
1140 \return list of files used by module: to be used by CORBAless modules
1141 \param theModuleName - name of module
1143 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1145 // Issue 21377 - using separate engine for each type of light module
1146 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1148 return aDefaultEngine->GetListOfFiles(id());
1150 std::vector<std::string> aListOfFiles;
1151 return aListOfFiles;
1155 Sets list of files used by module: to be used by CORBAless modules.
1156 Note that this method does not create or activate SalomeApp_Engine_i instance,
1157 therefore it can be called safely for any kind of module, but for full
1158 modules it simply does nothing.
1159 \param theModuleName - name of module
1160 \param theListOfFiles - list of files
1162 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1163 const std::vector<std::string> theListOfFiles )
1165 // Issue 21377 - using separate engine for each type of light module
1166 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1168 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1172 \return temporary directory for saving files of modules
1174 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1176 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1177 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1182 Removes temporary files
1184 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1189 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1190 if (aListOfFiles.size() > 0) {
1191 std::string aTmpDir = aListOfFiles[0];
1193 const int n = aListOfFiles.size() - 1;
1194 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1196 for (int i = 0; i < n; i++)
1197 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1199 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1203 #ifndef DISABLE_PYCONSOLE
1205 Mark the study as saved in the file
1206 \param theFileName - the name of file
1208 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1210 setStudyName(theFileName);
1211 studyDS()->Name(theFileName.toStdString());
1212 setIsSaved( isSaved );
1216 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1218 LightApp_DataObject* o = 0;
1220 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toLatin1().constData() ) );
1223 o = LightApp_Study::findObjectByEntry( theEntry );
1229 Deletes all references to object
1232 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1234 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1235 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1236 for( int i=0, n=aRefs.size(); i<n; i++ )
1238 _PTR( SObject ) o = aRefs[i];
1239 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1241 sb->RemoveReference( o );
1242 sb->RemoveObjectWithChildren( o );
1248 \return real entry by entry of reference
1249 \param entry - entry of reference object
1251 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1253 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1254 _PTR(SObject) refobj;
1256 if( obj && obj->ReferencedObject( refobj ) )
1257 return refobj->GetID().c_str();
1258 return LightApp_Study::referencedToEntry( entry );
1262 \return component data type for entry
1264 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1266 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1268 return LightApp_Study::componentDataType( entry );
1269 return obj->GetFatherComponent()->ComponentDataType().c_str();
1273 \return true if entry corresponds to component
1275 bool SalomeApp_Study::isComponent( const QString& entry ) const
1277 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1278 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1282 \return entries of object children
1284 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1286 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1287 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1288 anIter->InitEx( true );
1289 while( anIter->More() )
1291 _PTR(SObject) val( anIter->Value() );
1292 child_entries.append( val->GetID().c_str() );
1298 Fills list with components names
1299 \param comp - list to be filled
1301 void SalomeApp_Study::components( QStringList& comps ) const
1303 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1305 _PTR(SComponent) aComponent ( it->Value() );
1306 // skip the magic "Interface Applicative" component
1307 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1308 comps.append( aComponent->ComponentDataType().c_str() );
1313 Get the entry for the given module
1314 \param comp - list to be filled
1315 \return module root's entry
1317 QString SalomeApp_Study::centry( const QString& comp ) const
1320 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1322 _PTR(SComponent) aComponent ( it->Value() );
1323 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1324 e = aComponent->GetID().c_str();
1330 \return a list of saved points' IDs
1332 std::vector<int> SalomeApp_Study::getSavePoints()
1336 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1339 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1340 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1341 for(; anIter->More(); anIter->Next())
1343 _PTR(SObject) val( anIter->Value() );
1344 _PTR(GenericAttribute) genAttr;
1345 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1352 Removes a given save point
1354 void SalomeApp_Study::removeSavePoint(int savePoint)
1356 if(savePoint <= 0) return;
1357 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1358 _PTR(SObject) so = AP->GetSObject();
1359 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1360 builder->RemoveObjectWithChildren(so);
1364 \return a name of save point
1366 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1368 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1369 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1370 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1374 Sets a name of save point
1376 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1378 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1379 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1380 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1384 * \brief Restores the study state
1386 void SalomeApp_Study::restoreState(int savePoint)
1388 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1393 Slot: called on change of a root of a data model. Redefined from CAM_Study
1395 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1397 LightApp_Study::updateModelRoot( dm );
1399 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1400 // it must always be the last one.
1401 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );