1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #ifndef DISABLE_PYCONSOLE
24 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
27 #include "SalomeApp_Study.h"
29 #include "SalomeApp_Module.h"
30 #include "SalomeApp_DataObject.h"
31 #include "SalomeApp_DataModel.h"
32 #include "SalomeApp_Application.h"
33 #include "SalomeApp_Engine_i.h"
34 #include "SalomeApp_VisualState.h"
36 // temporary commented
37 //#include <OB_Browser.h>
39 #include <QCoreApplication>
42 #include "SALOME_Event.h"
43 #include "Basics_Utils.hxx"
45 #include <SUIT_ResourceMgr.h>
46 #include <SUIT_TreeModel.h>
47 #include <SUIT_DataBrowser.h>
48 #include <SUIT_MessageBox.h>
49 #include <SUIT_Session.h>
50 #include <SUIT_Desktop.h>
52 #include <LightApp_Displayer.h>
54 #include "utilities.h"
56 #include "SALOMEDS_Tool.hxx"
58 #include "SALOMEDSClient_ClientFactory.hxx"
60 #include <SALOMEconfig.h>
61 #include CORBA_SERVER_HEADER(SALOME_Exception)
63 //#define NOTIFY_BY_EVENT
65 class ObserverEvent : public QEvent
68 ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
78 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
80 typedef std::map<std::string, SalomeApp_DataObject*> EntryMap;
81 typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
85 Observer_i( SalomeApp_Study* aStudy):QObject(aStudy)
91 SUIT_DataObject* findObject( const char* theID ) const
93 EntryMap::const_iterator it = entry2SuitObject.find( theID );
94 return it != entry2SuitObject.end() ? it->second : 0;
97 virtual void notifyObserverID(const char* theID, CORBA::Long event)
99 #ifdef NOTIFY_BY_EVENT
100 QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
102 notifyObserverID_real(theID,event);
106 virtual bool event(QEvent *event)
108 if (event->type() == QEvent::User )
110 //START_TIMING(notify);
111 notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
112 //END_TIMING(notify,100);
117 void notifyObserverID_real(const std::string& theID, long event)
119 SalomeApp_DataObject* suit_obj = 0;
124 _PTR(SObject) aSObj = SalomeApp_Application::getStudy()->FindObjectID(theID);
125 _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
127 if (!aSComp || aSComp->IsNull()) {
128 MESSAGE("Entry " << theID << " has not father component. Problem ??");
132 // Mantis issue 0020136: Drag&Drop in OB
133 _PTR(UseCaseBuilder) aUseCaseBuilder = SalomeApp_Application::getStudy()->GetUseCaseBuilder();
134 if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
135 if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
136 // tree node is not yet set, it is a normal situation
140 _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
141 if (!aFatherSO || aFatherSO->IsNull()) {
142 MESSAGE("Father SObject is not found. Problem ??");
146 std::string parent_id = aFatherSO->GetID();
147 EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
149 if (it == entry2SuitObject.end()) {
150 MESSAGE("Father data object is not found. Problem ??");
154 SalomeApp_DataObject* aFatherDO = it->second;
156 it = entry2SuitObject.find(theID);
157 if (it != entry2SuitObject.end()) { // this SOobject is already added somethere
158 suit_obj = it->second;
159 SUIT_DataObject* oldFather = suit_obj->parent();
161 oldFather->removeChild(suit_obj, false);
162 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
163 // MESSAGE("myStudy: " << myStudy->id() << " app " << app);
164 // MESSAGE("objectBrowser: "<< app->objectBrowser());
165 if (!app->objectBrowser()) {
166 MESSAGE("Object Browser not found. Problem ??");
169 SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
170 model->forgetObject( suit_obj );
172 if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
173 oldFatherSA->updateItem();
178 suit_obj = new SalomeApp_DataObject(aSObj);
179 entry2SuitObject[theID] = suit_obj;
182 suit_obj->updateItem();
183 // define position in the data tree (in aFatherDO) to insert the aSObj
185 //int childDataObjCount = aFatherDO->childCount();
186 _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
187 for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
188 if (aUseCaseIter->Value()->GetID() == theID) {
194 aFatherDO->insertChildAtPos(suit_obj, pos);
195 //aFatherDO->insertChild(suit_obj, pos);
196 aFatherDO->updateItem();
198 /* Define visibility state */
199 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
200 if ( suit_obj && !isComponent && myStudy->visibilityState( theID.c_str() ) == Qtx::UnpresentableState ) {
201 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
202 if (!moduleTitle.isEmpty()) {
203 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
205 if(aDisplayer->canBeDisplayed(theID.c_str())) {
206 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState ); //hide the just added object
207 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
210 //MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
214 } // END: work with tree nodes structure
215 else { // BEGIN: work with study structure
216 EntryMapIter it = entry2SuitObject.find( theID );
217 if ( it != entry2SuitObject.end() ) {
218 MESSAGE("Entry " << theID << " is already added. Problem ??");
222 int last2Pnt_pos = theID.rfind( ":" );
223 std::string parent_id = theID.substr( 0, last2Pnt_pos );
224 int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
226 if ( parent_id.length() == 3 ) // "0:1" - root item?
228 // It's probably a SComponent
229 if ( theID == aSComp->GetID() )
230 suit_obj = new SalomeApp_ModuleObject( aSComp );
232 suit_obj = new SalomeApp_DataObject( aSObj );
236 suit_obj = new SalomeApp_DataObject( aSObj );
239 it = entry2SuitObject.find( parent_id );
240 if ( it != entry2SuitObject.end() ) {
241 SalomeApp_DataObject* father = it->second;
242 father->insertChildAtTag( suit_obj, tag );
245 if ( parent_id.length() == 3 ) // "0:1" - root item?
247 // This should be for a module
248 SUIT_DataObject* father=myStudy->root();
249 father->appendChild(suit_obj);
253 MESSAGE("SHOULD NEVER GET HERE!!!");
255 //Try to find the SalomeApp_DataObject object parent
256 std::string root_id = parent_id.substr( 0, 4 );
257 std::string obj_id = parent_id.substr( 4 );
260 std::string::size_type debut = 0;
261 std::string::size_type fin;
262 SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
264 fin = obj_id.find_first_of( ':', debut );
265 if ( fin == std::string::npos ) {
267 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
269 entry2SuitObject[parent_id] = anObj;
272 anID = root_id + obj_id.substr( 0, fin );
273 EntryMapIter it2 = entry2SuitObject.find( anID );
274 if ( it2 == entry2SuitObject.end() ) {
275 //the ID is not known in entry2SuitObject
276 anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
278 entry2SuitObject[anID] = anObj;
285 anObj->insertChildAtTag( suit_obj, tag );
288 entry2SuitObject[theID] = suit_obj;
289 } // END: work with study structure
294 EntryMapIter it = entry2SuitObject.find( theID );
295 if ( it != entry2SuitObject.end() )
297 suit_obj = it->second;
298 suit_obj->updateItem();
299 SUIT_DataObject* father=suit_obj->parent();
301 father->removeChild(suit_obj);
302 entry2SuitObject.erase(it);
306 MESSAGE("Want to remove an unknown object" << theID);
312 //MESSAGE("Want to modify an object " << theID);
313 EntryMapIter it = entry2SuitObject.find( theID );
314 if ( it != entry2SuitObject.end() )
316 suit_obj = it->second;
317 suit_obj->updateItem();
321 MESSAGE("Want to modify an unknown object" << theID);
325 case 5: //IOR of the object modified
327 EntryMapIter it = entry2SuitObject.find( theID );
328 if ( it != entry2SuitObject.end() )
329 suit_obj = it->second;
331 /* Define visibility state */
332 bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
333 if ( suit_obj && !isComponent ) {
334 QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
335 if (!moduleTitle.isEmpty()) {
336 LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
338 if(aDisplayer->canBeDisplayed(theID.c_str())) {
339 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
340 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
343 //MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
349 #ifndef DISABLE_PYCONSOLE
350 case 6: //NoteBook variables were modified
352 myStudy->onNoteBookVarUpdate( QString( theID.c_str() ) );
356 default:MESSAGE("Unknown event: " << event);break;
358 } //notifyObserverID_real
363 entry2SuitObject.clear();
364 SUIT_DataObject* o = myStudy->root();
366 SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
368 std::string entry = so->entry().toUtf8().constData();
370 entry2SuitObject[entry] = so;
372 if ( o->childCount() > 0 ) {
373 // parse the children
376 else if ( o->nextBrother() > 0 ) {
377 o = o->nextBrother();
380 // step to the next appropriate parent
383 if ( o->nextBrother() ) {
384 o = o->nextBrother();
394 SalomeApp_Study* myStudy;
395 EntryMap entry2SuitObject;
402 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
403 : LightApp_Study( app ), myObserver( 0 )
405 myStudyDS = SalomeApp_Application::getStudy();
411 SalomeApp_Study::~SalomeApp_Study()
414 PortableServer::ObjectId_var oid = myObserver->_default_POA()->servant_to_id( myObserver );
415 myObserver->_default_POA()->deactivate_object( oid.in() );
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(), listOfFiles);
631 // save SALOMEDS document
632 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
636 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
637 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
638 bool res = studyDS()->SaveAs( theFileName.toUtf8().data(), isMultiFile, isAscii )
639 && CAM_Study::saveDocumentAs( theFileName );
641 res = res && saveStudyData(theFileName);
650 Saves previously opened document
652 bool SalomeApp_Study::saveDocument()
654 bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
656 SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
658 ModelList list; dataModels( list );
660 QListIterator<CAM_DataModel*> it( list );
661 QStringList listOfFiles;
662 while ( it.hasNext() ) {
663 // Cast to LightApp class in order to give a chance
664 // to light modules to save their data
665 if ( LightApp_DataModel* aModel =
666 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
668 aModel->save(listOfFiles);
669 if ( !listOfFiles.isEmpty() )
670 saveModuleData(aModel->module()->name(), listOfFiles);
674 // save SALOMEDS document
675 SUIT_ResourceMgr* resMgr = application()->resourceMgr();
679 bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
680 bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
681 bool res = studyDS()->Save( isMultiFile, isAscii ) && CAM_Study::saveDocument();
683 res = res && saveStudyData(studyName());
693 void SalomeApp_Study::closeDocument(bool permanently)
695 LightApp_Study::closeDocument(permanently);
697 // close SALOMEDS document
699 myStudyDS->detach( myObserver->_this() );
701 SUIT_Desktop* desk = SUIT_Session::session()->activeApplication()->desktop();
702 bool isBlocked = desk->signalsBlocked();
703 desk->blockSignals( true );
705 desk->blockSignals( isBlocked );
706 #ifndef DISABLE_PYCONSOLE
707 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( application() );
708 app->getPyInterp()->destroy();
714 Dump study operation. Writes a Python dump file using
715 SALOMEDS services. Additionally, gives a chance to light modules
716 to participate in dump study operation.
718 \param theFileName - full path to the output Python file
719 \param toPublish - if true, all objects are published in a study
720 by the output script, including those not orignally present
721 in the current study.
722 \param isMultiFile - if true, each module's dump is written into
723 a separate Python file, otherwise a single output file is written
724 \param toSaveGUI - if true, the GUI state is written
726 \return - true if the operation succeeds, and false otherwise.
728 bool SalomeApp_Study::dump( const QString& theFileName,
734 _PTR(AttributeParameter) ap;
735 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
737 if( ip->isDumpPython() )
738 ip->setDumpPython(); //Unset DumpPython flag.
740 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
742 //SRN: create a temporary save point
743 savePoint = SalomeApp_VisualState(
744 dynamic_cast<SalomeApp_Application*>( application() ) ).storeState();
747 // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
748 // This is an optional but important step, it gives a chance to light modules
749 // to dump their data as a part of common dump study operation
753 QListIterator<CAM_DataModel*> it( list );
754 QStringList listOfFiles;
755 while ( it.hasNext() ) {
756 if ( LightApp_DataModel* aModel =
757 dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
759 if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) &&
760 !listOfFiles.isEmpty() )
761 // This call simply passes the data model's dump output to SalomeApp_Engine servant.
762 // This code is shared with persistence mechanism.
763 // NOTE: this should be revised if behavior of saveModuleData() changes!
764 saveModuleData(aModel->module()->name(), listOfFiles);
768 // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if
769 // any light module is present in the current configuration
770 QFileInfo aFileInfo( theFileName );
771 bool res = myStudyDS->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
772 aFileInfo.baseName().toUtf8().data(),
776 removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
778 // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
779 // This code is shared with persistence mechanism.
780 // NOTE: this should be revised if behavior of saveStudyData() changes!
781 saveStudyData( theFileName );
787 \return true, if study is modified in comparison with last open/save
789 bool SalomeApp_Study::isModified() const
791 bool isAnyChanged = studyDS() && studyDS()->IsModified();
793 isAnyChanged = LightApp_Study::isModified();
799 Set study modified to \a on.
801 void SalomeApp_Study::Modified()
803 myStudyDS->Modified();
804 LightApp_Study::Modified();
808 \return if data model is saved
810 bool SalomeApp_Study::isSaved() const
812 bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
814 isAllSaved = LightApp_Study::isSaved();
821 \param theModuleName - name of module
822 \param theListOfFiles - list of files to be saved
824 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
826 int aNb = theListOfFiles.count();
830 std::vector<std::string> aListOfFiles ( aNb );
832 for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
833 if ( (*it).isEmpty() )
835 aListOfFiles[anIndex] = (*it).toUtf8().data();
838 SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
843 \param theModuleName - name of module
844 \param theListOfFiles - list of files to be loaded
846 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
848 std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName.toStdString().c_str() );
850 int i, aLength = aListOfFiles.size() - 1;
854 //Get a temporary directory for saved a file
855 theListOfFiles.append(aListOfFiles[0].c_str());
857 for(i = 0; i < aLength; i++)
858 theListOfFiles.append(aListOfFiles[i+1].c_str());
862 Re-implemented from LightApp_Study, actually does not save anything but
863 simply cleans up light modules' data
865 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
867 ModelList list; dataModels( list );
868 QListIterator<CAM_DataModel*> it( list );
869 std::vector<std::string> listOfFiles(0);
870 while ( it.hasNext() ){
871 LightApp_DataModel* aLModel =
872 dynamic_cast<LightApp_DataModel*>( it.next() );
873 // It is safe to call SetListOfFiles() for any kind of module
874 // because SetListOfFiles() does nothing for full modules :)
876 SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
884 bool SalomeApp_Study::openStudyData( const QString& theFileName )
890 Virtual method re-implemented from LightApp_Study in order to create
891 the module object connected to SALOMEDS - SalomeApp_ModuleObject.
893 \param theDataModel - data model instance to create a module object for
894 \param theParent - the module object's parent (normally it's the study root)
895 \return the module object instance
896 \sa LightApp_Study class, LightApp_DataModel class
898 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel,
899 SUIT_DataObject* theParent ) const
901 SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
903 // Ensure that SComponent instance is published in the study for the given module
904 // This line causes automatic creation of SalomeApp_ModuleObject in case if
905 // WITH_SALOMEDS_OBSERVER is defined
906 that->addComponent( theDataModel );
908 // SalomeApp_ModuleObject might have been created by SALOMEDS observer
909 // or by someone else so check if it exists first of all
910 CAM_ModuleObject* res = 0;
912 DataObjectList children = root()->children();
913 DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
914 for( ; !res && anIt!=aLast; anIt++ )
916 SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
917 if ( obj && obj->componentDataType() == theDataModel->module()->name() )
922 _PTR(SComponent) aComp = myStudyDS->FindComponent(
923 theDataModel->module()->name().toStdString() );
927 res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
936 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
938 MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
940 CAM_Study::dataModelInserted(dm);
946 Create SComponent for module, using default engine (CORBAless)
948 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
950 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
951 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
953 // Check SComponent existance
955 std::string aCompDataType = dm->module()->name().toStdString();
957 _PTR(SComponent) aComp = myStudyDS->FindComponent(aCompDataType);
960 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
961 aComp = aBuilder->NewComponent(aCompDataType);
962 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
963 QString anIconName = dm->module()->iconName();
964 if (!anIconName.isEmpty()) {
965 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
967 anAttr->SetPixMap(anIconName.toStdString());
970 // Set default engine IOR
971 // Issue 21377 - using separate engine for each type of light module
972 std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
974 aBuilder->DefineComponentInstance(aComp, anEngineIOR);
975 //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
976 SalomeApp_DataModel::synchronize( aComp, this );
979 _PTR(StudyBuilder) aBuilder = myStudyDS->NewBuilder();
980 aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
981 QString anIconName = dm->module()->iconName();
982 if (!anIconName.isEmpty()) {
983 _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
985 anAttr->SetPixMap(anIconName.toStdString());
987 // Set default engine IOR
995 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
1000 // SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
1001 SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
1002 _PTR(SComponent) aSComp;
1004 // 1. aModule == 0 means that this is a light module (no CORBA enigine)
1006 // Issue 21377 - using separate engine for each type of light module
1007 std::string aCompDataType = dm->module()->name().toStdString();
1008 anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
1009 aSComp = myStudyDS->FindComponent( aCompDataType );
1012 SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1014 QString anId = aDM->getRootEntry( this );
1015 if ( anId.isEmpty() )
1016 return true; // Probably nothing to load
1017 anEngine = aDM->getModule()->engineIOR();
1018 if ( anEngine.isEmpty() )
1020 aSComp = myStudyDS->FindComponentID( std::string( anId.toLatin1() ) );
1024 _PTR(StudyBuilder) aBuilder( myStudyDS->NewBuilder() );
1027 aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
1029 catch( const SALOME::SALOME_Exception& ) {
1030 // Oops, something went wrong while loading -> return an error
1033 // Something has been read -> create data model tree
1034 //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
1035 // aDM->buildTree( aSComp, 0, this );
1038 // Don't return false here, for there might be no data
1039 // for a given component in the study yet
1041 QStringList listOfFiles;
1042 openModuleData(dm->module()->name(), listOfFiles);
1043 if (dm && dm->open(studyName, this, listOfFiles)) {
1044 // Remove the files and temporary directory, created
1045 // for this module by LightApp_Engine_i::Load()
1046 bool isMultiFile = false; // TODO: decide, how to access this parameter
1047 RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
1048 std::vector<std::string> listOfFiles ;
1049 SetListOfFiles( dm->module()->name().toStdString().c_str(), listOfFiles );
1051 // Something has been read -> create data model tree
1052 LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
1054 aDM->update(NULL, this);
1061 Note that this method does not create or activate SalomeApp_Engine_i instance,
1062 therefore it can be called safely for any kind of module, but for full
1063 modules it returns an empty list.
1064 \return list of files used by module: to be used by CORBAless modules
1065 \param theModuleName - name of module
1067 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const
1069 // Issue 21377 - using separate engine for each type of light module
1070 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1072 return aDefaultEngine->GetListOfFiles();
1074 std::vector<std::string> aListOfFiles;
1075 return aListOfFiles;
1079 Sets list of files used by module: to be used by CORBAless modules.
1080 Note that this method does not create or activate SalomeApp_Engine_i instance,
1081 therefore it can be called safely for any kind of module, but for full
1082 modules it simply does nothing.
1083 \param theModuleName - name of module
1084 \param theListOfFiles - list of files
1086 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
1087 const std::vector<std::string> theListOfFiles )
1089 // Issue 21377 - using separate engine for each type of light module
1090 SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
1092 aDefaultEngine->SetListOfFiles(theListOfFiles);
1096 \return temporary directory for saving files of modules
1098 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool isMultiFile )
1100 std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
1101 std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
1106 Removes temporary files
1108 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
1113 SALOMEDS_Tool::ListOfFiles aListOfFiles = GetListOfFiles( theModuleName );
1114 if (aListOfFiles.size() > 0) {
1115 std::string aTmpDir = aListOfFiles[0];
1117 const int n = aListOfFiles.size() - 1;
1118 std::vector<std::string> aSeq;
1120 for (int i = 0; i < n; i++)
1121 aSeq.push_back(CORBA::string_dup(aListOfFiles[i + 1].c_str()));
1123 SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq, true);
1127 #ifndef DISABLE_PYCONSOLE
1129 Mark the study as saved in the file
1130 \param theFileName - the name of file
1132 void SalomeApp_Study::updateFromNotebook( const QString& theFileName, bool isSaved )
1134 setStudyName(theFileName);
1135 studyDS()->URL(theFileName.toStdString());
1136 setIsSaved( isSaved );
1140 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
1142 LightApp_DataObject* o = 0;
1144 o = dynamic_cast<LightApp_DataObject*>( myObserver->findObject( theEntry.toUtf8().constData() ) );
1147 o = LightApp_Study::findObjectByEntry( theEntry );
1153 Deletes all references to object
1156 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
1158 _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
1159 std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
1160 for( int i=0, n=aRefs.size(); i<n; i++ )
1162 _PTR( SObject ) o = aRefs[i];
1163 if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
1165 sb->RemoveReference( o );
1166 sb->RemoveObjectWithChildren( o );
1172 \return real entry by entry of reference
1173 \param entry - entry of reference object
1175 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
1177 _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
1178 _PTR(SObject) refobj;
1180 if( obj && obj->ReferencedObject( refobj ) )
1181 return refobj->GetID().c_str();
1182 return LightApp_Study::referencedToEntry( entry );
1186 \return component data type for entry
1188 QString SalomeApp_Study::componentDataType( const QString& entry ) const
1190 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1192 return LightApp_Study::componentDataType( entry );
1193 return obj->GetFatherComponent()->ComponentDataType().c_str();
1197 \return true if entry corresponds to component
1199 bool SalomeApp_Study::isComponent( const QString& entry ) const
1201 _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
1202 return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
1206 \return entries of object children
1208 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
1210 _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
1211 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
1212 anIter->InitEx( true );
1213 while( anIter->More() )
1215 _PTR(SObject) val( anIter->Value() );
1216 child_entries.append( val->GetID().c_str() );
1222 Fills list with components names
1223 \param comp - list to be filled
1225 void SalomeApp_Study::components( QStringList& comps ) const
1227 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
1229 _PTR(SComponent) aComponent ( it->Value() );
1230 // skip the magic "Interface Applicative" component
1231 if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
1232 comps.append( aComponent->ComponentDataType().c_str() );
1237 Get the entry for the given module
1238 \param comp - list to be filled
1239 \return module root's entry
1241 QString SalomeApp_Study::centry( const QString& comp ) const
1244 for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
1246 _PTR(SComponent) aComponent ( it->Value() );
1247 if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
1248 e = aComponent->GetID().c_str();
1254 \return a list of saved points' IDs
1256 std::vector<int> SalomeApp_Study::getSavePoints()
1260 _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
1263 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1264 _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
1265 for(; anIter->More(); anIter->Next())
1267 _PTR(SObject) val( anIter->Value() );
1268 _PTR(GenericAttribute) genAttr;
1269 if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
1276 Removes a given save point
1278 void SalomeApp_Study::removeSavePoint(int savePoint)
1280 if(savePoint <= 0) return;
1281 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1282 _PTR(SObject) so = AP->GetSObject();
1283 _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
1284 builder->RemoveObjectWithChildren(so);
1288 \return a name of save point
1290 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
1292 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1293 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1294 return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
1298 Sets a name of save point
1300 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
1302 _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
1303 _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
1304 ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
1308 * \brief Restores the study state
1310 void SalomeApp_Study::restoreState(int savePoint)
1312 SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
1317 Slot: called on change of a root of a data model. Redefined from CAM_Study
1319 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
1321 LightApp_Study::updateModelRoot( dm );
1323 // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
1324 // it must always be the last one.
1325 ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );