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 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() );
420 #ifndef DISABLE_PYCONSOLE
421 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
423 emit notebookVarUpdated( theVarName );
430 QString SalomeApp_Study::studyName() const
432 // redefined from SUIT_Study to update study name properly since
433 // it can be changed outside of GUI
434 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
436 QString newName = QString::fromUtf8(studyDS()->URL().c_str());
437 if ( newName.isEmpty() )
438 newName = QString::fromUtf8(studyDS()->Name().c_str());
439 if ( LightApp_Study::studyName() != newName ) {
440 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
441 that->setStudyName( newName );
442 ((SalomeApp_Application*)application())->updateDesktopTitle();
445 return LightApp_Study::studyName();
449 Gets studyDS pointer.
451 _PTR(Study) SalomeApp_Study::studyDS() const
459 bool SalomeApp_Study::createDocument( const QString& theStr )
461 MESSAGE( "createDocument" );
463 setStudyName( QString::fromUtf8(myStudyDS->URL().c_str()) );
466 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
467 #ifdef WITH_SALOMEDS_OBSERVER
468 aRoot->setToSynchronize(false);
472 bool aRet = CAM_Study::createDocument( theStr );
474 #ifdef WITH_SALOMEDS_OBSERVER
475 myObserver = new Observer_i(this);
476 //attach an observer to the study with notification of modifications
477 myStudyDS->attach(myObserver->_this(),true);
480 emit created( this );
487 \param theFileName - name of file
489 bool SalomeApp_Study::openDocument( const QString& theFileName )
491 MESSAGE( "openDocument" );
495 bool showError = !application()->property("open_study_from_command_line").isValid() ||
496 !application()->property("open_study_from_command_line").toBool();
498 res = myStudyDS->Open( theFileName.toUtf8().data() );
500 catch(const SALOME_Exception& ex) {
501 application()->putInfo(tr(ex.what()));
503 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
504 tr("ERR_ERROR"), tr(ex.what()));
508 application()->putInfo(tr("OPEN_DOCUMENT_PROBLEM"));
510 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
511 tr("ERR_ERROR"), tr("OPEN_DOCUMENT_PROBLEM"));
518 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
520 // update loaded data models: call open() and update() on them.
523 QListIterator<CAM_DataModel*> it( dm_s );
524 while ( it.hasNext() )
525 openDataModel( studyName(), it.next() );
527 // this will build a SUIT_DataObject-s tree under myRoot member field
528 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
529 // but tree that corresponds to not-loaded data models will be updated any way.
530 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
532 #ifdef WITH_SALOMEDS_OBSERVER
533 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
534 myObserver = new Observer_i(this);
535 //attach an observer to the study with notification of modifications
536 myStudyDS->attach(myObserver->_this(),true);
539 res = CAM_Study::openDocument( theFileName );
542 myStudyDS->IsSaved(true);
544 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
546 std::vector<int> savePoints = getSavePoints();
547 if ( savePoints.size() > 0 )
548 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
551 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
556 Connects GUI study to SALOMEDS one
557 \param theStudyName - name of study
559 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
561 MESSAGE( "loadDocument" );
563 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
565 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
567 // update loaded data models: call open() and update() on them.
571 QListIterator<CAM_DataModel*> it( dm_s );
572 while ( it.hasNext() )
573 openDataModel( studyName(), it.next() );
575 bool res = CAM_Study::openDocument( theStudyName );
577 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
578 // mark study as "not saved" after call openDocument( ... ) method.
580 emit opened( this ); // myRoot is set to Object Browser here
582 // this will build a SUIT_DataObject-s tree under myRoot member field
583 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
584 // but tree that corresponds to not-loaded data models will be updated any way.
585 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
587 #ifdef WITH_SALOMEDS_OBSERVER
588 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
589 myObserver = new Observer_i(this);
590 //attach an observer to the study with notification of modifications
591 myStudyDS->attach(myObserver->_this(),true);
594 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
596 std::vector<int> savePoints = getSavePoints();
597 if ( savePoints.size() > 0 )
598 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
601 //SRN: BugID IPAL9021: End
607 \param theFileName - name of file
609 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
611 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
613 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
615 ModelList list; dataModels( list );
617 QListIterator<CAM_DataModel*> it( list );
618 QStringList listOfFiles;
619 while ( it.hasNext() ) {
620 // Cast to LightApp class in order to give a chance
621 // to light modules to save their data
622 if ( LightApp_DataModel* aModel =
623 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
625 aModel->saveAs( theFileName, this, listOfFiles );
626 if ( !listOfFiles.isEmpty() )
627 saveModuleData(aModel->module()->name(), 0, // 0 means persistence file
632 // save SALOMEDS document
633 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
637 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
638 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
639 bool res = studyDS()->SaveAs( theFileName.toUtf8().data(), isMultiFile, isAscii )
640 && CAM_Study::saveDocumentAs( theFileName );
642 res = res && saveStudyData(theFileName, 0); // 0 means persistence file
651 Saves previously opened document
653 bool SalomeApp_Study::saveDocument()
655 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
657 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
659 ModelList list; dataModels( list );
661 QListIterator<CAM_DataModel*> it( list );
662 QStringList listOfFiles;
663 while ( it.hasNext() ) {
664 // Cast to LightApp class in order to give a chance
665 // to light modules to save their data
666 if ( LightApp_DataModel* aModel =
667 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
669 aModel->save(listOfFiles);
670 if ( !listOfFiles.isEmpty() )
671 saveModuleData(aModel->module()->name(), 0, // 0 means persistence file
676 // save SALOMEDS document
677 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
681 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
682 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
683 bool res = studyDS()->Save( isMultiFile, isAscii ) && CAM_Study::saveDocument();
685 res = res && saveStudyData(studyName(), 0); // 0 means persistence file
695 void SalomeApp_Study::closeDocument(bool permanently)
697 LightApp_Study::closeDocument(permanently);
699 // close SALOMEDS document
701 myStudyDS->detach( myObserver->_this() );
703 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
704 bool isBlocked = desk->signalsBlocked();
705 desk->blockSignals( true );
707 desk->blockSignals( isBlocked );
708 #ifndef DISABLE_PYCONSOLE
709 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
710 app->getPyInterp()->destroy();
716 Dump study operation. Writes a Python dump file using
717 SALOMEDS services. Additionally, gives a chance to light modules
718 to participate in dump study operation.
720 \param theFileName - full path to the output Python file
721 \param toPublish - if true, all objects are published in a study
722 by the output script, including those not orignally present
723 in the current study.
724 \param isMultiFile - if true, each module's dump is written into
725 a separate Python file, otherwise a single output file is written
726 \param toSaveGUI - if true, the GUI state is written
728 \return - true if the operation succeeds, and false otherwise.
730 bool SalomeApp_Study::dump( const QString& theFileName,
736 _PTR(AttributeParameter) ap;
737 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
739 if( ip->isDumpPython() )
740 ip->setDumpPython(); //Unset DumpPython flag.
742 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
744 //SRN: create a temporary save point
745 savePoint = SalomeApp_VisualState(
746 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
749 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
750 // This is an optional but important step, it gives a chance to light modules
751 // to dump their data as a part of common dump study operation
755 QListIterator<CAM_DataModel*> it( list );
756 QStringList listOfFiles;
757 while ( it.hasNext() ) {
758 if ( LightApp_DataModel* aModel =
759 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
761 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
762 !listOfFiles.isEmpty() )
763 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
764 // This code is shared with persistence mechanism.
765 // NOTE: this should be revised if behavior of saveModuleData() changes!
766 saveModuleData(aModel->module()->name(), 1, // 1 means dump file
771 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
772 // any light module is present in the current configuration
773 QFileInfo aFileInfo( theFileName );
774 bool res = myStudyDS->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
775 aFileInfo.baseName().toUtf8().data(),
779 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
781 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
782 // This code is shared with persistence mechanism.
783 // NOTE: this should be revised if behavior of saveStudyData() changes!
784 saveStudyData( theFileName, 1 ); // 0 means persistence file
790 \return true, if study is modified in comparison with last open/save
792 bool SalomeApp_Study::isModified() const
794 bool isAnyChanged = studyDS() && studyDS()->IsModified();
796 isAnyChanged = LightApp_Study::isModified();
802 Set study modified to \a on.
804 void SalomeApp_Study::Modified()
806 myStudyDS->Modified();
807 LightApp_Study::Modified();
811 \return if data model is saved
813 bool SalomeApp_Study::isSaved() const
815 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
817 isAllSaved = LightApp_Study::isSaved();
824 \param theModuleName - name of module
825 \param theListOfFiles - list of files to be saved
827 void SalomeApp_Study::saveModuleData( QString theModuleName, int type, QStringList theListOfFiles )
829 int aNb = theListOfFiles.count();
833 std::vector<std::string> aListOfFiles ( aNb );
835 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
836 if ( (*it).isEmpty() )
838 aListOfFiles[anIndex] = (*it).toUtf8().data();
841 SetListOfFiles(theModuleName.toStdString().c_str(), type, aListOfFiles);
846 \param theModuleName - name of module
847 \param theListOfFiles - list of files to be loaded
849 void SalomeApp_Study::openModuleData( QString theModuleName, int type, QStringList& theListOfFiles )
851 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str(), type );
853 int i, aLength = aListOfFiles.size() - 1;
857 //Get a temporary directory for saved a file
858 theListOfFiles.append(aListOfFiles[0].c_str());
860 for(i = 0; i < aLength; i++)
861 theListOfFiles.append(aListOfFiles[i+1].c_str());
865 Re-implemented from LightApp_Study, actually does not save anything but
866 simply cleans up light modules' data
868 bool SalomeApp_Study::saveStudyData( const QString& theFileName, int type )
870 ModelList list; dataModels( list );
871 QListIterator<CAM_DataModel*> it( list );
872 while ( it.hasNext() ){
873 LightApp_DataModel* aLModel =
874 dynamic_cast<LightApp_DataModel*>( it.next() );
875 // It is safe to call SetListOfFiles() for any kind of module
876 // because SetListOfFiles() does nothing for full modules :)
878 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), type, std::vector<std::string>());
886 bool SalomeApp_Study::openStudyData( const QString& /*theFileName*/, int /*type*/ )
892 Virtual method re-implemented from LightApp_Study in order to create
893 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
895 \param theDataModel - data model instance to create a module object for
896 \param theParent - the module object's parent (normally it's the study root)
897 \return the module object instance
898 \sa LightApp_Study class, LightApp_DataModel class
900 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
901 SUIT_DataObject* theParent ) const
903 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
905 // Ensure that SComponent instance is published in the study for the given module
906 // This line causes automatic creation of SalomeApp_ModuleObject in case if
907 // WITH_SALOMEDS_OBSERVER is defined
908 that->addComponent( theDataModel );
910 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
911 // or by someone else so check if it exists first of all
912 CAM_ModuleObject* res = 0;
914 DataObjectList children = root()->children();
915 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
916 for( ; !res && anIt!=aLast; anIt++ )
918 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
919 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
924 _PTR(SComponent) aComp = myStudyDS->FindComponent(
925 theDataModel->module()->name().toStdString() );
929 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
938 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
940 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
942 CAM_Study::dataModelInserted(dm);
948 Create SComponent for module, using default engine (CORBAless)
950 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
952 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
953 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
955 // Check SComponent existance
957 std::string aCompDataType = dm->module()->name().toStdString();
959 _PTR(SComponent) aComp = myStudyDS->FindComponent(aCompDataType);
962 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
963 aComp = aBuilder->NewComponent(aCompDataType);
964 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
965 QString anIconName = dm->module()->iconName();
966 if (!anIconName.isEmpty()) {
967 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
969 anAttr->SetPixMap(anIconName.toStdString());
972 // Set default engine IOR
973 // Issue 21377 - using separate engine for each type of light module
974 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
976 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
977 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
978 SalomeApp_DataModel::synchronize( aComp, this );
981 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
982 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
983 QString anIconName = dm->module()->iconName();
984 if (!anIconName.isEmpty()) {
985 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
987 anAttr->SetPixMap(anIconName.toStdString());
989 // Set default engine IOR
997 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1002 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1003 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1004 _PTR(SComponent) aSComp;
1006 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1008 // Issue 21377 - using separate engine for each type of light module
1009 std::string aCompDataType = dm->module()->name().toStdString();
1010 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1011 aSComp = myStudyDS->FindComponent( aCompDataType );
1014 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1016 QString anId = aDM->getRootEntry( this );
1017 if ( anId.isEmpty() )
1018 return true; // Probably nothing to load
1019 anEngine = aDM->getModule()->engineIOR();
1020 if ( anEngine.isEmpty() )
1022 aSComp = myStudyDS->FindComponentID( std::string( anId.toLatin1() ) );
1026 _PTR(StudyBuilder) aBuilder( myStudyDS->NewBuilder() );
1029 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1031 catch( const SALOME::SALOME_Exception& ) {
1032 // Oops, something went wrong while loading -> return an error
1035 // Something has been read -> create data model tree
1036 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1037 // aDM->buildTree( aSComp, 0, this );
1040 // Don't return false here, for there might be no data
1041 // for a given component in the study yet
1043 QStringList listOfFiles;
1044 openModuleData(dm->module()->name(), 0, // 0 means persistence file
1046 if (dm && dm->open(studyName, this, listOfFiles)) {
1047 // Remove the files and temporary directory, created
1048 // for this module by LightApp_Engine_i::Load()
1049 bool isMultiFile = false; // TODO: decide, how to access this parameter
1050 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile, true );
1051 SetListOfFiles( dm->module()->name().toStdString().c_str(), 0, // 0 means persistence file
1052 std::vector<std::string>() );
1054 // Something has been read -> create data model tree
1055 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1057 aDM->update(NULL, this);
1064 Note that this method does not create or activate SalomeApp_Engine_i instance,
1065 therefore it can be called safely for any kind of module, but for full
1066 modules it returns an empty list.
1067 \return list of files used by module: to be used by CORBAless modules
1068 \param theModuleName - name of module
1070 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName, int type ) const
1072 // Issue 21377 - using separate engine for each type of light module
1073 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1075 return aDefaultEngine->GetListOfFiles( type );
1077 return std::vector<std::string>();
1081 Sets list of files used by module: to be used by CORBAless modules.
1082 Note that this method does not create or activate SalomeApp_Engine_i instance,
1083 therefore it can be called safely for any kind of module, but for full
1084 modules it simply does nothing.
1085 \param theModuleName - name of module
1086 \param theListOfFiles - list of files
1088 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName, int type,
1089 const std::vector<std::string> theListOfFiles )
1091 // Issue 21377 - using separate engine for each type of light module
1092 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1094 aDefaultEngine->SetListOfFiles(type, theListOfFiles);
1098 \return temporary directory for saving files of modules
1100 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1102 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1103 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1108 Removes temporary files
1110 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, bool isMultiFile, bool force )
1115 SALOMEDS_Tool::ListOfFiles aListOfFiles = GetListOfFiles( theModuleName, 0 );
1116 if (aListOfFiles.size() > 0) {
1117 std::string aTmpDir = aListOfFiles[0];
1119 const int n = aListOfFiles.size() - 1;
1120 std::vector<std::string> aSeq;
1122 for (int i = 0; i < n; i++)
1123 aSeq.push_back(CORBA::string_dup(aListOfFiles[i + 1].c_str()));
1125 SalomeApp_Engine_i* engine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1126 bool toRemove = force || engine && !engine->keepFiles();
1129 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq, true);
1130 engine->keepFiles( false );
1135 #ifndef DISABLE_PYCONSOLE
1137 Mark the study as saved in the file
1138 \param theFileName - the name of file
1140 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1142 setStudyName(theFileName);
1143 studyDS()->URL(theFileName.toStdString());
1144 setIsSaved( isSaved );
1148 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1150 LightApp_DataObject* o = 0;
1152 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toUtf8().constData() ) );
1155 o = LightApp_Study::findObjectByEntry( theEntry );
1161 Deletes all references to object
1164 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1166 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1167 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1168 for( int i=0, n=aRefs.size(); i<n; i++ )
1170 _PTR( SObject ) o = aRefs[i];
1171 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1173 sb->RemoveReference( o );
1174 sb->RemoveObjectWithChildren( o );
1180 \return real entry by entry of reference
1181 \param entry - entry of reference object
1183 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1185 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1186 _PTR(SObject) refobj;
1188 if( obj && obj->ReferencedObject( refobj ) )
1189 return refobj->GetID().c_str();
1190 return LightApp_Study::referencedToEntry( entry );
1194 \return component data type for entry
1196 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1198 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1200 return LightApp_Study::componentDataType( entry );
1201 return obj->GetFatherComponent()->ComponentDataType().c_str();
1205 \return true if entry corresponds to component
1207 bool SalomeApp_Study::isComponent( const QString& entry ) const
1209 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1210 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1214 \return entries of object children
1216 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1218 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1219 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1220 anIter->InitEx( true );
1221 while( anIter->More() )
1223 _PTR(SObject) val( anIter->Value() );
1224 child_entries.append( val->GetID().c_str() );
1230 Fills list with components names
1231 \param comp - list to be filled
1233 void SalomeApp_Study::components( QStringList& comps ) const
1235 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1237 _PTR(SComponent) aComponent ( it->Value() );
1238 // skip the magic "Interface Applicative" component
1239 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1240 comps.append( aComponent->ComponentDataType().c_str() );
1245 Get the entry for the given module
1246 \param comp - list to be filled
1247 \return module root's entry
1249 QString SalomeApp_Study::centry( const QString& comp ) const
1252 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1254 _PTR(SComponent) aComponent ( it->Value() );
1255 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1256 e = aComponent->GetID().c_str();
1262 \return a list of saved points' IDs
1264 std::vector<int> SalomeApp_Study::getSavePoints()
1268 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1271 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1272 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1273 for(; anIter->More(); anIter->Next())
1275 _PTR(SObject) val( anIter->Value() );
1276 _PTR(GenericAttribute) genAttr;
1277 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1284 Removes a given save point
1286 void SalomeApp_Study::removeSavePoint(int savePoint)
1288 if(savePoint <= 0) return;
1289 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1290 _PTR(SObject) so = AP->GetSObject();
1291 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1292 builder->RemoveObjectWithChildren(so);
1296 \return a name of save point
1298 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1300 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1301 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1302 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1306 Sets a name of save point
1308 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1310 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1311 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1312 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1316 * \brief Restores the study state
1318 void SalomeApp_Study::restoreState(int savePoint)
1320 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1325 Slot: called on change of a root of a data model. Redefined from CAM_Study
1327 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1329 LightApp_Study::updateModelRoot( dm );
1331 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1332 // it must always be the last one.
1333 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );