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