1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #ifndef DISABLE_PYCONSOLE
24 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
27 #include "SalomeApp_Study.h"
29 #include "SalomeApp_Module.h"
30 #include "SalomeApp_DataObject.h"
31 #include "SalomeApp_DataModel.h"
32 #include "SalomeApp_Application.h"
33 #include "SalomeApp_Engine_i.h"
34 #include "SalomeApp_VisualState.h"
36 // temporary commented
37 //#include <OB_Browser.h>
39 #include <QCoreApplication>
42 #include "SALOME_Event.h"
43 #include "Basics_Utils.hxx"
45 #include <SUIT_ResourceMgr.h>
46 #include <SUIT_TreeModel.h>
47 #include <SUIT_DataBrowser.h>
48 #include <SUIT_MessageBox.h>
49 #include <SUIT_Session.h>
50 #include <SUIT_Desktop.h>
52 #include <LightApp_Displayer.h>
54 #include "utilities.h"
56 #include "SALOMEDS_Tool.hxx"
58 #include "SALOMEDSClient_ClientFactory.hxx"
60 #include <SALOMEconfig.h>
61 #include CORBA_SERVER_HEADER(SALOME_Exception)
63 //#define NOTIFY_BY_EVENT
65 class ObserverEvent : public QEvent
68 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
78 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
80 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
81 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
85 Observer_i(_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 // MESSAGE("myStudy: " << myStudy->id() << " app " << app);
165 // MESSAGE("objectBrowser: "<< app->objectBrowser());
166 if (!app->objectBrowser()) {
167 MESSAGE("Object Browser not found. Problem ??");
170 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
171 model->forgetObject( suit_obj );
173 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
174 oldFatherSA->updateItem();
179 suit_obj = new SalomeApp_DataObject(aSObj);
180 entry2SuitObject[theID] = suit_obj;
183 suit_obj->updateItem();
184 // define position in the data tree (in aFatherDO) to insert the aSObj
186 //int childDataObjCount = aFatherDO->childCount();
187 _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
188 for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
189 if (aUseCaseIter->Value()->GetID() == theID) {
195 aFatherDO->insertChildAtPos(suit_obj, pos);
196 //aFatherDO->insertChild(suit_obj, pos);
197 aFatherDO->updateItem();
199 /* Define visibility state */
200 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
201 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
202 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
203 if (!moduleTitle.isEmpty()) {
204 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
206 if(aDisplayer->canBeDisplayed(theID.c_str())) {
207 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState ); //hide the just added object
208 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
211 //MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
215 } // END: work with tree nodes structure
216 else { // BEGIN: work with study structure
217 EntryMapIter it = entry2SuitObject.find( theID );
218 if ( it != entry2SuitObject.end() ) {
219 MESSAGE("Entry " << theID << " is already added. Problem ??");
223 int last2Pnt_pos = theID.rfind( ":" );
224 std::string parent_id = theID.substr( 0, last2Pnt_pos );
225 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
227 if ( parent_id.length() == 3 ) // "0:1" - root item?
229 // It's probably a SComponent
230 if ( theID == aSComp->GetID() )
231 suit_obj = new SalomeApp_ModuleObject( aSComp );
233 suit_obj = new SalomeApp_DataObject( aSObj );
237 suit_obj = new SalomeApp_DataObject( aSObj );
240 it = entry2SuitObject.find( parent_id );
241 if ( it != entry2SuitObject.end() ) {
242 SalomeApp_DataObject* father = it->second;
243 father->insertChildAtTag( suit_obj, tag );
246 if ( parent_id.length() == 3 ) // "0:1" - root item?
248 // This should be for a module
249 SUIT_DataObject* father=myStudy->root();
250 father->appendChild(suit_obj);
254 MESSAGE("SHOULD NEVER GET HERE!!!");
256 //Try to find the SalomeApp_DataObject object parent
257 std::string root_id = parent_id.substr( 0, 4 );
258 std::string obj_id = parent_id.substr( 4 );
261 std::string::size_type debut = 0;
262 std::string::size_type fin;
263 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
265 fin = obj_id.find_first_of( ':', debut );
266 if ( fin == std::string::npos ) {
268 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
270 entry2SuitObject[parent_id] = anObj;
273 anID = root_id + obj_id.substr( 0, fin );
274 EntryMapIter it2 = entry2SuitObject.find( anID );
275 if ( it2 == entry2SuitObject.end() ) {
276 //the ID is not known in entry2SuitObject
277 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
279 entry2SuitObject[anID] = anObj;
286 anObj->insertChildAtTag( suit_obj, tag );
289 entry2SuitObject[theID] = suit_obj;
290 } // END: work with study structure
295 EntryMapIter it = entry2SuitObject.find( theID );
296 if ( it != entry2SuitObject.end() )
298 suit_obj = it->second;
299 suit_obj->updateItem();
300 SUIT_DataObject* father=suit_obj->parent();
302 father->removeChild(suit_obj);
303 entry2SuitObject.erase(it);
307 MESSAGE("Want to remove an unknown object" << theID);
313 //MESSAGE("Want to modify an object " << theID);
314 EntryMapIter it = entry2SuitObject.find( theID );
315 if ( it != entry2SuitObject.end() )
317 suit_obj = it->second;
318 suit_obj->updateItem();
322 MESSAGE("Want to modify an unknown object" << theID);
326 case 5: //IOR of the object modified
328 EntryMapIter it = entry2SuitObject.find( theID );
329 if ( it != entry2SuitObject.end() )
330 suit_obj = it->second;
332 /* Define visibility state */
333 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
334 if ( suit_obj && !isComponent ) {
335 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
336 if (!moduleTitle.isEmpty()) {
337 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
339 if(aDisplayer->canBeDisplayed(theID.c_str())) {
340 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
341 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
344 //MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
350 #ifndef DISABLE_PYCONSOLE
351 case 6: //NoteBook variables were modified
353 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
357 default:MESSAGE("Unknown event: " << event);break;
359 } //notifyObserverID_real
364 entry2SuitObject.clear();
365 SUIT_DataObject* o = myStudy->root();
367 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
369 std::string entry = so->entry().toLatin1().constData();
371 entry2SuitObject[entry] = so;
373 if ( o->childCount() > 0 ) {
374 // parse the children
377 else if ( o->nextBrother() > 0 ) {
378 o = o->nextBrother();
381 // step to the next appropriate parent
384 if ( o->nextBrother() ) {
385 o = o->nextBrother();
395 _PTR(Study) myStudyDS;
396 SalomeApp_Study* myStudy;
397 EntryMap entry2SuitObject;
404 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
405 : LightApp_Study( app ), myObserver( 0 )
412 SalomeApp_Study::~SalomeApp_Study()
415 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
416 myObserver->_default_POA()->deactivate_object( oid.in() );
420 #ifndef DISABLE_PYCONSOLE
421 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
423 emit notebookVarUpdated( theVarName );
430 int SalomeApp_Study::id() const
434 id = studyDS()->StudyId();
441 QString SalomeApp_Study::studyName() const
443 // redefined from SUIT_Study to update study name properly since
444 // it can be changed outside of GUI
445 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
447 QString newName = QString::fromUtf8(studyDS()->Name().c_str());
448 if ( LightApp_Study::studyName() != newName ) {
449 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
450 that->setStudyName( newName );
451 ((SalomeApp_Application*)application())->updateDesktopTitle();
454 return LightApp_Study::studyName();
458 Gets studyDS pointer.
460 _PTR(Study) SalomeApp_Study::studyDS() const
468 bool SalomeApp_Study::createDocument( const QString& theStr )
470 MESSAGE( "createDocument" );
472 // initialize myStudyDS, read HDF file
473 QString aName = newStudyName();
476 bool showError = !application()->property("open_study_from_command_line").isValid() ||
477 !application()->property("open_study_from_command_line").toBool();
479 study = _PTR(Study)( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
481 catch(const SALOME_Exception& ex) {
482 application()->putInfo(tr(ex.what()));
484 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
485 tr("ERR_ERROR"), tr(ex.what()));
489 application()->putInfo(tr("CREATE_DOCUMENT_PROBLEM"));
491 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
492 tr("ERR_ERROR"), tr("CREATE_DOCUMENT_PROBLEM"));
500 setStudyName( aName );
503 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
504 #ifdef WITH_SALOMEDS_OBSERVER
505 aRoot->setToSynchronize(false);
509 bool aRet = CAM_Study::createDocument( theStr );
511 #ifdef WITH_SALOMEDS_OBSERVER
512 myObserver = new Observer_i(myStudyDS,this);
513 //attach an observer to the study with notification of modifications
514 myStudyDS->attach(myObserver->_this(),true);
517 emit created( this );
524 \param theFileName - name of file
526 bool SalomeApp_Study::openDocument( const QString& theFileName )
528 MESSAGE( "openDocument" );
530 // initialize myStudyDS, read HDF file
532 bool showError = !application()->property("open_study_from_command_line").isValid() ||
533 !application()->property("open_study_from_command_line").toBool();
535 study = _PTR(Study) ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
537 catch(const SALOME_Exception& ex) {
538 application()->putInfo(tr(ex.what()));
540 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
541 tr("ERR_ERROR"), tr(ex.what()));
545 application()->putInfo(tr("OPEN_DOCUMENT_PROBLEM"));
547 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
548 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
557 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
559 // update loaded data models: call open() and update() on them.
562 QListIterator<CAM_DataModel*> it( dm_s );
563 while ( it.hasNext() )
564 openDataModel( studyName(), it.next() );
566 // this will build a SUIT_DataObject-s tree under myRoot member field
567 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
568 // but tree that corresponds to not-loaded data models will be updated any way.
569 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
571 #ifdef WITH_SALOMEDS_OBSERVER
572 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
573 myObserver = new Observer_i(myStudyDS,this);
574 //attach an observer to the study with notification of modifications
575 myStudyDS->attach(myObserver->_this(),true);
578 bool res = CAM_Study::openDocument( theFileName );
581 study->IsSaved(true);
583 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
585 std::vector<int> savePoints = getSavePoints();
586 if ( savePoints.size() > 0 )
587 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
590 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
595 Connects GUI study to SALOMEDS one already loaded into StudyManager
596 \param theStudyName - name of study
598 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
600 MESSAGE( "loadDocument" );
602 // obtain myStudyDS from StudyManager
603 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
609 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
611 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
613 // update loaded data models: call open() and update() on them.
617 QListIterator<CAM_DataModel*> it( dm_s );
618 while ( it.hasNext() )
619 openDataModel( studyName(), it.next() );
621 // this will build a SUIT_DataObject-s tree under myRoot member field
622 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
623 // but tree that corresponds to not-loaded data models will be updated any way.
624 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
626 #ifdef WITH_SALOMEDS_OBSERVER
627 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
628 myObserver = new Observer_i(myStudyDS,this);
629 //attach an observer to the study with notification of modifications
630 myStudyDS->attach(myObserver->_this(),true);
633 bool res = CAM_Study::openDocument( theStudyName );
635 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
636 // mark study as "not saved" after call openDocument( ... ) method.
640 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
642 std::vector<int> savePoints = getSavePoints();
643 if ( savePoints.size() > 0 )
644 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
647 //SRN: BugID IPAL9021: End
653 \param theFileName - name of file
655 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
657 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
659 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
661 ModelList list; dataModels( list );
663 QListIterator<CAM_DataModel*> it( list );
664 QStringList listOfFiles;
665 while ( it.hasNext() ) {
666 // Cast to LightApp class in order to give a chance
667 // to light modules to save their data
668 if ( LightApp_DataModel* aModel =
669 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
671 aModel->saveAs( theFileName, this, listOfFiles );
672 if ( !listOfFiles.isEmpty() )
673 saveModuleData(aModel->module()->name(), listOfFiles);
677 // save SALOMEDS document
678 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
682 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
683 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
684 bool res = (isAscii ?
685 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
686 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
687 && CAM_Study::saveDocumentAs( theFileName );
689 res = res && saveStudyData(theFileName);
698 Saves previously opened document
700 bool SalomeApp_Study::saveDocument()
702 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
704 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
706 ModelList list; dataModels( list );
708 QListIterator<CAM_DataModel*> it( list );
709 QStringList listOfFiles;
710 while ( it.hasNext() ) {
711 // Cast to LightApp class in order to give a chance
712 // to light modules to save their data
713 if ( LightApp_DataModel* aModel =
714 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
716 aModel->save(listOfFiles);
717 if ( !listOfFiles.isEmpty() )
718 saveModuleData(aModel->module()->name(), listOfFiles);
722 // save SALOMEDS document
723 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
727 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
728 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
729 bool res = (isAscii ?
730 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
731 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
733 res = res && saveStudyData(studyName());
743 void SalomeApp_Study::closeDocument(bool permanently)
745 LightApp_Study::closeDocument(permanently);
747 // close SALOMEDS document
748 _PTR(Study) studyPtr = studyDS();
752 myStudyDS->detach( myObserver->_this() );
754 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
755 bool isBlocked = desk->signalsBlocked();
756 desk->blockSignals( true );
757 SalomeApp_Application::studyMgr()->Close( studyPtr );
758 desk->blockSignals( isBlocked );
759 #ifndef DISABLE_PYCONSOLE
760 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
761 app->getPyInterp()->destroy();
764 SALOMEDSClient_Study* aStudy = 0;
765 setStudyDS( _PTR(Study)(aStudy) );
770 Dump study operation. Writes a Python dump file using
771 SALOMEDS services. Additionally, gives a chance to light modules
772 to participate in dump study operation.
774 \param theFileName - full path to the output Python file
775 \param toPublish - if true, all objects are published in a study
776 by the output script, including those not orignally present
777 in the current study.
778 \param isMultiFile - if true, each module's dump is written into
779 a separate Python file, otherwise a single output file is written
780 \param toSaveGUI - if true, the GUI state is written
782 \return - true if the operation succeeds, and false otherwise.
784 bool SalomeApp_Study::dump( const QString& theFileName,
790 _PTR(AttributeParameter) ap;
791 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
792 _PTR(Study) aStudy = studyDS();
794 if( ip->isDumpPython( aStudy ) )
795 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
797 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
798 ip->setDumpPython( aStudy );
799 //SRN: create a temporary save point
800 savePoint = SalomeApp_VisualState(
801 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
804 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
805 // This is an optional but important step, it gives a chance to light modules
806 // to dump their data as a part of common dump study operation
810 QListIterator<CAM_DataModel*> it( list );
811 QStringList listOfFiles;
812 while ( it.hasNext() ) {
813 if ( LightApp_DataModel* aModel =
814 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
816 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
817 !listOfFiles.isEmpty() )
818 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
819 // This code is shared with persistence mechanism.
820 // NOTE: this should be revised if behavior of saveModuleData() changes!
821 saveModuleData(aModel->module()->name(), listOfFiles);
825 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
826 // any light module is present in the current configuration
827 QFileInfo aFileInfo( theFileName );
828 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
829 aFileInfo.baseName().toUtf8().data(),
833 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
835 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
836 // This code is shared with persistence mechanism.
837 // NOTE: this should be revised if behavior of saveStudyData() changes!
838 saveStudyData( theFileName );
844 \return true, if study is modified in comparison with last open/save
846 bool SalomeApp_Study::isModified() const
848 bool isAnyChanged = studyDS() && studyDS()->IsModified();
850 isAnyChanged = LightApp_Study::isModified();
856 Set study modified to \a on.
858 void SalomeApp_Study::Modified()
860 if(_PTR(Study) aStudy = studyDS())
862 LightApp_Study::Modified();
866 \return if data model is saved
868 bool SalomeApp_Study::isSaved() const
870 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
872 isAllSaved = LightApp_Study::isSaved();
879 \param theModuleName - name of module
880 \param theListOfFiles - list of files to be saved
882 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
884 int aNb = theListOfFiles.count();
888 std::vector<std::string> aListOfFiles ( aNb );
890 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
891 if ( (*it).isEmpty() )
893 aListOfFiles[anIndex] = (*it).toUtf8().data();
896 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
901 \param theModuleName - name of module
902 \param theListOfFiles - list of files to be loaded
904 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
906 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
908 int i, aLength = aListOfFiles.size() - 1;
912 //Get a temporary directory for saved a file
913 theListOfFiles.append(aListOfFiles[0].c_str());
915 for(i = 0; i < aLength; i++)
916 theListOfFiles.append(aListOfFiles[i+1].c_str());
920 Re-implemented from LightApp_Study, actually does not save anything but
921 simply cleans up light modules' data
923 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
925 ModelList list; dataModels( list );
926 QListIterator<CAM_DataModel*> it( list );
927 std::vector<std::string> listOfFiles(0);
928 while ( it.hasNext() ){
929 LightApp_DataModel* aLModel =
930 dynamic_cast<LightApp_DataModel*>( it.next() );
931 // It is safe to call SetListOfFiles() for any kind of module
932 // because SetListOfFiles() does nothing for full modules :)
934 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
942 bool SalomeApp_Study::openStudyData( const QString& theFileName )
950 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
956 Virtual method re-implemented from LightApp_Study in order to create
957 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
959 \param theDataModel - data model instance to create a module object for
960 \param theParent - the module object's parent (normally it's the study root)
961 \return the module object instance
962 \sa LightApp_Study class, LightApp_DataModel class
964 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
965 SUIT_DataObject* theParent ) const
967 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
969 // Ensure that SComponent instance is published in the study for the given module
970 // This line causes automatic creation of SalomeApp_ModuleObject in case if
971 // WITH_SALOMEDS_OBSERVER is defined
972 that->addComponent( theDataModel );
974 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
975 // or by someone else so check if it exists first of all
976 CAM_ModuleObject* res = 0;
978 DataObjectList children = root()->children();
979 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
980 for( ; !res && anIt!=aLast; anIt++ )
982 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
983 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
988 _PTR(Study) aStudy = studyDS();
992 _PTR(SComponent) aComp = aStudy->FindComponent(
993 theDataModel->module()->name().toStdString() );
997 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
1006 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
1008 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
1010 CAM_Study::dataModelInserted(dm);
1012 // addComponent(dm);
1016 Create SComponent for module, using default engine (CORBAless)
1018 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
1020 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1021 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1023 // Check SComponent existance
1024 _PTR(Study) aStudy = studyDS();
1028 std::string aCompDataType = dm->module()->name().toStdString();
1030 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
1032 // Create SComponent
1033 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1034 aComp = aBuilder->NewComponent(aCompDataType);
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());
1043 // Set default engine IOR
1044 // Issue 21377 - using separate engine for each type of light module
1045 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
1047 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
1048 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
1049 SalomeApp_DataModel::synchronize( aComp, this );
1052 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1053 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1054 QString anIconName = dm->module()->iconName();
1055 if (!anIconName.isEmpty()) {
1056 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1058 anAttr->SetPixMap(anIconName.toStdString());
1060 // Set default engine IOR
1068 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1073 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1074 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1075 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
1076 _PTR(SComponent) aSComp;
1078 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1080 // Issue 21377 - using separate engine for each type of light module
1081 std::string aCompDataType = dm->module()->name().toStdString();
1082 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1083 aSComp = aStudy->FindComponent( aCompDataType );
1086 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1088 QString anId = aDM->getRootEntry( this );
1089 if ( anId.isEmpty() )
1090 return true; // Probably nothing to load
1091 anEngine = aDM->getModule()->engineIOR();
1092 if ( anEngine.isEmpty() )
1094 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1098 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1101 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1103 catch( const SALOME::SALOME_Exception& ) {
1104 // Oops, something went wrong while loading -> return an error
1107 // Something has been read -> create data model tree
1108 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1109 // aDM->buildTree( aSComp, 0, this );
1112 // Don't return false here, for there might be no data
1113 // for a given component in the study yet
1115 QStringList listOfFiles;
1116 openModuleData(dm->module()->name(), listOfFiles);
1117 if (dm && dm->open(studyName, this, listOfFiles)) {
1118 // Remove the files and temporary directory, created
1119 // for this module by LightApp_Engine_i::Load()
1120 bool isMultiFile = false; // TODO: decide, how to access this parameter
1121 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1123 // Something has been read -> create data model tree
1124 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1126 aDM->update(NULL, this);
1133 Create new study name.
1135 QString SalomeApp_Study::newStudyName() const
1137 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1138 QString prefix( "Study%1" ), newName, curName;
1139 int i = 1, j, n = studies.size();
1140 while ( newName.isEmpty() ){
1141 curName = prefix.arg( i );
1142 for ( j = 0 ; j < n; j++ ){
1143 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1155 Note that this method does not create or activate SalomeApp_Engine_i instance,
1156 therefore it can be called safely for any kind of module, but for full
1157 modules it returns an empty list.
1158 \return list of files used by module: to be used by CORBAless modules
1159 \param theModuleName - name of module
1161 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1163 // Issue 21377 - using separate engine for each type of light module
1164 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1166 return aDefaultEngine->GetListOfFiles(id());
1168 std::vector<std::string> aListOfFiles;
1169 return aListOfFiles;
1173 Sets list of files used by module: to be used by CORBAless modules.
1174 Note that this method does not create or activate SalomeApp_Engine_i instance,
1175 therefore it can be called safely for any kind of module, but for full
1176 modules it simply does nothing.
1177 \param theModuleName - name of module
1178 \param theListOfFiles - list of files
1180 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1181 const std::vector<std::string> theListOfFiles )
1183 // Issue 21377 - using separate engine for each type of light module
1184 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1186 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1190 \return temporary directory for saving files of modules
1192 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1194 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1195 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1200 Removes temporary files
1202 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1207 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1208 if (aListOfFiles.size() > 0) {
1209 std::string aTmpDir = aListOfFiles[0];
1211 const int n = aListOfFiles.size() - 1;
1212 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1214 for (int i = 0; i < n; i++)
1215 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1217 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1221 #ifndef DISABLE_PYCONSOLE
1223 Mark the study as saved in the file
1224 \param theFileName - the name of file
1226 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1228 setStudyName(theFileName);
1229 studyDS()->Name(theFileName.toStdString());
1230 setIsSaved( isSaved );
1234 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1236 LightApp_DataObject* o = 0;
1238 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toLatin1().constData() ) );
1241 o = LightApp_Study::findObjectByEntry( theEntry );
1247 Deletes all references to object
1250 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1252 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1253 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1254 for( int i=0, n=aRefs.size(); i<n; i++ )
1256 _PTR( SObject ) o = aRefs[i];
1257 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1259 sb->RemoveReference( o );
1260 sb->RemoveObjectWithChildren( o );
1266 \return real entry by entry of reference
1267 \param entry - entry of reference object
1269 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1271 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1272 _PTR(SObject) refobj;
1274 if( obj && obj->ReferencedObject( refobj ) )
1275 return refobj->GetID().c_str();
1276 return LightApp_Study::referencedToEntry( entry );
1280 \return component data type for entry
1282 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1284 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1286 return LightApp_Study::componentDataType( entry );
1287 return obj->GetFatherComponent()->ComponentDataType().c_str();
1291 \return true if entry corresponds to component
1293 bool SalomeApp_Study::isComponent( const QString& entry ) const
1295 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1296 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1300 \return entries of object children
1302 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1304 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1305 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1306 anIter->InitEx( true );
1307 while( anIter->More() )
1309 _PTR(SObject) val( anIter->Value() );
1310 child_entries.append( val->GetID().c_str() );
1316 Fills list with components names
1317 \param comp - list to be filled
1319 void SalomeApp_Study::components( QStringList& comps ) const
1321 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1323 _PTR(SComponent) aComponent ( it->Value() );
1324 // skip the magic "Interface Applicative" component
1325 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1326 comps.append( aComponent->ComponentDataType().c_str() );
1331 Get the entry for the given module
1332 \param comp - list to be filled
1333 \return module root's entry
1335 QString SalomeApp_Study::centry( const QString& comp ) const
1338 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1340 _PTR(SComponent) aComponent ( it->Value() );
1341 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1342 e = aComponent->GetID().c_str();
1348 \return a list of saved points' IDs
1350 std::vector<int> SalomeApp_Study::getSavePoints()
1354 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1357 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1358 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1359 for(; anIter->More(); anIter->Next())
1361 _PTR(SObject) val( anIter->Value() );
1362 _PTR(GenericAttribute) genAttr;
1363 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1370 Removes a given save point
1372 void SalomeApp_Study::removeSavePoint(int savePoint)
1374 if(savePoint <= 0) return;
1375 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1376 _PTR(SObject) so = AP->GetSObject();
1377 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1378 builder->RemoveObjectWithChildren(so);
1382 \return a name of save point
1384 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1386 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1387 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1388 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1392 Sets a name of save point
1394 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1396 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1397 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1398 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1402 * \brief Restores the study state
1404 void SalomeApp_Study::restoreState(int savePoint)
1406 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1411 Slot: called on change of a root of a data model. Redefined from CAM_Study
1413 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1415 LightApp_Study::updateModelRoot( dm );
1417 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1418 // it must always be the last one.
1419 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );