1 // Copyright (C) 2007-2015 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));
264 entry2SuitObject[parent_id] = anObj;
267 anID = root_id + obj_id.substr( 0, fin );
268 EntryMapIter it2 = entry2SuitObject.find( anID );
269 if ( it2 == entry2SuitObject.end() ) {
270 //the ID is not known in entry2SuitObject
271 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
273 entry2SuitObject[anID] = anObj;
280 anObj->insertChildAtTag( suit_obj, tag );
283 entry2SuitObject[theID] = suit_obj;
284 } // END: work with study structure
289 EntryMapIter it = entry2SuitObject.find( theID );
290 if ( it != entry2SuitObject.end() )
292 suit_obj = it->second;
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();
470 bool showError = !application()->property("open_study_from_command_line").isValid() ||
471 !application()->property("open_study_from_command_line").toBool();
473 study = _PTR(Study)( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
475 catch(const SALOME_Exception& ex) {
476 application()->putInfo(tr(ex.what()));
478 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
479 tr("ERR_ERROR"), tr(ex.what()));
483 application()->putInfo(tr("CREATE_DOCUMENT_PROBLEM"));
485 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
486 tr("ERR_ERROR"), tr("CREATE_DOCUMENT_PROBLEM"));
494 setStudyName( aName );
497 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
498 #ifdef WITH_SALOMEDS_OBSERVER
499 aRoot->setToSynchronize(false);
503 bool aRet = CAM_Study::createDocument( theStr );
505 #ifdef WITH_SALOMEDS_OBSERVER
506 myObserver = new Observer_i(myStudyDS,this);
507 //attach an observer to the study with notification of modifications
508 myStudyDS->attach(myObserver->_this(),true);
511 emit created( this );
518 \param theFileName - name of file
520 bool SalomeApp_Study::openDocument( const QString& theFileName )
522 MESSAGE( "openDocument" );
524 // initialize myStudyDS, read HDF file
526 bool showError = !application()->property("open_study_from_command_line").isValid() ||
527 !application()->property("open_study_from_command_line").toBool();
529 study = _PTR(Study) ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
531 catch(const SALOME_Exception& ex) {
532 application()->putInfo(tr(ex.what()));
534 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
535 tr("ERR_ERROR"), tr(ex.what()));
539 application()->putInfo(tr("OPEN_DOCUMENT_PROBLEM"));
541 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
542 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
551 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
553 // update loaded data models: call open() and update() on them.
556 QListIterator<CAM_DataModel*> it( dm_s );
557 while ( it.hasNext() )
558 openDataModel( studyName(), it.next() );
560 // this will build a SUIT_DataObject-s tree under myRoot member field
561 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
562 // but tree that corresponds to not-loaded data models will be updated any way.
563 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
565 #ifdef WITH_SALOMEDS_OBSERVER
566 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
567 myObserver = new Observer_i(myStudyDS,this);
568 //attach an observer to the study with notification of modifications
569 myStudyDS->attach(myObserver->_this(),true);
572 bool res = CAM_Study::openDocument( theFileName );
575 study->IsSaved(true);
577 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
579 std::vector<int> savePoints = getSavePoints();
580 if ( savePoints.size() > 0 )
581 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
584 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
589 Connects GUI study to SALOMEDS one already loaded into StudyManager
590 \param theStudyName - name of study
592 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
594 MESSAGE( "loadDocument" );
596 // obtain myStudyDS from StudyManager
597 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
603 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
605 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
607 // update loaded data models: call open() and update() on them.
611 QListIterator<CAM_DataModel*> it( dm_s );
612 while ( it.hasNext() )
613 openDataModel( studyName(), it.next() );
615 // this will build a SUIT_DataObject-s tree under myRoot member field
616 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
617 // but tree that corresponds to not-loaded data models will be updated any way.
618 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
620 #ifdef WITH_SALOMEDS_OBSERVER
621 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
622 myObserver = new Observer_i(myStudyDS,this);
623 //attach an observer to the study with notification of modifications
624 myStudyDS->attach(myObserver->_this(),true);
627 bool res = CAM_Study::openDocument( theStudyName );
629 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
630 // mark study as "not saved" after call openDocument( ... ) method.
634 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
636 std::vector<int> savePoints = getSavePoints();
637 if ( savePoints.size() > 0 )
638 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
641 //SRN: BugID IPAL9021: End
647 \param theFileName - name of file
649 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
651 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
653 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
655 ModelList list; dataModels( list );
657 QListIterator<CAM_DataModel*> it( list );
658 QStringList listOfFiles;
659 while ( it.hasNext() ) {
660 // Cast to LightApp class in order to give a chance
661 // to light modules to save their data
662 if ( LightApp_DataModel* aModel =
663 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
665 aModel->saveAs( theFileName, this, listOfFiles );
666 if ( !listOfFiles.isEmpty() )
667 saveModuleData(aModel->module()->name(), listOfFiles);
671 // save SALOMEDS document
672 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
676 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
677 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
678 bool res = (isAscii ?
679 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
680 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
681 && CAM_Study::saveDocumentAs( theFileName );
683 res = res && saveStudyData(theFileName);
692 Saves previously opened document
694 bool SalomeApp_Study::saveDocument()
696 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
698 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
700 ModelList list; dataModels( list );
702 QListIterator<CAM_DataModel*> it( list );
703 QStringList listOfFiles;
704 while ( it.hasNext() ) {
705 // Cast to LightApp class in order to give a chance
706 // to light modules to save their data
707 if ( LightApp_DataModel* aModel =
708 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
710 aModel->save(listOfFiles);
711 if ( !listOfFiles.isEmpty() )
712 saveModuleData(aModel->module()->name(), listOfFiles);
716 // save SALOMEDS document
717 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
721 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
722 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
723 bool res = (isAscii ?
724 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
725 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
727 res = res && saveStudyData(studyName());
737 void SalomeApp_Study::closeDocument(bool permanently)
739 LightApp_Study::closeDocument(permanently);
741 // close SALOMEDS document
742 _PTR(Study) studyPtr = studyDS();
746 myStudyDS->detach( myObserver->_this() );
748 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
749 bool isBlocked = desk->signalsBlocked();
750 desk->blockSignals( true );
751 SalomeApp_Application::studyMgr()->Close( studyPtr );
752 desk->blockSignals( isBlocked );
753 #ifndef DISABLE_PYCONSOLE
754 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
755 app->getPyInterp()->destroy();
758 SALOMEDSClient_Study* aStudy = 0;
759 setStudyDS( _PTR(Study)(aStudy) );
764 Dump study operation. Writes a Python dump file using
765 SALOMEDS services. Additionally, gives a chance to light modules
766 to participate in dump study operation.
768 \param theFileName - full path to the output Python file
769 \param toPublish - if true, all objects are published in a study
770 by the output script, including those not orignally present
771 in the current study.
772 \param isMultiFile - if true, each module's dump is written into
773 a separate Python file, otherwise a single output file is written
774 \param toSaveGUI - if true, the GUI state is written
776 \return - true if the operation succeeds, and false otherwise.
778 bool SalomeApp_Study::dump( const QString& theFileName,
784 _PTR(AttributeParameter) ap;
785 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
786 _PTR(Study) aStudy = studyDS();
788 if( ip->isDumpPython( aStudy ) )
789 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
791 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
792 ip->setDumpPython( aStudy );
793 //SRN: create a temporary save point
794 savePoint = SalomeApp_VisualState(
795 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
798 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
799 // This is an optional but important step, it gives a chance to light modules
800 // to dump their data as a part of common dump study operation
804 QListIterator<CAM_DataModel*> it( list );
805 QStringList listOfFiles;
806 while ( it.hasNext() ) {
807 if ( LightApp_DataModel* aModel =
808 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
810 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
811 !listOfFiles.isEmpty() )
812 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
813 // This code is shared with persistence mechanism.
814 // NOTE: this should be revised if behavior of saveModuleData() changes!
815 saveModuleData(aModel->module()->name(), listOfFiles);
819 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
820 // any light module is present in the current configuration
821 QFileInfo aFileInfo( theFileName );
822 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
823 aFileInfo.baseName().toUtf8().data(),
827 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
829 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
830 // This code is shared with persistence mechanism.
831 // NOTE: this should be revised if behavior of saveStudyData() changes!
832 saveStudyData( theFileName );
838 \return true, if study is modified in comparison with last open/save
840 bool SalomeApp_Study::isModified() const
842 bool isAnyChanged = studyDS() && studyDS()->IsModified();
844 isAnyChanged = LightApp_Study::isModified();
850 Set study modified to \a on.
852 void SalomeApp_Study::Modified()
854 if(_PTR(Study) aStudy = studyDS())
856 LightApp_Study::Modified();
860 \return if data model is saved
862 bool SalomeApp_Study::isSaved() const
864 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
866 isAllSaved = LightApp_Study::isSaved();
873 \param theModuleName - name of module
874 \param theListOfFiles - list of files to be saved
876 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
878 int aNb = theListOfFiles.count();
882 std::vector<std::string> aListOfFiles ( aNb );
884 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
885 if ( (*it).isEmpty() )
887 aListOfFiles[anIndex] = (*it).toUtf8().data();
890 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
895 \param theModuleName - name of module
896 \param theListOfFiles - list of files to be loaded
898 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
900 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
902 int i, aLength = aListOfFiles.size() - 1;
906 //Get a temporary directory for saved a file
907 theListOfFiles.append(aListOfFiles[0].c_str());
909 for(i = 0; i < aLength; i++)
910 theListOfFiles.append(aListOfFiles[i+1].c_str());
914 Re-implemented from LightApp_Study, actually does not save anything but
915 simply cleans up light modules' data
917 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
919 ModelList list; dataModels( list );
920 QListIterator<CAM_DataModel*> it( list );
921 std::vector<std::string> listOfFiles(0);
922 while ( it.hasNext() ){
923 LightApp_DataModel* aLModel =
924 dynamic_cast<LightApp_DataModel*>( it.next() );
925 // It is safe to call SetListOfFiles() for any kind of module
926 // because SetListOfFiles() does nothing for full modules :)
928 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
936 bool SalomeApp_Study::openStudyData( const QString& theFileName )
944 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
950 Virtual method re-implemented from LightApp_Study in order to create
951 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
953 \param theDataModel - data model instance to create a module object for
954 \param theParent - the module object's parent (normally it's the study root)
955 \return the module object instance
956 \sa LightApp_Study class, LightApp_DataModel class
958 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
959 SUIT_DataObject* theParent ) const
961 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
963 // Ensure that SComponent instance is published in the study for the given module
964 // This line causes automatic creation of SalomeApp_ModuleObject in case if
965 // WITH_SALOMEDS_OBSERVER is defined
966 that->addComponent( theDataModel );
968 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
969 // or by someone else so check if it exists first of all
970 CAM_ModuleObject* res = 0;
972 DataObjectList children = root()->children();
973 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
974 for( ; !res && anIt!=aLast; anIt++ )
976 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
977 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
982 _PTR(Study) aStudy = studyDS();
986 _PTR(SComponent) aComp = aStudy->FindComponent(
987 theDataModel->module()->name().toStdString() );
991 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
1000 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
1002 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
1004 CAM_Study::dataModelInserted(dm);
1006 // addComponent(dm);
1010 Create SComponent for module, using default engine (CORBAless)
1012 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
1014 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1015 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1017 // Check SComponent existance
1018 _PTR(Study) aStudy = studyDS();
1022 std::string aCompDataType = dm->module()->name().toStdString();
1024 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
1026 // Create SComponent
1027 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1028 aComp = aBuilder->NewComponent(aCompDataType);
1029 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1030 QString anIconName = dm->module()->iconName();
1031 if (!anIconName.isEmpty()) {
1032 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1034 anAttr->SetPixMap(anIconName.toStdString());
1037 // Set default engine IOR
1038 // Issue 21377 - using separate engine for each type of light module
1039 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
1041 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
1042 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
1043 SalomeApp_DataModel::synchronize( aComp, this );
1046 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1047 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1048 QString anIconName = dm->module()->iconName();
1049 if (!anIconName.isEmpty()) {
1050 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1052 anAttr->SetPixMap(anIconName.toStdString());
1054 // Set default engine IOR
1062 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1067 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1068 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1069 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
1070 _PTR(SComponent) aSComp;
1072 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1074 // Issue 21377 - using separate engine for each type of light module
1075 std::string aCompDataType = dm->module()->name().toStdString();
1076 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1077 aSComp = aStudy->FindComponent( aCompDataType );
1080 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1082 QString anId = aDM->getRootEntry( this );
1083 if ( anId.isEmpty() )
1084 return true; // Probably nothing to load
1085 anEngine = aDM->getModule()->engineIOR();
1086 if ( anEngine.isEmpty() )
1088 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1092 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1095 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1097 catch( const SALOME::SALOME_Exception& ) {
1098 // Oops, something went wrong while loading -> return an error
1101 // Something has been read -> create data model tree
1102 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1103 // aDM->buildTree( aSComp, 0, this );
1106 // Don't return false here, for there might be no data
1107 // for a given component in the study yet
1109 QStringList listOfFiles;
1110 openModuleData(dm->module()->name(), listOfFiles);
1111 if (dm && dm->open(studyName, this, listOfFiles)) {
1112 // Remove the files and temporary directory, created
1113 // for this module by LightApp_Engine_i::Load()
1114 bool isMultiFile = false; // TODO: decide, how to access this parameter
1115 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1117 // Something has been read -> create data model tree
1118 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1120 aDM->update(NULL, this);
1127 Create new study name.
1129 QString SalomeApp_Study::newStudyName() const
1131 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1132 QString prefix( "Study%1" ), newName, curName;
1133 int i = 1, j, n = studies.size();
1134 while ( newName.isEmpty() ){
1135 curName = prefix.arg( i );
1136 for ( j = 0 ; j < n; j++ ){
1137 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1149 Note that this method does not create or activate SalomeApp_Engine_i instance,
1150 therefore it can be called safely for any kind of module, but for full
1151 modules it returns an empty list.
1152 \return list of files used by module: to be used by CORBAless modules
1153 \param theModuleName - name of module
1155 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1157 // Issue 21377 - using separate engine for each type of light module
1158 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1160 return aDefaultEngine->GetListOfFiles(id());
1162 std::vector<std::string> aListOfFiles;
1163 return aListOfFiles;
1167 Sets list of files used by module: to be used by CORBAless modules.
1168 Note that this method does not create or activate SalomeApp_Engine_i instance,
1169 therefore it can be called safely for any kind of module, but for full
1170 modules it simply does nothing.
1171 \param theModuleName - name of module
1172 \param theListOfFiles - list of files
1174 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1175 const std::vector<std::string> theListOfFiles )
1177 // Issue 21377 - using separate engine for each type of light module
1178 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1180 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1184 \return temporary directory for saving files of modules
1186 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1188 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1189 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1194 Removes temporary files
1196 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1201 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1202 if (aListOfFiles.size() > 0) {
1203 std::string aTmpDir = aListOfFiles[0];
1205 const int n = aListOfFiles.size() - 1;
1206 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1208 for (int i = 0; i < n; i++)
1209 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1211 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1215 #ifndef DISABLE_PYCONSOLE
1217 Mark the study as saved in the file
1218 \param theFileName - the name of file
1220 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1222 setStudyName(theFileName);
1223 studyDS()->Name(theFileName.toStdString());
1224 setIsSaved( isSaved );
1228 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1230 LightApp_DataObject* o = 0;
1232 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toLatin1().constData() ) );
1235 o = LightApp_Study::findObjectByEntry( theEntry );
1241 Deletes all references to object
1244 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1246 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1247 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1248 for( int i=0, n=aRefs.size(); i<n; i++ )
1250 _PTR( SObject ) o = aRefs[i];
1251 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1253 sb->RemoveReference( o );
1254 sb->RemoveObjectWithChildren( o );
1260 \return real entry by entry of reference
1261 \param entry - entry of reference object
1263 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1265 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1266 _PTR(SObject) refobj;
1268 if( obj && obj->ReferencedObject( refobj ) )
1269 return refobj->GetID().c_str();
1270 return LightApp_Study::referencedToEntry( entry );
1274 \return component data type for entry
1276 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1278 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1280 return LightApp_Study::componentDataType( entry );
1281 return obj->GetFatherComponent()->ComponentDataType().c_str();
1285 \return true if entry corresponds to component
1287 bool SalomeApp_Study::isComponent( const QString& entry ) const
1289 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1290 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1294 \return entries of object children
1296 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1298 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1299 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1300 anIter->InitEx( true );
1301 while( anIter->More() )
1303 _PTR(SObject) val( anIter->Value() );
1304 child_entries.append( val->GetID().c_str() );
1310 Fills list with components names
1311 \param comp - list to be filled
1313 void SalomeApp_Study::components( QStringList& comps ) const
1315 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1317 _PTR(SComponent) aComponent ( it->Value() );
1318 // skip the magic "Interface Applicative" component
1319 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1320 comps.append( aComponent->ComponentDataType().c_str() );
1325 Get the entry for the given module
1326 \param comp - list to be filled
1327 \return module root's entry
1329 QString SalomeApp_Study::centry( const QString& comp ) const
1332 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1334 _PTR(SComponent) aComponent ( it->Value() );
1335 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1336 e = aComponent->GetID().c_str();
1342 \return a list of saved points' IDs
1344 std::vector<int> SalomeApp_Study::getSavePoints()
1348 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1351 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1352 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1353 for(; anIter->More(); anIter->Next())
1355 _PTR(SObject) val( anIter->Value() );
1356 _PTR(GenericAttribute) genAttr;
1357 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1364 Removes a given save point
1366 void SalomeApp_Study::removeSavePoint(int savePoint)
1368 if(savePoint <= 0) return;
1369 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1370 _PTR(SObject) so = AP->GetSObject();
1371 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1372 builder->RemoveObjectWithChildren(so);
1376 \return a name of save point
1378 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1380 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1381 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1382 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1386 Sets a name of save point
1388 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1390 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1391 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1392 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1396 * \brief Restores the study state
1398 void SalomeApp_Study::restoreState(int savePoint)
1400 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1405 Slot: called on change of a root of a data model. Redefined from CAM_Study
1407 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1409 LightApp_Study::updateModelRoot( dm );
1411 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1412 // it must always be the last one.
1413 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );