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