1 // Copyright (C) 2005-2008 OPEN CASCADE
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // LIGHT : sample (no-corba-engine) SALOME module
20 // File : LIGHTGUI_DataModel.cxx
21 // Author : Julia DOROVSKIKH
23 #include "LIGHTGUI_DataModel.h"
24 #include "LIGHTGUI_DataObject.h"
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>
34 #include <QTextStream>
35 #include <QStringList>
38 \class LIGHTGUI_DataModel
39 \brief LIGHT module data model.
44 \param module parent module
46 LIGHTGUI_DataModel::LIGHTGUI_DataModel( CAM_Module* module )
47 : LightApp_DataModel( module ),
57 LIGHTGUI_DataModel::~LIGHTGUI_DataModel()
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)
68 bool LIGHTGUI_DataModel::open( const QString& url, CAM_Study* study, QStringList listOfFiles )
70 LightApp_Study* aDoc = dynamic_cast<LightApp_Study*>( study );
74 LightApp_DataModel::open( url, aDoc, listOfFiles );
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] );
81 // This module operates with a single persistent file
82 if ( listOfFiles.size() == 2 ) {
84 QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + listOfFiles[1];
85 loadFile( aFullPath, aDoc );
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)
97 bool LIGHTGUI_DataModel::save( QStringList& theListOfFiles )
99 bool isMultiFile = false; // TODO: decide, how to access this parameter
101 LightApp_DataModel::save( theListOfFiles );
103 LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
105 QString aTmpDir = study->GetTmpDir( myStudyURL.toLatin1(), isMultiFile ).c_str();
107 QString aFileName = SUIT_Tools::file( myStudyURL, false ) + "_LIGHTGUI.txt";
108 QString aFullPath = aTmpDir + aFileName;
109 dumpFile( aFullPath );
111 theListOfFiles.append( aTmpDir );
112 theListOfFiles.append( aFileName );
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)
124 bool LIGHTGUI_DataModel::saveAs( const QString& url, CAM_Study* study, QStringList& theListOfFiles )
127 return save( theListOfFiles );
131 \brief Close data model (remove all relevant data).
132 \return operation status (\c true on success and \c false on error)
134 bool LIGHTGUI_DataModel::close()
136 return LightApp_DataModel::close();
140 \brief Create empty data model.
141 \param study study pointer
142 \return operation status (\c true on success and \c false on error)
144 bool LIGHTGUI_DataModel::create( CAM_Study* study )
150 \brief Get 'modified' flag.
151 \return \c true if data is changed from the last saving
153 bool LIGHTGUI_DataModel::isModified() const
155 // return false to avoid masking study's isModified()
160 \brief Get 'saved' flag.
161 \return \c true if data has been saved
163 bool LIGHTGUI_DataModel::isSaved() const
165 // return true to avoid masking study's isSaved()
170 \brief Update data model.
171 \param obj data object (starting for the update)
172 \param study study pointer
174 void LIGHTGUI_DataModel::update( LightApp_DataObject* /*obj*/, LightApp_Study* /*study*/ )
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
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
187 bool LIGHTGUI_DataModel::loadFile( const QString& filename, CAM_Study* study )
189 if ( filename.isEmpty() ) return false;
191 myFileName = filename;
194 QFile file ( myFileName );
195 if ( file.open( QIODevice::ReadOnly ) ) {
196 QTextStream stream ( &file );
198 while ( !stream.atEnd() ) {
199 line = stream.readLine(); // line of text excluding '\n'
205 study = (CAM_Study*)module()->application()->activeStudy();
206 buildTree( study->root(), lines );
215 \brief Save text data to the file
216 \param filename file path
217 \return \c true if data is loaded successfully
219 bool LIGHTGUI_DataModel::dumpFile( const QString& filename )
221 QString aFileName = filename;
222 if ( aFileName.isEmpty() )
223 aFileName = myFileName;
225 if ( aFileName.isEmpty() ) return false;
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() );
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";
243 myFileName = aFileName;
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)
254 QString LIGHTGUI_DataModel::fileName() const
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)
265 QString LIGHTGUI_DataModel::getLineText( const int id ) const
269 LIGHTGUI_DataObject* obj = findObject( id );
271 aText = obj->lineText();
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
282 bool LIGHTGUI_DataModel::setLineText( const int id, const QString& txt )
284 LIGHTGUI_DataObject* obj = findObject( id );
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();
292 obj->setParent( newParent );
293 while ( SUIT_DataObject* first = obj->firstChild() )
294 first->setParent( newParent );
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 );
309 obj->setLineText( txt );
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
322 bool LIGHTGUI_DataModel::insertLineBefore( const int id, const QString& txt )
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() );
331 LIGHTGUI_DataObject* obj = findObject( id );
332 if ( !obj || !obj->parent() )
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 );
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 );
350 // insert new text line
351 if ( obj->lineText().trimmed().isEmpty() ) {
352 SUIT_DataObject* prevParent = obj->prevBrother();
354 prevParent->appendChild( new LIGHTGUI_DataObject( generateId(), txt, prevParent ) );
357 int pos = parent->childPos( obj );
358 parent->insertChild( new LIGHTGUI_DataObject( generateId(), txt, 0 ), pos );
363 // append new paragraph/line
365 txt.trimmed().isEmpty() ? new LIGHTGUI_DataObject( generateId(), txt, modelRoot ) :
366 new LIGHTGUI_DataObject( generateId(), txt, modelRoot->lastChild() );
369 if ( !txt.trimmed().isEmpty() )
371 buildTree( study->root(), lines );
379 \brief Remove text line.
380 \param id line identifier
381 \return \c true on success or \c false if \a id is invalid
383 bool LIGHTGUI_DataModel::deleteTextLine( const int id )
385 LightApp_ModuleObject* modelRoot = dynamic_cast<LightApp_ModuleObject*>( root() );
390 LIGHTGUI_DataObject* obj = findObject( id );
391 if ( !obj || !obj->parent() )
394 if ( obj->lineText().trimmed().isEmpty() ) {
395 // if paragraph : put all child lines to the previous paragraph
396 SUIT_DataObject* newParent = obj->prevBrother();
398 while ( SUIT_DataObject* first = obj->firstChild() )
399 first->setParent( newParent );
402 obj->parent()->removeChild( obj );
408 \brief Remove all lines.
410 void LIGHTGUI_DataModel::clearAll()
412 CAM_Study* study = (CAM_Study*)module()->application()->activeStudy();
413 buildTree( study->root(), QStringList() );
417 \brief Getnerate unique line identifier.
419 int LIGHTGUI_DataModel::generateId()
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
429 int LIGHTGUI_DataModel::id( const QString& entry )
432 QStringList ids = entry.split( ":", QString::SkipEmptyParts );
433 if ( ids.count() == 2 && ids[0] == "LIGHTGUI" ) {
435 int p = ids[1].toInt( &bOk );
443 \brief Get object entry for the line with sepcified identifier.
445 \return object entry corresponding to the given \a id
447 QString LIGHTGUI_DataModel::entry( const int id )
451 entry = QString( "LIGHTGUI:%1" ).arg( id );
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
460 int LIGHTGUI_DataModel::lineNb( const QString& entry )
462 return lineNb( LIGHTGUI_DataModel::id( entry ) );
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
470 int LIGHTGUI_DataModel::lineNb( const int id )
472 LIGHTGUI_DataObject* obj = findObject( id );
473 return obj ? obj->lineNb() : 0;
477 \brief Get all existing lines identifiers.
478 \return list of lines identifiers
480 QList<int> LIGHTGUI_DataModel::getIds() const
483 for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
484 LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
486 l.append( obj->id() );
492 \brief Rebuild data tree.
493 \param studyRoot study root data object
494 \param lines string data
496 void LIGHTGUI_DataModel::buildTree( SUIT_DataObject* studyRoot, const QStringList& lines )
501 LightApp_ModuleObject* modelRoot = new LightApp_ModuleObject( this, studyRoot );
502 LIGHTGUI_DataObject* aParaObject;
503 LIGHTGUI_DataObject* aLineObject;
505 aParaObject = new LIGHTGUI_DataObject ( generateId(), "", modelRoot );
507 QStringList::ConstIterator it1 = lines.begin(),
509 for ( ; it1 != it2; ++it1 ) {
510 if ( (*it1).trimmed().isEmpty() ) {
511 aParaObject = new LIGHTGUI_DataObject ( generateId(), *it1, modelRoot );
514 aLineObject = new LIGHTGUI_DataObject ( generateId(), *it1, aParaObject );
518 modelRoot->setDataModel( this );
519 setRoot( modelRoot );
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
527 LIGHTGUI_DataObject* LIGHTGUI_DataModel::findObject( const int id ) const
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 )