1 // Copyright (C) 2007-2014 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 #include "SalomeApp_Study.h"
25 #include "SalomeApp_Module.h"
26 #include "SalomeApp_DataObject.h"
27 #include "SalomeApp_DataModel.h"
28 #include "SalomeApp_Application.h"
29 #include "SalomeApp_Engine_i.h"
30 #include "SalomeApp_VisualState.h"
32 // temporary commented
33 //#include <OB_Browser.h>
35 #include <QCoreApplication>
38 #include "SALOME_Event.h"
39 #include "Basics_Utils.hxx"
41 #include <SUIT_ResourceMgr.h>
42 #include <SUIT_TreeModel.h>
43 #include <SUIT_DataBrowser.h>
44 #include <SUIT_MessageBox.h>
45 #include <SUIT_Session.h>
46 #include <SUIT_Desktop.h>
48 #include <LightApp_Displayer.h>
50 #include "utilities.h"
52 #include "SALOMEDS_Tool.hxx"
54 #include "SALOMEDSClient_ClientFactory.hxx"
56 #include <SALOMEconfig.h>
57 #include CORBA_SERVER_HEADER(SALOME_Exception)
59 //#define NOTIFY_BY_EVENT
61 class ObserverEvent : public QEvent
64 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
74 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
76 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
77 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
81 Observer_i(_PTR(Study) aStudyDS, SalomeApp_Study* aStudy):QObject(aStudy)
88 SUIT_DataObject* findObject( const char* theID ) const
90 EntryMap::const_iterator it = entry2SuitObject.find( theID );
91 return it != entry2SuitObject.end() ? it->second : 0;
94 virtual void notifyObserverID(const char* theID, CORBA::Long event)
96 #ifdef NOTIFY_BY_EVENT
97 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
99 notifyObserverID_real(theID,event);
103 virtual bool event(QEvent *event)
105 if (event->type() == QEvent::User )
107 //START_TIMING(notify);
108 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
109 //END_TIMING(notify,100);
114 void notifyObserverID_real(const std::string& theID, long event)
116 SalomeApp_DataObject* suit_obj = 0;
121 _PTR(SObject) aSObj = myStudyDS->FindObjectID(theID);
122 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
124 if (!aSComp || aSComp->IsNull()) {
125 MESSAGE("Entry " << theID << " has not father component. Problem ??");
129 // Mantis issue 0020136: Drag&Drop in OB
130 _PTR(UseCaseBuilder) aUseCaseBuilder = myStudyDS->GetUseCaseBuilder();
131 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
132 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
133 // tree node is not yet set, it is a normal situation
137 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
138 if (!aFatherSO || aFatherSO->IsNull()) {
139 MESSAGE("Father SObject is not found. Problem ??");
143 std::string parent_id = aFatherSO->GetID();
144 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
146 if (it == entry2SuitObject.end()) {
147 MESSAGE("Father data object is not found. Problem ??");
151 SalomeApp_DataObject* aFatherDO = it->second;
153 it = entry2SuitObject.find(theID);
154 if (it != entry2SuitObject.end()) { // this SOobject is already added somethere
155 suit_obj = it->second;
156 SUIT_DataObject* oldFather = suit_obj->parent();
158 oldFather->removeChild(suit_obj, false);
159 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
160 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
161 model->forgetObject( suit_obj );
163 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
164 oldFatherSA->updateItem();
169 suit_obj = new SalomeApp_DataObject(aSObj);
170 entry2SuitObject[theID] = suit_obj;
173 suit_obj->updateItem();
174 // define position in the data tree (in aFatherDO) to insert the aSObj
176 //int childDataObjCount = aFatherDO->childCount();
177 _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
178 for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
179 if (aUseCaseIter->Value()->GetID() == theID) {
185 aFatherDO->insertChildAtPos(suit_obj, pos);
186 //aFatherDO->insertChild(suit_obj, pos);
187 aFatherDO->updateItem();
189 /* Define visibility state */
190 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
191 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
192 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
193 if (!moduleTitle.isEmpty()) {
194 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
196 if(aDisplayer->canBeDisplayed(theID.c_str())) {
197 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState ); //hide the just added object
198 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
201 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
205 } // END: work with tree nodes structure
206 else { // BEGIN: work with study structure
207 EntryMapIter it = entry2SuitObject.find( theID );
208 if ( it != entry2SuitObject.end() ) {
209 MESSAGE("Entry " << theID << " is already added. Problem ??");
213 int last2Pnt_pos = theID.rfind( ":" );
214 std::string parent_id = theID.substr( 0, last2Pnt_pos );
215 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
217 if ( parent_id.length() == 3 ) // "0:1" - root item?
219 // It's probably a SComponent
220 if ( theID == aSComp->GetID() )
221 suit_obj = new SalomeApp_ModuleObject( aSComp );
223 suit_obj = new SalomeApp_DataObject( aSObj );
227 suit_obj = new SalomeApp_DataObject( aSObj );
230 it = entry2SuitObject.find( parent_id );
231 if ( it != entry2SuitObject.end() ) {
232 SalomeApp_DataObject* father = it->second;
233 father->insertChildAtTag( suit_obj, tag );
236 if ( parent_id.length() == 3 ) // "0:1" - root item?
238 // This should be for a module
239 SUIT_DataObject* father=myStudy->root();
240 father->appendChild(suit_obj);
244 MESSAGE("SHOULD NEVER GET HERE!!!");
246 //Try to find the SalomeApp_DataObject object parent
247 std::string root_id = parent_id.substr( 0, 4 );
248 std::string obj_id = parent_id.substr( 4 );
251 std::string::size_type debut = 0;
252 std::string::size_type fin;
253 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
255 fin = obj_id.find_first_of( ':', debut );
256 if ( fin == std::string::npos ) {
258 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
259 entry2SuitObject[parent_id] = anObj;
262 anID = root_id + obj_id.substr( 0, fin );
263 EntryMapIter it2 = entry2SuitObject.find( anID );
264 if ( it2 == entry2SuitObject.end() ) {
265 //the ID is not known in entry2SuitObject
266 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
267 entry2SuitObject[anID] = anObj;
273 anObj->insertChildAtTag( suit_obj, tag );
276 entry2SuitObject[theID] = suit_obj;
277 } // END: work with study structure
282 EntryMapIter it = entry2SuitObject.find( theID );
283 if ( it != entry2SuitObject.end() )
285 suit_obj = it->second;
286 // VSR: object is not removed, since SALOMEDS::SObject is not actually removed,
287 // only its attributes are cleared;
288 // thus, the object can be later reused
289 suit_obj->updateItem();
290 //SUIT_DataObject* father=suit_obj->parent();
292 // father->removeChild(suit_obj);
293 //entry2SuitObject.erase(it);
297 MESSAGE("Want to remove an unknown object" << theID);
303 //MESSAGE("Want to modify an object " << theID);
304 EntryMapIter it = entry2SuitObject.find( theID );
305 if ( it != entry2SuitObject.end() )
307 suit_obj = it->second;
308 suit_obj->updateItem();
312 MESSAGE("Want to modify an unknown object" << theID);
316 case 5: //IOR of the object modified
318 EntryMapIter it = entry2SuitObject.find( theID );
319 if ( it != entry2SuitObject.end() )
320 suit_obj = it->second;
322 /* Define visibility state */
323 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
324 if ( suit_obj && !isComponent ) {
325 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
326 if (!moduleTitle.isEmpty()) {
327 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
329 if(aDisplayer->canBeDisplayed(theID.c_str())) {
330 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
331 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
334 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
340 #ifndef DISABLE_PYCONSOLE
341 case 6: //NoteBook variables were modified
343 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
347 default:MESSAGE("Unknown event: " << event);break;
349 } //notifyObserverID_real
354 entry2SuitObject.clear();
355 SUIT_DataObject* o = myStudy->root();
357 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
359 std::string entry = so->entry().toLatin1().constData();
361 entry2SuitObject[entry] = so;
363 if ( o->childCount() > 0 ) {
364 // parse the children
367 else if ( o->nextBrother() > 0 ) {
368 o = o->nextBrother();
371 // step to the next appropriate parent
374 if ( o->nextBrother() ) {
375 o = o->nextBrother();
385 _PTR(Study) myStudyDS;
386 SalomeApp_Study* myStudy;
387 EntryMap entry2SuitObject;
394 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
395 : LightApp_Study( app ), myObserver( 0 )
402 SalomeApp_Study::~SalomeApp_Study()
405 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
406 myObserver->_default_POA()->deactivate_object( oid.in() );
410 #ifndef DISABLE_PYCONSOLE
411 void SalomeApp_Study::onNoteBookVarUpdate( QString theVarName)
413 emit notebookVarUpdated( theVarName );
420 int SalomeApp_Study::id() const
424 id = studyDS()->StudyId();
431 QString SalomeApp_Study::studyName() const
433 // redefined from SUIT_Study to update study name properly since
434 // it can be changed outside of GUI
435 // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
437 QString newName = QString::fromUtf8(studyDS()->Name().c_str());
438 if ( LightApp_Study::studyName() != newName ) {
439 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
440 that->setStudyName( newName );
441 ((SalomeApp_Application*)application())->updateDesktopTitle();
444 return LightApp_Study::studyName();
448 Gets studyDS pointer.
450 _PTR(Study) SalomeApp_Study::studyDS() const
458 bool SalomeApp_Study::createDocument( const QString& theStr )
460 MESSAGE( "createDocument" );
462 // initialize myStudyDS, read HDF file
463 QString aName = newStudyName();
467 study = _PTR(Study)( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
470 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
471 tr("ERR_ERROR"), tr("ERR_ACTIVE_STUDY_CREATE") );
477 setStudyName( aName );
480 SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
481 #ifdef WITH_SALOMEDS_OBSERVER
482 aRoot->setToSynchronize(false);
486 bool aRet = CAM_Study::createDocument( theStr );
488 #ifdef WITH_SALOMEDS_OBSERVER
489 myObserver = new Observer_i(myStudyDS,this);
490 //attach an observer to the study with notification of modifications
491 myStudyDS->attach(myObserver->_this(),true);
494 emit created( this );
501 \param theFileName - name of file
503 bool SalomeApp_Study::openDocument( const QString& theFileName )
505 MESSAGE( "openDocument" );
507 // initialize myStudyDS, read HDF file
510 study = _PTR(Study) ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
513 SUIT_MessageBox::critical( SUIT_Session::session()->activeApplication()->desktop(),
514 tr("ERR_ERROR"), tr("ERR_ACTIVE_STUDY_OPEN") );
521 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
523 // update loaded data models: call open() and update() on them.
526 QListIterator<CAM_DataModel*> it( dm_s );
527 while ( it.hasNext() )
528 openDataModel( studyName(), it.next() );
530 // this will build a SUIT_DataObject-s tree under myRoot member field
531 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
532 // but tree that corresponds to not-loaded data models will be updated any way.
533 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
535 #ifdef WITH_SALOMEDS_OBSERVER
536 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
537 myObserver = new Observer_i(myStudyDS,this);
538 //attach an observer to the study with notification of modifications
539 myStudyDS->attach(myObserver->_this(),true);
542 bool res = CAM_Study::openDocument( theFileName );
545 study->IsSaved(true);
547 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
549 std::vector<int> savePoints = getSavePoints();
550 if ( savePoints.size() > 0 )
551 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
554 ((SalomeApp_Application*)application())->updateObjectBrowser( true );
559 Connects GUI study to SALOMEDS one already loaded into StudyManager
560 \param theStudyName - name of study
562 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
564 MESSAGE( "loadDocument" );
566 // obtain myStudyDS from StudyManager
567 _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
573 setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
575 //SRN: BugID IPAL9021, put there the same code as in a method openDocument
577 // update loaded data models: call open() and update() on them.
581 QListIterator<CAM_DataModel*> it( dm_s );
582 while ( it.hasNext() )
583 openDataModel( studyName(), it.next() );
585 // this will build a SUIT_DataObject-s tree under myRoot member field
586 // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
587 // but tree that corresponds to not-loaded data models will be updated any way.
588 ((SalomeApp_Application*)application())->updateObjectBrowser( false );
590 #ifdef WITH_SALOMEDS_OBSERVER
591 dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
592 myObserver = new Observer_i(myStudyDS,this);
593 //attach an observer to the study with notification of modifications
594 myStudyDS->attach(myObserver->_this(),true);
597 bool res = CAM_Study::openDocument( theStudyName );
599 //rnv: to fix the "0051779: TC7.2.0: Save operation works incorrectly for study loaded from data server"
600 // mark study as "not saved" after call openDocument( ... ) method.
604 bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
606 std::vector<int> savePoints = getSavePoints();
607 if ( savePoints.size() > 0 )
608 SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
611 //SRN: BugID IPAL9021: End
617 \param theFileName - name of file
619 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
621 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
623 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
625 ModelList list; dataModels( list );
627 QListIterator<CAM_DataModel*> it( list );
628 QStringList listOfFiles;
629 while ( it.hasNext() ) {
630 // Cast to LightApp class in order to give a chance
631 // to light modules to save their data
632 if ( LightApp_DataModel* aModel =
633 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
635 aModel->saveAs( theFileName, this, listOfFiles );
636 if ( !listOfFiles.isEmpty() )
637 saveModuleData(aModel->module()->name(), listOfFiles);
641 // save SALOMEDS document
642 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
646 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
647 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
648 bool res = (isAscii ?
649 SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
650 SalomeApp_Application::studyMgr()->SaveAs ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
651 && CAM_Study::saveDocumentAs( theFileName );
653 res = res && saveStudyData(theFileName);
662 Saves previously opened document
664 bool SalomeApp_Study::saveDocument()
666 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
668 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
670 ModelList list; dataModels( list );
672 QListIterator<CAM_DataModel*> it( list );
673 QStringList listOfFiles;
674 while ( it.hasNext() ) {
675 // Cast to LightApp class in order to give a chance
676 // to light modules to save their data
677 if ( LightApp_DataModel* aModel =
678 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
680 aModel->save(listOfFiles);
681 if ( !listOfFiles.isEmpty() )
682 saveModuleData(aModel->module()->name(), listOfFiles);
686 // save SALOMEDS document
687 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
691 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
692 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
693 bool res = (isAscii ?
694 SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
695 SalomeApp_Application::studyMgr()->Save ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
697 res = res && saveStudyData(studyName());
707 void SalomeApp_Study::closeDocument(bool permanently)
709 LightApp_Study::closeDocument(permanently);
711 // close SALOMEDS document
712 _PTR(Study) studyPtr = studyDS();
716 myStudyDS->detach( myObserver->_this() );
718 SalomeApp_Application::studyMgr()->Close( studyPtr );
720 SALOMEDSClient_Study* aStudy = 0;
721 setStudyDS( _PTR(Study)(aStudy) );
726 Dump study operation. Writes a Python dump file using
727 SALOMEDS services. Additionally, gives a chance to light modules
728 to participate in dump study operation.
730 \param theFileName - full path to the output Python file
731 \param toPublish - if true, all objects are published in a study
732 by the output script, including those not orignally present
733 in the current study.
734 \param isMultiFile - if true, each module's dump is written into
735 a separate Python file, otherwise a single output file is written
736 \param toSaveGUI - if true, the GUI state is written
738 \return - true if the operation succeeds, and false otherwise.
740 bool SalomeApp_Study::dump( const QString& theFileName,
746 _PTR(AttributeParameter) ap;
747 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
748 _PTR(Study) aStudy = studyDS();
750 if( ip->isDumpPython( aStudy ) )
751 ip->setDumpPython( aStudy ); //Unset DumpPython flag.
753 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
754 ip->setDumpPython( aStudy );
755 //SRN: create a temporary save point
756 savePoint = SalomeApp_VisualState(
757 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
760 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
761 // This is an optional but important step, it gives a chance to light modules
762 // to dump their data as a part of common dump study operation
766 QListIterator<CAM_DataModel*> it( list );
767 QStringList listOfFiles;
768 while ( it.hasNext() ) {
769 if ( LightApp_DataModel* aModel =
770 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
772 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
773 !listOfFiles.isEmpty() )
774 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
775 // This code is shared with persistence mechanism.
776 // NOTE: this should be revised if behavior of saveModuleData() changes!
777 saveModuleData(aModel->module()->name(), listOfFiles);
781 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
782 // any light module is present in the current configuration
783 QFileInfo aFileInfo( theFileName );
784 bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
785 aFileInfo.baseName().toUtf8().data(),
789 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
791 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
792 // This code is shared with persistence mechanism.
793 // NOTE: this should be revised if behavior of saveStudyData() changes!
794 saveStudyData( theFileName );
800 \return true, if study is modified in comparison with last open/save
802 bool SalomeApp_Study::isModified() const
804 bool isAnyChanged = studyDS() && studyDS()->IsModified();
806 isAnyChanged = LightApp_Study::isModified();
812 Set study modified to \a on.
814 void SalomeApp_Study::Modified()
816 if(_PTR(Study) aStudy = studyDS())
818 LightApp_Study::Modified();
822 \return if data model is saved
824 bool SalomeApp_Study::isSaved() const
826 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
828 isAllSaved = LightApp_Study::isSaved();
835 \param theModuleName - name of module
836 \param theListOfFiles - list of files to be saved
838 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
840 int aNb = theListOfFiles.count();
844 std::vector<std::string> aListOfFiles ( aNb );
846 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
847 if ( (*it).isEmpty() )
849 aListOfFiles[anIndex] = (*it).toUtf8().data();
852 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
857 \param theModuleName - name of module
858 \param theListOfFiles - list of files to be loaded
860 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
862 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
864 int i, aLength = aListOfFiles.size() - 1;
868 //Get a temporary directory for saved a file
869 theListOfFiles.append(aListOfFiles[0].c_str());
871 for(i = 0; i < aLength; i++)
872 theListOfFiles.append(aListOfFiles[i+1].c_str());
876 Re-implemented from LightApp_Study, actually does not save anything but
877 simply cleans up light modules' data
879 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
881 ModelList list; dataModels( list );
882 QListIterator<CAM_DataModel*> it( list );
883 std::vector<std::string> listOfFiles(0);
884 while ( it.hasNext() ){
885 LightApp_DataModel* aLModel =
886 dynamic_cast<LightApp_DataModel*>( it.next() );
887 // It is safe to call SetListOfFiles() for any kind of module
888 // because SetListOfFiles() does nothing for full modules :)
890 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
898 bool SalomeApp_Study::openStudyData( const QString& theFileName )
906 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
912 Virtual method re-implemented from LightApp_Study in order to create
913 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
915 \param theDataModel - data model instance to create a module object for
916 \param theParent - the module object's parent (normally it's the study root)
917 \return the module object instance
918 \sa LightApp_Study class, LightApp_DataModel class
920 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
921 SUIT_DataObject* theParent ) const
923 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
925 // Ensure that SComponent instance is published in the study for the given module
926 // This line causes automatic creation of SalomeApp_ModuleObject in case if
927 // WITH_SALOMEDS_OBSERVER is defined
928 that->addComponent( theDataModel );
930 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
931 // or by someone else so check if it exists first of all
932 CAM_ModuleObject* res = 0;
934 DataObjectList children = root()->children();
935 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
936 for( ; !res && anIt!=aLast; anIt++ )
938 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
939 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
944 _PTR(Study) aStudy = studyDS();
948 _PTR(SComponent) aComp = aStudy->FindComponent(
949 theDataModel->module()->name().toStdString() );
953 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
962 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
964 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
966 CAM_Study::dataModelInserted(dm);
972 Create SComponent for module, using default engine (CORBAless)
974 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
976 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
977 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
979 // Check SComponent existance
980 _PTR(Study) aStudy = studyDS();
984 std::string aCompDataType = dm->module()->name().toStdString();
986 _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
989 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
990 aComp = aBuilder->NewComponent(aCompDataType);
991 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
992 QString anIconName = dm->module()->iconName();
993 if (!anIconName.isEmpty()) {
994 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
996 anAttr->SetPixMap(anIconName.toStdString());
999 // Set default engine IOR
1000 // Issue 21377 - using separate engine for each type of light module
1001 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
1003 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
1004 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
1005 SalomeApp_DataModel::synchronize( aComp, this );
1008 _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
1009 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
1010 QString anIconName = dm->module()->iconName();
1011 if (!anIconName.isEmpty()) {
1012 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
1014 anAttr->SetPixMap(anIconName.toStdString());
1016 // Set default engine IOR
1024 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1029 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1030 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1031 _PTR(Study) aStudy = studyDS(); // shared_ptr cannot be used here
1032 _PTR(SComponent) aSComp;
1034 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1036 // Issue 21377 - using separate engine for each type of light module
1037 std::string aCompDataType = dm->module()->name().toStdString();
1038 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1039 aSComp = aStudy->FindComponent( aCompDataType );
1042 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1044 QString anId = aDM->getRootEntry( this );
1045 if ( anId.isEmpty() )
1046 return true; // Probably nothing to load
1047 anEngine = aDM->getModule()->engineIOR();
1048 if ( anEngine.isEmpty() )
1050 aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
1054 _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
1057 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1059 catch( const SALOME::SALOME_Exception& ) {
1060 // Oops, something went wrong while loading -> return an error
1063 // Something has been read -> create data model tree
1064 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1065 // aDM->buildTree( aSComp, 0, this );
1068 // Don't return false here, for there might be no data
1069 // for a given component in the study yet
1071 QStringList listOfFiles;
1072 openModuleData(dm->module()->name(), listOfFiles);
1073 if (dm && dm->open(studyName, this, listOfFiles)) {
1074 // Remove the files and temporary directory, created
1075 // for this module by LightApp_Engine_i::Load()
1076 bool isMultiFile = false; // TODO: decide, how to access this parameter
1077 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1079 // Something has been read -> create data model tree
1080 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1082 aDM->update(NULL, this);
1089 Create new study name.
1091 QString SalomeApp_Study::newStudyName() const
1093 std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
1094 QString prefix( "Study%1" ), newName, curName;
1095 int i = 1, j, n = studies.size();
1096 while ( newName.isEmpty() ){
1097 curName = prefix.arg( i );
1098 for ( j = 0 ; j < n; j++ ){
1099 if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
1111 Note that this method does not create or activate SalomeApp_Engine_i instance,
1112 therefore it can be called safely for any kind of module, but for full
1113 modules it returns an empty list.
1114 \return list of files used by module: to be used by CORBAless modules
1115 \param theModuleName - name of module
1117 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1119 // Issue 21377 - using separate engine for each type of light module
1120 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1122 return aDefaultEngine->GetListOfFiles(id());
1124 std::vector<std::string> aListOfFiles;
1125 return aListOfFiles;
1129 Sets list of files used by module: to be used by CORBAless modules.
1130 Note that this method does not create or activate SalomeApp_Engine_i instance,
1131 therefore it can be called safely for any kind of module, but for full
1132 modules it simply does nothing.
1133 \param theModuleName - name of module
1134 \param theListOfFiles - list of files
1136 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1137 const std::vector<std::string> theListOfFiles )
1139 // Issue 21377 - using separate engine for each type of light module
1140 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1142 aDefaultEngine->SetListOfFiles(theListOfFiles, id());
1146 \return temporary directory for saving files of modules
1148 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1150 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1151 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1156 Removes temporary files
1158 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1163 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
1164 if (aListOfFiles.size() > 0) {
1165 std::string aTmpDir = aListOfFiles[0];
1167 const int n = aListOfFiles.size() - 1;
1168 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
1170 for (int i = 0; i < n; i++)
1171 aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
1173 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
1177 #ifndef DISABLE_PYCONSOLE
1179 Mark the study as saved in the file
1180 \param theFileName - the name of file
1182 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1184 setStudyName(theFileName);
1185 studyDS()->Name(theFileName.toStdString());
1186 setIsSaved( isSaved );
1190 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1192 LightApp_DataObject* o = 0;
1194 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toLatin1().constData() ) );
1197 o = LightApp_Study::findObjectByEntry( theEntry );
1203 Deletes all references to object
1206 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1208 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1209 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1210 for( int i=0, n=aRefs.size(); i<n; i++ )
1212 _PTR( SObject ) o = aRefs[i];
1213 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1215 sb->RemoveReference( o );
1216 sb->RemoveObjectWithChildren( o );
1222 \return real entry by entry of reference
1223 \param entry - entry of reference object
1225 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1227 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1228 _PTR(SObject) refobj;
1230 if( obj && obj->ReferencedObject( refobj ) )
1231 return refobj->GetID().c_str();
1232 return LightApp_Study::referencedToEntry( entry );
1236 \return component data type for entry
1238 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1240 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1242 return LightApp_Study::componentDataType( entry );
1243 return obj->GetFatherComponent()->ComponentDataType().c_str();
1247 \return true if entry corresponds to component
1249 bool SalomeApp_Study::isComponent( const QString& entry ) const
1251 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1252 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1256 \return entries of object children
1258 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1260 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1261 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1262 anIter->InitEx( true );
1263 while( anIter->More() )
1265 _PTR(SObject) val( anIter->Value() );
1266 child_entries.append( val->GetID().c_str() );
1272 Fills list with components names
1273 \param comp - list to be filled
1275 void SalomeApp_Study::components( QStringList& comps ) const
1277 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1279 _PTR(SComponent) aComponent ( it->Value() );
1280 // skip the magic "Interface Applicative" component
1281 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1282 comps.append( aComponent->ComponentDataType().c_str() );
1287 Get the entry for the given module
1288 \param comp - list to be filled
1289 \return module root's entry
1291 QString SalomeApp_Study::centry( const QString& comp ) const
1294 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1296 _PTR(SComponent) aComponent ( it->Value() );
1297 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1298 e = aComponent->GetID().c_str();
1304 \return a list of saved points' IDs
1306 std::vector<int> SalomeApp_Study::getSavePoints()
1310 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1313 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1314 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1315 for(; anIter->More(); anIter->Next())
1317 _PTR(SObject) val( anIter->Value() );
1318 _PTR(GenericAttribute) genAttr;
1319 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1326 Removes a given save point
1328 void SalomeApp_Study::removeSavePoint(int savePoint)
1330 if(savePoint <= 0) return;
1331 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1332 _PTR(SObject) so = AP->GetSObject();
1333 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1334 builder->RemoveObjectWithChildren(so);
1338 \return a name of save point
1340 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1342 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1343 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1344 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1348 Sets a name of save point
1350 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1352 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1353 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1354 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1358 * \brief Restores the study state
1360 void SalomeApp_Study::restoreState(int savePoint)
1362 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1367 Slot: called on change of a root of a data model. Redefined from CAM_Study
1369 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1371 LightApp_Study::updateModelRoot( dm );
1373 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1374 // it must always be the last one.
1375 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );