1 // Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #ifndef DISABLE_PYCONSOLE
24 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
27 #include "SalomeApp_Study.h"
29 #include "SalomeApp_Module.h"
30 #include "SalomeApp_DataObject.h"
31 #include "SalomeApp_DataModel.h"
32 #include "SalomeApp_Application.h"
33 #include "SalomeApp_Engine_i.h"
34 #include "SalomeApp_VisualState.h"
36 // temporary commented
37 //#include <OB_Browser.h>
39 #include <QCoreApplication>
42 #include "SALOME_Event.h"
43 #include "Basics_Utils.hxx"
45 #include <SUIT_ResourceMgr.h>
46 #include <SUIT_TreeModel.h>
47 #include <SUIT_DataBrowser.h>
48 #include <SUIT_MessageBox.h>
49 #include <SUIT_Session.h>
50 #include <SUIT_Desktop.h>
52 #include <LightApp_Displayer.h>
54 #include "utilities.h"
56 #include "SALOMEDS_Tool.hxx"
58 #include "SALOMEDSClient_ClientFactory.hxx"
60 #include <SALOMEconfig.h>
61 #include CORBA_SERVER_HEADER(SALOME_Exception)
63 //#define NOTIFY_BY_EVENT
65 class ObserverEvent : public QEvent
68 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
78 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
80 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
81 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
85 Observer_i( SalomeApp_Study* aStudy):QObject(aStudy)
91 SUIT_DataObject* findObject( const char* theID ) const
93 EntryMap::const_iterator it = entry2SuitObject.find( theID );
94 return it != entry2SuitObject.end() ? it->second : 0;
97 virtual void notifyObserverID(const char* theID, CORBA::Long event)
99 #ifdef NOTIFY_BY_EVENT
100 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
102 notifyObserverID_real(theID,event);
106 virtual bool event(QEvent *event)
108 if (event->type() == QEvent::User )
110 //START_TIMING(notify);
111 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
112 //END_TIMING(notify,100);
117 void notifyObserverID_real(const std::string& theID, long event)
119 SalomeApp_DataObject* suit_obj = 0;
124 _PTR(SObject) aSObj = SalomeApp_Application::getStudy()->FindObjectID(theID);
125 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
127 if (!aSComp || aSComp->IsNull()) {
128 MESSAGE("Entry " << theID << " has not father component. Problem ??");
132 // Mantis issue 0020136: Drag&Drop in OB
133 _PTR(UseCaseBuilder) aUseCaseBuilder = SalomeApp_Application::getStudy()->GetUseCaseBuilder();
134 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
135 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
136 // tree node is not yet set, it is a normal situation
140 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
141 if (!aFatherSO || aFatherSO->IsNull()) {
142 MESSAGE("Father SObject is not found. Problem ??");
146 std::string parent_id = aFatherSO->GetID();
147 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
149 if (it == entry2SuitObject.end()) {
150 MESSAGE("Father data object is not found. Problem ??");
154 SalomeApp_DataObject* aFatherDO = it->second;
156 it = entry2SuitObject.find(theID);
157 if (it != entry2SuitObject.end()) { // this SOobject is already added somewhere
158 suit_obj = it->second;
159 SUIT_DataObject* oldFather = suit_obj->parent();
161 oldFather->removeChild(suit_obj, false);
162 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
163 // MESSAGE("myStudy: " << myStudy->id() << " app " << app);
164 // MESSAGE("objectBrowser: "<< app->objectBrowser());
165 if (!app->objectBrowser()) {
166 MESSAGE("Object Browser not found. Problem ??");
169 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
170 model->forgetObject( suit_obj );
172 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
173 oldFatherSA->updateItem();
178 suit_obj = new SalomeApp_DataObject(aSObj);
179 entry2SuitObject[theID] = suit_obj;
182 suit_obj->updateItem();
183 // define position in the data tree (in aFatherDO) to insert the aSObj
184 int pos = aUseCaseBuilder->GetIndexInFather(aFatherSO, aSObj);
186 aFatherDO->insertChildAtPos(suit_obj, pos);
187 //aFatherDO->insertChild(suit_obj, pos);
188 aFatherDO->updateItem();
190 /* Define visibility state */
191 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
192 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
193 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
194 if (!moduleTitle.isEmpty()) {
195 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
197 if(aDisplayer->canBeDisplayed(theID.c_str())) {
198 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState ); //hide the just added object
199 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
202 //MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
206 } // END: work with tree nodes structure
207 else { // BEGIN: work with study structure
208 EntryMapIter it = entry2SuitObject.find( theID );
209 if ( it != entry2SuitObject.end() ) {
210 MESSAGE("Entry " << theID << " is already added. Problem ??");
214 int last2Pnt_pos = (int)theID.rfind( ":" ); //!< TODO: conversion from size_t to int
215 std::string parent_id = theID.substr( 0, last2Pnt_pos );
216 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
218 if ( parent_id.length() == 3 ) // "0:1" - root item?
220 // It's probably a SComponent
221 if ( theID == aSComp->GetID() )
222 suit_obj = new SalomeApp_ModuleObject( aSComp );
224 suit_obj = new SalomeApp_DataObject( aSObj );
228 suit_obj = new SalomeApp_DataObject( aSObj );
231 it = entry2SuitObject.find( parent_id );
232 if ( it != entry2SuitObject.end() ) {
233 SalomeApp_DataObject* father = it->second;
234 father->insertChildAtTag( suit_obj, tag );
237 if ( parent_id.length() == 3 ) // "0:1" - root item?
239 // This should be for a module
240 SUIT_DataObject* father=myStudy->root();
241 father->appendChild(suit_obj);
245 MESSAGE("SHOULD NEVER GET HERE!!!");
247 //Try to find the SalomeApp_DataObject object parent
248 std::string root_id = parent_id.substr( 0, 4 );
249 std::string obj_id = parent_id.substr( 4 );
252 std::string::size_type debut = 0;
253 std::string::size_type fin;
254 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
256 fin = obj_id.find_first_of( ':', debut );
257 if ( fin == std::string::npos ) {
259 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
261 entry2SuitObject[parent_id] = anObj;
264 anID = root_id + obj_id.substr( 0, fin );
265 EntryMapIter it2 = entry2SuitObject.find( anID );
266 if ( it2 == entry2SuitObject.end() ) {
267 //the ID is not known in entry2SuitObject
268 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
270 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 suit_obj->updateItem();
291 SUIT_DataObject* father=suit_obj->parent();
293 father->removeChild(suit_obj);
294 entry2SuitObject.erase(it);
298 MESSAGE("Want to remove an unknown object" << theID);
304 //MESSAGE("Want to modify an object " << theID);
305 EntryMapIter it = entry2SuitObject.find( theID );
306 if ( it != entry2SuitObject.end() )
308 suit_obj = it->second;
309 suit_obj->updateItem();
313 MESSAGE("Want to modify an unknown object" << theID);
317 case 5: //IOR of the object modified
319 EntryMapIter it = entry2SuitObject.find( theID );
320 if ( it != entry2SuitObject.end() )
321 suit_obj = it->second;
323 /* Define visibility state */
324 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
325 if ( suit_obj && !isComponent ) {
326 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
327 if (!moduleTitle.isEmpty()) {
328 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
330 if(aDisplayer->canBeDisplayed(theID.c_str())) {
331 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
332 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
335 //MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
341 #ifndef DISABLE_PYCONSOLE
342 case 6: //NoteBook variables were modified
344 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
348 default:MESSAGE("Unknown event: " << event);break;
350 } //notifyObserverID_real
355 entry2SuitObject.clear();
356 SUIT_DataObject* o = myStudy->root();
358 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
360 std::string entry = so->entry().toUtf8().constData();
362 entry2SuitObject[entry] = so;
364 if ( o->childCount() > 0 ) {
365 // parse the children
368 else if ( o->nextBrother() ) {
369 o = o->nextBrother();
372 // step to the next appropriate parent
375 if ( o->nextBrother() ) {
376 o = o->nextBrother();
386 SalomeApp_Study* myStudy;
387 EntryMap entry2SuitObject;
394 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
395 : LightApp_Study( app ), myObserver( 0 )
397 myStudyDS = SalomeApp_Application::getStudy();
403 SalomeApp_Study::~SalomeApp_Study()
406 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
407 myObserver->_default_POA()->deactivate_object( oid.in() );
412 #ifndef DISABLE_PYCONSOLE
413 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
415 emit notebookVarUpdated( theVarName );
422 QString SalomeApp_Study::studyName() const
424 // redefined from SUIT_Study to update study name properly since
425 // it can be changed outside of GUI
426 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
428 QString newName = QString::fromUtf8(studyDS()->URL().c_str());
429 if ( newName.isEmpty() )
430 newName = QString::fromUtf8(studyDS()->Name().c_str());
431 if ( LightApp_Study::studyName() != newName ) {
432 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
433 that->setStudyName( newName );
434 ((SalomeApp_Application*)application())->updateDesktopTitle();
437 return LightApp_Study::studyName();
441 Gets studyDS pointer.
443 _PTR(Study) SalomeApp_Study::studyDS() const
451 bool SalomeApp_Study::createDocument( const QString& theStr )
453 MESSAGE( "createDocument" );
455 setStudyName( QString::fromUtf8(myStudyDS->URL().c_str()) );
458 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
459 #ifdef WITH_SALOMEDS_OBSERVER
460 aRoot->setToSynchronize(false);
464 bool aRet = CAM_Study::createDocument( theStr );
466 #ifdef WITH_SALOMEDS_OBSERVER
467 myObserver = new Observer_i(this);
468 //attach an observer to the study with notification of modifications
469 myStudyDS->attach(myObserver->_this(),true);
472 emit created( this );
479 \param theFileName - name of file
481 bool SalomeApp_Study::openDocument( const QString& theFileName )
483 MESSAGE( "openDocument" );
487 bool showError = !application()->property("open_study_from_command_line").isValid() ||
488 !application()->property("open_study_from_command_line").toBool();
490 res = myStudyDS->Open( theFileName.toUtf8().data() );
492 catch(const SALOME_Exception& ex) {
493 application()->putInfo(tr(ex.what()));
495 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
496 tr("ERR_ERROR"), tr(ex.what()));
500 application()->putInfo(tr("OPEN_DOCUMENT_PROBLEM"));
502 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
503 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
510 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
512 // update loaded data models: call open() and update() on them.
515 QListIterator<CAM_DataModel*> it( dm_s );
516 while ( it.hasNext() )
517 openDataModel( studyName(), it.next() );
519 // this will build a SUIT_DataObject-s tree under myRoot member field
520 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
521 // but tree that corresponds to not-loaded data models will be updated any way.
522 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
524 #ifdef WITH_SALOMEDS_OBSERVER
525 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
526 myObserver = new Observer_i(this);
527 //attach an observer to the study with notification of modifications
528 myStudyDS->attach(myObserver->_this(),true);
531 res = CAM_Study::openDocument( theFileName );
534 myStudyDS->IsSaved(true);
536 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
538 std::vector<int> savePoints = getSavePoints();
539 if ( savePoints.size() > 0 )
540 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
543 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
548 Connects GUI study to SALOMEDS one
549 \param theStudyName - name of study
551 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
553 MESSAGE( "loadDocument" );
555 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
557 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
559 // update loaded data models: call open() and update() on them.
563 QListIterator<CAM_DataModel*> it( dm_s );
564 while ( it.hasNext() )
565 openDataModel( studyName(), it.next() );
567 bool res = CAM_Study::openDocument( theStudyName );
569 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
570 // mark study as "not saved" after call openDocument( ... ) method.
572 emit opened( this ); // myRoot is set to Object Browser here
574 // this will build a SUIT_DataObject-s tree under myRoot member field
575 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
576 // but tree that corresponds to not-loaded data models will be updated any way.
577 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
579 #ifdef WITH_SALOMEDS_OBSERVER
580 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
581 myObserver = new Observer_i(this);
582 //attach an observer to the study with notification of modifications
583 myStudyDS->attach(myObserver->_this(),true);
586 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
588 std::vector<int> savePoints = getSavePoints();
589 if ( savePoints.size() > 0 )
590 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
593 //SRN: BugID IPAL9021: End
599 \param theFileName - name of file
601 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
603 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
605 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
607 ModelList list; dataModels( list );
609 QListIterator<CAM_DataModel*> it( list );
610 QStringList listOfFiles;
611 while ( it.hasNext() ) {
612 // Cast to LightApp class in order to give a chance
613 // to light modules to save their data
614 if ( LightApp_DataModel* aModel =
615 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
617 aModel->saveAs( theFileName, this, listOfFiles );
618 if ( !listOfFiles.isEmpty() )
619 saveModuleData(aModel->module()->name(), 0, // 0 means persistence file
624 // save SALOMEDS document
625 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
629 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
630 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
631 bool res = studyDS()->SaveAs( theFileName.toUtf8().data(), isMultiFile, isAscii )
632 && CAM_Study::saveDocumentAs( theFileName );
634 res = res && saveStudyData(theFileName, 0); // 0 means persistence file
643 Saves previously opened document
645 bool SalomeApp_Study::saveDocument()
647 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
649 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
651 ModelList list; dataModels( list );
653 QListIterator<CAM_DataModel*> it( list );
654 QStringList listOfFiles;
655 while ( it.hasNext() ) {
656 // Cast to LightApp class in order to give a chance
657 // to light modules to save their data
658 if ( LightApp_DataModel* aModel =
659 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
661 aModel->save(listOfFiles);
662 if ( !listOfFiles.isEmpty() )
663 saveModuleData(aModel->module()->name(), 0, // 0 means persistence file
668 // save SALOMEDS document
669 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
673 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
674 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
675 bool res = studyDS()->Save( isMultiFile, isAscii ) && CAM_Study::saveDocument();
677 res = res && saveStudyData(studyName(), 0); // 0 means persistence file
687 void SalomeApp_Study::closeDocument(bool permanently)
689 LightApp_Study::closeDocument(permanently);
691 // close SALOMEDS document
693 myStudyDS->detach( myObserver->_this() );
695 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
696 bool isBlocked = desk->signalsBlocked();
697 desk->blockSignals( true );
699 desk->blockSignals( isBlocked );
700 #ifndef DISABLE_PYCONSOLE
701 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
702 app->getPyInterp()->destroy();
708 Dump study operation. Writes a Python dump file using
709 SALOMEDS services. Additionally, gives a chance to light modules
710 to participate in dump study operation.
712 \param theFileName - full path to the output Python file
713 \param toPublish - if true, all objects are published in a study
714 by the output script, including those not orignally present
715 in the current study.
716 \param isMultiFile - if true, each module's dump is written into
717 a separate Python file, otherwise a single output file is written
718 \param toSaveGUI - if true, the GUI state is written
720 \return - true if the operation succeeds, and false otherwise.
722 bool SalomeApp_Study::dump( const QString& theFileName,
728 _PTR(AttributeParameter) ap;
729 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
731 if( ip->isDumpPython() )
732 ip->setDumpPython(); //Unset DumpPython flag.
734 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
736 //SRN: create a temporary save point
737 savePoint = SalomeApp_VisualState(
738 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
741 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
742 // This is an optional but important step, it gives a chance to light modules
743 // to dump their data as a part of common dump study operation
747 QListIterator<CAM_DataModel*> it( list );
748 QStringList listOfFiles;
749 while ( it.hasNext() ) {
750 if ( LightApp_DataModel* aModel =
751 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
753 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
754 !listOfFiles.isEmpty() )
755 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
756 // This code is shared with persistence mechanism.
757 // NOTE: this should be revised if behavior of saveModuleData() changes!
758 saveModuleData(aModel->module()->name(), 1, // 1 means dump file
763 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
764 // any light module is present in the current configuration
765 QFileInfo aFileInfo( theFileName );
766 bool res = myStudyDS->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
767 aFileInfo.baseName().toUtf8().data(),
771 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
773 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
774 // This code is shared with persistence mechanism.
775 // NOTE: this should be revised if behavior of saveStudyData() changes!
776 saveStudyData( theFileName, 1 ); // 0 means persistence file
782 \return true, if study is modified in comparison with last open/save
784 bool SalomeApp_Study::isModified() const
786 bool isAnyChanged = studyDS() && studyDS()->IsModified();
788 isAnyChanged = LightApp_Study::isModified();
794 Set study modified to \a on.
796 void SalomeApp_Study::Modified()
798 myStudyDS->Modified();
799 LightApp_Study::Modified();
803 \return if data model is saved
805 bool SalomeApp_Study::isSaved() const
807 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
809 isAllSaved = LightApp_Study::isSaved();
816 \param theModuleName - name of module
817 \param theListOfFiles - list of files to be saved
819 void SalomeApp_Study::saveModuleData( QString theModuleName, int type, QStringList theListOfFiles )
821 int aNb = theListOfFiles.count();
825 std::vector<std::string> aListOfFiles ( aNb );
827 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
828 if ( (*it).isEmpty() )
830 aListOfFiles[anIndex] = (*it).toUtf8().data();
833 SetListOfFiles(theModuleName.toStdString().c_str(), type, aListOfFiles);
838 \param theModuleName - name of module
839 \param theListOfFiles - list of files to be loaded
841 void SalomeApp_Study::openModuleData( QString theModuleName, int type, QStringList& theListOfFiles )
843 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str(), type );
845 int i, aLength = (int)aListOfFiles.size() - 1; //!< TODO: conversion from size_t to int
849 //Get a temporary directory for saved a file
850 theListOfFiles.append(aListOfFiles[0].c_str());
852 for(i = 0; i < aLength; i++)
853 theListOfFiles.append(aListOfFiles[i+1].c_str());
857 Re-implemented from LightApp_Study, actually does not save anything but
858 simply cleans up light modules' data
860 bool SalomeApp_Study::saveStudyData( const QString& /*theFileName*/, int type )
862 ModelList list; dataModels( list );
863 QListIterator<CAM_DataModel*> it( list );
864 while ( it.hasNext() ){
865 LightApp_DataModel* aLModel =
866 dynamic_cast<LightApp_DataModel*>( it.next() );
867 // It is safe to call SetListOfFiles() for any kind of module
868 // because SetListOfFiles() does nothing for full modules :)
870 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), type, std::vector<std::string>());
878 bool SalomeApp_Study::openStudyData( const QString& /*theFileName*/, int /*type*/ )
884 Virtual method re-implemented from LightApp_Study in order to create
885 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
887 \param theDataModel - data model instance to create a module object for
888 \param theParent - the module object's parent (normally it's the study root)
889 \return the module object instance
890 \sa LightApp_Study class, LightApp_DataModel class
892 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
893 SUIT_DataObject* theParent ) const
895 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
897 // Ensure that SComponent instance is published in the study for the given module
898 // This line causes automatic creation of SalomeApp_ModuleObject in case if
899 // WITH_SALOMEDS_OBSERVER is defined
900 that->addComponent( theDataModel );
902 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
903 // or by someone else so check if it exists first of all
904 CAM_ModuleObject* res = 0;
906 DataObjectList children = root()->children();
907 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
908 for( ; !res && anIt!=aLast; anIt++ )
910 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
911 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
916 _PTR(SComponent) aComp = myStudyDS->FindComponent(
917 theDataModel->module()->name().toStdString() );
921 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
930 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
932 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
934 CAM_Study::dataModelInserted(dm);
940 Create SComponent for module, using default engine (CORBAless)
942 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
944 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
945 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
947 // Check SComponent existance
949 std::string aCompDataType = dm->module()->name().toStdString();
951 _PTR(SComponent) aComp = myStudyDS->FindComponent(aCompDataType);
954 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
955 aComp = aBuilder->NewComponent(aCompDataType);
956 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
957 QString anIconName = dm->module()->iconName();
958 if (!anIconName.isEmpty()) {
959 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
961 anAttr->SetPixMap(anIconName.toStdString());
964 // Set default engine IOR
965 // Issue 21377 - using separate engine for each type of light module
966 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
968 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
969 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
970 SalomeApp_DataModel::synchronize( aComp, this );
973 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
974 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
975 QString anIconName = dm->module()->iconName();
976 if (!anIconName.isEmpty()) {
977 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
979 anAttr->SetPixMap(anIconName.toStdString());
981 // Set default engine IOR
989 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
994 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
995 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
996 _PTR(SComponent) aSComp;
998 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1000 // Issue 21377 - using separate engine for each type of light module
1001 std::string aCompDataType = dm->module()->name().toStdString();
1002 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1003 aSComp = myStudyDS->FindComponent( aCompDataType );
1006 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1008 QString anId = aDM->getRootEntry( this );
1009 if ( anId.isEmpty() )
1010 return true; // Probably nothing to load
1011 anEngine = aDM->getModule()->engineIOR();
1012 if ( anEngine.isEmpty() )
1014 aSComp = myStudyDS->FindComponentID( std::string( anId.toLatin1() ) );
1018 _PTR(StudyBuilder) aBuilder( myStudyDS->NewBuilder() );
1021 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1023 catch( const SALOME::SALOME_Exception& ) {
1024 // Oops, something went wrong while loading -> return an error
1027 // Something has been read -> create data model tree
1028 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1029 // aDM->buildTree( aSComp, 0, this );
1032 // Don't return false here, for there might be no data
1033 // for a given component in the study yet
1035 QStringList listOfFiles;
1036 openModuleData(dm->module()->name(), 0, // 0 means persistence file
1038 if (dm && dm->open(studyName, this, listOfFiles)) {
1039 // Remove the files and temporary directory, created
1040 // for this module by LightApp_Engine_i::Load()
1041 bool isMultiFile = false; // TODO: decide, how to access this parameter
1042 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile, true );
1043 SetListOfFiles( dm->module()->name().toStdString().c_str(), 0, // 0 means persistence file
1044 std::vector<std::string>() );
1046 // Something has been read -> create data model tree
1047 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1049 aDM->update(NULL, this);
1056 Note that this method does not create or activate SalomeApp_Engine_i instance,
1057 therefore it can be called safely for any kind of module, but for full
1058 modules it returns an empty list.
1059 \return list of files used by module: to be used by CORBAless modules
1060 \param theModuleName - name of module
1062 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName, int type ) const
1064 // Issue 21377 - using separate engine for each type of light module
1065 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1067 return aDefaultEngine->GetListOfFiles( type );
1069 return std::vector<std::string>();
1073 Sets list of files used by module: to be used by CORBAless modules.
1074 Note that this method does not create or activate SalomeApp_Engine_i instance,
1075 therefore it can be called safely for any kind of module, but for full
1076 modules it simply does nothing.
1077 \param theModuleName - name of module
1078 \param theListOfFiles - list of files
1080 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName, int type,
1081 const std::vector<std::string> theListOfFiles )
1083 // Issue 21377 - using separate engine for each type of light module
1084 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1086 aDefaultEngine->SetListOfFiles(type, theListOfFiles);
1090 \return temporary directory for saving files of modules
1092 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1094 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1095 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1100 Removes temporary files
1102 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, bool isMultiFile, bool force )
1107 SALOMEDS_Tool::ListOfFiles aListOfFiles = GetListOfFiles( theModuleName, 0 );
1108 if (aListOfFiles.size() > 0) {
1109 std::string aTmpDir = aListOfFiles[0];
1111 const int n = (int)aListOfFiles.size() - 1; //!< TODO: conversion from size_t to int
1112 std::vector<std::string> aSeq;
1114 for (int i = 0; i < n; i++)
1115 aSeq.push_back(CORBA::string_dup(aListOfFiles[i + 1].c_str()));
1117 SalomeApp_Engine_i* engine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1118 bool toRemove = force || ( engine && !engine->keepFiles() );
1121 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq, true);
1122 engine->keepFiles( false );
1127 #ifndef DISABLE_PYCONSOLE
1129 Mark the study as saved in the file
1130 \param theFileName - the name of file
1132 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1134 setStudyName(theFileName);
1135 studyDS()->URL(theFileName.toStdString());
1136 setIsSaved( isSaved );
1140 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1142 LightApp_DataObject* o = 0;
1144 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toUtf8().constData() ) );
1147 o = LightApp_Study::findObjectByEntry( theEntry );
1153 Deletes all references to object
1156 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1158 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1159 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1160 for( size_t i=0, n=aRefs.size(); i<n; i++ )
1162 _PTR( SObject ) o = aRefs[i];
1163 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1165 sb->RemoveReference( o );
1166 sb->RemoveObjectWithChildren( o );
1172 \return real entry by entry of reference
1173 \param entry - entry of reference object
1175 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1177 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1178 _PTR(SObject) refobj;
1180 if( obj && obj->ReferencedObject( refobj ) )
1181 return refobj->GetID().c_str();
1182 return LightApp_Study::referencedToEntry( entry );
1186 \return component data type for entry
1188 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1190 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1192 return LightApp_Study::componentDataType( entry );
1193 return obj->GetFatherComponent()->ComponentDataType().c_str();
1197 \return true if entry corresponds to component
1199 bool SalomeApp_Study::isComponent( const QString& entry ) const
1201 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1202 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1206 \return entries of object children
1208 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1210 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1211 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1212 anIter->InitEx( true );
1213 while( anIter->More() )
1215 _PTR(SObject) val( anIter->Value() );
1216 child_entries.append( val->GetID().c_str() );
1222 Fills list with components names
1223 \param comp - list to be filled
1225 void SalomeApp_Study::components( QStringList& comps ) const
1227 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1229 _PTR(SComponent) aComponent ( it->Value() );
1230 // skip the magic "Interface Applicative" component
1231 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1232 comps.append( aComponent->ComponentDataType().c_str() );
1237 Get the entry for the given module
1238 \param comp - list to be filled
1239 \return module root's entry
1241 QString SalomeApp_Study::centry( const QString& comp ) const
1244 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1246 _PTR(SComponent) aComponent ( it->Value() );
1247 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1248 e = aComponent->GetID().c_str();
1254 \return a list of saved points' IDs
1256 std::vector<int> SalomeApp_Study::getSavePoints()
1260 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1263 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1264 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1265 for(; anIter->More(); anIter->Next())
1267 _PTR(SObject) val( anIter->Value() );
1268 _PTR(GenericAttribute) genAttr;
1269 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1276 Removes a given save point
1278 void SalomeApp_Study::removeSavePoint(int savePoint)
1280 if(savePoint <= 0) return;
1281 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1282 _PTR(SObject) so = AP->GetSObject();
1283 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1284 builder->RemoveObjectWithChildren(so);
1288 \return a name of save point
1290 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1292 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1293 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1294 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1298 Sets a name of save point
1300 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1302 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1303 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1304 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1308 * \brief Restores the study state
1310 void SalomeApp_Study::restoreState(int savePoint)
1312 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1317 Slot: called on change of a root of a data model. Redefined from CAM_Study
1319 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1321 LightApp_Study::updateModelRoot( dm );
1323 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1324 // it must always be the last one.
1325 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );