Salome HOME
Join modifications from branch BR_DEBUG_3_2_0b1
[modules/gui.git] / src / SalomeApp / SalomeApp_DataModel.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/ or email : webmaster.salome@opencascade.com
18 //
19 // File:      SalomeApp_DataModel.cxx
20 // Created:   10/25/2004 10:36:06 AM
21 // Author:    Sergey LITONIN
22 // Copyright (C) CEA 2004
23
24 #include "SalomeApp_DataModel.h"
25 #include "SalomeApp_Study.h"
26 #include "SalomeApp_DataObject.h"
27 #include "SalomeApp_Module.h"
28 #include "SalomeApp_Application.h"
29 #include "SalomeApp_Engine_i.hxx"
30
31 #include "LightApp_RootObject.h"
32
33 #include <CAM_DataObject.h>
34
35 #include <SUIT_Application.h>
36 #include <SUIT_ResourceMgr.h>
37 #include <SUIT_Session.h>
38 #include <SUIT_TreeSync.h>
39 #include <SUIT_DataObjectIterator.h>
40
41 #include "SALOMEDS_Tool.hxx"
42
43 #include <SALOMEconfig.h>
44 #include CORBA_SERVER_HEADER(SALOME_Exception)
45
46 typedef _PTR(SObject)     kerPtr;
47 typedef SUIT_DataObject*  suitPtr;
48
49 /*!
50   \class SalomeApp_DataModelSync
51   Auxiliary class for synchronizing tree of kernel objects and SUIT_DataObjects
52 */
53 class SalomeApp_DataModelSync
54 {
55 public:
56   SalomeApp_DataModelSync( _PTR( Study ), SUIT_DataObject* );
57
58   suitPtr  createItem( const kerPtr&, const suitPtr&, const suitPtr&, const bool ) const;
59   void     deleteItemWithChildren( const suitPtr& ) const;
60   bool     isEqual( const kerPtr&, const suitPtr& ) const;
61   kerPtr   nullSrc() const;
62   suitPtr  nullTrg() const;
63   void     children( const kerPtr&, QValueList<kerPtr>& ) const;
64   void     children( const suitPtr&, QValueList<suitPtr>& ) const;
65   suitPtr  parent( const suitPtr& ) const;
66   bool     isCorrect( const kerPtr& ) const;
67   void     updateItem( const suitPtr& ) const;
68
69 private:
70   _PTR( Study )     myStudy;
71   SUIT_DataObject*  myRoot;
72 };
73
74 /*!
75   Constructor
76 */
77 SalomeApp_DataModelSync::SalomeApp_DataModelSync( _PTR( Study ) aStudy, SUIT_DataObject* aRoot )
78 : myStudy( aStudy ),
79   myRoot( aRoot )
80 {
81 }
82
83 /*!
84   \return true if kernel object is correct (has non empty name or is reference)
85 */
86 bool SalomeApp_DataModelSync::isCorrect( const kerPtr& so ) const
87 {
88   kerPtr refObj;
89   QString name = so->GetName().c_str();
90   bool res = so && ( so->GetName().size() || so->ReferencedObject( refObj ) );
91   return res;
92 }
93
94 /*!
95   Creates SUIT object by KERNEL object
96   \param so - corresponding KERNEL object
97   \param parent - parent for SUIT object
98   \param after - previous sibling for SUIT object
99   \param prepend - SUIT object must be added to start of children list
100 */
101 suitPtr SalomeApp_DataModelSync::createItem( const kerPtr& so,
102                                              const suitPtr& parent,
103                                              const suitPtr& after,
104                                              const bool prepend ) const
105 {
106   if( !isCorrect( so ) )
107     return 0;
108
109   _PTR(SComponent) aSComp( so );
110   suitPtr nitem = aSComp ? new SalomeApp_ModuleObject( aSComp, 0 ) :
111                            new SalomeApp_DataObject( so, 0 );
112   if( parent )
113     if( after )
114     {
115       DataObjectList ch;
116       parent->children( ch );
117       int pos = ch.find( after );
118       if( pos>=0 )
119         parent->insertChild( nitem, pos+1 );
120       else
121         parent->appendChild( nitem );
122     }
123     else if( prepend )
124       parent->insertChild( nitem, 0 );
125     else // append
126       parent->appendChild( nitem );
127   else if( myRoot )
128     myRoot->appendChild( nitem );
129   return nitem;
130 }
131
132 /*!
133   Deletes object with all children
134   \param p - SUIT object
135 */
136 void SalomeApp_DataModelSync::deleteItemWithChildren( const suitPtr& p ) const
137 {
138   if( !p )
139     return;
140
141   DataObjectList ch;
142   p->children( ch );
143   DataObjectList::const_iterator anIt = ch.begin(), aLast = ch.end();
144   for( ; anIt!=aLast; anIt++ )
145     deleteItemWithChildren( *anIt );
146   delete p;
147 }
148
149 /*!
150   \return true if objects correspond each other at all
151   \param p - kernel object
152   \param q - suit object
153 */
154 bool SalomeApp_DataModelSync::isEqual( const kerPtr& p, const suitPtr& q ) const
155 {
156   LightApp_ModuleObject* lobj = dynamic_cast<LightApp_ModuleObject*>( q );
157   SalomeApp_DataObject* sobj = dynamic_cast<SalomeApp_DataObject*>( q );
158   _PTR( SComponent ) aComp( p );
159   bool res = ( !p && !q ) ||
160              ( lobj && !sobj && aComp ) ||
161              ( sobj && isCorrect( p ) && p->GetID().c_str()==sobj->entry() );
162   return res;
163 }
164
165 /*!
166   \return null kernel object
167 */
168 kerPtr SalomeApp_DataModelSync::nullSrc() const
169 {
170   return kerPtr();
171 }
172
173 /*!
174   \return null suit object
175 */
176 suitPtr SalomeApp_DataModelSync::nullTrg() const
177 {
178   return suitPtr( 0 );
179 }
180
181 /*!
182   Fills list with children of kernel object
183   \param obj - kernel object
184   \param ch - list to be filled
185 */
186 void SalomeApp_DataModelSync::children( const kerPtr& obj, QValueList<kerPtr>& ch ) const
187 {
188   ch.clear();
189   _PTR(ChildIterator) it ( myStudy->NewChildIterator( obj ) );
190   for( ; it->More(); it->Next() )
191     ch.append( it->Value() );
192 }
193
194 /*!
195   Fills list with children of SUIT object
196   \param p - SUIT object
197   \param ch - list to be filled
198 */
199 void SalomeApp_DataModelSync::children( const suitPtr& p, QValueList<suitPtr>& ch ) const
200 {
201   DataObjectList l;
202   if( p )
203   {
204     p->children( l );
205     ch.clear();
206     for( SUIT_DataObject* o = l.first(); o; o = l.next() )
207       ch.append( o );
208   }
209 }
210
211 /*!
212   \return parent of SUIT object
213   \param p - SUIT object
214 */
215 suitPtr SalomeApp_DataModelSync::parent( const suitPtr& p ) const
216 {
217   return p ? p->parent(): 0;
218 }
219
220 /*!
221   Updates SUIT object
222   \param p - SUIT object
223 */
224 void SalomeApp_DataModelSync::updateItem( const suitPtr& ) const
225 {
226 }
227
228 /*!
229   Auxiliary function, shows SUIT tree
230 */
231 void showTree( SUIT_DataObject* root )
232 {
233   qDebug( root ? "<tree>" : "<empty tree>" );
234   if( !root )
235     return;
236
237   SUIT_DataObjectIterator it( root, SUIT_DataObjectIterator::DepthLeft );
238   for( ; it.current(); ++it )
239   {
240     QString marg; marg.fill( ' ', 3*it.depth() );
241     QString nnn = "%1 '%2'";
242     qDebug( nnn.arg( marg ).arg( it.current()->name() ) );
243   }
244 }
245
246 /*!
247   Constructor
248 */
249 SalomeApp_DataModel::SalomeApp_DataModel( CAM_Module* theModule )
250 : LightApp_DataModel( theModule )
251 {
252 }
253
254 /*!
255   Destructor
256 */
257 SalomeApp_DataModel::~SalomeApp_DataModel()
258 {
259 }
260
261 /*!
262   Opens data model
263 */
264 bool SalomeApp_DataModel::open( const QString& name, CAM_Study* study, QStringList )
265 {
266   SalomeApp_Study* aDoc = dynamic_cast<SalomeApp_Study*>( study );
267   if ( !aDoc )
268     return false;
269
270   QString anId = getRootEntry( aDoc );
271   if ( anId.isEmpty() )
272     return true; // Probably nothing to load
273
274   _PTR(Study)      aStudy ( aDoc->studyDS() ); // shared_ptr cannot be used here
275   _PTR(SComponent) aSComp ( aStudy->FindComponentID( std::string( anId.latin1() ) ) );
276   if ( aSComp )
277     updateTree( aSComp, aDoc );
278
279   QStringList listOfFiles;
280   LightApp_DataModel::open(name, study, listOfFiles);
281   return true;
282 }
283
284 /*!
285   Creates data model
286 */
287 bool SalomeApp_DataModel::create( CAM_Study* theStudy )
288 {
289   update(NULL, (LightApp_Study*)theStudy);
290   return true;
291 }
292
293 /*!
294   Updates application.
295 */
296 void SalomeApp_DataModel::update( LightApp_DataObject*, LightApp_Study* study )
297 {
298   SalomeApp_Study* aSStudy = dynamic_cast<SalomeApp_Study*>(study);
299   LightApp_RootObject* studyRoot = 0;
300   _PTR(SComponent) sobj;
301   SalomeApp_DataObject* modelRoot = dynamic_cast<SalomeApp_DataObject*>( root() );
302   if ( !modelRoot ){ // not yet connected to a study -> try using <study> argument
303     if ( !aSStudy )
304       aSStudy = dynamic_cast<SalomeApp_Study*>( getModule()->getApp()->activeStudy() );
305     if ( aSStudy ){
306       studyRoot = dynamic_cast<LightApp_RootObject*>( aSStudy->root() );
307       QString anId = getRootEntry( aSStudy );
308       if ( !anId.isEmpty() ){ // if nothing is published in the study for this module -> do nothing
309         _PTR(Study) aStudy ( aSStudy->studyDS() );
310         sobj = aStudy->FindComponentID( std::string( anId.latin1() ) );
311       }
312     }
313   }
314   else{
315     studyRoot = dynamic_cast<LightApp_RootObject*>( modelRoot->root() );
316     if ( studyRoot ) {
317       aSStudy = dynamic_cast<SalomeApp_Study*>( studyRoot->study() ); // <study> value should not change here theoretically, but just to make sure
318       if ( aSStudy ) {
319         _PTR(Study) aStudy ( aSStudy->studyDS() );
320         // modelRoot->object() cannot be reused here: it is about to be deleted by buildTree() soon
321         sobj = aStudy->FindComponentID( std::string( modelRoot->entry().latin1() ) );
322       }
323     }
324   }
325   if ( sobj && aSStudy )
326     updateTree( sobj, aSStudy );
327 }
328
329 /*!
330   Synchronizes kernel tree and suit data tree starting from component 'sobj'
331 */
332 SUIT_DataObject* SalomeApp_DataModel::synchronize( const _PTR( SComponent )& sobj, SalomeApp_Study* study )
333 {
334   if( !study || !study->root() || !sobj )
335     return 0;
336
337   DataObjectList ch; study->root()->children( ch );
338   DataObjectList::const_iterator anIt = ch.begin(), aLast = ch.end();
339   SUIT_DataObject* suitObj = 0;
340   for( ; anIt!=aLast; anIt++ )
341   {
342     LightApp_DataObject* dobj = dynamic_cast<LightApp_DataObject*>( *anIt );
343     if( dobj && dobj->name() == sobj->GetName().c_str() )
344     {
345       suitObj = dobj;
346       break;
347     }
348   }
349
350   SalomeApp_DataModelSync sync( study->studyDS(), study->root() );
351
352   if( !suitObj || dynamic_cast<SalomeApp_DataObject*>( suitObj ) )
353     return ::synchronize<kerPtr,suitPtr,SalomeApp_DataModelSync>( sobj, suitObj, sync );
354   else
355     return 0;
356 }
357
358 /*!
359   Updates tree.
360 */
361 void SalomeApp_DataModel::updateTree( const _PTR( SComponent )& comp, SalomeApp_Study* study )
362 {
363   SalomeApp_ModuleObject* aNewRoot = dynamic_cast<SalomeApp_ModuleObject*>( synchronize( comp, study ) );
364   if( aNewRoot )
365   {
366     aNewRoot->setDataModel( this );
367     setRoot( aNewRoot );
368   }
369 }
370
371 /*!
372   \return module
373 */
374 SalomeApp_Module* SalomeApp_DataModel::getModule() const
375 {
376   return dynamic_cast<SalomeApp_Module*>( module() );
377 }
378
379 /*!
380   \return study
381 */
382 SalomeApp_Study* SalomeApp_DataModel::getStudy() const
383 {
384   if(!root()) return 0;
385   LightApp_RootObject* aRoot = dynamic_cast<LightApp_RootObject*>( root()->root() );
386   if ( !aRoot )
387     return 0;
388   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( aRoot->study() );
389   if ( !aStudy )
390     return 0;
391   return aStudy;
392 }
393
394 /*!
395   \return study entry corresponding to this data model
396 */
397 QString SalomeApp_DataModel::getRootEntry( SalomeApp_Study* study ) const
398 {
399   QString anEntry;
400   if ( root() && root()->root() ) { // data model already in a study
401     SalomeApp_DataObject* anObj = dynamic_cast<SalomeApp_DataObject*>( root() );
402     if ( anObj )
403       anEntry = anObj->entry();
404   }
405   else if ( study && study->studyDS() ) { // this works even if <myRoot> is null
406     _PTR(SComponent) aSComp( study->studyDS()->FindComponent( module()->name() ) );
407     if ( aSComp )
408       anEntry = aSComp->GetID().c_str();
409   }
410   return anEntry;
411 }