1 // Copyright (C) 2005-2022 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, or (at your option) any later version.
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 // File : LIGHTGUI_DataModel.cxx
20 // Author : Julia DOROVSKIKH
22 #include "LIGHTGUI_DataModel.h"
23 #include "LIGHTGUI_DataObject.h"
25 #include <CAM_Application.h>
26 #include <CAM_Module.h>
27 #include <LightApp_Study.h>
28 #include <SUIT_DataObjectIterator.h>
29 #include <SUIT_Tools.h>
32 #include <QTextStream>
35 \class LIGHTGUI_DataModel
36 \brief LIGHT module data model.
38 This class defines an internal organization of the module's data and the way
39 how these data are presented in the study (e.g. in the Object Browser).
41 In addition, this class includes methods which modify the data tree:
42 load/save text file, insert/remove text line, etc.
47 \param module parent module
49 LIGHTGUI_DataModel::LIGHTGUI_DataModel( CAM_Module* module )
50 : LightApp_DataModel( module ),
60 LIGHTGUI_DataModel::~LIGHTGUI_DataModel()
65 \brief Open data model (read data from the files).
66 \param url study file path
67 \param study study pointer
68 \param listOfFiles list of the (temporary) files with data
69 \return operation status (\c true on success and \c false on error)
71 bool LIGHTGUI_DataModel::open( const QString& url, CAM_Study* study, QStringList listOfFiles )
73 LightApp_Study* aDoc = dynamic_cast<LightApp_Study*>( study );
77 LightApp_DataModel::open( url, aDoc, listOfFiles );
79 // The first list item contains path to a temporary
80 // directory, where the persistent files was placed
81 if ( listOfFiles.count() > 0 ) {
82 QString aTmpDir ( listOfFiles[0] );
84 // This module operates with a single persistent file
85 if ( listOfFiles.size() == 2 ) {
87 QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + listOfFiles[1];
88 loadFile( aFullPath, aDoc );
96 \brief Save data model (write data to the files).
97 \param listOfFiles returning list of the (temporary) files with saved data
98 \return operation status (\c true on success and \c false on error)
100 bool LIGHTGUI_DataModel::save( QStringList& theListOfFiles )
102 bool isMultiFile = false; // TODO: decide, how to access this parameter
104 LightApp_DataModel::save( theListOfFiles );
106 LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
108 QString aTmpDir = study->GetTmpDir( myStudyURL.toLatin1(), isMultiFile ).c_str();
110 QString aFileName = SUIT_Tools::file( myStudyURL, false ) + "_LIGHTGUI.txt";
111 QString aFullPath = aTmpDir + aFileName;
112 dumpFile( aFullPath );
114 theListOfFiles.append( aTmpDir );
115 theListOfFiles.append( aFileName );
121 \brief Save data model (write data to the files).
122 \param url study file path
123 \param study study pointer
124 \param listOfFiles returning list of the (temporary) files with saved data
125 \return operation status (\c true on success and \c false on error)
127 bool LIGHTGUI_DataModel::saveAs( const QString& url, CAM_Study* study, QStringList& theListOfFiles )
130 return save( theListOfFiles );
134 \brief Close data model (remove all relevant data).
135 \return operation status (\c true on success and \c false on error)
137 bool LIGHTGUI_DataModel::close()
139 return LightApp_DataModel::close();
143 \brief Create empty data model.
144 \param study study pointer
145 \return operation status (\c true on success and \c false on error)
147 bool LIGHTGUI_DataModel::create( CAM_Study* study )
153 \brief Get 'modified' flag.
154 \return \c true if data is changed from the last saving
156 bool LIGHTGUI_DataModel::isModified() const
158 // return false to avoid masking study's isModified()
163 \brief Get 'saved' flag.
164 \return \c true if data has been saved
166 bool LIGHTGUI_DataModel::isSaved() const
168 // return true to avoid masking study's isSaved()
173 \brief Update data model.
174 \param obj data object (starting for the update)
175 \param study study pointer
177 void LIGHTGUI_DataModel::update( LightApp_DataObject* /*obj*/, LightApp_Study* /*study*/ )
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
185 \brief Load text data from the file.
186 \param filename file path
187 \param study study pointer
188 \return \c true if data is loaded successfully
190 bool LIGHTGUI_DataModel::loadFile( const QString& filename, CAM_Study* study )
192 if ( filename.isEmpty() ) return false;
194 myFileName = filename;
197 QFile file ( myFileName );
198 if ( file.open( QIODevice::ReadOnly ) ) {
199 QTextStream stream ( &file );
201 while ( !stream.atEnd() ) {
202 line = stream.readLine(); // line of text excluding '\n'
208 study = (CAM_Study*)module()->application()->activeStudy();
209 buildTree( study->root(), lines );
218 \brief Save text data to the file
219 \param filename file path
220 \return \c true if data is loaded successfully
222 bool LIGHTGUI_DataModel::dumpFile( const QString& filename )
224 QString aFileName = filename;
225 if ( aFileName.isEmpty() )
226 aFileName = myFileName;
228 if ( aFileName.isEmpty() ) return false;
231 for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
232 LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
233 if ( obj && obj->lineNb() > 0 )
234 lines.insert( obj->lineNb()-1, obj->lineText() );
237 QFile file ( aFileName );
238 if ( file.open( QIODevice::WriteOnly ) ) {
239 QTextStream stream ( &file );
240 QStringList::Iterator it = lines.begin();
241 for ( ; it != lines.end(); ++it ) {
242 stream << *it << "\n";
246 myFileName = aFileName;
254 \brief Get latest loaded or saved text file's name.
255 \return file name (empty string if file has not been loaded or saved)
257 QString LIGHTGUI_DataModel::fileName() const
263 \brief Get text for the specified line.
264 \param id line identifier
265 \return string text for the line with identifier \a id
266 (empty string is \a id is invalid)
268 QString LIGHTGUI_DataModel::getLineText( const int id ) const
272 LIGHTGUI_DataObject* obj = findObject( id );
274 aText = obj->lineText();
280 \brief Set text for the specified line.
281 \param id line identifier
282 \param txt new string text for the line
283 \return \c true on success or \c false if \a id is invalid
285 bool LIGHTGUI_DataModel::setLineText( const int id, const QString& txt )
287 LIGHTGUI_DataObject* obj = findObject( id );
289 if ( ( txt.trimmed().isEmpty() && !obj->lineText().trimmed().isEmpty() ) ||
290 ( !txt.trimmed().isEmpty() && obj->lineText().trimmed().isEmpty() ) ) {
291 if ( obj->lineText().trimmed().isEmpty() ) {
292 // paragraph becomes a text line
293 SUIT_DataObject* newParent = obj->prevBrother();
295 obj->setParent( newParent );
296 while ( SUIT_DataObject* first = obj->firstChild() )
297 first->setParent( newParent );
301 // text line becomes a paragraph
302 SUIT_DataObject* parent = obj->parent();
303 SUIT_DataObject* modelRoot = parent ? parent->parent() : 0;
304 if ( modelRoot && parent ) {
305 int pos = parent->childPos( obj );
306 modelRoot->insertChild( obj, modelRoot->childPos( parent ) + 1 );
307 while ( SUIT_DataObject* next = parent->childObject( pos ) )
308 obj->appendChild( next );
312 obj->setLineText( txt );
319 \brief Insert new text line.
320 \param id identifier of the line after which new one should be inserted
321 (if <=0, new line is added to the end)
322 \param txt string text
323 \return \c true on success or \c false if \a id is invalid
325 bool LIGHTGUI_DataModel::insertLineBefore( const int id, const QString& txt )
327 // Insert new line before the item at position in the list,
328 // or at the end() if position is out of range
329 LightApp_DataObject* modelRoot = dynamic_cast<LightApp_DataObject*>( root() );
330 LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
334 LIGHTGUI_DataObject* obj = findObject( id );
335 if ( !obj || !obj->parent() )
337 SUIT_DataObject* parent = obj->parent();
338 if ( txt.trimmed().isEmpty() ) {
339 // insert new paragraph
340 if ( obj->lineText().trimmed().isEmpty() ) {
341 int pos = modelRoot->childPos( obj );
342 modelRoot->insertChild( new LIGHTGUI_DataObject( generateId(), txt, 0 ), pos );
345 int pos = parent->childPos( obj );
346 LIGHTGUI_DataObject* newObj = new LIGHTGUI_DataObject( generateId(), txt, 0 );
347 modelRoot->insertChild( newObj, modelRoot->childPos( parent ) + 1 );
348 while ( SUIT_DataObject* next = parent->childObject( pos ) )
349 newObj->appendChild( next );
353 // insert new text line
354 if ( obj->lineText().trimmed().isEmpty() ) {
355 SUIT_DataObject* prevParent = obj->prevBrother();
357 prevParent->appendChild( new LIGHTGUI_DataObject( generateId(), txt, prevParent ) );
360 int pos = parent->childPos( obj );
361 parent->insertChild( new LIGHTGUI_DataObject( generateId(), txt, 0 ), pos );
366 // append new paragraph/line
368 txt.trimmed().isEmpty() ? new LIGHTGUI_DataObject( generateId(), txt, modelRoot ) :
369 new LIGHTGUI_DataObject( generateId(), txt, modelRoot->lastChild() );
372 if ( !txt.trimmed().isEmpty() )
374 buildTree( study->root(), lines );
382 \brief Remove text line.
383 \param id line identifier
384 \return \c true on success or \c false if \a id is invalid
386 bool LIGHTGUI_DataModel::deleteTextLine( const int id )
388 LightApp_DataObject* modelRoot = dynamic_cast<LightApp_DataObject*>( root() );
393 LIGHTGUI_DataObject* obj = findObject( id );
394 if ( !obj || !obj->parent() )
397 if ( obj->lineText().trimmed().isEmpty() ) {
398 // if paragraph : put all child lines to the previous paragraph
399 SUIT_DataObject* newParent = obj->prevBrother();
401 while ( SUIT_DataObject* first = obj->firstChild() )
402 first->setParent( newParent );
405 obj->parent()->removeChild( obj );
411 \brief Remove all lines.
413 void LIGHTGUI_DataModel::clearAll()
415 CAM_Study* study = (CAM_Study*)module()->application()->activeStudy();
416 buildTree( study->root(), QStringList() );
420 \brief Getnerate unique line identifier.
422 int LIGHTGUI_DataModel::generateId()
428 \brief Get line identifier from the object entry.
429 \param entry object entry
430 \return object ID or -1 if \a entry is invalid
432 int LIGHTGUI_DataModel::id( const QString& entry )
435 QStringList ids = entry.split( ":", QString::SkipEmptyParts );
436 if ( ids.count() == 2 && ids[0] == "LIGHTGUI" ) {
438 int p = ids[1].toInt( &bOk );
446 \brief Get object entry for the line with sepcified identifier.
448 \return object entry corresponding to the given \a id
450 QString LIGHTGUI_DataModel::entry( const int id )
454 entry = QString( "LIGHTGUI:%1" ).arg( id );
459 \brief Get line number for the object with the specified entry.
460 \param entry object entry
461 \return line number or 0 if \a entry is invalid
463 int LIGHTGUI_DataModel::lineNb( const QString& entry )
465 return lineNb( LIGHTGUI_DataModel::id( entry ) );
469 \brief Get line number for the specified identifier.
470 \param id line identifier
471 \return line number or 0 if \a id is invalid
473 int LIGHTGUI_DataModel::lineNb( const int id )
475 LIGHTGUI_DataObject* obj = findObject( id );
476 return obj ? obj->lineNb() : 0;
480 \brief Get all existing lines identifiers.
481 \return list of lines identifiers
483 QList<int> LIGHTGUI_DataModel::getIds() const
486 for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
487 LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
489 l.append( obj->id() );
495 \brief Rebuild data tree.
496 \param studyRoot study root data object
497 \param lines string data
499 void LIGHTGUI_DataModel::buildTree( SUIT_DataObject* studyRoot, const QStringList& lines )
504 CAM_ModuleObject* modelRoot = createModuleObject( studyRoot );
505 LIGHTGUI_DataObject* aParaObject;
506 LIGHTGUI_DataObject* aLineObject;
508 aParaObject = new LIGHTGUI_DataObject ( generateId(), "", modelRoot );
510 QStringList::ConstIterator it1 = lines.begin(),
512 for ( ; it1 != it2; ++it1 ) {
513 if ( (*it1).trimmed().isEmpty() ) {
514 aParaObject = new LIGHTGUI_DataObject ( generateId(), *it1, modelRoot );
517 aLineObject = new LIGHTGUI_DataObject ( generateId(), *it1, aParaObject );
521 modelRoot->setDataModel( this );
522 setRoot( modelRoot );
526 \brief Search data object corresponding to the specified line number.
527 \param id line identifier
528 \return data object or 0 if \a id is invalid
530 LIGHTGUI_DataObject* LIGHTGUI_DataModel::findObject( const int id ) const
532 for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
533 LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
534 if ( obj && obj->id() == id )