Salome HOME
IPAL BugID9021, modified method closeDocument, added a boolean argument "permanently"
[modules/gui.git] / src / SalomeApp / SalomeApp_DataModel.cxx
1 // File:      SalomeApp_DataModel.cxx
2 // Created:   10/25/2004 10:36:06 AM
3 // Author:    Sergey LITONIN
4 // Copyright (C) CEA 2004
5
6 #include "SalomeApp_DataModel.h"
7 #include "SalomeApp_Study.h"
8 #include "SalomeApp_RootObject.h"
9 #include "SalomeApp_DataObject.h"
10 #include "SalomeApp_Module.h"
11 #include "SalomeApp_Application.h"
12 #include "SalomeApp_SelectionMgr.h"
13 #include "SalomeApp_Engine_i.hxx"
14
15 #include <CAM_DataObject.h>
16
17 #include <SUIT_Application.h>
18 #include <SUIT_ResourceMgr.h>
19
20 #include "SALOMEDS_Tool.hxx"
21
22 #include <SALOMEconfig.h>
23 #include CORBA_SERVER_HEADER(SALOME_Exception)
24
25 //=======================================================================
26 // name    : BuildTree
27 // Purpose : static method used by SalomeApp_Study and SalomeApp_DataModel classes
28 //           to create default SALOMEDS-based data object tree
29 //=======================================================================
30 SUIT_DataObject* SalomeApp_DataModel::BuildTree( const _PTR(SObject)& obj,
31                                                  SUIT_DataObject* parent,
32                                                  SalomeApp_Study* study,
33                                                  bool skip  )
34 {
35   SalomeApp_DataObject* aDataObj = 0;
36   if ( !obj || !study )
37     return aDataObj;
38
39   _PTR(SObject) refObj;
40   if ( obj->GetName().size() || obj->ReferencedObject( refObj ) )  // skip nameless non references SObjects
41   {
42     _PTR(SComponent) aSComp( obj );
43
44     // patch for bug IPAL9313
45     if ( aSComp && parent && skip ) 
46     {
47       QString aSName( aSComp->GetName().c_str() );
48       DataObjectList allComponents = parent->children( /*recursive=*/false );
49       for ( DataObjectListIterator it( allComponents ); it.current(); ++it )
50         if ( it.current()->name() == aSName )
51           return it.current();
52     }
53
54     aDataObj = aSComp ? new SalomeApp_ModuleObject( aSComp, parent ) :
55                         new SalomeApp_DataObject  ( obj, parent );
56
57     _PTR(ChildIterator) it ( study->studyDS()->NewChildIterator( obj ) );
58     for ( ; it->More();it->Next() ) {
59       // don't use shared_ptr here, for Data Object will take
60       // ownership of this pointer
61       _PTR(SObject) aSO( it->Value() );
62       BuildTree( aSO, aDataObj, study );
63     }
64   }
65   return aDataObj;
66 }
67
68 //=======================================================================
69 // name    : SalomeApp_DataModel::SalomeApp_DataModel
70 // Purpose : Constructor
71 //=======================================================================
72 SalomeApp_DataModel::SalomeApp_DataModel( CAM_Module* theModule )
73 : CAM_DataModel( theModule )
74 {
75 }
76
77 //=======================================================================
78 // name    : SalomeApp_DataModel::~SalomeApp_DataModel
79 // Purpose : Destructor
80 //=======================================================================
81 SalomeApp_DataModel::~SalomeApp_DataModel()
82 {
83 }
84
85 //================================================================
86 // Function : open
87 // Purpose  :
88 //================================================================
89 bool SalomeApp_DataModel::open( const QString&, CAM_Study* study )
90 {
91   SalomeApp_Study* aDoc = dynamic_cast<SalomeApp_Study*>( study );
92   if ( !aDoc )
93     return false;
94
95   QString anId = getRootEntry( aDoc );
96   if ( anId.isEmpty() )
97     return true; // Probably nothing to load
98
99   QString anEngine = getModule()->engineIOR();
100   if ( anEngine == "-1" ) {
101     // Module doesn't have a CORBA engine and doesn't use
102     // a default one -> SALOMEDS persistence cannot be used
103     return false;
104   }
105
106   if ( anEngine.isEmpty() ) {
107     // Module use a default engine
108     //TODO: deside, if the below code has to be copyed in a light data model to avoid bulding of data tree twice
109     anEngine = SalomeApp_Application::defaultEngineIOR();
110   }
111
112   _PTR(Study)      aStudy ( aDoc->studyDS() ); // shared_ptr cannot be used here
113   _PTR(SComponent) aSComp ( aStudy->FindComponentID( std::string( anId.latin1() ) ) );
114
115   if ( aSComp ) {
116     _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() );
117     if ( aBuilder ) {
118       try {
119         aBuilder->LoadWith( aSComp, std::string( anEngine.latin1() ) );
120       }
121       catch( const SALOME::SALOME_Exception& ) {
122         // Oops, something went wrong while loading -> return an error
123         return false;
124       }
125
126       // Something has been read -> create data model tree
127       buildTree( aSComp, 0, aDoc );
128     }
129   } else {
130     // Don't return false here, for there might be no data
131     // for a given component in the study yet
132   }
133
134   emit opened(); //TODO: is it really needed? to be removed maybe...
135   return true;
136 }
137
138 //================================================================
139 // Function : save
140 // Purpose  :
141 //================================================================
142 bool SalomeApp_DataModel::save()
143 {
144   emit saved();
145   return true;
146 }
147
148 //================================================================
149 // Function : saveAs
150 // Purpose  :
151 //================================================================
152 bool SalomeApp_DataModel::saveAs( const QString&, CAM_Study* )
153 {
154   emit saved();
155   return true;
156 }
157
158 //================================================================
159 // Function : close
160 // Purpose  :
161 //================================================================
162 bool SalomeApp_DataModel::close()
163 {
164   emit closed();
165   return true;
166 }
167
168 //================================================================
169 // Function : update
170 // Purpose  :
171 //================================================================
172 void SalomeApp_DataModel::update( SalomeApp_DataObject*, SalomeApp_Study* study )
173 {
174   SalomeApp_RootObject* studyRoot = 0;
175   _PTR(SObject) sobj;
176   SalomeApp_DataObject* modelRoot = dynamic_cast<SalomeApp_DataObject*>( root() );
177   if ( !modelRoot ){ // not yet connected to a study -> try using <study> argument
178     if ( !study )
179       study = dynamic_cast<SalomeApp_Study*>( getModule()->getApp()->activeStudy() );
180
181     if ( study ){
182       studyRoot = dynamic_cast<SalomeApp_RootObject*>( study->root() );
183       QString anId = getRootEntry( study );
184       if ( !anId.isEmpty() ){ // if nothing is published in the study for this module -> do nothing
185         _PTR(Study) aStudy ( study->studyDS() );
186         sobj = aStudy->FindComponentID( std::string( anId.latin1() ) );
187       }
188     }
189   }
190   else{
191     studyRoot = dynamic_cast<SalomeApp_RootObject*>( modelRoot->root() );
192     study = studyRoot->study(); // <study> value should not change here theoretically, but just to make sure
193     _PTR(Study) aStudy ( study->studyDS() );
194
195     // modelRoot->object() cannot be reused here: it is about to be deleted by buildTree() soon
196     sobj = aStudy->FindComponentID( std::string( modelRoot->entry().latin1() ) );
197   }
198   buildTree( sobj, studyRoot, study );
199 }
200
201 //================================================================
202 // Function : buildTree
203 // Purpose  : private method
204 //================================================================
205 void SalomeApp_DataModel::buildTree( const _PTR(SObject)& obj,
206                                      SUIT_DataObject* parent,
207                                      SalomeApp_Study* study )
208 {
209   if ( !obj )
210     return;
211   //if ( !root() ){ // Build default SALOMEDS-based data object tree and insert it into study
212     SalomeApp_ModuleObject* aNewRoot = dynamic_cast<SalomeApp_ModuleObject*>( BuildTree( obj, parent, study ) );
213     if ( aNewRoot ){
214       aNewRoot->setDataModel( this );
215       setRoot( aNewRoot );
216     }
217     //}
218 }
219
220 //================================================================
221 // Function : getModule
222 // Purpose  :
223 //================================================================
224
225 SalomeApp_Module* SalomeApp_DataModel::getModule() const
226 {
227   return dynamic_cast<SalomeApp_Module*>( module() );
228 }
229
230 //================================================================
231 // Function : getStudy
232 // Purpose  :
233 //================================================================
234 SalomeApp_Study* SalomeApp_DataModel::getStudy() const
235 {
236   SalomeApp_RootObject* aRoot = dynamic_cast<SalomeApp_RootObject*>( root()->root() );
237   if ( !aRoot )
238     return 0;
239   return aRoot->study();
240 }
241
242 //================================================================
243 // Function : getRootEntry
244 // Purpose  : returns study entry corresponding to this data model
245 //================================================================
246 QString SalomeApp_DataModel::getRootEntry( SalomeApp_Study* study ) const
247 {
248   QString anEntry;
249   if ( root() && root()->root() ) { // data model already in a study
250     SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( root() );
251     if ( anObj )
252       anEntry = anObj->entry();
253   }
254   else if ( study && study->studyDS() ) { // this works even if <myRoot> is null
255     _PTR(SComponent) aSComp( study->studyDS()->FindComponent( module()->name() ) );
256     if ( aSComp )
257       anEntry = aSComp->GetID().c_str();
258   }
259   return anEntry;
260 }
261
262 //================================================================
263 // Function : isModified
264 // Purpose  : default implementation, always returns false so as not to mask study's isModified()
265 //================================================================
266 bool SalomeApp_DataModel::isModified() const
267 {
268   return false;
269 }
270
271 //================================================================
272 // Function : isSaved
273 // Purpose  : default implementation, always returns true so as not to mask study's isSaved()
274 //================================================================
275 bool SalomeApp_DataModel::isSaved() const
276 {
277   return true;
278 }
279
280 // BEGIN: methods to be used by CORBAless modules
281
282 //================================================================
283 // Function : GetListOfFiles
284 // Purpose  : to be used by CORBAless modules
285 //================================================================
286 std::vector<std::string> SalomeApp_DataModel::GetListOfFiles() const
287        //(const int theStudyId, const char* theComponentName) const
288 {
289   SUIT_Study* anActiveStudy = getModule()->getApp()->activeStudy();
290   if (anActiveStudy) {
291     int aStudyId = anActiveStudy->id();
292     SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance();
293     if (aDefaultEngine) {
294       return aDefaultEngine->GetListOfFiles(aStudyId, module()->name());
295     }
296   }
297
298   std::vector<std::string> aListOfFiles;
299   return aListOfFiles;
300 }
301
302 //================================================================
303 // Function : SetListOfFiles
304 // Purpose  : to be used by CORBAless modules
305 //================================================================
306 void SalomeApp_DataModel::SetListOfFiles (const std::vector<std::string> theListOfFiles)
307      //(const std::vector<std::string> theListOfFiles,
308      // const int                      theStudyId,
309      // const char*                    theComponentName)
310 {
311   SUIT_Study* anActiveStudy = getModule()->getApp()->activeStudy();
312   if (anActiveStudy) {
313     int aStudyId = anActiveStudy->id();
314     SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance();
315     if (aDefaultEngine) {
316       aDefaultEngine->SetListOfFiles(theListOfFiles, aStudyId, module()->name());
317     }
318   }
319 }
320
321 //================================================================
322 // Function : GetTmpDir
323 // Purpose  : Static method. To be used by CORBAless modules
324 //================================================================
325 std::string SalomeApp_DataModel::GetTmpDir (const char* theURL,
326                                             const bool  isMultiFile)
327 {
328   std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL);
329   std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir();
330   return aTmpDir;
331 }
332
333 //================================================================
334 // Function : RemoveTemporaryFiles
335 // Purpose  : to be used by CORBAless modules
336 //================================================================
337 void SalomeApp_DataModel::RemoveTemporaryFiles (const bool isMultiFile) const
338 {
339   if (isMultiFile)
340     return;
341
342   std::vector<std::string> aListOfFiles = GetListOfFiles();
343   if (aListOfFiles.size() > 0) {
344     std::string aTmpDir = aListOfFiles[0];
345
346     const int n = aListOfFiles.size() - 1;
347     SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
348     aSeq->length(n);
349     for (int i = 0; i < n; i++)
350       aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str());
351
352     SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
353   }
354 }
355
356 // END: methods to be used by CORBAless modules