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().toLatin1().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()->URL().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 );
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 ) 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();
1069 std::vector<std::string> aListOfFiles;
1070 return aListOfFiles;
1074 Sets list of files used by module: to be used by CORBAless modules.
1075 Note that this method does not create or activate SalomeApp_Engine_i instance,
1076 therefore it can be called safely for any kind of module, but for full
1077 modules it simply does nothing.
1078 \param theModuleName - name of module
1079 \param theListOfFiles - list of files
1081 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1082 const std::vector<std::string> theListOfFiles )
1084 // Issue 21377 - using separate engine for each type of light module
1085 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1087 aDefaultEngine->SetListOfFiles(theListOfFiles);
1091 \return temporary directory for saving files of modules
1093 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1095 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1096 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1101 Removes temporary files
1103 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1108 SALOMEDS_Tool::ListOfFiles aListOfFiles = GetListOfFiles( theModuleName );
1109 if (aListOfFiles.size() > 0) {
1110 std::string aTmpDir = aListOfFiles[0];
1112 const int n = aListOfFiles.size() - 1;
1113 std::vector<std::string> aSeq;
1115 for (int i = 0; i < n; i++)
1116 aSeq.push_back(CORBA::string_dup(aListOfFiles[i + 1].c_str()));
1118 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq, true);
1122 #ifndef DISABLE_PYCONSOLE
1124 Mark the study as saved in the file
1125 \param theFileName - the name of file
1127 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1129 setStudyName(theFileName);
1130 studyDS()->URL(theFileName.toStdString());
1131 setIsSaved( isSaved );
1135 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1137 LightApp_DataObject* o = 0;
1139 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toLatin1().constData() ) );
1142 o = LightApp_Study::findObjectByEntry( theEntry );
1148 Deletes all references to object
1151 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1153 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1154 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1155 for( int i=0, n=aRefs.size(); i<n; i++ )
1157 _PTR( SObject ) o = aRefs[i];
1158 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1160 sb->RemoveReference( o );
1161 sb->RemoveObjectWithChildren( o );
1167 \return real entry by entry of reference
1168 \param entry - entry of reference object
1170 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1172 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1173 _PTR(SObject) refobj;
1175 if( obj && obj->ReferencedObject( refobj ) )
1176 return refobj->GetID().c_str();
1177 return LightApp_Study::referencedToEntry( entry );
1181 \return component data type for entry
1183 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1185 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1187 return LightApp_Study::componentDataType( entry );
1188 return obj->GetFatherComponent()->ComponentDataType().c_str();
1192 \return true if entry corresponds to component
1194 bool SalomeApp_Study::isComponent( const QString& entry ) const
1196 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1197 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1201 \return entries of object children
1203 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1205 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1206 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1207 anIter->InitEx( true );
1208 while( anIter->More() )
1210 _PTR(SObject) val( anIter->Value() );
1211 child_entries.append( val->GetID().c_str() );
1217 Fills list with components names
1218 \param comp - list to be filled
1220 void SalomeApp_Study::components( QStringList& comps ) const
1222 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1224 _PTR(SComponent) aComponent ( it->Value() );
1225 // skip the magic "Interface Applicative" component
1226 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1227 comps.append( aComponent->ComponentDataType().c_str() );
1232 Get the entry for the given module
1233 \param comp - list to be filled
1234 \return module root's entry
1236 QString SalomeApp_Study::centry( const QString& comp ) const
1239 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1241 _PTR(SComponent) aComponent ( it->Value() );
1242 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1243 e = aComponent->GetID().c_str();
1249 \return a list of saved points' IDs
1251 std::vector<int> SalomeApp_Study::getSavePoints()
1255 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1258 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1259 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1260 for(; anIter->More(); anIter->Next())
1262 _PTR(SObject) val( anIter->Value() );
1263 _PTR(GenericAttribute) genAttr;
1264 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1271 Removes a given save point
1273 void SalomeApp_Study::removeSavePoint(int savePoint)
1275 if(savePoint <= 0) return;
1276 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1277 _PTR(SObject) so = AP->GetSObject();
1278 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1279 builder->RemoveObjectWithChildren(so);
1283 \return a name of save point
1285 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1287 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1288 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1289 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1293 Sets a name of save point
1295 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1297 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1298 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1299 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1303 * \brief Restores the study state
1305 void SalomeApp_Study::restoreState(int savePoint)
1307 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1312 Slot: called on change of a root of a data model. Redefined from CAM_Study
1314 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1316 LightApp_Study::updateModelRoot( dm );
1318 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1319 // it must always be the last one.
1320 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );