Salome HOME
44dd52f53f7f0514fc0db902e099609be8b25da1
[samples/atomic.git] / src / ATOMICGUI / ATOMICGUI_DataModel.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
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, or (at your option) any later version.
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
20 #include "ATOMICGUI_DataModel.h"
21 #include "ATOMICGUI_DataObject.h"
22
23 #include <LightApp_Study.h>
24 #include <SUIT_Tools.h>
25 #include <SUIT_DataObjectIterator.h>
26 #include <CAM_Module.h>
27 #include <CAM_Application.h>
28
29 #include <CAM_Module.h>
30 #include <CAM_Application.h>
31
32 #include <qstring.h>
33 #include <qfile.h>
34 #ifndef QT_NO_DOM
35 #include <qdom.h>
36 #endif
37
38 #include <vector>
39 #include <string>
40 #include <fstream>
41
42 const QString doc_name     = "Atomic";
43 const QString doc_tag      = "document";
44 const QString molecule_tag = "molecule";
45 const QString atom_tag     = "atom";
46 const QString name_attr    = "name";
47 const QString x_attr       = "x";
48 const QString y_attr       = "y";
49 const QString z_attr       = "z";
50
51 /*! Constructor */
52 ATOMICGUI_DataModel::ATOMICGUI_DataModel( CAM_Module* module )
53   : LightApp_DataModel( module ),
54     myStudyURL( "" )
55 {
56 }
57
58 /*! Destructor */
59 ATOMICGUI_DataModel::~ATOMICGUI_DataModel()
60 {
61 }
62
63 /*! Open Data Model.  Build data structure from the given list of files. */
64 bool ATOMICGUI_DataModel::open( const QString& URL, CAM_Study* study, QStringList listOfFiles )
65 {
66   myMolecules.clear();
67
68   LightApp_Study* aDoc = dynamic_cast<LightApp_Study*>( study );
69   if ( !aDoc )
70     return false;
71
72   LightApp_DataModel::open( URL, aDoc, listOfFiles );
73
74   // The first list item contains path to a temporary
75   // directory, where the persistent files was placed
76   if ( listOfFiles.count() > 0 ) {
77     QString aTmpDir ( listOfFiles[0] );
78
79     // This module operates with a single persistent file
80     if ( listOfFiles.size() == 2 ) {
81       myStudyURL = URL;
82       QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + listOfFiles[1];
83       return importFile( aFullPath, aDoc );
84     }
85   }
86
87   return false;
88 }
89
90 /*! Save Data Model.  Export data structure to temprorary files and return the list of files. */
91 bool ATOMICGUI_DataModel::save( QStringList& listOfFiles )
92 {
93   bool isMultiFile = false; // TODO: decide, how to access this parameter
94
95   LightApp_DataModel::save( listOfFiles );
96
97   LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
98
99   QString aTmpDir(study->GetTmpDir( myStudyURL.toLatin1(), isMultiFile ).c_str());
100
101   QString aFileName = SUIT_Tools::file( myStudyURL, false ) + "_ATOMICGUI.xml";
102   QString aFullPath = aTmpDir + aFileName;
103   bool ok = exportFile( aFullPath );
104
105   listOfFiles.append( aTmpDir );
106   listOfFiles.append( aFileName );
107
108   printf( " \n saved to %s\n ", aFullPath.toLatin1().data() );
109
110   return ok;
111 }
112
113 /*! Save Data Model under given name.  Export data structure to temprorary files and return the list of files. */
114 bool ATOMICGUI_DataModel::saveAs ( const QString& URL, CAM_Study* study, QStringList& listOfFiles )
115 {
116   myStudyURL = URL;
117   return save( listOfFiles );
118 }
119
120 /*! Called on Study closure */
121 bool ATOMICGUI_DataModel::close()
122 {
123   myStudyURL = "";
124   //myMolecules.clear();
125   return LightApp_DataModel::close();
126 }
127
128 /*! Called on Study creation */
129 bool ATOMICGUI_DataModel::create( CAM_Study* study )
130 {
131   myMolecules.clear();
132   return true;
133 }
134
135 /*! Default implementation, always returns false so as not to mask study's isModified() */
136 bool ATOMICGUI_DataModel::isModified() const
137 {
138   return false;
139 }
140
141 /*! Default implementation, always returns true so as not to mask study's isSaved() */
142 bool ATOMICGUI_DataModel::isSaved() const
143 {
144   return true;
145 }
146
147 /*! Called on update of the structure of Data Objects */
148 void ATOMICGUI_DataModel::build()
149 {
150   //VSR: module object should be created in a different way for "full" and "light" SALOME
151   //ATOMICGUI_ModuleObject* modelRoot = dynamic_cast<ATOMICGUI_ModuleObject*>( root() );
152   CAM_ModuleObject* modelRoot = dynamic_cast<CAM_ModuleObject*>( root() );
153   if( !modelRoot )  {  // root is not set yet
154     //VSR: module object should be created in a different way for "full" and "light" SALOME
155     //modelRoot = new ATOMICGUI_ModuleObject( this, 0 );
156     LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
157     modelRoot = createModuleObject( study->root() );
158     setRoot( modelRoot );
159   }
160
161   // create 'molecule' objects under model root object and 'atom' objects under 'molecule'-s
162   for ( int i = 0; i < myMolecules.count(); i++ ) {
163     ATOMICGUI_DataObject* molObj = new ATOMICGUI_DataObject ( modelRoot, &myMolecules[i] );
164     for ( int j = 0; j < myMolecules[ i ].count(); j++ ) {
165       /*ATOMICGUI_DataObject* atomObj = */new ATOMICGUI_DataObject ( molObj, &myMolecules[i], j );
166     }
167   }
168
169   //root()->dump();
170 }
171
172 /*! Loads data from the XML file. */
173 bool ATOMICGUI_DataModel::importFile( const QString& fileName, CAM_Study* study )
174 {
175   bool res = false;
176
177 #ifndef QT_NO_DOM
178
179   QFile file( fileName );
180   if ( !file.open( QIODevice::ReadOnly ) )
181     return false;
182
183   QDomDocument doc;
184
185   res = doc.setContent( &file );
186   file.close();
187
188   if ( !res )
189     return false;
190
191   QDomElement root = doc.documentElement();
192   if ( root.isNull() || root.tagName() != doc_tag )
193     return false;
194
195   QDomNode molNode = root.firstChild();
196   while ( res && !molNode.isNull() ) {
197     res = molNode.isElement();
198     if ( res ) {
199       QDomElement molElem = molNode.toElement();
200       if ( molElem.tagName() == molecule_tag && molElem.hasAttribute( name_attr ) ) {
201         ATOMICGUI_AtomicMolecule aMol( molElem.attribute( name_attr ) );
202         QDomNode atomNode = molNode.firstChild();
203         while ( res && !atomNode.isNull() ) {
204           res = atomNode.isElement();
205           if ( res ) {
206             QDomElement atomElem = atomNode.toElement();
207             if ( atomElem.tagName() == atom_tag &&
208                  atomElem.hasAttribute( name_attr ) && 
209                  atomElem.hasAttribute( x_attr ) &&
210                  atomElem.hasAttribute( y_attr ) &&
211                  atomElem.hasAttribute( z_attr ) ) {
212               aMol.addAtom( atomElem.attribute( name_attr ),
213                              atomElem.attribute( x_attr ).toDouble(),
214                              atomElem.attribute( y_attr ).toDouble(),
215                              atomElem.attribute( z_attr ).toDouble() );
216             }
217             else
218               res = false;
219           }
220           else
221             res = atomNode.isComment();
222
223           atomNode = atomNode.nextSibling();
224         }
225         myMolecules.append( aMol );
226       }
227       else
228         res = false;
229     }
230     else
231       res = molNode.isComment();
232
233     molNode = molNode.nextSibling();
234   }
235
236 #endif
237
238   return res;
239 }
240
241 /*! Saves data to the XML file */
242 bool ATOMICGUI_DataModel::exportFile( const QString& fileName )
243 {
244   bool res = false;
245
246 #ifndef QT_NO_DOM
247
248   QFile file( fileName );
249   if ( !file.open( QIODevice::WriteOnly ) )
250     return false;
251
252   QDomDocument doc( doc_name );
253   QDomElement root = doc.createElement( doc_tag );
254   doc.appendChild( root );
255
256   for ( int i = 0; i < myMolecules.count(); i++ ) {
257     QDomElement molecule = doc.createElement( molecule_tag );
258     molecule.setAttribute( name_attr, myMolecules[ i ].name() );
259     root.appendChild( molecule );
260     for ( int j = 0; j < myMolecules[ i ].count(); j++ ) {
261       QDomElement atom = doc.createElement( atom_tag );
262       atom.setAttribute( name_attr, myMolecules[ i ].atomName( j ) );
263       atom.setAttribute( x_attr, myMolecules[ i ].atomX( j ) );
264       atom.setAttribute( y_attr, myMolecules[ i ].atomY( j ) );
265       atom.setAttribute( z_attr, myMolecules[ i ].atomZ( j ) );
266       molecule.appendChild( atom );
267     }
268   }
269
270   QString docStr = doc.toString();
271   res = file.write( docStr.toLatin1(), docStr.length() ) == (int)docStr.length();
272   file.close();
273
274 #endif
275
276   return res;
277 }
278
279 /*! Adds a new molecule to the data structure */
280 QString ATOMICGUI_DataModel::createMolecule ()
281 {
282   ATOMICGUI_AtomicMolecule mol;
283   
284   // temporary code to add a few atoms to a molecule..
285   //mol.addAtom( "atom_1", 0, 0, 0 );
286   //mol.addAtom( "atom_2", 0, 0, 0 );
287   //mol.addAtom( "atom_3", 0, 0, 0 );
288   // end of temporary code
289   
290   myMolecules.append( mol );
291
292   QString id = QString( "ATOMICGUI_%1" ).arg( mol.id() );
293  
294   update();
295   return id;
296 }
297
298 /*! Adds a new atom to the given molecule */
299 bool ATOMICGUI_DataModel::addAtom( const QString& entry, const QString& atom, 
300                                    const double x, const double y, const double z )
301 {
302   ATOMICGUI_DataObject* obj = findMolecule( entry );
303   if ( obj && obj->isMolecule() ) {
304     obj->molecule()->addAtom( atom, x, y, z );
305   }
306   return true;
307 }
308
309 /*! Rename the given (by entry) object */
310 bool ATOMICGUI_DataModel::renameObj( const QString& entry, const QString& name )
311 {
312   ATOMICGUI_DataObject* obj = findObject( entry );
313   if ( obj ) {
314     if ( obj->isMolecule() || obj->isAtom() ) {
315       obj->molecule()->setName( name, obj->atomIndex() );
316       return true;
317     }
318   }
319   return false;
320 }
321
322 /*! Delete the given objects (list of entries) */
323 bool ATOMICGUI_DataModel::deleteObjs( const QStringList& entries )
324 {
325   QMap<QString, ATOMICGUI_DataObject*> cmap;
326   // first find all molecules
327   for ( int i = 0; i < entries.count(); i++ ) {
328     ATOMICGUI_DataObject* o = findObject( entries[i] );
329     if ( o && o->isMolecule() )
330       cmap[ entries[i] ] = o;
331   }
332   // then find all atoms
333   typedef QList<int> IntList;
334   QMap<ATOMICGUI_DataObject*, IntList> amap;
335   for ( int i = 0; i < entries.count(); i++ ) {
336     ATOMICGUI_DataObject* o = findObject( entries[i] );
337     if ( o && o->isAtom() ) {
338       ATOMICGUI_DataObject* c = dynamic_cast<ATOMICGUI_DataObject*>( o->parent() );
339       if ( !c || cmap.find( c->entry() ) == cmap.end() )
340         amap[ c ].append( o->atomIndex() );
341     }
342   }
343   // now perform deleting
344   int removed = 0;
345   QMap<QString, ATOMICGUI_DataObject*>::Iterator it;
346   for ( it = cmap.begin(); it != cmap.end(); ++it ) {
347     for ( int i = 0; i < myMolecules.count(); i++ ) {
348       if ( &myMolecules[ i ] == it.value()->molecule() ) {
349         myMolecules.removeAt( i );
350         removed++;
351         break;
352       }
353     }
354   }
355   QMap<ATOMICGUI_DataObject*, IntList>::Iterator it1;
356   for ( it1 = amap.begin(); it1 != amap.end(); ++it1 ) {
357     IntList indices = it1.value();
358     qSort( indices );
359     for ( int i = indices.count() - 1; i >= 0; i-- ) {
360       it1.key()->molecule()->deleteAtom( indices[i] );
361       removed++;
362     }
363   }
364   return removed;
365 }
366
367 /*! Returns the Data Object by entry */
368 ATOMICGUI_DataObject* ATOMICGUI_DataModel::findObject( const QString& entry )
369 {
370   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
371     ATOMICGUI_DataObject* obj = dynamic_cast<ATOMICGUI_DataObject*>( it.current() );
372     if ( obj && obj->entry() == entry )
373       return obj;
374   }
375   return 0;
376 }
377
378 /*! Returns the Data Object by entry.  If object is an Atom, its parent Molecule is returned. */
379 ATOMICGUI_DataObject* ATOMICGUI_DataModel::findMolecule( const QString& entry )
380 {
381   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
382     ATOMICGUI_DataObject* obj = dynamic_cast<ATOMICGUI_DataObject*>( it.current() );
383     if ( obj && obj->entry() == entry ) {
384       if ( obj->isMolecule() )
385         return obj;
386       else if ( obj->isAtom() )
387         return dynamic_cast<ATOMICGUI_DataObject*>( obj->parent() );
388       else
389         return 0;
390     }
391   }
392   return 0;
393 }
394 /*! Dump the data model in the python script. */
395 bool ATOMICGUI_DataModel::dumpPython( const QString& theURL,
396                                       CAM_Study* theStudy,
397                                       bool isMultiFile,
398                                       QStringList& theListOfFiles  ) {
399   QString aScript = "from AtomicPy import *\n";
400   QString aPrefix = "";
401   if(isMultiFile) {
402     aScript += "def RebuildData(theStudy):\n";
403     aPrefix = "    ";
404   }
405   
406   for ( int i = 0; i < myMolecules.count(); i++ ) {
407     aScript += aPrefix + QString("mol_%1 = AtomicMolecule('").arg(i) + myMolecules[ i ].name()+"')\n";
408     for ( int j = 0; j < myMolecules[ i ].count(); j++ ) {
409       aScript += aPrefix + QString("mol_%1.addAtom('").arg(i) + myMolecules[ i ].atomName( j );
410       aScript += QString("', %1, %2, %3)\n").arg(myMolecules[ i ].atomX( j )).arg(myMolecules[ i ].atomY( j )).arg(myMolecules[ i ].atomZ( j ));
411     }
412   }
413   
414   if(isMultiFile) {
415     aScript += aPrefix+"pass\n";
416   }
417
418   LightApp_Study* study = dynamic_cast<LightApp_Study*>( theStudy );
419   if(!study)
420     return false;
421   
422   std::string aTmpDir = study->GetTmpDir( theURL.toLatin1().constData(), isMultiFile );
423   std::string aFile = aTmpDir + "atomic_dump.tmp";
424
425   std::ofstream outfile(aFile.c_str());
426   outfile.write (aScript.toLatin1().data(),aScript.size());
427   outfile.close();
428
429   theListOfFiles.append(aTmpDir.c_str());
430   theListOfFiles.append("atomic_dump.tmp");
431   
432   return true;
433 }