]> SALOME platform Git repositories - samples/light.git/blob - src/LIGHTGUI/LIGHTGUI_DataModel.cxx
Salome HOME
Merge from BR_V5_DEV 17Feb09
[samples/light.git] / src / LIGHTGUI / LIGHTGUI_DataModel.cxx
1 //  Copyright (C) 2005-2008  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.
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 // LIGHT : sample (no-corba-engine) SALOME module
20 // File   : LIGHTGUI_DataModel.cxx
21 // Author : Julia DOROVSKIKH
22 //
23 #include "LIGHTGUI_DataModel.h"
24 #include "LIGHTGUI_DataObject.h"
25
26 #include <LightApp_Study.h>
27 #include <CAM_Module.h>
28 #include <CAM_Application.h>
29 #include <SUIT_Tools.h>
30 #include <SUIT_DataObjectIterator.h>
31
32 #include <QString>
33 #include <QFile>
34 #include <QTextStream>
35 #include <QStringList>
36
37 /*!
38   \class LIGHTGUI_DataModel
39   \brief LIGHT module data model.
40 */
41
42 /*!
43   \brief Constructor
44   \param module parent module
45 */
46 LIGHTGUI_DataModel::LIGHTGUI_DataModel( CAM_Module* module )
47 : LightApp_DataModel( module ),
48   myFileName( "" ),
49   myStudyURL( "" ),
50   myMaxId( 0 )
51 {
52 }
53
54 /*!
55   \brief Destructor.
56 */
57 LIGHTGUI_DataModel::~LIGHTGUI_DataModel()
58 {
59 }
60
61 /*!
62   \brief Open data model (read data from the files).
63   \param url study file path
64   \param study study pointer
65   \param listOfFiles list of the (temporary) files with data
66   \return operation status (\c true on success and \c false on error)
67 */
68 bool LIGHTGUI_DataModel::open( const QString& url, CAM_Study* study, QStringList listOfFiles )
69 {
70   LightApp_Study* aDoc = dynamic_cast<LightApp_Study*>( study );
71   if ( !aDoc )
72     return false;
73
74   LightApp_DataModel::open( url, aDoc, listOfFiles );
75
76   // The first list item contains path to a temporary
77   // directory, where the persistent files was placed
78   if ( listOfFiles.count() > 0 ) {
79     QString aTmpDir ( listOfFiles[0] );
80
81     // This module operates with a single persistent file
82     if ( listOfFiles.size() == 2 ) {
83       myStudyURL = url;
84       QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + listOfFiles[1];
85       loadFile( aFullPath, aDoc );
86     }
87   }
88
89   return true;
90 }
91
92 /*!
93   \brief Save data model (write data to the files).
94   \param listOfFiles returning list of the (temporary) files with saved data
95   \return operation status (\c true on success and \c false on error)
96 */
97 bool LIGHTGUI_DataModel::save( QStringList& theListOfFiles )
98 {
99   bool isMultiFile = false; // TODO: decide, how to access this parameter
100
101   LightApp_DataModel::save( theListOfFiles );
102
103   LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
104
105   QString aTmpDir = study->GetTmpDir( myStudyURL.toLatin1(), isMultiFile ).c_str();
106
107   QString aFileName = SUIT_Tools::file( myStudyURL, false ) + "_LIGHTGUI.txt";
108   QString aFullPath = aTmpDir + aFileName;
109   dumpFile( aFullPath );
110
111   theListOfFiles.append( aTmpDir );
112   theListOfFiles.append( aFileName );
113
114   return true;
115 }
116
117 /*!
118   \brief Save data model (write data to the files).
119   \param url study file path
120   \param study study pointer
121   \param listOfFiles returning list of the (temporary) files with saved data
122   \return operation status (\c true on success and \c false on error)
123 */
124 bool LIGHTGUI_DataModel::saveAs( const QString& url, CAM_Study* study, QStringList& theListOfFiles )
125 {
126   myStudyURL = url;
127   return save( theListOfFiles );
128 }
129
130 /*!
131   \brief Close data model (remove all relevant data).
132   \return operation status (\c true on success and \c false on error)
133 */
134 bool LIGHTGUI_DataModel::close()
135 {
136   return LightApp_DataModel::close();
137 }
138
139 /*!
140   \brief Create empty data model.
141   \param study study pointer
142   \return operation status (\c true on success and \c false on error)
143 */
144 bool LIGHTGUI_DataModel::create( CAM_Study* study )
145 {
146   return true;
147 }
148
149 /*!
150   \brief Get 'modified' flag.
151   \return \c true if data is changed from the last saving
152 */
153 bool LIGHTGUI_DataModel::isModified() const
154 {
155   // return false to avoid masking study's isModified()
156   return false;
157 }
158
159 /*!
160   \brief Get 'saved' flag.
161   \return \c true if data has been saved
162 */
163 bool LIGHTGUI_DataModel::isSaved() const
164 {
165   // return true to avoid masking study's isSaved()
166   return true;
167 }
168
169 /*!
170   \brief Update data model.
171   \param obj data object (starting for the update)
172   \param study study pointer
173 */
174 void LIGHTGUI_DataModel::update( LightApp_DataObject* /*obj*/, LightApp_Study* /*study*/ )
175 {
176   // Nothing to do here: we always keep the data tree in the up-to-date state
177   // The only goal of this method is to hide default behavior from LightApp_DataModel
178   return;
179 }
180
181 /*
182   \brief Load text data from the file.
183   \param filename file path
184   \param study study pointer
185   \return \c true if data is loaded successfully
186 */  
187 bool LIGHTGUI_DataModel::loadFile( const QString& filename, CAM_Study* study )
188 {
189   if ( filename.isEmpty() ) return false;
190
191   myFileName = filename;
192   
193   QStringList lines;
194   QFile file ( myFileName );
195   if ( file.open( QIODevice::ReadOnly ) ) {
196     QTextStream stream ( &file );
197     QString line;
198     while ( !stream.atEnd() ) {
199       line = stream.readLine(); // line of text excluding '\n'
200       lines += line;
201     }
202     file.close();
203
204     if  ( !study )
205       study = (CAM_Study*)module()->application()->activeStudy();
206     buildTree( study->root(), lines );
207
208     return true;
209   }
210
211   return false;
212 }
213
214 /*!
215   \brief Save text data to the file
216   \param filename file path
217   \return \c true if data is loaded successfully
218 */
219 bool LIGHTGUI_DataModel::dumpFile( const QString& filename )
220 {
221   QString aFileName = filename;
222   if ( aFileName.isEmpty() )
223     aFileName = myFileName;
224
225   if ( aFileName.isEmpty() ) return false;
226
227   QStringList lines;
228   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
229     LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
230     if ( obj && obj->lineNb() > 0 )
231       lines.insert( obj->lineNb()-1, obj->lineText() );
232   }
233
234   QFile file ( aFileName );
235   if ( file.open( QIODevice::WriteOnly ) ) {
236     QTextStream stream ( &file );
237     QStringList::Iterator it = lines.begin();
238     for ( ; it != lines.end(); ++it ) {
239       stream << *it << "\n";
240     }
241     file.close();
242
243     myFileName = aFileName;
244     return true;
245   }
246
247   return false;
248 }
249
250 /*!
251   \brief Get latest loaded or saved text file's name.
252   \return file name (empty string if file has not been loaded or saved)
253 */
254 QString LIGHTGUI_DataModel::fileName() const
255 {
256   return myFileName;
257 }
258
259 /*!
260   \brief Get text for the specified line.
261   \param id line identifier
262   \return string text for the line with identifier \a id
263           (empty string is \a id is invalid)
264 */
265 QString LIGHTGUI_DataModel::getLineText( const int id ) const
266 {
267   QString aText;
268
269   LIGHTGUI_DataObject* obj = findObject( id );
270   if ( obj )
271     aText = obj->lineText();
272
273   return aText;
274 }
275
276 /*!
277   \brief Set text for the specified line.
278   \param id line identifier
279   \param txt new string text for the line
280   \return \c true on success or \c false if \a id is invalid
281 */
282 bool LIGHTGUI_DataModel::setLineText( const int id, const QString& txt )
283 {
284   LIGHTGUI_DataObject* obj = findObject( id );
285   if ( obj ) {
286     if ( txt.trimmed().isEmpty() && !obj->lineText().trimmed().isEmpty() ||
287         !txt.trimmed().isEmpty() &&  obj->lineText().trimmed().isEmpty() ) {
288       if ( obj->lineText().trimmed().isEmpty() ) {
289         // paragraph becomes a text line
290         SUIT_DataObject* newParent = obj->prevBrother();
291         if ( newParent ) {
292           obj->setParent( newParent );
293           while ( SUIT_DataObject* first = obj->firstChild() )
294             first->setParent( newParent );
295         }
296       }
297       else {
298         // text line becomes a paragraph
299         SUIT_DataObject* parent = obj->parent();
300         SUIT_DataObject* modelRoot = parent ? parent->parent() : 0;
301         if ( modelRoot && parent ) {
302           int pos = parent->childPos( obj );
303           modelRoot->insertChild( obj, modelRoot->childPos( parent ) + 1 );
304           while ( SUIT_DataObject* next = parent->childObject( pos ) )
305             obj->appendChild( next );
306         }
307       }
308     }
309     obj->setLineText( txt );
310     return true;
311   }
312   return false;
313 }
314
315 /*!
316   \brief Insert new text line.
317   \param id identifier of the line after which new one should be inserted
318          (if <=0, new line is added to the end)
319   \param txt string text
320   \return \c true on success or \c false if \a id is invalid
321 */
322 bool LIGHTGUI_DataModel::insertLineBefore( const int id, const QString& txt )
323 {
324   // Insert new line before the item at position in the list,
325   // or at the end() if position is out of range
326   LightApp_ModuleObject* modelRoot = dynamic_cast<LightApp_ModuleObject*>( root() );
327   LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
328   if ( id > 0 ) {
329     if ( !modelRoot )
330       return false;
331     LIGHTGUI_DataObject* obj = findObject( id );
332     if ( !obj || !obj->parent() )
333       return false;
334     SUIT_DataObject* parent = obj->parent();
335     if ( txt.trimmed().isEmpty() ) {
336       // insert new paragraph
337       if ( obj->lineText().trimmed().isEmpty() ) {
338         int pos = modelRoot->childPos( obj );
339         modelRoot->insertChild( new LIGHTGUI_DataObject( generateId(), txt, 0 ), pos );
340       }
341       else {
342         int pos = parent->childPos( obj );
343         LIGHTGUI_DataObject* newObj = new LIGHTGUI_DataObject( generateId(), txt, 0 );
344         modelRoot->insertChild( newObj, modelRoot->childPos( parent ) + 1 );
345         while ( SUIT_DataObject* next = parent->childObject( pos ) )
346           newObj->appendChild( next );
347       }
348     }
349     else {
350       // insert new text line
351       if ( obj->lineText().trimmed().isEmpty() ) {
352         SUIT_DataObject* prevParent = obj->prevBrother();
353         if ( prevParent )
354           prevParent->appendChild( new LIGHTGUI_DataObject( generateId(), txt, prevParent ) );
355       }
356       else {
357         int pos = parent->childPos( obj );
358         parent->insertChild( new LIGHTGUI_DataObject( generateId(), txt, 0 ), pos );
359       }
360     }
361   }
362   else {
363     // append new paragraph/line
364     if ( modelRoot )
365       txt.trimmed().isEmpty() ? new LIGHTGUI_DataObject( generateId(), txt, modelRoot ) : 
366                                 new LIGHTGUI_DataObject( generateId(), txt, modelRoot->lastChild() );
367     else {
368       QStringList lines;
369       if ( !txt.trimmed().isEmpty() ) 
370         lines.append( txt );
371       buildTree( study->root(), lines );
372     }
373       
374   }
375   return true;
376 }
377
378 /*!
379   \brief Remove text line.
380   \param id line identifier
381   \return \c true on success or \c false if \a id is invalid
382 */
383 bool LIGHTGUI_DataModel::deleteTextLine( const int id )
384 {
385   LightApp_ModuleObject* modelRoot = dynamic_cast<LightApp_ModuleObject*>( root() );
386
387   if ( !modelRoot )
388     return false;
389
390   LIGHTGUI_DataObject* obj = findObject( id );
391   if ( !obj || !obj->parent() )
392     return false;
393   
394   if ( obj->lineText().trimmed().isEmpty() ) {
395     // if paragraph : put all child lines to the previous paragraph
396     SUIT_DataObject* newParent = obj->prevBrother();
397     if ( newParent ) {
398       while ( SUIT_DataObject* first = obj->firstChild() )
399         first->setParent( newParent );
400     }
401   }
402   obj->parent()->removeChild( obj );
403
404   return true;
405 }
406
407 /*!
408   \brief Remove all lines.
409 */
410 void LIGHTGUI_DataModel::clearAll()
411 {
412   CAM_Study* study = (CAM_Study*)module()->application()->activeStudy();
413   buildTree( study->root(), QStringList() );
414 }
415
416 /*!
417   \brief Getnerate unique line identifier.
418 */
419 int LIGHTGUI_DataModel::generateId()
420 {
421   return ++myMaxId;
422 }
423
424 /*!
425   \brief Get line identifier from the object entry.
426   \param entry object entry
427   \return object ID or -1 if \a entry is invalid
428 */
429 int LIGHTGUI_DataModel::id( const QString& entry )
430 {
431   int id = -1;
432   QStringList ids = entry.split( ":", QString::SkipEmptyParts );
433   if ( ids.count() == 2 && ids[0] == "LIGHTGUI" ) {
434     bool bOk;
435     int p = ids[1].toInt( &bOk );
436     if ( bOk ) 
437       id = p;
438   }
439   return id;
440 }
441
442 /*!
443   \brief Get object entry for the line with sepcified identifier.
444   \param id object ID
445   \return object entry corresponding to the given \a id
446 */
447 QString LIGHTGUI_DataModel::entry( const int id )
448 {
449   QString entry;
450   if ( id > 0 )
451     entry = QString( "LIGHTGUI:%1" ).arg( id );
452   return entry;
453 }
454
455 /*!
456   \brief Get line number for the object with the specified entry.
457   \param entry object entry
458   \return line number or 0 if \a entry is invalid
459 */
460 int LIGHTGUI_DataModel::lineNb( const QString& entry )
461 {
462   return lineNb( LIGHTGUI_DataModel::id( entry ) );
463 }
464
465 /*!
466   \brief Get line number for the specified identifier.
467   \param id line identifier
468   \return line number or 0 if \a id is invalid
469 */
470 int LIGHTGUI_DataModel::lineNb( const int id )
471 {
472   LIGHTGUI_DataObject* obj = findObject( id );
473   return obj ? obj->lineNb() : 0;
474 }
475
476 /*!
477   \brief Get all existing lines identifiers.
478   \return list of lines identifiers
479 */
480 QList<int> LIGHTGUI_DataModel::getIds() const
481 {
482   QList<int> l;
483   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
484     LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
485     if ( obj )
486       l.append( obj->id() );
487   }
488   return l;
489 }
490
491 /*!
492   \brief Rebuild data tree.
493   \param studyRoot study root data object
494   \param lines string data
495 */
496 void LIGHTGUI_DataModel::buildTree( SUIT_DataObject* studyRoot, const QStringList& lines )
497 {
498   if ( !studyRoot )
499     return;
500
501   LightApp_ModuleObject* modelRoot = new LightApp_ModuleObject( this, studyRoot );
502   LIGHTGUI_DataObject* aParaObject;
503   LIGHTGUI_DataObject* aLineObject;
504
505   aParaObject = new LIGHTGUI_DataObject ( generateId(), "", modelRoot );
506
507   QStringList::ConstIterator it1 = lines.begin(),
508                              it2 = lines.end();
509   for ( ; it1 != it2; ++it1 ) {
510     if ( (*it1).trimmed().isEmpty() ) {
511       aParaObject = new LIGHTGUI_DataObject ( generateId(), *it1, modelRoot );
512     }
513     else {
514       aLineObject = new LIGHTGUI_DataObject ( generateId(), *it1, aParaObject );
515     }
516   }
517
518   modelRoot->setDataModel( this );
519   setRoot( modelRoot );
520 }
521
522 /*!
523   \brief Search data object corresponding to the specified line number.
524   \param id line identifier
525   \return data object or 0 if \a id is invalid
526 */
527 LIGHTGUI_DataObject* LIGHTGUI_DataModel::findObject( const int id ) const
528 {
529   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
530     LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
531     if ( obj && obj->id() == id )
532       return obj;
533   }
534   return 0;
535 }