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( 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 somethere
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
185 //int childDataObjCount = aFatherDO->childCount();
186 _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
187 for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
188 if (aUseCaseIter->Value()->GetID() == theID) {
194 aFatherDO->insertChildAtPos(suit_obj, pos);
195 //aFatherDO->insertChild(suit_obj, pos);
196 aFatherDO->updateItem();
198 /* Define visibility state */
199 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
200 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
201 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
202 if (!moduleTitle.isEmpty()) {
203 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
205 if(aDisplayer->canBeDisplayed(theID.c_str())) {
206 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState ); //hide the just added object
207 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
210 //MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
214 } // END: work with tree nodes structure
215 else { // BEGIN: work with study structure
216 EntryMapIter it = entry2SuitObject.find( theID );
217 if ( it != entry2SuitObject.end() ) {
218 MESSAGE("Entry " << theID << " is already added. Problem ??");
222 int last2Pnt_pos = theID.rfind( ":" );
223 std::string parent_id = theID.substr( 0, last2Pnt_pos );
224 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
226 if ( parent_id.length() == 3 ) // "0:1" - root item?
228 // It's probably a SComponent
229 if ( theID == aSComp->GetID() )
230 suit_obj = new SalomeApp_ModuleObject( aSComp );
232 suit_obj = new SalomeApp_DataObject( aSObj );
236 suit_obj = new SalomeApp_DataObject( aSObj );
239 it = entry2SuitObject.find( parent_id );
240 if ( it != entry2SuitObject.end() ) {
241 SalomeApp_DataObject* father = it->second;
242 father->insertChildAtTag( suit_obj, tag );
245 if ( parent_id.length() == 3 ) // "0:1" - root item?
247 // This should be for a module
248 SUIT_DataObject* father=myStudy->root();
249 father->appendChild(suit_obj);
253 MESSAGE("SHOULD NEVER GET HERE!!!");
255 //Try to find the SalomeApp_DataObject object parent
256 std::string root_id = parent_id.substr( 0, 4 );
257 std::string obj_id = parent_id.substr( 4 );
260 std::string::size_type debut = 0;
261 std::string::size_type fin;
262 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
264 fin = obj_id.find_first_of( ':', debut );
265 if ( fin == std::string::npos ) {
267 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
269 entry2SuitObject[parent_id] = anObj;
272 anID = root_id + obj_id.substr( 0, fin );
273 EntryMapIter it2 = entry2SuitObject.find( anID );
274 if ( it2 == entry2SuitObject.end() ) {
275 //the ID is not known in entry2SuitObject
276 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
278 entry2SuitObject[anID] = anObj;
285 anObj->insertChildAtTag( suit_obj, tag );
288 entry2SuitObject[theID] = suit_obj;
289 } // END: work with study structure
294 EntryMapIter it = entry2SuitObject.find( theID );
295 if ( it != entry2SuitObject.end() )
297 suit_obj = it->second;
298 suit_obj->updateItem();
299 SUIT_DataObject* father=suit_obj->parent();
301 father->removeChild(suit_obj);
302 entry2SuitObject.erase(it);
306 MESSAGE("Want to remove an unknown object" << theID);
312 //MESSAGE("Want to modify an object " << theID);
313 EntryMapIter it = entry2SuitObject.find( theID );
314 if ( it != entry2SuitObject.end() )
316 suit_obj = it->second;
317 suit_obj->updateItem();
321 MESSAGE("Want to modify an unknown object" << theID);
325 case 5: //IOR of the object modified
327 EntryMapIter it = entry2SuitObject.find( theID );
328 if ( it != entry2SuitObject.end() )
329 suit_obj = it->second;
331 /* Define visibility state */
332 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
333 if ( suit_obj && !isComponent ) {
334 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
335 if (!moduleTitle.isEmpty()) {
336 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
338 if(aDisplayer->canBeDisplayed(theID.c_str())) {
339 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
340 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
343 //MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
349 #ifndef DISABLE_PYCONSOLE
350 case 6: //NoteBook variables were modified
352 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
356 default:MESSAGE("Unknown event: " << event);break;
358 } //notifyObserverID_real
363 entry2SuitObject.clear();
364 SUIT_DataObject* o = myStudy->root();
366 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
368 std::string entry = so->entry().toUtf8().constData();
370 entry2SuitObject[entry] = so;
372 if ( o->childCount() > 0 ) {
373 // parse the children
376 else if ( o->nextBrother() > 0 ) {
377 o = o->nextBrother();
380 // step to the next appropriate parent
383 if ( o->nextBrother() ) {
384 o = o->nextBrother();
394 SalomeApp_Study* myStudy;
395 EntryMap entry2SuitObject;
402 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
403 : LightApp_Study( app ), myObserver( 0 )
405 myStudyDS = SalomeApp_Application::getStudy();
411 SalomeApp_Study::~SalomeApp_Study()
414 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
415 myObserver->_default_POA()->deactivate_object( oid.in() );
419 #ifndef DISABLE_PYCONSOLE
420 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
422 emit notebookVarUpdated( theVarName );
429 QString SalomeApp_Study::studyName() const
431 // redefined from SUIT_Study to update study name properly since
432 // it can be changed outside of GUI
433 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
435 QString newName = QString::fromUtf8(studyDS()->Name().c_str());
436 if ( LightApp_Study::studyName() != newName ) {
437 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
438 that->setStudyName( newName );
439 ((SalomeApp_Application*)application())->updateDesktopTitle();
442 return LightApp_Study::studyName();
446 Gets studyDS pointer.
448 _PTR(Study) SalomeApp_Study::studyDS() const
456 bool SalomeApp_Study::createDocument( const QString& theStr )
458 MESSAGE( "createDocument" );
460 setStudyName( QString::fromUtf8(myStudyDS->URL().c_str()) );
463 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
464 #ifdef WITH_SALOMEDS_OBSERVER
465 aRoot->setToSynchronize(false);
469 bool aRet = CAM_Study::createDocument( theStr );
471 #ifdef WITH_SALOMEDS_OBSERVER
472 myObserver = new Observer_i(this);
473 //attach an observer to the study with notification of modifications
474 myStudyDS->attach(myObserver->_this(),true);
477 emit created( this );
484 \param theFileName - name of file
486 bool SalomeApp_Study::openDocument( const QString& theFileName )
488 MESSAGE( "openDocument" );
492 bool showError = !application()->property("open_study_from_command_line").isValid() ||
493 !application()->property("open_study_from_command_line").toBool();
495 res = myStudyDS->Open( theFileName.toUtf8().data() );
497 catch(const SALOME_Exception& ex) {
498 application()->putInfo(tr(ex.what()));
500 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
501 tr("ERR_ERROR"), tr(ex.what()));
505 application()->putInfo(tr("OPEN_DOCUMENT_PROBLEM"));
507 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
508 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
515 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
517 // update loaded data models: call open() and update() on them.
520 QListIterator<CAM_DataModel*> it( dm_s );
521 while ( it.hasNext() )
522 openDataModel( studyName(), it.next() );
524 // this will build a SUIT_DataObject-s tree under myRoot member field
525 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
526 // but tree that corresponds to not-loaded data models will be updated any way.
527 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
529 #ifdef WITH_SALOMEDS_OBSERVER
530 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
531 myObserver = new Observer_i(this);
532 //attach an observer to the study with notification of modifications
533 myStudyDS->attach(myObserver->_this(),true);
536 res = CAM_Study::openDocument( theFileName );
539 myStudyDS->IsSaved(true);
541 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
543 std::vector<int> savePoints = getSavePoints();
544 if ( savePoints.size() > 0 )
545 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
548 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
553 Connects GUI study to SALOMEDS one
554 \param theStudyName - name of study
556 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
558 MESSAGE( "loadDocument" );
560 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
562 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
564 // update loaded data models: call open() and update() on them.
568 QListIterator<CAM_DataModel*> it( dm_s );
569 while ( it.hasNext() )
570 openDataModel( studyName(), it.next() );
572 // this will build a SUIT_DataObject-s tree under myRoot member field
573 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
574 // but tree that corresponds to not-loaded data models will be updated any way.
575 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
577 #ifdef WITH_SALOMEDS_OBSERVER
578 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
579 myObserver = new Observer_i(this);
580 //attach an observer to the study with notification of modifications
581 myStudyDS->attach(myObserver->_this(),true);
584 bool res = CAM_Study::openDocument( theStudyName );
586 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
587 // mark study as "not saved" after call openDocument( ... ) method.
591 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
593 std::vector<int> savePoints = getSavePoints();
594 if ( savePoints.size() > 0 )
595 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
598 //SRN: BugID IPAL9021: End
604 \param theFileName - name of file
606 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
608 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
610 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
612 ModelList list; dataModels( list );
614 QListIterator<CAM_DataModel*> it( list );
615 QStringList listOfFiles;
616 while ( it.hasNext() ) {
617 // Cast to LightApp class in order to give a chance
618 // to light modules to save their data
619 if ( LightApp_DataModel* aModel =
620 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
622 aModel->saveAs( theFileName, this, listOfFiles );
623 if ( !listOfFiles.isEmpty() )
624 saveModuleData(aModel->module()->name(), listOfFiles);
628 // save SALOMEDS document
629 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
633 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
634 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
635 bool res = studyDS()->SaveAs( theFileName.toUtf8().data(), isMultiFile, isAscii )
636 && CAM_Study::saveDocumentAs( theFileName );
638 res = res && saveStudyData(theFileName);
647 Saves previously opened document
649 bool SalomeApp_Study::saveDocument()
651 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
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->save(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 = studyDS()->Save( isMultiFile, isAscii ) && CAM_Study::saveDocument();
680 res = res && saveStudyData(studyName());
690 void SalomeApp_Study::closeDocument(bool permanently)
692 LightApp_Study::closeDocument(permanently);
694 // close SALOMEDS document
696 myStudyDS->detach( myObserver->_this() );
698 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
699 bool isBlocked = desk->signalsBlocked();
700 desk->blockSignals( true );
702 desk->blockSignals( isBlocked );
703 #ifndef DISABLE_PYCONSOLE
704 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
705 app->getPyInterp()->destroy();
711 Dump study operation. Writes a Python dump file using
712 SALOMEDS services. Additionally, gives a chance to light modules
713 to participate in dump study operation.
715 \param theFileName - full path to the output Python file
716 \param toPublish - if true, all objects are published in a study
717 by the output script, including those not orignally present
718 in the current study.
719 \param isMultiFile - if true, each module's dump is written into
720 a separate Python file, otherwise a single output file is written
721 \param toSaveGUI - if true, the GUI state is written
723 \return - true if the operation succeeds, and false otherwise.
725 bool SalomeApp_Study::dump( const QString& theFileName,
731 _PTR(AttributeParameter) ap;
732 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
734 if( ip->isDumpPython() )
735 ip->setDumpPython(); //Unset DumpPython flag.
737 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
739 //SRN: create a temporary save point
740 savePoint = SalomeApp_VisualState(
741 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
744 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
745 // This is an optional but important step, it gives a chance to light modules
746 // to dump their data as a part of common dump study operation
750 QListIterator<CAM_DataModel*> it( list );
751 QStringList listOfFiles;
752 while ( it.hasNext() ) {
753 if ( LightApp_DataModel* aModel =
754 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
756 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
757 !listOfFiles.isEmpty() )
758 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
759 // This code is shared with persistence mechanism.
760 // NOTE: this should be revised if behavior of saveModuleData() changes!
761 saveModuleData(aModel->module()->name(), listOfFiles);
765 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
766 // any light module is present in the current configuration
767 QFileInfo aFileInfo( theFileName );
768 bool res = myStudyDS->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
769 aFileInfo.baseName().toUtf8().data(),
773 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
775 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
776 // This code is shared with persistence mechanism.
777 // NOTE: this should be revised if behavior of saveStudyData() changes!
778 saveStudyData( theFileName );
784 \return true, if study is modified in comparison with last open/save
786 bool SalomeApp_Study::isModified() const
788 bool isAnyChanged = studyDS() && studyDS()->IsModified();
790 isAnyChanged = LightApp_Study::isModified();
796 Set study modified to \a on.
798 void SalomeApp_Study::Modified()
800 myStudyDS->Modified();
801 LightApp_Study::Modified();
805 \return if data model is saved
807 bool SalomeApp_Study::isSaved() const
809 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
811 isAllSaved = LightApp_Study::isSaved();
818 \param theModuleName - name of module
819 \param theListOfFiles - list of files to be saved
821 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
823 int aNb = theListOfFiles.count();
827 std::vector<std::string> aListOfFiles ( aNb );
829 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
830 if ( (*it).isEmpty() )
832 aListOfFiles[anIndex] = (*it).toUtf8().data();
835 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
840 \param theModuleName - name of module
841 \param theListOfFiles - list of files to be loaded
843 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
845 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
847 int i, aLength = aListOfFiles.size() - 1;
851 //Get a temporary directory for saved a file
852 theListOfFiles.append(aListOfFiles[0].c_str());
854 for(i = 0; i < aLength; i++)
855 theListOfFiles.append(aListOfFiles[i+1].c_str());
859 Re-implemented from LightApp_Study, actually does not save anything but
860 simply cleans up light modules' data
862 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
864 ModelList list; dataModels( list );
865 QListIterator<CAM_DataModel*> it( list );
866 std::vector<std::string> listOfFiles(0);
867 while ( it.hasNext() ){
868 LightApp_DataModel* aLModel =
869 dynamic_cast<LightApp_DataModel*>( it.next() );
870 // It is safe to call SetListOfFiles() for any kind of module
871 // because SetListOfFiles() does nothing for full modules :)
873 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
881 bool SalomeApp_Study::openStudyData( const QString& theFileName )
887 Virtual method re-implemented from LightApp_Study in order to create
888 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
890 \param theDataModel - data model instance to create a module object for
891 \param theParent - the module object's parent (normally it's the study root)
892 \return the module object instance
893 \sa LightApp_Study class, LightApp_DataModel class
895 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
896 SUIT_DataObject* theParent ) const
898 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
900 // Ensure that SComponent instance is published in the study for the given module
901 // This line causes automatic creation of SalomeApp_ModuleObject in case if
902 // WITH_SALOMEDS_OBSERVER is defined
903 that->addComponent( theDataModel );
905 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
906 // or by someone else so check if it exists first of all
907 CAM_ModuleObject* res = 0;
909 DataObjectList children = root()->children();
910 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
911 for( ; !res && anIt!=aLast; anIt++ )
913 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
914 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
919 _PTR(SComponent) aComp = myStudyDS->FindComponent(
920 theDataModel->module()->name().toStdString() );
924 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
933 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
935 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
937 CAM_Study::dataModelInserted(dm);
943 Create SComponent for module, using default engine (CORBAless)
945 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
947 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
948 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
950 // Check SComponent existance
952 std::string aCompDataType = dm->module()->name().toStdString();
954 _PTR(SComponent) aComp = myStudyDS->FindComponent(aCompDataType);
957 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
958 aComp = aBuilder->NewComponent(aCompDataType);
959 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
960 QString anIconName = dm->module()->iconName();
961 if (!anIconName.isEmpty()) {
962 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
964 anAttr->SetPixMap(anIconName.toStdString());
967 // Set default engine IOR
968 // Issue 21377 - using separate engine for each type of light module
969 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
971 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
972 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
973 SalomeApp_DataModel::synchronize( aComp, this );
976 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
977 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
978 QString anIconName = dm->module()->iconName();
979 if (!anIconName.isEmpty()) {
980 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
982 anAttr->SetPixMap(anIconName.toStdString());
984 // Set default engine IOR
992 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
997 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
998 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
999 _PTR(SComponent) aSComp;
1001 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1003 // Issue 21377 - using separate engine for each type of light module
1004 std::string aCompDataType = dm->module()->name().toStdString();
1005 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1006 aSComp = myStudyDS->FindComponent( aCompDataType );
1009 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1011 QString anId = aDM->getRootEntry( this );
1012 if ( anId.isEmpty() )
1013 return true; // Probably nothing to load
1014 anEngine = aDM->getModule()->engineIOR();
1015 if ( anEngine.isEmpty() )
1017 aSComp = myStudyDS->FindComponentID( std::string( anId.toLatin1() ) );
1021 _PTR(StudyBuilder) aBuilder( myStudyDS->NewBuilder() );
1024 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1026 catch( const SALOME::SALOME_Exception& ) {
1027 // Oops, something went wrong while loading -> return an error
1030 // Something has been read -> create data model tree
1031 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1032 // aDM->buildTree( aSComp, 0, this );
1035 // Don't return false here, for there might be no data
1036 // for a given component in the study yet
1038 QStringList listOfFiles;
1039 openModuleData(dm->module()->name(), listOfFiles);
1040 if (dm && dm->open(studyName, this, listOfFiles)) {
1041 // Remove the files and temporary directory, created
1042 // for this module by LightApp_Engine_i::Load()
1043 bool isMultiFile = false; // TODO: decide, how to access this parameter
1044 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1045 std::vector<std::string> listOfFiles ;
1046 SetListOfFiles( dm->module()->name().toStdString().c_str(), listOfFiles );
1048 // Something has been read -> create data model tree
1049 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1051 aDM->update(NULL, this);
1058 Note that this method does not create or activate SalomeApp_Engine_i instance,
1059 therefore it can be called safely for any kind of module, but for full
1060 modules it returns an empty list.
1061 \return list of files used by module: to be used by CORBAless modules
1062 \param theModuleName - name of module
1064 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1066 // Issue 21377 - using separate engine for each type of light module
1067 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1069 return aDefaultEngine->GetListOfFiles();
1071 std::vector<std::string> aListOfFiles;
1072 return aListOfFiles;
1076 Sets list of files used by module: to be used by CORBAless modules.
1077 Note that this method does not create or activate SalomeApp_Engine_i instance,
1078 therefore it can be called safely for any kind of module, but for full
1079 modules it simply does nothing.
1080 \param theModuleName - name of module
1081 \param theListOfFiles - list of files
1083 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1084 const std::vector<std::string> theListOfFiles )
1086 // Issue 21377 - using separate engine for each type of light module
1087 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1089 aDefaultEngine->SetListOfFiles(theListOfFiles);
1093 \return temporary directory for saving files of modules
1095 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1097 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1098 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1103 Removes temporary files
1105 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1110 SALOMEDS_Tool::ListOfFiles aListOfFiles = GetListOfFiles( theModuleName );
1111 if (aListOfFiles.size() > 0) {
1112 std::string aTmpDir = aListOfFiles[0];
1114 const int n = aListOfFiles.size() - 1;
1115 std::vector<std::string> aSeq;
1117 for (int i = 0; i < n; i++)
1118 aSeq.push_back(CORBA::string_dup(aListOfFiles[i + 1].c_str()));
1120 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq, true);
1124 #ifndef DISABLE_PYCONSOLE
1126 Mark the study as saved in the file
1127 \param theFileName - the name of file
1129 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1131 setStudyName(theFileName);
1132 studyDS()->URL(theFileName.toStdString());
1133 setIsSaved( isSaved );
1137 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1139 LightApp_DataObject* o = 0;
1141 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toUtf8().constData() ) );
1144 o = LightApp_Study::findObjectByEntry( theEntry );
1150 Deletes all references to object
1153 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1155 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1156 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1157 for( int i=0, n=aRefs.size(); i<n; i++ )
1159 _PTR( SObject ) o = aRefs[i];
1160 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1162 sb->RemoveReference( o );
1163 sb->RemoveObjectWithChildren( o );
1169 \return real entry by entry of reference
1170 \param entry - entry of reference object
1172 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1174 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1175 _PTR(SObject) refobj;
1177 if( obj && obj->ReferencedObject( refobj ) )
1178 return refobj->GetID().c_str();
1179 return LightApp_Study::referencedToEntry( entry );
1183 \return component data type for entry
1185 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1187 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1189 return LightApp_Study::componentDataType( entry );
1190 return obj->GetFatherComponent()->ComponentDataType().c_str();
1194 \return true if entry corresponds to component
1196 bool SalomeApp_Study::isComponent( const QString& entry ) const
1198 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1199 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1203 \return entries of object children
1205 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1207 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1208 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1209 anIter->InitEx( true );
1210 while( anIter->More() )
1212 _PTR(SObject) val( anIter->Value() );
1213 child_entries.append( val->GetID().c_str() );
1219 Fills list with components names
1220 \param comp - list to be filled
1222 void SalomeApp_Study::components( QStringList& comps ) const
1224 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1226 _PTR(SComponent) aComponent ( it->Value() );
1227 // skip the magic "Interface Applicative" component
1228 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1229 comps.append( aComponent->ComponentDataType().c_str() );
1234 Get the entry for the given module
1235 \param comp - list to be filled
1236 \return module root's entry
1238 QString SalomeApp_Study::centry( const QString& comp ) const
1241 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1243 _PTR(SComponent) aComponent ( it->Value() );
1244 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1245 e = aComponent->GetID().c_str();
1251 \return a list of saved points' IDs
1253 std::vector<int> SalomeApp_Study::getSavePoints()
1257 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1260 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1261 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1262 for(; anIter->More(); anIter->Next())
1264 _PTR(SObject) val( anIter->Value() );
1265 _PTR(GenericAttribute) genAttr;
1266 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1273 Removes a given save point
1275 void SalomeApp_Study::removeSavePoint(int savePoint)
1277 if(savePoint <= 0) return;
1278 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1279 _PTR(SObject) so = AP->GetSObject();
1280 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1281 builder->RemoveObjectWithChildren(so);
1285 \return a name of save point
1287 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1289 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1290 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1291 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1295 Sets a name of save point
1297 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1299 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1300 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1301 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1305 * \brief Restores the study state
1307 void SalomeApp_Study::restoreState(int savePoint)
1309 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1314 Slot: called on change of a root of a data model. Redefined from CAM_Study
1316 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1318 LightApp_Study::updateModelRoot( dm );
1320 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1321 // it must always be the last one.
1322 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );