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