Salome HOME
5d7befe6ae65bfdf5ea57ef730bee805b6709389
[samples/light.git] / src / LIGHTGUI / LIGHTGUI_DataModel.cxx
1 //  LIGHT : sample (no-corba-engine) SALOME module
2 //
3 //  Copyright (C) 2003  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 //  Author : Julia DOROVSKIKH
23 //  Date   : 01/01/2005
24 //  $Header$
25
26 #include "LIGHTGUI_DataModel.h"
27 #include "LIGHTGUI_DataObject.h"
28
29 #include <LightApp_Study.h>
30 #include <SUIT_Tools.h>
31 #include <SUIT_DataObjectIterator.h>
32 #include <CAM_Module.h>
33 #include <CAM_Application.h>
34
35 #include <CAM_Module.h>
36 #include <CAM_Application.h>
37
38 #include <qstring.h>
39 #include <qfile.h>
40
41 #include <vector.h>
42 #include <string.h>
43
44 //=================================================================================
45 // function : LIGHTGUI_DataModel()
46 // purpose  : constructor
47 //=================================================================================
48 LIGHTGUI_DataModel::LIGHTGUI_DataModel ( CAM_Module* theModule )
49      : LightApp_DataModel( theModule ),
50        myFileName( "" ),
51        myStudyURL( "" )
52 {
53 }
54
55 //=================================================================================
56 // function : ~LIGHTGUI_DataModel()
57 // purpose  : destructor
58 //=================================================================================
59 LIGHTGUI_DataModel::~LIGHTGUI_DataModel()
60 {
61 }
62
63 //=================================================================================
64 // function : open()
65 // purpose  : Open data model operation
66 //=================================================================================
67 bool LIGHTGUI_DataModel::open ( const QString& theURL, CAM_Study* study, QStringList listOfFiles )
68 {
69   LightApp_Study* aDoc = dynamic_cast<LightApp_Study*>( study );
70   if ( !aDoc )
71     return false;
72
73   LightApp_DataModel::open( theURL, aDoc, listOfFiles );
74
75   // The first list item contains path to a temporary
76   // directory, where the persistent files was placed
77   if ( listOfFiles.count() > 0 ) {
78     QString aTmpDir ( listOfFiles[0] );
79
80     // This module operates with a single persistent file
81     if ( listOfFiles.size() == 2 ) {
82       myStudyURL = theURL;
83       QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + listOfFiles[1];
84       loadFile( aFullPath, aDoc );
85     }
86   }
87
88   return true;
89 }
90
91 //=================================================================================
92 // function : save()
93 // purpose  : Save data model operation
94 //=================================================================================
95 bool LIGHTGUI_DataModel::save( QStringList& theListOfFiles )
96 {
97   // 1. Save data to temporary files
98   bool isMultiFile = false; // TODO: decide, how to access this parameter
99
100   LightApp_DataModel::save(theListOfFiles);
101
102   LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
103
104   QString aTmpDir = study->GetTmpDir( myStudyURL.latin1(), isMultiFile );
105
106   QString aFileName = SUIT_Tools::file( myStudyURL, false ) + "_LIGHTGUI.txt";
107   QString aFullPath = aTmpDir + aFileName;
108   dumpFile( aFullPath );
109
110   theListOfFiles.append(aTmpDir);
111   theListOfFiles.append(aFileName);
112
113   return true;
114 }
115
116 //=================================================================================
117 // function : saveAs()
118 // purpose  : SaveAs data model operation
119 //=================================================================================
120 bool LIGHTGUI_DataModel::saveAs ( const QString& theURL, CAM_Study* theStudy, QStringList& theListOfFiles)
121 {
122   myStudyURL = theURL;
123   return save(theListOfFiles);
124 }
125
126 //=================================================================================
127 // function : close()
128 // purpose  : Close data model operation
129 //=================================================================================
130 bool LIGHTGUI_DataModel::close()
131 {
132   LightApp_DataModel::close();
133   return true;
134 }
135
136 //=================================================================================
137 // function : create()
138 // purpose  : Create data model operation
139 //=================================================================================
140 bool LIGHTGUI_DataModel::create( CAM_Study* study )
141 {
142   //  buildTree( study->root(), QStringList() );
143   return true;
144 }
145
146 //=================================================================================
147 // function : isModified()
148 // purpose  : default implementation, always returns false so as not to mask study's isModified()
149 //=================================================================================
150 bool LIGHTGUI_DataModel::isModified() const
151 {
152   return false;
153 }
154
155 //=================================================================================
156 // function : isSaved()
157 // purpose  : default implementation, always returns true so as not to mask study's isSaved()
158 //=================================================================================
159 bool LIGHTGUI_DataModel::isSaved() const
160 {
161   return true;
162 }
163
164 //=================================================================================
165 // function : update()
166 // purpose  : updates data model
167 //=================================================================================
168 void LIGHTGUI_DataModel::update ( LightApp_DataObject* theObj, LightApp_Study* theStudy )
169 {
170   // Nothing to do here: we always keep the data tree in the up-to-date state
171   // The only goal of this method is to hide default behavior from LightApp_DataModel
172   return;
173 }
174
175 //=================================================================================
176 // function : loadFile()
177 // purpose  : loads text data from the file
178 //=================================================================================
179 bool LIGHTGUI_DataModel::loadFile ( const QString& theFileName, CAM_Study* study )
180 {
181   if ( theFileName.isEmpty() ) return false;
182
183   myFileName = theFileName;
184   
185   QStringList lines;
186   QFile file ( myFileName );
187   if ( file.open( IO_ReadOnly ) ) {
188     QTextStream stream ( &file );
189     QString line;
190     while ( !stream.eof() ) {
191       line = stream.readLine(); // line of text excluding '\n'
192       lines += line;
193     }
194     file.close();
195
196     if  ( !study )
197       study = (CAM_Study*)module()->application()->activeStudy();
198     buildTree( study->root(), lines );
199
200     return true;
201   }
202
203   return false;
204 }
205
206 //=================================================================================
207 // function : dumpFile()
208 // purpose  : saves text data to the file
209 //=================================================================================
210 bool LIGHTGUI_DataModel::dumpFile ( const QString& theFileName )
211 {
212   QString aFileName = theFileName;
213   if ( aFileName.isEmpty() )
214     aFileName = myFileName;
215
216   if ( aFileName.isEmpty() ) return false;
217
218   QStringList lines;
219   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
220     LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
221     if ( obj && obj->lineNb() > 0 )
222       lines.insert( lines.at( obj->lineNb()-1 ), obj->lineText() );
223   }
224
225   QFile file ( aFileName );
226   if ( file.open( IO_WriteOnly ) ) {
227     QTextStream stream ( &file );
228     QStringList::Iterator it = lines.begin();
229     for ( ; it != lines.end(); ++it ) {
230       stream << *it << "\n";
231     }
232     file.close();
233
234     myFileName = aFileName;
235     return true;
236   }
237
238   return false;
239 }
240
241 //=================================================================================
242 // function : fileName()
243 // purpose  : gets a name of text file previously loaded or saved
244 //=================================================================================
245 QString LIGHTGUI_DataModel::fileName () const
246 {
247   return myFileName;
248 }
249
250 //=================================================================================
251 // function : getLineText()
252 // purpose  : gets text from the given line
253 //=================================================================================
254 QString LIGHTGUI_DataModel::getLineText ( const int thePosition ) const
255 {
256   QString aText;
257
258   LIGHTGUI_DataObject* obj = findObject( thePosition );
259   if ( obj )
260     aText = obj->lineText();
261
262   return aText;
263 }
264
265 //=================================================================================
266 // function : setLineText()
267 // purpose  : sets new text to the given line
268 //=================================================================================
269 bool LIGHTGUI_DataModel::setLineText ( const int thePosition, const QString& theText )
270 {
271   if ( thePosition <= 0 ) return false;
272   LIGHTGUI_DataObject* obj = findObject( thePosition );
273   if ( obj ) {
274     if ( theText.stripWhiteSpace().isEmpty() && !obj->lineText().stripWhiteSpace().isEmpty() ||
275         !theText.stripWhiteSpace().isEmpty() &&  obj->lineText().stripWhiteSpace().isEmpty() ) {
276       if ( obj->lineText().stripWhiteSpace().isEmpty() ) {
277         // paragraph becomes a text line
278         SUIT_DataObject* newParent = obj->prevBrother();
279         if ( newParent ) {
280           obj->setParent( newParent );
281           while ( SUIT_DataObject* first = obj->firstChild() )
282             first->setParent( newParent );
283         }
284       }
285       else {
286         // text line becomes a paragraph
287         SUIT_DataObject* parent = obj->parent();
288         SUIT_DataObject* modelRoot = parent ? parent->parent() : 0;
289         if ( modelRoot && parent ) {
290           int pos = parent->childPos( obj );
291           modelRoot->insertChild( obj, modelRoot->childPos( parent )+1 );
292           while ( SUIT_DataObject* next = parent->childObject( pos ) )
293             obj->appendChild( next );
294         }
295       }
296     }
297     obj->setLineText( theText );
298     return true;
299   }
300   return false;
301 }
302
303 //=================================================================================
304 // function : insertLineBefore()
305 // purpose  : inserts the text line before the given one or appends a new line
306 //=================================================================================
307 bool LIGHTGUI_DataModel::insertLineBefore ( const int thePosition, const QString& theText )
308 {
309   // Insert new line before the item at thePosition in the list,
310   // or at the end() if thePosition is out of range
311   LIGHTGUI_ModuleObject* modelRoot = dynamic_cast<LIGHTGUI_ModuleObject*>( root() );
312   LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
313   if ( thePosition > 0 ) {
314     if ( !modelRoot )
315       return false;
316     LIGHTGUI_DataObject* obj = findObject( thePosition );
317     if ( !obj || !obj->parent() )
318       return false;
319     SUIT_DataObject* parent = obj->parent();
320     if ( theText.stripWhiteSpace().isEmpty() ) {
321       // insert new paragraph
322       if ( obj->lineText().stripWhiteSpace().isEmpty() ) {
323         int pos = modelRoot->childPos( obj );
324         modelRoot->insertChild( new LIGHTGUI_DataObject( theText, 0 ), pos );
325       }
326       else {
327         int pos = parent->childPos( obj );
328         LIGHTGUI_DataObject* newObj = new LIGHTGUI_DataObject( theText, 0 );
329         modelRoot->insertChild( newObj, modelRoot->childPos( parent )+1 );
330         while ( SUIT_DataObject* next = parent->childObject( pos ) )
331           newObj->appendChild( next );
332       }
333     }
334     else {
335       // insert new text line
336       if ( obj->lineText().stripWhiteSpace().isEmpty() ) {
337         SUIT_DataObject* prevParent = obj->prevBrother();
338         if ( prevParent )
339           prevParent->appendChild( new LIGHTGUI_DataObject( theText, prevParent ) );
340       }
341       else {
342         int pos = parent->childPos( obj );
343         parent->insertChild( new LIGHTGUI_DataObject( theText, 0 ), pos );
344       }
345     }
346   }
347   else {
348     // append new paragraph/line
349     if ( modelRoot )
350       theText.stripWhiteSpace().isEmpty() ? new LIGHTGUI_DataObject( theText, modelRoot ) : 
351                                             new LIGHTGUI_DataObject( theText, modelRoot->lastChild() );
352     else {
353       QStringList lines;
354       if ( !theText.stripWhiteSpace().isEmpty() ) 
355         lines.append( theText );
356       buildTree( study->root(), lines );
357     }
358       
359   }
360   return true;
361 }
362
363 //=================================================================================
364 // function : deleteTextLine()
365 // purpose  : remove text line at the given position
366 //=================================================================================
367 bool LIGHTGUI_DataModel::deleteTextLine( const int thePosition )
368 {
369   LIGHTGUI_ModuleObject* modelRoot = dynamic_cast<LIGHTGUI_ModuleObject*>( root() );
370   if ( !modelRoot )
371     return false;
372   if ( thePosition <= 0 )
373     return false;
374   LIGHTGUI_DataObject* obj = findObject( thePosition );
375   if ( !obj || !obj->parent() )
376     return false;
377   
378   if ( obj->lineText().stripWhiteSpace().isEmpty() ) {
379     // if paragraph : put all child lines to the previous paragraph
380     SUIT_DataObject* newParent = obj->prevBrother();
381     if ( newParent ) {
382       while ( SUIT_DataObject* first = obj->firstChild() )
383         first->setParent( newParent );
384     }
385   }
386   obj->parent()->removeChild( obj );
387   return true;
388 }
389
390 //=================================================================================
391 // function : clearAll()
392 // purpose  : removes all text lines
393 //=================================================================================
394 void LIGHTGUI_DataModel::clearAll()
395 {
396   LIGHTGUI_DataObject* obj = findObject( 0 );
397   if ( obj ) {
398     CAM_Study* study = (CAM_Study*)module()->application()->activeStudy();
399     buildTree( study->root(), QStringList() );
400   }
401 }
402
403 //=================================================================================
404 // function : buildTree()
405 // purpose  : rebuilds data tree
406 //=================================================================================
407 void LIGHTGUI_DataModel::buildTree ( SUIT_DataObject* studyRoot, const QStringList& lines )
408 {
409   if ( !studyRoot )
410     return;
411
412   LIGHTGUI_ModuleObject* modelRoot = new LIGHTGUI_ModuleObject( this, studyRoot );
413   LIGHTGUI_DataObject* aParaObject;
414   LIGHTGUI_DataObject* aLineObject;
415
416   aParaObject = new LIGHTGUI_DataObject ( "", modelRoot );
417
418   QStringList::ConstIterator it1 = lines.begin(),
419                              it2 = lines.end();
420   for ( ; it1 != it2; ++it1 ) {
421     if ( (*it1).stripWhiteSpace().isEmpty() ) {
422       aParaObject = new LIGHTGUI_DataObject ( *it1, modelRoot );
423     }
424     else {
425       aLineObject = new LIGHTGUI_DataObject ( *it1, aParaObject );
426     }
427   }
428
429   modelRoot->setDataModel( this );
430   setRoot( modelRoot );
431 }
432
433 //=================================================================================
434 // function : findObject()
435 // purpose  : finds a data object corresponding to the given line number
436 //=================================================================================
437 LIGHTGUI_DataObject* LIGHTGUI_DataModel::findObject( const int thePosition ) const
438 {
439   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
440     LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
441     if ( obj && obj->lineNb() == thePosition )
442       return obj;
443   }
444   return 0;
445 }