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