Salome HOME
Copyrights update
[modules/gui.git] / src / SalomeApp / SalomeApp_Study.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/
18 //
19 #include "SalomeApp_Study.h"
20
21 #include "SalomeApp_Module.h"
22 #include "SalomeApp_DataModel.h"
23 #include "SalomeApp_DataObject.h"
24 #include "SalomeApp_Application.h"
25 #include "SalomeApp_Engine_i.hxx"
26
27 #include "LightApp_RootObject.h"
28
29 #include <OB_Browser.h>
30
31 #include <SUIT_ResourceMgr.h>
32
33 #include <qptrlist.h>
34
35 #include "utilities.h"
36 #include "string.h"
37 #include "vector.h"
38
39 #include "SALOMEDS_Tool.hxx"
40
41 #include <SALOMEconfig.h>
42 #include CORBA_SERVER_HEADER(SALOME_Exception)
43
44 /*!
45   Constructor.
46 */
47 SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
48 : LightApp_Study( app )
49 {
50 }  
51
52 /*!
53   Destructor.
54 */
55 SalomeApp_Study::~SalomeApp_Study()
56 {
57 }
58
59 /*!
60   Gets study id.
61 */
62 int SalomeApp_Study::id() const
63 {
64   int id = -1;
65   if ( myStudyDS )
66     id = studyDS()->StudyId();
67   return id;
68 }
69
70 /*!
71   Gets studyDS pointer.
72 */
73 _PTR(Study) SalomeApp_Study::studyDS() const
74 {
75   return myStudyDS;
76 }
77
78 /*!
79   Create document.
80 */
81 void SalomeApp_Study::createDocument()
82 {
83   MESSAGE( "openDocument" );
84
85   // initialize myStudyDS, read HDF file
86   QString aName = newStudyName();
87   _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.latin1() ) );
88   if ( !study )
89     return;
90
91   setStudyDS( study );
92   setStudyName( aName );
93
94   // create myRoot
95   setRoot( new LightApp_RootObject( this ) );
96
97   CAM_Study::createDocument();
98   emit created( this );
99 }
100
101 //=======================================================================
102 // name    : openDocument
103 /*! Purpose : Open document*/
104 //=======================================================================
105 bool SalomeApp_Study::openDocument( const QString& theFileName )
106 {
107   MESSAGE( "openDocument" );
108
109   // initialize myStudyDS, read HDF file
110   _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( (char*) theFileName.latin1() ) );
111   if ( !study )
112     return false;
113
114   setStudyDS( study );
115
116   setRoot( new LightApp_RootObject( this ) ); // create myRoot
117
118   // update loaded data models: call open() and update() on them.
119   ModelList dm_s;
120   dataModels( dm_s );
121   for ( ModelListIterator it( dm_s ); it.current(); ++it )
122     openDataModel( studyName(), it.current() );
123
124   // this will build a SUIT_DataObject-s tree under myRoot member field
125   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
126   // but tree that corresponds to not-loaded data models will be updated any way. 
127   ((SalomeApp_Application*)application())->updateObjectBrowser( false ); 
128
129   bool res = CAM_Study::openDocument( theFileName );
130   
131   emit opened( this );
132   study->IsSaved(true);
133   return res;
134 }
135
136 //=======================================================================
137 // name    : loadDocument
138 /*! Purpose : Connects GUI study to SALOMEDS one already loaded into StudyManager*/
139 //=======================================================================
140 bool SalomeApp_Study::loadDocument( const QString& theStudyName )
141 {
142   MESSAGE( "loadDocument" );
143
144   // obtain myStudyDS from StudyManager
145   _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( (char*) theStudyName.latin1() ) );
146   if ( !study )
147     return false;
148
149   setStudyDS( study );
150
151   setRoot( new LightApp_RootObject( this ) ); // create myRoot
152
153   //SRN: BugID IPAL9021, put there the same code as in a method openDocument
154
155   // update loaded data models: call open() and update() on them.
156   ModelList dm_s;
157   dataModels( dm_s );
158
159   for ( ModelListIterator it( dm_s ); it.current(); ++it )
160     openDataModel( studyName(), it.current() );
161
162   // this will build a SUIT_DataObject-s tree under myRoot member field
163   // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step
164   // but tree that corresponds to not-loaded data models will be updated any way. 
165   ((SalomeApp_Application*)application())->updateObjectBrowser( false ); 
166
167   bool res = CAM_Study::openDocument( theStudyName );
168   emit opened( this );
169
170   //SRN: BugID IPAL9021: End
171
172   return res;
173 }
174
175 //=======================================================================
176 // name    : saveDocumentAs
177 /*! Purpose : Save document*/
178 //=======================================================================
179 bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
180 {
181   ModelList list; dataModels( list );
182
183   SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
184   QStringList listOfFiles;
185   for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() ) {
186     listOfFiles.clear();
187     aModel->saveAs( theFileName, this, listOfFiles );
188     if ( !listOfFiles.isEmpty() )
189       saveModuleData(aModel->module()->name(), listOfFiles);
190   }
191
192   // save SALOMEDS document
193   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
194   if( !resMgr )
195     return false;
196
197   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false ),
198        isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
199   isAscii ? SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.latin1(), studyDS(), isMultiFile ) :
200             SalomeApp_Application::studyMgr()->SaveAs     ( theFileName.latin1(), studyDS(), isMultiFile );
201
202   bool res = CAM_Study::saveDocumentAs( theFileName );  //SRN: BugID IPAL9377, removed usage of uninitialized variable <res>
203   res = res && saveStudyData(theFileName);
204   if ( res )
205     emit saved( this );
206
207   return res;
208 }
209
210 //=======================================================================
211 // name    : saveDocument
212 /*! Purpose : Save document*/
213 //=======================================================================
214 bool SalomeApp_Study::saveDocument()
215 {
216   ModelList list; dataModels( list );
217
218   SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
219   QStringList listOfFiles;
220   for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() ) {
221     listOfFiles.clear();
222     aModel->save(listOfFiles);
223     if ( !listOfFiles.isEmpty() )
224       saveModuleData(aModel->module()->name(), listOfFiles);
225   }
226
227   // save SALOMEDS document
228   SUIT_ResourceMgr* resMgr = application()->resourceMgr();
229   if( !resMgr )
230     return false;
231
232   bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false ),
233        isAscii = resMgr->booleanValue( "Study", "ascii_file", false );
234   isAscii ? SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
235             SalomeApp_Application::studyMgr()->Save     ( studyDS(), isMultiFile );
236
237   bool res = CAM_Study::saveDocument();
238
239   res = res && saveStudyData(studyName());
240   if ( res )
241     emit saved( this );  
242
243   return res;
244 }
245
246 //================================================================
247 // Function : closeDocument
248 /*! Purpose  : Close document*/
249 //================================================================
250 void SalomeApp_Study::closeDocument(bool permanently)
251 {
252   LightApp_Study::closeDocument(permanently);
253
254   // close SALOMEDS document
255   _PTR(Study) studyPtr = studyDS();
256   if ( studyPtr )
257   {
258     if(permanently) SalomeApp_Application::studyMgr()->Close( studyPtr );
259     SALOMEDSClient_Study* aStudy = 0;
260     setStudyDS( _PTR(Study)(aStudy) );
261   }
262 }
263
264 //================================================================
265 // Function : isModified
266 // Purpose  : 
267 //================================================================
268 bool SalomeApp_Study::isModified() const
269 {
270   bool isAnyChanged = studyDS() && studyDS()->IsModified();
271   if (!isAnyChanged)
272     isAnyChanged = LightApp_Study::isModified();
273
274   return isAnyChanged; 
275 }
276
277 //================================================================
278 // Function : isSaved
279 /*! Purpose  : Check: data model is saved?*/
280 //================================================================
281 bool SalomeApp_Study::isSaved() const
282 {
283   bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
284   if (!isAllSaved)
285     isAllSaved = LightApp_Study::isModified();
286
287   return isAllSaved; 
288 }
289
290 //=======================================================================
291 // name    : saveModuleData
292 /*! Purpose : save list file for module 'theModuleName' */
293 //=======================================================================
294 void SalomeApp_Study::saveModuleData( QString theModuleName, QStringList theListOfFiles )
295 {
296   int aNb = theListOfFiles.count();
297   if ( aNb == 0 )
298     return;
299
300   std::vector<std::string> aListOfFiles ( aNb );
301   int anIndex = 0;
302   for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) {
303     if ( (*it).isEmpty() )
304       continue;
305     aListOfFiles[anIndex] = (*it).latin1();
306     anIndex++;
307   }
308   SetListOfFiles(theModuleName, aListOfFiles);
309 }
310
311 //=======================================================================
312 // name    : openModuleData
313 /*! Purpose : gets list of file for module 'theModuleNam' */
314 //=======================================================================
315 void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theListOfFiles )
316 {
317   std::vector<std::string> aListOfFiles =  GetListOfFiles( theModuleName );
318
319   int i, aLength = aListOfFiles.size() - 1;
320   if ( aLength < 0 )
321     return;
322
323   //Get a temporary directory for saved a file
324   theListOfFiles.append(aListOfFiles[0].c_str());
325
326   for(i = 0; i < aLength; i++)
327     theListOfFiles.append(aListOfFiles[i+1].c_str());
328 }
329
330 //=======================================================================
331 // name    : saveStudyData
332 /*! Purpose : save data from study */
333 //=======================================================================
334 bool SalomeApp_Study::saveStudyData( const QString& theFileName )
335 {
336   ModelList list; dataModels( list );
337   SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
338   std::vector<std::string> listOfFiles(0);
339   for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() )
340     SetListOfFiles(aModel->module()->name(), listOfFiles);
341   return true;
342 }
343
344 //=======================================================================
345 // name    : openStudyData
346 /*! Purpose : open data for study */
347 //=======================================================================
348 bool SalomeApp_Study::openStudyData( const QString& theFileName )
349 {
350  return true;
351 }
352
353 /*!
354   Set studyDS.
355 */
356 void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
357 {
358   myStudyDS = s;
359 }
360
361 /*!
362   Insert data model.
363 */
364 void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
365 {
366   MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name());
367
368   CAM_Study::dataModelInserted(dm);
369
370   //  addComponent(dm);
371 }
372
373 /*!
374  Create SComponent for module, using default engine (CORBAless)
375 */
376 void SalomeApp_Study::addComponent(const CAM_DataModel* dm)
377 {
378   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
379   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
380   if (!aModule) {
381     // Check SComponent existance
382     _PTR(Study) aStudy = studyDS();
383     if (!aStudy) 
384       return;
385     _PTR(SComponent) aComp = aStudy->FindComponent(dm->module()->name());
386     if (!aComp) {
387       // Create SComponent
388       _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder();
389       aComp = aBuilder->NewComponent(dm->module()->name());
390       aBuilder->SetName(aComp, dm->module()->moduleName().latin1());
391       QString anIconName = dm->module()->iconName();
392       if (!anIconName.isEmpty()) {
393         _PTR(AttributePixMap) anAttr = aBuilder->FindOrCreateAttribute(aComp, "AttributePixMap");
394         if (anAttr)
395           anAttr->SetPixMap(anIconName.latin1());
396       }
397       // Set default engine IOR
398       aBuilder->DefineComponentInstance(aComp, SalomeApp_Application::defaultEngineIOR().latin1());
399       SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true );
400     }
401   }
402 }
403
404 /*!
405   Open data model
406 */
407 bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
408 {
409   if (!dm)
410     return false;
411
412   //  SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
413   SalomeApp_Module* aModule = dynamic_cast<SalomeApp_Module*>( dm->module() );
414   _PTR(Study)       aStudy = studyDS(); // shared_ptr cannot be used here
415   _PTR(SComponent)  aSComp;
416   QString anEngine;
417   // 1. aModule == 0 means that this is a light module (no CORBA enigine)
418   if (!aModule) {
419     anEngine = SalomeApp_Application::defaultEngineIOR();
420     aSComp = aStudy->FindComponent(dm->module()->name());
421   }
422   else {
423     SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
424     if ( aDM ) {
425       QString anId = aDM->getRootEntry( this );
426       if ( anId.isEmpty() )
427         return true; // Probably nothing to load
428       anEngine = aDM->getModule()->engineIOR();
429       if ( anEngine.isEmpty() )
430         return false;
431       aSComp = aStudy->FindComponentID( std::string( anId.latin1() ) );
432     }
433   }
434   if ( aSComp ) {
435     _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
436     if ( aBuilder ) {
437       try {
438         aBuilder->LoadWith( aSComp, std::string( anEngine.latin1() ) );
439       }
440       catch( const SALOME::SALOME_Exception& ) {
441         // Oops, something went wrong while loading -> return an error
442         return false;
443       }
444       // Something has been read -> create data model tree
445       //SalomeApp_DataModel* aDM = dynamic_cast<SalomeApp_DataModel*>( dm );
446       // aDM->buildTree( aSComp, 0, this );
447     }
448   } else {
449     // Don't return false here, for there might be no data
450     // for a given component in the study yet
451   }
452   QStringList listOfFiles;
453   openModuleData(dm->module()->name(), listOfFiles);
454   if (dm && dm->open(studyName, this, listOfFiles)) {
455     // Remove the files and temporary directory, created
456     // for this module by LightApp_Engine_i::Load()
457     bool isMultiFile = false; // TODO: decide, how to access this parameter
458     RemoveTemporaryFiles( dm->module()->name(), isMultiFile );
459
460     // Something has been read -> create data model tree
461     LightApp_DataModel* aDM = dynamic_cast<LightApp_DataModel*>( dm );
462     if ( aDM )
463       aDM->update(NULL, this);
464     return true;
465   }
466   return false;
467 }
468
469 /*!
470   Create new study name.
471 */
472 QString SalomeApp_Study::newStudyName() const
473 {
474   std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
475   QString prefix( "Study%1" ), newName, curName;
476   int i = 1, j, n = studies.size();
477   while ( newName.isEmpty() ){
478     curName = prefix.arg( i );
479     for ( j = 0 ; j < n; j++ ){
480       if ( !strcmp( studies[j].c_str(), curName.latin1() ) )
481         break;
482     }
483     if ( j == n )
484       newName = curName;
485     else
486       i++;
487   }
488   return newName;
489 }
490
491 //================================================================
492 // Function : GetListOfFiles
493 /*! Purpose  : to be used by CORBAless modules*/
494 //================================================================
495 std::vector<std::string> SalomeApp_Study::GetListOfFiles( const char* theModuleName  ) const
496 {
497   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance();
498   if (aDefaultEngine)
499     return aDefaultEngine->GetListOfFiles(id(), theModuleName);
500
501   std::vector<std::string> aListOfFiles;
502   return aListOfFiles;
503 }
504
505 //================================================================
506 // Function : SetListOfFiles
507 /*! Purpose  : to be used by CORBAless modules*/
508 //================================================================
509 void SalomeApp_Study::SetListOfFiles ( const char* theModuleName,
510                                        const std::vector<std::string> theListOfFiles )
511 {
512   SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance();
513   if (aDefaultEngine)
514     aDefaultEngine->SetListOfFiles(theListOfFiles, id(), theModuleName);
515 }
516
517 //================================================================
518 // Function : GetTmpDir
519 /*! Purpose  : to be used by CORBAless modules*/
520 //================================================================
521 std::string SalomeApp_Study::GetTmpDir ( const char* theURL, const bool  isMultiFile )
522 {
523   std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
524   std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
525   return aTmpDir;
526 }
527
528 //================================================================
529 // Function : RemoveTemporaryFiles
530 /*! Purpose  : to be used by CORBAless modules*/
531 //================================================================
532 void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const
533 {
534   if (isMultiFile)
535     return;
536
537   std::vector<std::string> aListOfFiles = GetListOfFiles( theModuleName );
538   if (aListOfFiles.size() > 0) {
539     std::string aTmpDir = aListOfFiles[0];
540
541     const int n = aListOfFiles.size() - 1;
542     SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
543     aSeq->length(n);
544     for (int i = 0; i < n; i++)
545       aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
546
547     SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
548   }
549 }
550
551 // END: methods to be used by CORBAless modules
552
553 void SalomeApp_Study::deleteReferencesTo( _PTR( SObject ) obj )
554 {
555   _PTR(StudyBuilder) sb = studyDS()->NewBuilder();
556   std::vector<_PTR(SObject)> aRefs = studyDS()->FindDependances( obj );
557   for( int i=0, n=aRefs.size(); i<n; i++ )
558   {
559     _PTR( SObject ) o = aRefs[i];
560     if( o->GetFatherComponent()->ComponentDataType()==obj->GetFatherComponent()->ComponentDataType() )
561     {
562       sb->RemoveReference( o );
563       sb->RemoveObjectWithChildren( o );
564     }
565   }
566 }
567
568 //================================================================
569 // Function : referencedToEntry
570 /*! Purpose  : Return referenced entry from entry*/
571 //================================================================
572 QString SalomeApp_Study::referencedToEntry( const QString& entry ) const
573 {
574   _PTR(SObject) obj = studyDS()->FindObjectID( entry.latin1() );
575   _PTR(SObject) refobj;
576
577   if( obj && obj->ReferencedObject( refobj ) )
578     return refobj->GetID().c_str();
579   return LightApp_Study::referencedToEntry( entry );
580 }
581
582 //================================================================
583 // Function : componentDataType
584 /*! Purpose  : Return component data type from entry*/
585 //================================================================
586 QString SalomeApp_Study::componentDataType( const QString& entry ) const
587 {
588   _PTR(SObject) obj( studyDS()->FindObjectID( entry.latin1() ) );
589   if ( !obj )
590     return LightApp_Study::componentDataType( entry );
591   return obj->GetFatherComponent()->ComponentDataType().c_str();
592 }
593
594 //================================================================
595 // Function : componentDataType
596 /*! Purpose  : Return component data type from entry*/
597 //================================================================
598 bool SalomeApp_Study::isComponent( const QString& entry ) const
599 {
600   _PTR(SObject) obj( studyDS()->FindObjectID( entry.latin1() ) );
601   return obj && QString( obj->GetID().c_str() ) == obj->GetFatherComponent()->GetID().c_str();
602 }
603
604 //================================================================
605 // Function : children
606 /*! Purpose : Return entries of children of object*/
607 //================================================================
608 void SalomeApp_Study::children( const QString& entry, QStringList& child_entries ) const
609 {
610   _PTR(SObject) SO = studyDS()->FindObjectID( entry.latin1() );
611   _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( SO ) );
612   anIter->InitEx( true );
613   while( anIter->More() )
614   {
615     _PTR(SObject) val( anIter->Value() );
616     child_entries.append( val->GetID().c_str() );
617     anIter->Next();
618   }
619 }
620
621 void SalomeApp_Study::components( QStringList& comps ) const
622 {
623   for( _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() ); it->More(); it->Next() ) 
624   {
625     _PTR(SComponent) aComponent ( it->Value() );
626     if( aComponent && aComponent->ComponentDataType() == "Interface Applicative" )
627       continue; // skip the magic "Interface Applicative" component
628     comps.append( aComponent->ComponentDataType().c_str() );
629   }
630 }