Back to index

salome-gui  6.5.0
SalomeApp_Study.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 #include "SalomeApp_Study.h"
00024 
00025 #include "SalomeApp_Module.h"
00026 #include "SalomeApp_DataObject.h"
00027 #include "SalomeApp_DataModel.h"
00028 #include "SalomeApp_Application.h"
00029 #include "SalomeApp_Engine_i.hxx"
00030 #include "SalomeApp_VisualState.h"
00031 
00032 // temporary commented
00033 //#include <OB_Browser.h>
00034 
00035 #include <QCoreApplication>
00036 #include <QEvent>
00037 #include <QFileInfo>
00038 #include "SALOME_Event.h"
00039 #include "Basics_Utils.hxx"
00040 
00041 #include <SUIT_ResourceMgr.h>
00042 #include <SUIT_TreeModel.h>
00043 #include <SUIT_DataBrowser.h>
00044 
00045 #include <LightApp_Displayer.h>
00046 
00047 #include "utilities.h"
00048 
00049 #include "SALOMEDS_Tool.hxx"
00050 
00051 #include "SALOMEDSClient_ClientFactory.hxx"
00052 
00053 #include <SALOMEconfig.h>
00054 #include CORBA_SERVER_HEADER(SALOME_Exception)
00055 
00056 //#define NOTIFY_BY_EVENT
00057 
00058 class ObserverEvent : public QEvent
00059 {
00060 public:
00061   ObserverEvent(const char* theID, CORBA::Long event):QEvent(QEvent::User)
00062   {
00063     _anID=theID;
00064     _event=event;
00065   }
00066 
00067   std::string _anID;
00068   CORBA::Long _event;
00069 };
00070 
00071 class SalomeApp_Study::Observer_i : public virtual POA_SALOMEDS::Observer, QObject
00072 {
00073   typedef std::map<std::string, SalomeApp_DataObject*>           EntryMap;
00074   typedef std::map<std::string, SalomeApp_DataObject*>::iterator EntryMapIter;
00075 
00076 public:
00077 
00078   Observer_i(_PTR(Study) aStudyDS, SalomeApp_Study* aStudy)
00079   {
00080     myStudyDS=aStudyDS;
00081     myStudy=aStudy;
00082     fillEntryMap();
00083   }
00084 
00085   SUIT_DataObject* findObject( const char* theID ) const
00086   {
00087     EntryMap::const_iterator it = entry2SuitObject.find( theID );
00088     return it != entry2SuitObject.end() ? it->second : 0;
00089   }
00090 
00091   virtual void notifyObserverID(const char* theID, CORBA::Long event)
00092   {
00093 #ifdef NOTIFY_BY_EVENT
00094     QCoreApplication::postEvent(this,new ObserverEvent(theID,event));
00095 #else
00096     notifyObserverID_real(theID,event);
00097 #endif
00098   }
00099 
00100   virtual bool event(QEvent *event)
00101   {
00102     if (event->type() == QEvent::User )
00103     {
00104       //START_TIMING(notify);
00105       notifyObserverID_real(static_cast<ObserverEvent *>(event)->_anID.c_str(),static_cast<ObserverEvent *>(event)->_event);
00106       //END_TIMING(notify,100);
00107     }
00108     return true;
00109   }
00110 
00111   void notifyObserverID_real(const std::string& theID, long event)
00112   {
00113     SalomeApp_DataObject* suit_obj = 0;
00114 
00115     switch(event) {
00116     case 1:
00117       { //Add sobject
00118         _PTR(SObject) aSObj = myStudyDS->FindObjectID(theID);
00119         _PTR(SComponent) aSComp = aSObj->GetFatherComponent();
00120 
00121         if (!aSComp || aSComp->IsNull()) {
00122           MESSAGE("Entry " << theID << " has not father component. Problem ??");
00123           return;
00124         }
00125 
00126         // Mantis issue 0020136: Drag&Drop in OB
00127         _PTR(UseCaseBuilder) aUseCaseBuilder = myStudyDS->GetUseCaseBuilder();
00128         if (aUseCaseBuilder->IsUseCaseNode(aSComp)) { // BEGIN: work with tree nodes structure
00129           if (!aUseCaseBuilder->IsUseCaseNode(aSObj)) {
00130             // tree node is not yet set, it is a normal situation
00131             return;
00132           }
00133 
00134           _PTR(SObject) aFatherSO = aUseCaseBuilder->GetFather(aSObj);
00135           if (!aFatherSO || aFatherSO->IsNull()) {
00136             MESSAGE("Father SObject is not found. Problem ??");
00137             return;
00138           }
00139 
00140           std::string parent_id = aFatherSO->GetID();
00141           EntryMapIter it = entry2SuitObject.find(parent_id.c_str());
00142 
00143           if (it == entry2SuitObject.end()) {
00144             MESSAGE("Father data object is not found. Problem ??");
00145             return;
00146           }
00147 
00148           SalomeApp_DataObject* aFatherDO = it->second;
00149 
00150           it = entry2SuitObject.find(theID);
00151           if (it != entry2SuitObject.end()) { // this SOobject is already added somethere
00152             suit_obj = it->second;
00153             SUIT_DataObject* oldFather = suit_obj->parent();
00154             if (oldFather) {
00155               oldFather->removeChild(suit_obj, false);
00156              SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( myStudy->application() );
00157              SUIT_AbstractModel* model = dynamic_cast<SUIT_AbstractModel*>(app->objectBrowser()->model());
00158              model->forgetObject( suit_obj );
00159               
00160               if (SalomeApp_DataObject* oldFatherSA = dynamic_cast<SalomeApp_DataObject*>(oldFather)) {
00161                 oldFatherSA->updateItem();
00162               }
00163             }
00164           }
00165           else {
00166             suit_obj = new SalomeApp_DataObject(aSObj);
00167             entry2SuitObject[theID] = suit_obj;
00168           }
00169 
00170          suit_obj->updateItem();
00171           // define position in the data tree (in aFatherDO) to insert the aSObj
00172           int pos = -1;
00173           //int childDataObjCount = aFatherDO->childCount();
00174           _PTR(UseCaseIterator) aUseCaseIter = aUseCaseBuilder->GetUseCaseIterator(aFatherSO);
00175           for (int cur = 0; aUseCaseIter->More() && pos < 0; cur++, aUseCaseIter->Next()) {
00176             if (aUseCaseIter->Value()->GetID() == theID) {
00177               pos = cur;
00178               break;
00179             }
00180           }
00181 
00182           aFatherDO->insertChildAtPos(suit_obj, pos);
00183           //aFatherDO->insertChild(suit_obj, pos);
00184           aFatherDO->updateItem();
00185 
00186         } // END: work with tree nodes structure
00187         else { // BEGIN: work with study structure
00188           EntryMapIter it = entry2SuitObject.find( theID );
00189           if ( it != entry2SuitObject.end() ) {
00190             MESSAGE("Entry " << theID << " is already added. Problem ??");
00191             return;
00192           }
00193 
00194           int last2Pnt_pos = theID.rfind( ":" );
00195           std::string parent_id = theID.substr( 0, last2Pnt_pos );
00196           int tag = atoi( theID.substr( last2Pnt_pos+1 ).c_str() );
00197 
00198           if ( parent_id.length() == 3 ) // "0:1" - root item?
00199           {
00200             // It's probably a SComponent
00201             if ( theID == aSComp->GetID() )
00202               suit_obj = new SalomeApp_ModuleObject( aSComp );
00203             else
00204               suit_obj = new SalomeApp_DataObject( aSObj );
00205           }
00206           else
00207           {
00208             suit_obj = new SalomeApp_DataObject( aSObj );
00209           }
00210 
00211           it = entry2SuitObject.find( parent_id );
00212           if ( it != entry2SuitObject.end() ) {
00213             SalomeApp_DataObject* father = it->second;
00214             father->insertChildAtTag( suit_obj, tag );
00215           }
00216           else {
00217             if ( parent_id.length() == 3 ) // "0:1" - root item?
00218             {
00219               // This should be for a module
00220               SUIT_DataObject* father=myStudy->root();
00221               father->appendChild(suit_obj);
00222             }
00223             else
00224             {
00225               MESSAGE("SHOULD NEVER GET HERE!!!");
00226 
00227               //Try to find the SalomeApp_DataObject object parent
00228               std::string root_id = parent_id.substr( 0, 4 );
00229               std::string obj_id = parent_id.substr( 4 );
00230 
00231               std::string anID;
00232               std::string::size_type debut = 0;
00233               std::string::size_type fin;
00234               SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( myStudy->root() );
00235               while ( 1 ) {
00236                 fin = obj_id.find_first_of( ':', debut );
00237                 if ( fin == std::string::npos ) {
00238                   //last id
00239                   anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut).c_str())-1));
00240                   entry2SuitObject[parent_id] = anObj;
00241                   break;
00242                 }
00243                 anID = root_id + obj_id.substr( 0, fin );
00244                 EntryMapIter it2 = entry2SuitObject.find( anID );
00245                 if ( it2 == entry2SuitObject.end() ) {
00246                   //the ID is not known in entry2SuitObject
00247                   anObj = dynamic_cast<SalomeApp_DataObject*>(anObj->childObject(atoi(obj_id.substr(debut, fin-debut).c_str())-1));
00248                   entry2SuitObject[anID] = anObj;
00249                 }
00250                 else
00251                   anObj = it2->second;
00252                 debut = fin+1;
00253               }
00254               anObj->insertChildAtTag( suit_obj, tag );
00255             }
00256           }
00257           entry2SuitObject[theID] = suit_obj;
00258         } // END: work with study structure
00259         break;
00260       }
00261     case 2:
00262       { // Remove sobject
00263         EntryMapIter it = entry2SuitObject.find( theID );
00264         if ( it != entry2SuitObject.end() )
00265         {
00266           suit_obj = it->second;
00267           // VSR: object is not removed, since SALOMEDS::SObject is not actually removed,
00268           //      only its attributes are cleared;
00269           //      thus, the object can be later reused
00270           suit_obj->updateItem();
00271           //SUIT_DataObject* father=suit_obj->parent();
00272           //if(father)
00273           //  father->removeChild(suit_obj);
00274           //entry2SuitObject.erase(it);
00275         }
00276         else
00277         {
00278           MESSAGE("Want to remove an unknown object" << theID);
00279         }
00280         break;
00281       }
00282     case 0:
00283       { //modify sobject
00284         //MESSAGE("Want to modify an object "  << theID);
00285         EntryMapIter it = entry2SuitObject.find( theID );
00286         if ( it != entry2SuitObject.end() )
00287         {
00288           suit_obj = it->second;
00289           suit_obj->updateItem();
00290         }
00291         else
00292         {
00293           MESSAGE("Want to modify an unknown object"  << theID);
00294         }
00295         break;
00296       }
00297     case 5: //IOR of the object modified
00298       {
00299         EntryMapIter it = entry2SuitObject.find( theID );
00300         if ( it != entry2SuitObject.end() )
00301           suit_obj = it->second;
00302 
00303         /* Define visibility state */
00304         bool isComponent = dynamic_cast<SalomeApp_ModuleObject*>( suit_obj ) != 0;
00305         if ( suit_obj && !isComponent ) {
00306           QString moduleTitle = ((CAM_Application*)myStudy->application())->moduleTitle(suit_obj->componentDataType());
00307           if (!moduleTitle.isEmpty()) {
00308             LightApp_Displayer* aDisplayer = LightApp_Displayer::FindDisplayer(moduleTitle,false);
00309             if (aDisplayer) {
00310               if(aDisplayer->canBeDisplayed(theID.c_str())) {
00311                 myStudy->setVisibilityState( theID.c_str(), Qtx::HiddenState );
00312                 //MESSAGE("Object with entry : "<< theID <<" CAN be displayed !!!");
00313               }
00314               else
00315                 MESSAGE("Object with entry : "<< theID <<" CAN'T be displayed !!!");
00316             }
00317           }
00318         }
00319         break;
00320       }
00321     default:MESSAGE("Unknown event: "  << event);break;
00322     } //switch
00323   } //notifyObserverID_real
00324 
00325 private:
00326   void fillEntryMap()
00327   {
00328     entry2SuitObject.clear();
00329     SUIT_DataObject* o = myStudy->root();
00330     while (o) {
00331       SalomeApp_DataObject* so = dynamic_cast<SalomeApp_DataObject*>( o );
00332       if ( so ) {
00333         std::string entry = so->entry().toLatin1().constData();
00334         if ( entry.size() )
00335           entry2SuitObject[entry] = so;
00336       }
00337       if ( o->childCount() > 0 ) {
00338         // parse the children
00339         o = o->firstChild();
00340       }
00341       else if ( o->nextBrother() > 0 ) {
00342         o = o->nextBrother();
00343       }
00344       else {
00345         // step to the next appropriate parent
00346         o = o->parent();
00347         while ( o ) {
00348           if ( o->nextBrother() ) {
00349             o = o->nextBrother();
00350             break;
00351           }
00352           o = o->parent();
00353         }
00354       }
00355     }
00356   }
00357 
00358 private:
00359   _PTR(Study)      myStudyDS;
00360   SalomeApp_Study* myStudy;
00361   EntryMap         entry2SuitObject;
00362 };
00363 
00364 
00368 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
00369 : LightApp_Study( app ), myObserver( 0 )
00370 {
00371 }
00372 
00376 SalomeApp_Study::~SalomeApp_Study()
00377 {
00378 }
00379 
00383 int SalomeApp_Study::id() const
00384 {
00385   int id = -1;
00386   if ( studyDS() )
00387     id = studyDS()->StudyId();
00388   return id;
00389 }
00390 
00394 QString SalomeApp_Study::studyName() const
00395 {
00396   // redefined from SUIT_Study to update study name properly since
00397   // it can be changed outside of GUI
00398   // TEMPORARILY SOLUTION: better to be implemented with help of SALOMEDS observers
00399   if ( studyDS() ) {
00400     QString newName = studyDS()->Name().c_str();
00401     if ( LightApp_Study::studyName() != newName ) {
00402       SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
00403       that->setStudyName( newName );
00404       ((SalomeApp_Application*)application())->updateDesktopTitle();
00405     }
00406   }
00407   return LightApp_Study::studyName();
00408 }
00409 
00413 _PTR(Study) SalomeApp_Study::studyDS() const
00414 {
00415   return myStudyDS;
00416 }
00417 
00421 bool SalomeApp_Study::createDocument( const QString& theStr )
00422 {
00423   MESSAGE( "createDocument" );
00424 
00425   // initialize myStudyDS, read HDF file
00426   QString aName = newStudyName();
00427   _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.toUtf8().data() ) );
00428   if ( !study )
00429     return false;
00430 
00431   setStudyDS( study );
00432   setStudyName( aName );
00433 
00434   // create myRoot
00435   SalomeApp_RootObject* aRoot=new SalomeApp_RootObject( this );
00436 #ifdef WITH_SALOMEDS_OBSERVER
00437   aRoot->setToSynchronize(false);
00438 #endif
00439   setRoot( aRoot );
00440 
00441   bool aRet = CAM_Study::createDocument( theStr );
00442 
00443 #ifdef WITH_SALOMEDS_OBSERVER
00444   myObserver = new Observer_i(myStudyDS,this);
00445   //attach an observer to the study with notification of modifications
00446   myStudyDS->attach(myObserver->_this(),true);
00447 #endif
00448 
00449   emit created( this );
00450 
00451   return aRet;
00452 }
00453 
00458 bool SalomeApp_Study::openDocument( const QString& theFileName )
00459 {
00460   MESSAGE( "openDocument" );
00461 
00462   // initialize myStudyDS, read HDF file
00463   _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( theFileName.toUtf8().data() ) );
00464   if ( !study )
00465     return false;
00466 
00467   setStudyDS( study );
00468 
00469   setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
00470 
00471   // update loaded data models: call open() and update() on them.
00472   ModelList dm_s;
00473   dataModels( dm_s );
00474   QListIterator<CAM_DataModel*> it( dm_s );
00475   while ( it.hasNext() )
00476     openDataModel( studyName(), it.next() );
00477 
00478   // this will build a SUIT_DataObject-s tree under myRoot member field
00479   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
00480   // but tree that corresponds to not-loaded data models will be updated any way.
00481   ((SalomeApp_Application*)application())->updateObjectBrowser( false );
00482 
00483 #ifdef WITH_SALOMEDS_OBSERVER
00484   dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
00485   myObserver = new Observer_i(myStudyDS,this);
00486   //attach an observer to the study with notification of modifications
00487   myStudyDS->attach(myObserver->_this(),true);
00488 #endif
00489 
00490   bool res = CAM_Study::openDocument( theFileName );
00491 
00492   emit opened( this );
00493   study->IsSaved(true);
00494 
00495   bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
00496   if ( restore ) {
00497     std::vector<int> savePoints = getSavePoints();
00498     if ( savePoints.size() > 0 )
00499       SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
00500   }
00501 
00502   ((SalomeApp_Application*)application())->updateObjectBrowser( true );
00503   return res;
00504 }
00505 
00510 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
00511 {
00512   MESSAGE( "loadDocument" );
00513 
00514   // obtain myStudyDS from StudyManager
00515   _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( theStudyName.toUtf8().data() ) );
00516   if ( !study )
00517     return false;
00518 
00519   setStudyDS( study );
00520 
00521   setRoot( new SalomeApp_RootObject( this ) ); // create myRoot
00522 
00523   //SRN: BugID IPAL9021, put there the same code as in a method openDocument
00524 
00525   // update loaded data models: call open() and update() on them.
00526   ModelList dm_s;
00527   dataModels( dm_s );
00528 
00529   QListIterator<CAM_DataModel*> it( dm_s );
00530   while ( it.hasNext() )
00531     openDataModel( studyName(), it.next() );
00532 
00533   // this will build a SUIT_DataObject-s tree under myRoot member field
00534   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
00535   // but tree that corresponds to not-loaded data models will be updated any way.
00536   ((SalomeApp_Application*)application())->updateObjectBrowser( false );
00537 
00538 #ifdef WITH_SALOMEDS_OBSERVER
00539   dynamic_cast<SalomeApp_RootObject*>( root() )->setToSynchronize(false);
00540   myObserver = new Observer_i(myStudyDS,this);
00541   //attach an observer to the study with notification of modifications
00542   myStudyDS->attach(myObserver->_this(),true);
00543 #endif
00544 
00545   bool res = CAM_Study::openDocument( theStudyName );
00546   emit opened( this );
00547 
00548   bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
00549   if ( restore ) {
00550     std::vector<int> savePoints = getSavePoints();
00551     if ( savePoints.size() > 0 )
00552       SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] );
00553   }
00554 
00555   //SRN: BugID IPAL9021: End
00556   return res;
00557 }
00558 
00563 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
00564 {
00565   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", false );
00566   if ( store )
00567     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
00568 
00569   ModelList list; dataModels( list );
00570 
00571   QListIterator<CAM_DataModel*> it( list );
00572   QStringList listOfFiles;
00573   while ( it.hasNext() ) {
00574     // Cast to LightApp class in order to give a chance
00575     // to light modules to save their data
00576     if ( LightApp_DataModel* aModel = 
00577         dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
00578       listOfFiles.clear();
00579       aModel->saveAs( theFileName, this, listOfFiles );
00580       if ( !listOfFiles.isEmpty() )
00581         saveModuleData(aModel->module()->name(), listOfFiles);
00582     }
00583   }
00584 
00585   // save SALOMEDS document
00586   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
00587   if( !resMgr )
00588     return false;
00589 
00590   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
00591   bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
00592   bool res = (isAscii ?
00593     SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.toUtf8().data(), studyDS(), isMultiFile ) :
00594     SalomeApp_Application::studyMgr()->SaveAs     ( theFileName.toUtf8().data(), studyDS(), isMultiFile ))
00595     && CAM_Study::saveDocumentAs( theFileName );
00596 
00597   res = res && saveStudyData(theFileName);
00598 
00599   if ( res )
00600     emit saved( this );
00601 
00602   return res;
00603 }
00604 
00608 bool SalomeApp_Study::saveDocument()
00609 {
00610   bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true );
00611   if ( store )
00612     SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState();
00613 
00614   ModelList list; dataModels( list );
00615 
00616   QListIterator<CAM_DataModel*> it( list );
00617   QStringList listOfFiles;
00618   while ( it.hasNext() ) {
00619     // Cast to LightApp class in order to give a chance
00620     // to light modules to save their data
00621     if ( LightApp_DataModel* aModel = 
00622         dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
00623       listOfFiles.clear();
00624       aModel->save(listOfFiles);
00625       if ( !listOfFiles.isEmpty() )
00626         saveModuleData(aModel->module()->name(), listOfFiles);
00627     }
00628   }
00629 
00630   // save SALOMEDS document
00631   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
00632   if( !resMgr )
00633     return false;
00634 
00635   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false );
00636   bool isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
00637   bool res = (isAscii ?
00638     SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
00639     SalomeApp_Application::studyMgr()->Save     ( studyDS(), isMultiFile )) && CAM_Study::saveDocument();
00640 
00641   res = res && saveStudyData(studyName());
00642   if ( res )
00643     emit saved( this );
00644 
00645   return res;
00646 }
00647 
00651 void SalomeApp_Study::closeDocument(bool permanently)
00652 {
00653   LightApp_Study::closeDocument(permanently);
00654 
00655   // close SALOMEDS document
00656   _PTR(Study) studyPtr = studyDS();
00657   if ( studyPtr )
00658   {
00659     if(permanently) {
00660       SalomeApp_Application::studyMgr()->Close( studyPtr );
00661     }
00662     SALOMEDSClient_Study* aStudy = 0;
00663     setStudyDS( _PTR(Study)(aStudy) );
00664   }
00665 }
00666 
00682 bool SalomeApp_Study::dump( const QString& theFileName, 
00683                          bool toPublish, 
00684                          bool isMultiFile,
00685                          bool toSaveGUI )
00686 {
00687   int savePoint;
00688   _PTR(AttributeParameter) ap;
00689   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
00690   _PTR(Study) aStudy = studyDS();
00691 
00692   if( ip->isDumpPython( aStudy ) ) 
00693     ip->setDumpPython( aStudy ); //Unset DumpPython flag.
00694 
00695   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
00696     ip->setDumpPython( aStudy );
00697     //SRN: create a temporary save point
00698     savePoint = SalomeApp_VisualState( 
00699       dynamic_cast<SalomeApp_Application*>( application() ) ).storeState(); 
00700   }
00701 
00702   // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study.
00703   // This is an optional but important step, it gives a chance to light modules
00704   // to dump their data as a part of common dump study operation
00705   ModelList list; 
00706   dataModels( list );
00707 
00708   QListIterator<CAM_DataModel*> it( list );
00709   QStringList listOfFiles;
00710   while ( it.hasNext() ) {
00711     if ( LightApp_DataModel* aModel = 
00712         dynamic_cast<LightApp_DataModel*>( it.next() ) ) {
00713       listOfFiles.clear();
00714       if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) && 
00715           !listOfFiles.isEmpty() )
00716        // This call simply passes the data model's dump output to SalomeApp_Engine servant.
00717        // This code is shared with persistence mechanism.
00718        // NOTE: this should be revised if behavior of saveModuleData() changes!
00719         saveModuleData(aModel->module()->name(), listOfFiles);
00720     }
00721   }
00722 
00723   // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if 
00724   // any light module is present in the current configuration
00725   QFileInfo aFileInfo( theFileName );
00726   bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toUtf8().data(),
00727                             aFileInfo.baseName().toUtf8().data(),
00728                             toPublish,
00729                             isMultiFile);
00730   if ( toSaveGUI )
00731     removeSavePoint( savePoint ); //SRN: remove the created temporary save point.
00732 
00733   // Issue 21377 - Clean up light module data in SalomeApp_Engine servant
00734   // This code is shared with persistence mechanism.
00735   // NOTE: this should be revised if behavior of saveStudyData() changes!
00736   saveStudyData( theFileName );
00737 
00738   return res;
00739 }
00740 
00744 bool SalomeApp_Study::isModified() const
00745 {
00746   bool isAnyChanged = studyDS() && studyDS()->IsModified();
00747   if (!isAnyChanged)
00748     isAnyChanged = LightApp_Study::isModified();
00749 
00750   return isAnyChanged;
00751 }
00752 
00756 void SalomeApp_Study::Modified()
00757 {
00758   if(_PTR(Study) aStudy = studyDS())
00759     aStudy->Modified();
00760   LightApp_Study::Modified();
00761 }
00762 
00766 bool SalomeApp_Study::isSaved() const
00767 {
00768   bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
00769   if (!isAllSaved)
00770     isAllSaved = LightApp_Study::isSaved();
00771 
00772   return isAllSaved;
00773 }
00774 
00780 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
00781 {
00782   int aNb = theListOfFiles.count();
00783   if ( aNb == 0 )
00784     return;
00785 
00786   std::vector<std::string> aListOfFiles ( aNb );
00787   int anIndex = 0;
00788   for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
00789     if ( (*it).isEmpty() )
00790       continue;
00791     aListOfFiles[anIndex] = (*it).toUtf8().data();
00792     anIndex++;
00793   }
00794   SetListOfFiles(theModuleName.toStdString().c_str(), aListOfFiles);
00795 }
00796 
00802 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
00803 {
00804   std::vector<std::string> aListOfFiles =  GetListOfFiles( theModuleName.toStdString().c_str() );
00805 
00806   int i, aLength = aListOfFiles.size() - 1;
00807   if ( aLength < 0 )
00808     return;
00809 
00810   //Get a temporary directory for saved a file
00811   theListOfFiles.append(aListOfFiles[0].c_str());
00812 
00813   for(i = 0; i < aLength; i++)
00814     theListOfFiles.append(aListOfFiles[i+1].c_str());
00815 }
00816 
00821 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
00822 {
00823   ModelList list; dataModels( list );
00824   QListIterator<CAM_DataModel*> it( list );
00825   std::vector<std::string> listOfFiles(0);
00826   while ( it.hasNext() ){
00827     LightApp_DataModel* aLModel = 
00828       dynamic_cast<LightApp_DataModel*>( it.next() );
00829     // It is safe to call SetListOfFiles() for any kind of module
00830     // because SetListOfFiles() does nothing for full modules :)
00831     if ( aLModel )
00832       SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles);
00833   }
00834   return true;
00835 }
00836 
00840 bool SalomeApp_Study::openStudyData( const QString& theFileName )
00841 {
00842  return true;
00843 }
00844 
00848 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
00849 {
00850   myStudyDS = s;
00851 }
00852 
00862 CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDataModel, 
00863                                                  SUIT_DataObject* theParent ) const
00864 {
00865   SalomeApp_Study* that = const_cast<SalomeApp_Study*>( this );
00866   
00867   // Ensure that SComponent instance is published in the study for the given module
00868   // This line causes automatic creation of SalomeApp_ModuleObject in case if
00869   // WITH_SALOMEDS_OBSERVER is defined
00870   that->addComponent( theDataModel );
00871   
00872   // SalomeApp_ModuleObject might have been created by SALOMEDS observer
00873   // or by someone else so check if it exists first of all
00874   CAM_ModuleObject* res = 0;
00875 
00876   DataObjectList children = root()->children();
00877   DataObjectList::const_iterator anIt = children.begin(), aLast = children.end();
00878   for( ; !res && anIt!=aLast; anIt++ )
00879   {
00880     SalomeApp_ModuleObject* obj = dynamic_cast<SalomeApp_ModuleObject*>( *anIt );
00881     if ( obj && obj->componentDataType() == theDataModel->module()->name() )
00882       res = obj;
00883   }
00884 
00885   if ( !res ){
00886     _PTR(Study) aStudy = studyDS();
00887     if ( !aStudy )
00888       return res;
00889 
00890     _PTR(SComponent) aComp = aStudy->FindComponent( 
00891       theDataModel->module()->name().toStdString() );
00892     if ( !aComp )
00893       return res;
00894 
00895     res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent );
00896   }
00897 
00898   return res;
00899 }
00900 
00904 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
00905 {
00906   MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name().toStdString());
00907 
00908   CAM_Study::dataModelInserted(dm);
00909 
00910   //  addComponent(dm);
00911 }
00912 
00916 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
00917 {
00918   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
00919   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
00920   if (!aModule) {
00921     // Check SComponent existance
00922     _PTR(Study) aStudy = studyDS();
00923     if (!aStudy)
00924       return;
00925 
00926     std::string aCompDataType = dm->module()->name().toStdString();
00927 
00928     _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType);
00929     if (!aComp) {
00930       // Create SComponent
00931       _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
00932       aComp = aBuilder->NewComponent(aCompDataType);
00933       aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
00934       QString anIconName = dm->module()->iconName();
00935       if (!anIconName.isEmpty()) {
00936         _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
00937         if (anAttr)
00938           anAttr->SetPixMap(anIconName.toStdString());
00939       }
00940 
00941       // Set default engine IOR
00942       // Issue 21377 - using separate engine for each type of light module
00943       std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(),
00944                                                                   true );
00945       aBuilder->DefineComponentInstance(aComp, anEngineIOR);
00946       //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
00947       SalomeApp_DataModel::synchronize( aComp, this );
00948     }
00949     else {
00950       _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
00951       aBuilder->SetName(aComp, dm->module()->moduleName().toStdString());
00952       QString anIconName = dm->module()->iconName();
00953       if (!anIconName.isEmpty()) {
00954         _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
00955         if (anAttr)
00956           anAttr->SetPixMap(anIconName.toStdString());
00957       }
00958       // Set default engine IOR
00959     }
00960   }
00961 }
00962 
00966 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
00967 {
00968   if (!dm)
00969     return false;
00970 
00971   //  SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
00972   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
00973   _PTR(Study)       aStudy = studyDS(); // shared_ptr cannot be used here
00974   _PTR(SComponent)  aSComp;
00975   QString anEngine;
00976   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
00977   if (!aModule) {
00978     // Issue 21377 - using separate engine for each type of light module
00979     std::string aCompDataType = dm->module()->name().toStdString();
00980     anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str();
00981     aSComp = aStudy->FindComponent( aCompDataType );
00982   }
00983   else {
00984     SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
00985     if ( aDM ) {
00986       QString anId = aDM->getRootEntry( this );
00987       if ( anId.isEmpty() )
00988         return true; // Probably nothing to load
00989       anEngine = aDM->getModule()->engineIOR();
00990       if ( anEngine.isEmpty() )
00991         return false;
00992       aSComp = aStudy->FindComponentID( std::string( anId.toLatin1() ) );
00993     }
00994   }
00995   if ( aSComp ) {
00996     _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
00997     if ( aBuilder ) {
00998       try {
00999         aBuilder->LoadWith( aSComp, std::string( anEngine.toLatin1() ) );
01000       }
01001       catch( const SALOME::SALOME_Exception& ) {
01002         // Oops, something went wrong while loading -> return an error
01003         return false;
01004       }
01005       // Something has been read -> create data model tree
01006       //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
01007       // aDM->buildTree( aSComp, 0, this );
01008     }
01009   } else {
01010     // Don't return false here, for there might be no data
01011     // for a given component in the study yet
01012   }
01013   QStringList listOfFiles;
01014   openModuleData(dm->module()->name(), listOfFiles);
01015   if (dm && dm->open(studyName, this, listOfFiles)) {
01016     // Remove the files and temporary directory, created
01017     // for this module by LightApp_Engine_i::Load()
01018     bool isMultiFile = false; // TODO: decide, how to access this parameter
01019     RemoveTemporaryFiles( dm->module()->name().toStdString().c_str(), isMultiFile );
01020 
01021     // Something has been read -> create data model tree
01022     LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
01023     if ( aDM )
01024       aDM->update(NULL, this);
01025     return true;
01026   }
01027   return false;
01028 }
01029 
01033 QString SalomeApp_Study::newStudyName() const
01034 {
01035   std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
01036   QString prefix( "Study%1" ), newName, curName;
01037   int i = 1, j, n = studies.size();
01038   while ( newName.isEmpty() ){
01039     curName = prefix.arg( i );
01040     for ( j = 0 ; j < n; j++ ){
01041       if ( !strcmp( studies[j].c_str(), curName.toLatin1() ) )
01042         break;
01043     }
01044     if ( j == n )
01045       newName = curName;
01046     else
01047       i++;
01048   }
01049   return newName;
01050 }
01051 
01059 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName  ) const
01060 {
01061   // Issue 21377 - using separate engine for each type of light module
01062   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
01063   if (aDefaultEngine)
01064     return aDefaultEngine->GetListOfFiles(id());
01065 
01066   std::vector<std::string> aListOfFiles;
01067   return aListOfFiles;
01068 }
01069 
01078 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
01079                                        const std::vector<std::string> theListOfFiles )
01080 {
01081   // Issue 21377 - using separate engine for each type of light module
01082   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false );
01083   if (aDefaultEngine)
01084     aDefaultEngine->SetListOfFiles(theListOfFiles, id());
01085 }
01086 
01090 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool  isMultiFile )
01091 {
01092   std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
01093   std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
01094   return aTmpDir;
01095 }
01096 
01100 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
01101 {
01102   if (isMultiFile)
01103     return;
01104 
01105   std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
01106   if (aListOfFiles.size() > 0) {
01107     std::string aTmpDir = aListOfFiles[0];
01108 
01109     const int n = aListOfFiles.size() - 1;
01110     SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
01111     aSeq->length(n);
01112     for (int i = 0; i < n; i++)
01113       aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
01114 
01115     SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
01116   }
01117 }
01118 
01123 void SalomeApp_Study::markAsSavedIn(QString theFileName)
01124 {
01125   setStudyName(theFileName);
01126   setIsSaved(true);
01127 }
01128 
01129 LightApp_DataObject* SalomeApp_Study::findObjectByEntry( const QString& theEntry )
01130 {
01131   LightApp_DataObject* o = dynamic_cast<LightApp_DataObject*>( myObserver ? myObserver->findObject( theEntry.toLatin1().constData() ) : 0 );
01132   return o;
01133 }
01134 
01139 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
01140 {
01141   _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
01142   std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
01143   for( int i=0, n=aRefs.size(); i<n; i++ )
01144   {
01145     _PTR( SObject ) o = aRefs[i];
01146     if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
01147     {
01148       sb->RemoveReference( o );
01149       sb->RemoveObjectWithChildren( o );
01150     }
01151   }
01152 }
01153 
01158 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
01159 {
01160   _PTR(SObject) obj = studyDS()->FindObjectID( entry.toStdString() );
01161   _PTR(SObject) refobj;
01162 
01163   if( obj && obj->ReferencedObject( refobj ) )
01164     return refobj->GetID().c_str();
01165   return LightApp_Study::referencedToEntry( entry );
01166 }
01167 
01171 QString SalomeApp_Study::componentDataType( const QString& entry ) const
01172 {
01173   _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
01174   if ( !obj )
01175     return LightApp_Study::componentDataType( entry );
01176   return obj->GetFatherComponent()->ComponentDataType().c_str();
01177 }
01178 
01182 bool SalomeApp_Study::isComponent( const QString& entry ) const
01183 {
01184   _PTR(SObject) obj( studyDS()->FindObjectID( entry.toStdString() ) );
01185   return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
01186 }
01187 
01191 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
01192 {
01193   _PTR(SObject) SO = studyDS()->FindObjectID( entry.toStdString() );
01194   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
01195   anIter->InitEx( true );
01196   while( anIter->More() )
01197   {
01198     _PTR(SObject) val( anIter->Value() );
01199     child_entries.append( val->GetID().c_str() );
01200     anIter->Next();
01201   }
01202 }
01203 
01208 void SalomeApp_Study::components( QStringList& comps ) const
01209 {
01210   for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() )
01211   {
01212     _PTR(SComponent) aComponent ( it->Value() );
01213     // skip the magic "Interface Applicative" component
01214     if ( aComponent && aComponent->ComponentDataType() != getVisualComponentName().toLatin1().constData() )
01215       comps.append( aComponent->ComponentDataType().c_str() );
01216   }
01217 }
01218 
01224 QString SalomeApp_Study::centry( const QString& comp ) const
01225 {
01226   QString e;
01227   for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More() && e.isEmpty(); it->Next() )
01228   {
01229     _PTR(SComponent) aComponent ( it->Value() );
01230     if ( aComponent && comp == aComponent->ComponentDataType().c_str() )
01231       e = aComponent->GetID().c_str();
01232   }
01233   return e;
01234 }
01235 
01239 std::vector<int> SalomeApp_Study::getSavePoints()
01240 {
01241   std::vector<int> v;
01242 
01243   _PTR(SObject) so = studyDS()->FindComponent( getVisualComponentName().toLatin1().constData() );
01244   if(!so) return v;
01245 
01246   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
01247   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) );
01248   for(; anIter->More(); anIter->Next())
01249   {
01250     _PTR(SObject) val( anIter->Value() );
01251     _PTR(GenericAttribute) genAttr;
01252     if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag());
01253   }
01254 
01255   return v;
01256 }
01257 
01261 void SalomeApp_Study::removeSavePoint(int savePoint)
01262 {
01263   if(savePoint <= 0) return;
01264  _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
01265   _PTR(SObject) so = AP->GetSObject();
01266   _PTR(StudyBuilder) builder = studyDS()->NewBuilder();
01267   builder->RemoveObjectWithChildren(so);
01268 }
01269 
01273 QString SalomeApp_Study::getNameOfSavePoint(int savePoint)
01274 {
01275   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
01276   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
01277   return ip->getProperty("AP_SAVEPOINT_NAME").c_str();
01278 }
01279 
01283 void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint)
01284 {
01285   _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName().toLatin1().constData(), savePoint);
01286   _PTR(IParameters) ip = ClientFactory::getIParameters(AP);
01287   ip->setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.toStdString());
01288 }
01289 
01293 void SalomeApp_Study::restoreState(int savePoint)
01294 {
01295   SalomeApp_VisualState((SalomeApp_Application*)application()).restoreState(savePoint);
01296 }
01297 
01298 
01302 void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
01303 {
01304   LightApp_Study::updateModelRoot( dm );
01305 
01306   // calling updateSavePointDataObjects in order to set correct order of "Gui states" object
01307   // it must always be the last one.
01308   ((SalomeApp_Application*)application())->updateSavePointDataObjects( this );
01309 }