1 // Copyright (C) 2005-2012 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
20 // LIGHT : sample (no-corba-engine) SALOME module
21 // File : LIGHTGUI_DataModel.cxx
22 // Author : Julia DOROVSKIKH
24 #include "LIGHTGUI_DataModel.h"
25 #include "LIGHTGUI_DataObject.h"
27 #include <LightApp_Study.h>
28 #include <CAM_Module.h>
29 #include <CAM_Application.h>
30 #include <SUIT_Tools.h>
31 #include <SUIT_DataObjectIterator.h>
35 #include <QTextStream>
36 #include <QStringList>
39 \class LIGHTGUI_DataModel
40 \brief LIGHT module data model.
45 \param module parent module
47 LIGHTGUI_DataModel::LIGHTGUI_DataModel( CAM_Module* module )
48 : LightApp_DataModel( module ),
58 LIGHTGUI_DataModel::~LIGHTGUI_DataModel()
63 \brief Open data model (read data from the files).
64 \param url study file path
65 \param study study pointer
66 \param listOfFiles list of the (temporary) files with data
67 \return operation status (\c true on success and \c false on error)
69 bool LIGHTGUI_DataModel::open( const QString& url, CAM_Study* study, QStringList listOfFiles )
71 LightApp_Study* aDoc = dynamic_cast<LightApp_Study*>( study );
75 LightApp_DataModel::open( url, aDoc, listOfFiles );
77 // The first list item contains path to a temporary
78 // directory, where the persistent files was placed
79 if ( listOfFiles.count() > 0 ) {
80 QString aTmpDir ( listOfFiles[0] );
82 // This module operates with a single persistent file
83 if ( listOfFiles.size() == 2 ) {
85 QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + listOfFiles[1];
86 loadFile( aFullPath, aDoc );
94 \brief Save data model (write data to the files).
95 \param listOfFiles returning list of the (temporary) files with saved data
96 \return operation status (\c true on success and \c false on error)
98 bool LIGHTGUI_DataModel::save( QStringList& theListOfFiles )
100 bool isMultiFile = false; // TODO: decide, how to access this parameter
102 LightApp_DataModel::save( theListOfFiles );
104 LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
106 QString aTmpDir = study->GetTmpDir( myStudyURL.toLatin1(), isMultiFile ).c_str();
108 QString aFileName = SUIT_Tools::file( myStudyURL, false ) + "_LIGHTGUI.txt";
109 QString aFullPath = aTmpDir + aFileName;
110 dumpFile( aFullPath );
112 theListOfFiles.append( aTmpDir );
113 theListOfFiles.append( aFileName );
119 \brief Save data model (write data to the files).
120 \param url study file path
121 \param study study pointer
122 \param listOfFiles returning list of the (temporary) files with saved data
123 \return operation status (\c true on success and \c false on error)
125 bool LIGHTGUI_DataModel::saveAs( const QString& url, CAM_Study* study, QStringList& theListOfFiles )
128 return save( theListOfFiles );
132 \brief Close data model (remove all relevant data).
133 \return operation status (\c true on success and \c false on error)
135 bool LIGHTGUI_DataModel::close()
137 return LightApp_DataModel::close();
141 \brief Create empty data model.
142 \param study study pointer
143 \return operation status (\c true on success and \c false on error)
145 bool LIGHTGUI_DataModel::create( CAM_Study* study )
151 \brief Get 'modified' flag.
152 \return \c true if data is changed from the last saving
154 bool LIGHTGUI_DataModel::isModified() const
156 // return false to avoid masking study's isModified()
161 \brief Get 'saved' flag.
162 \return \c true if data has been saved
164 bool LIGHTGUI_DataModel::isSaved() const
166 // return true to avoid masking study's isSaved()
171 \brief Update data model.
172 \param obj data object (starting for the update)
173 \param study study pointer
175 void LIGHTGUI_DataModel::update( LightApp_DataObject* /*obj*/, LightApp_Study* /*study*/ )
177 // Nothing to do here: we always keep the data tree in the up-to-date state
178 // The only goal of this method is to hide default behavior from LightApp_DataModel
183 \brief Load text data from the file.
184 \param filename file path
185 \param study study pointer
186 \return \c true if data is loaded successfully
188 bool LIGHTGUI_DataModel::loadFile( const QString& filename, CAM_Study* study )
190 if ( filename.isEmpty() ) return false;
192 myFileName = filename;
195 QFile file ( myFileName );
196 if ( file.open( QIODevice::ReadOnly ) ) {
197 QTextStream stream ( &file );
199 while ( !stream.atEnd() ) {
200 line = stream.readLine(); // line of text excluding '\n'
206 study = (CAM_Study*)module()->application()->activeStudy();
207 buildTree( study->root(), lines );
216 \brief Save text data to the file
217 \param filename file path
218 \return \c true if data is loaded successfully
220 bool LIGHTGUI_DataModel::dumpFile( const QString& filename )
222 QString aFileName = filename;
223 if ( aFileName.isEmpty() )
224 aFileName = myFileName;
226 if ( aFileName.isEmpty() ) return false;
229 for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
230 LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
231 if ( obj && obj->lineNb() > 0 )
232 lines.insert( obj->lineNb()-1, obj->lineText() );
235 QFile file ( aFileName );
236 if ( file.open( QIODevice::WriteOnly ) ) {
237 QTextStream stream ( &file );
238 QStringList::Iterator it = lines.begin();
239 for ( ; it != lines.end(); ++it ) {
240 stream << *it << "\n";
244 myFileName = aFileName;
252 \brief Get latest loaded or saved text file's name.
253 \return file name (empty string if file has not been loaded or saved)
255 QString LIGHTGUI_DataModel::fileName() const
261 \brief Get text for the specified line.
262 \param id line identifier
263 \return string text for the line with identifier \a id
264 (empty string is \a id is invalid)
266 QString LIGHTGUI_DataModel::getLineText( const int id ) const
270 LIGHTGUI_DataObject* obj = findObject( id );
272 aText = obj->lineText();
278 \brief Set text for the specified line.
279 \param id line identifier
280 \param txt new string text for the line
281 \return \c true on success or \c false if \a id is invalid
283 bool LIGHTGUI_DataModel::setLineText( const int id, const QString& txt )
285 LIGHTGUI_DataObject* obj = findObject( id );
287 if ( txt.trimmed().isEmpty() && !obj->lineText().trimmed().isEmpty() ||
288 !txt.trimmed().isEmpty() && obj->lineText().trimmed().isEmpty() ) {
289 if ( obj->lineText().trimmed().isEmpty() ) {
290 // paragraph becomes a text line
291 SUIT_DataObject* newParent = obj->prevBrother();
293 obj->setParent( newParent );
294 while ( SUIT_DataObject* first = obj->firstChild() )
295 first->setParent( newParent );
299 // text line becomes a paragraph
300 SUIT_DataObject* parent = obj->parent();
301 SUIT_DataObject* modelRoot = parent ? parent->parent() : 0;
302 if ( modelRoot && parent ) {
303 int pos = parent->childPos( obj );
304 modelRoot->insertChild( obj, modelRoot->childPos( parent ) + 1 );
305 while ( SUIT_DataObject* next = parent->childObject( pos ) )
306 obj->appendChild( next );
310 obj->setLineText( txt );
317 \brief Insert new text line.
318 \param id identifier of the line after which new one should be inserted
319 (if <=0, new line is added to the end)
320 \param txt string text
321 \return \c true on success or \c false if \a id is invalid
323 bool LIGHTGUI_DataModel::insertLineBefore( const int id, const QString& txt )
325 // Insert new line before the item at position in the list,
326 // or at the end() if position is out of range
327 LightApp_DataObject* modelRoot = dynamic_cast<LightApp_DataObject*>( root() );
328 LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
332 LIGHTGUI_DataObject* obj = findObject( id );
333 if ( !obj || !obj->parent() )
335 SUIT_DataObject* parent = obj->parent();
336 if ( txt.trimmed().isEmpty() ) {
337 // insert new paragraph
338 if ( obj->lineText().trimmed().isEmpty() ) {
339 int pos = modelRoot->childPos( obj );
340 modelRoot->insertChild( new LIGHTGUI_DataObject( generateId(), txt, 0 ), pos );
343 int pos = parent->childPos( obj );
344 LIGHTGUI_DataObject* newObj = new LIGHTGUI_DataObject( generateId(), txt, 0 );
345 modelRoot->insertChild( newObj, modelRoot->childPos( parent ) + 1 );
346 while ( SUIT_DataObject* next = parent->childObject( pos ) )
347 newObj->appendChild( next );
351 // insert new text line
352 if ( obj->lineText().trimmed().isEmpty() ) {
353 SUIT_DataObject* prevParent = obj->prevBrother();
355 prevParent->appendChild( new LIGHTGUI_DataObject( generateId(), txt, prevParent ) );
358 int pos = parent->childPos( obj );
359 parent->insertChild( new LIGHTGUI_DataObject( generateId(), txt, 0 ), pos );
364 // append new paragraph/line
366 txt.trimmed().isEmpty() ? new LIGHTGUI_DataObject( generateId(), txt, modelRoot ) :
367 new LIGHTGUI_DataObject( generateId(), txt, modelRoot->lastChild() );
370 if ( !txt.trimmed().isEmpty() )
372 buildTree( study->root(), lines );
380 \brief Remove text line.
381 \param id line identifier
382 \return \c true on success or \c false if \a id is invalid
384 bool LIGHTGUI_DataModel::deleteTextLine( const int id )
386 LightApp_DataObject* modelRoot = dynamic_cast<LightApp_DataObject*>( root() );
391 LIGHTGUI_DataObject* obj = findObject( id );
392 if ( !obj || !obj->parent() )
395 if ( obj->lineText().trimmed().isEmpty() ) {
396 // if paragraph : put all child lines to the previous paragraph
397 SUIT_DataObject* newParent = obj->prevBrother();
399 while ( SUIT_DataObject* first = obj->firstChild() )
400 first->setParent( newParent );
403 obj->parent()->removeChild( obj );
409 \brief Remove all lines.
411 void LIGHTGUI_DataModel::clearAll()
413 CAM_Study* study = (CAM_Study*)module()->application()->activeStudy();
414 buildTree( study->root(), QStringList() );
418 \brief Getnerate unique line identifier.
420 int LIGHTGUI_DataModel::generateId()
426 \brief Get line identifier from the object entry.
427 \param entry object entry
428 \return object ID or -1 if \a entry is invalid
430 int LIGHTGUI_DataModel::id( const QString& entry )
433 QStringList ids = entry.split( ":", QString::SkipEmptyParts );
434 if ( ids.count() == 2 && ids[0] == "LIGHTGUI" ) {
436 int p = ids[1].toInt( &bOk );
444 \brief Get object entry for the line with sepcified identifier.
446 \return object entry corresponding to the given \a id
448 QString LIGHTGUI_DataModel::entry( const int id )
452 entry = QString( "LIGHTGUI:%1" ).arg( id );
457 \brief Get line number for the object with the specified entry.
458 \param entry object entry
459 \return line number or 0 if \a entry is invalid
461 int LIGHTGUI_DataModel::lineNb( const QString& entry )
463 return lineNb( LIGHTGUI_DataModel::id( entry ) );
467 \brief Get line number for the specified identifier.
468 \param id line identifier
469 \return line number or 0 if \a id is invalid
471 int LIGHTGUI_DataModel::lineNb( const int id )
473 LIGHTGUI_DataObject* obj = findObject( id );
474 return obj ? obj->lineNb() : 0;
478 \brief Get all existing lines identifiers.
479 \return list of lines identifiers
481 QList<int> LIGHTGUI_DataModel::getIds() const
484 for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
485 LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
487 l.append( obj->id() );
493 \brief Rebuild data tree.
494 \param studyRoot study root data object
495 \param lines string data
497 void LIGHTGUI_DataModel::buildTree( SUIT_DataObject* studyRoot, const QStringList& lines )
502 CAM_ModuleObject* modelRoot = createModuleObject( studyRoot );
503 LIGHTGUI_DataObject* aParaObject;
504 LIGHTGUI_DataObject* aLineObject;
506 aParaObject = new LIGHTGUI_DataObject ( generateId(), "", modelRoot );
508 QStringList::ConstIterator it1 = lines.begin(),
510 for ( ; it1 != it2; ++it1 ) {
511 if ( (*it1).trimmed().isEmpty() ) {
512 aParaObject = new LIGHTGUI_DataObject ( generateId(), *it1, modelRoot );
515 aLineObject = new LIGHTGUI_DataObject ( generateId(), *it1, aParaObject );
519 modelRoot->setDataModel( this );
520 setRoot( modelRoot );
524 \brief Search data object corresponding to the specified line number.
525 \param id line identifier
526 \return data object or 0 if \a id is invalid
528 LIGHTGUI_DataObject* LIGHTGUI_DataModel::findObject( const int id ) const
530 for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
531 LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
532 if ( obj && obj->id() == id )