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