Salome HOME
Update copyrights 2014.
[samples/light.git] / src / LIGHTGUI / LIGHTGUI_DataModel.cxx
index 675fcbe80b77d13f65237e49030c483a465c9389..3eb608332fd8e55fe559f2399ef36a7492b23b85 100644 (file)
-//  LIGHT : sample (no-corba-engine) SALOME module
+// Copyright (C) 2005-2014  OPEN CASCADE
 //
-//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
 //
-//  This library is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU Lesser General Public
-//  License as published by the Free Software Foundation; either
-//  version 2.1 of the License.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
 //
-//  This library is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-//  Lesser General Public License for more details.
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-//  You should have received a copy of the GNU Lesser General Public
-//  License along with this library; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
-//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
-//
-//  Author : Julia DOROVSKIKH
-//  Date   : 01/01/2005
-//  $Header$
 
+// LIGHT : sample (no-corba-engine) SALOME module
+// File   : LIGHTGUI_DataModel.cxx
+// Author : Julia DOROVSKIKH
+//
 #include "LIGHTGUI_DataModel.h"
 #include "LIGHTGUI_DataObject.h"
 
-#include <SalomeApp_Study.h>
+#include <LightApp_Study.h>
+#include <CAM_Module.h>
+#include <CAM_Application.h>
 #include <SUIT_Tools.h>
 #include <SUIT_DataObjectIterator.h>
 
-#include <qstring.h>
-#include <qfile.h>
-
-//=================================================================================
-// function : LIGHTGUI_DataModel()
-// purpose  : constructor
-//=================================================================================
-LIGHTGUI_DataModel::LIGHTGUI_DataModel ( CAM_Module* theModule )
-     : SalomeApp_DataModel( theModule ),
-       myFileName( "" ),
-       myStudyURL( "" )
+#include <QString>
+#include <QFile>
+#include <QTextStream>
+#include <QStringList>
+
+/*!
+  \class LIGHTGUI_DataModel
+  \brief LIGHT module data model.
+*/
+
+/*!
+  \brief Constructor
+  \param module parent module
+*/
+LIGHTGUI_DataModel::LIGHTGUI_DataModel( CAM_Module* module )
+: LightApp_DataModel( module ),
+  myFileName( "" ),
+  myStudyURL( "" ),
+  myMaxId( 0 )
 {
 }
 
-//=================================================================================
-// function : ~LIGHTGUI_DataModel()
-// purpose  : destructor
-//=================================================================================
+/*!
+  \brief Destructor.
+*/
 LIGHTGUI_DataModel::~LIGHTGUI_DataModel()
 {
 }
 
-//=================================================================================
-// function : open()
-// purpose  : Open data model operation
-//=================================================================================
-bool LIGHTGUI_DataModel::open ( const QString& theURL, CAM_Study* study )
+/*!
+  \brief Open data model (read data from the files).
+  \param url study file path
+  \param study study pointer
+  \param listOfFiles list of the (temporary) files with data
+  \return operation status (\c true on success and \c false on error)
+*/
+bool LIGHTGUI_DataModel::open( const QString& url, CAM_Study* study, QStringList listOfFiles )
 {
-  SalomeApp_Study* aDoc = dynamic_cast<SalomeApp_Study*>( study );
+  LightApp_Study* aDoc = dynamic_cast<LightApp_Study*>( study );
   if ( !aDoc )
     return false;
 
-  SalomeApp_DataModel::open( theURL, study );
-
-  // Get list of files, created for this module by SalomeApp_Engine_i::Load().
-  std::vector<std::string> aListOfFiles = GetListOfFiles();
+  LightApp_DataModel::open( url, aDoc, listOfFiles );
 
   // The first list item contains path to a temporary
   // directory, where the persistent files was placed
-  if ( aListOfFiles.size() > 0 ) {
-    QString aTmpDir ( aListOfFiles[0] );
+  if ( listOfFiles.count() > 0 ) {
+    QString aTmpDir ( listOfFiles[0] );
 
     // This module operates with a single persistent file
-    if ( aListOfFiles.size() == 2 ) {
-      myStudyURL = theURL;
-      QString aFileName ( aListOfFiles[1] );
-      QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + aFileName;
-
-      loadFile( aFullPath, study );
+    if ( listOfFiles.size() == 2 ) {
+      myStudyURL = url;
+      QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + listOfFiles[1];
+      loadFile( aFullPath, aDoc );
     }
-
-    // Remove the files and temporary directory, created
-    // for this module by SalomeApp_Engine_i::Load()
-    bool isMultiFile = false; // TODO: decide, how to access this parameter
-    RemoveTemporaryFiles( isMultiFile );
   }
 
   return true;
 }
 
-//=================================================================================
-// function : save()
-// purpose  : Save data model operation
-//=================================================================================
-bool LIGHTGUI_DataModel::save()
+/*!
+  \brief Save data model (write data to the files).
+  \param listOfFiles returning list of the (temporary) files with saved data
+  \return operation status (\c true on success and \c false on error)
+*/
+bool LIGHTGUI_DataModel::save( QStringList& theListOfFiles )
 {
-  // 1. Save data to temporary files
   bool isMultiFile = false; // TODO: decide, how to access this parameter
 
-  QString aTmpDir ( SalomeApp_DataModel::GetTmpDir( myStudyURL.latin1(), isMultiFile ) );
+  LightApp_DataModel::save( theListOfFiles );
+
+  LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
+
+  QString aTmpDir = study->GetTmpDir( myStudyURL.toLatin1(), isMultiFile ).c_str();
+
   QString aFileName = SUIT_Tools::file( myStudyURL, false ) + "_LIGHTGUI.txt";
   QString aFullPath = aTmpDir + aFileName;
   dumpFile( aFullPath );
 
-  // 2. Set list of temporary files to Engine
-  std::vector<std::string> aListOfFiles ( 2 );
-  aListOfFiles[0] = aTmpDir.latin1();
-  aListOfFiles[1] = aFileName.latin1();
-  SetListOfFiles( aListOfFiles );
+  theListOfFiles.append( aTmpDir );
+  theListOfFiles.append( aFileName );
 
   return true;
 }
 
-//=================================================================================
-// function : saveAs()
-// purpose  : SaveAs data model operation
-//=================================================================================
-bool LIGHTGUI_DataModel::saveAs ( const QString& theURL, CAM_Study* )
+/*!
+  \brief Save data model (write data to the files).
+  \param url study file path
+  \param study study pointer
+  \param listOfFiles returning list of the (temporary) files with saved data
+  \return operation status (\c true on success and \c false on error)
+*/
+bool LIGHTGUI_DataModel::saveAs( const QString& url, CAM_Study* study, QStringList& theListOfFiles )
 {
-  myStudyURL = theURL;
-  return save();
+  myStudyURL = url;
+  return save( theListOfFiles );
 }
 
-//=================================================================================
-// function : close()
-// purpose  : Close data model operation
-//=================================================================================
+/*!
+  \brief Close data model (remove all relevant data).
+  \return operation status (\c true on success and \c false on error)
+*/
 bool LIGHTGUI_DataModel::close()
 {
-  return true;
+  return LightApp_DataModel::close();
 }
 
-//=================================================================================
-// function : create()
-// purpose  : Create data model operation
-//=================================================================================
+/*!
+  \brief Create empty data model.
+  \param study study pointer
+  \return operation status (\c true on success and \c false on error)
+*/
 bool LIGHTGUI_DataModel::create( CAM_Study* study )
 {
-  buildTree( study->root(), QStringList() );
   return true;
 }
 
-//=================================================================================
-// function : isModified()
-// purpose  : default implementation, always returns false so as not to mask study's isModified()
-//=================================================================================
+/*!
+  \brief Get 'modified' flag.
+  \return \c true if data is changed from the last saving
+*/
 bool LIGHTGUI_DataModel::isModified() const
 {
+  // return false to avoid masking study's isModified()
   return false;
 }
 
-//=================================================================================
-// function : isSaved()
-// purpose  : default implementation, always returns true so as not to mask study's isSaved()
-//=================================================================================
+/*!
+  \brief Get 'saved' flag.
+  \return \c true if data has been saved
+*/
 bool LIGHTGUI_DataModel::isSaved() const
 {
+  // return true to avoid masking study's isSaved()
   return true;
 }
 
-//=================================================================================
-// function : update()
-// purpose  : updates data model
-//=================================================================================
-void LIGHTGUI_DataModel::update ( SalomeApp_DataObject*, SalomeApp_Study* )
+/*!
+  \brief Update data model.
+  \param obj data object (starting for the update)
+  \param study study pointer
+*/
+void LIGHTGUI_DataModel::update( LightApp_DataObject* /*obj*/, LightApp_Study* /*study*/ )
 {
   // Nothing to do here: we always keep the data tree in the up-to-date state
-  // The only goal of this method is to hide default behavior from SalomApp_DataModel
+  // The only goal of this method is to hide default behavior from LightApp_DataModel
   return;
 }
 
-//=================================================================================
-// function : loadFile()
-// purpose  : loads text data from the file
-//=================================================================================
-bool LIGHTGUI_DataModel::loadFile ( const QString& theFileName, CAM_Study* study )
+/*
+  \brief Load text data from the file.
+  \param filename file path
+  \param study study pointer
+  \return \c true if data is loaded successfully
+*/  
+bool LIGHTGUI_DataModel::loadFile( const QString& filename, CAM_Study* study )
 {
-  if ( theFileName.isEmpty() ) return false;
+  if ( filename.isEmpty() ) return false;
 
-  myFileName = theFileName;
+  myFileName = filename;
   
   QStringList lines;
   QFile file ( myFileName );
-  if ( file.open( IO_ReadOnly ) ) {
+  if ( file.open( QIODevice::ReadOnly ) ) {
     QTextStream stream ( &file );
     QString line;
-    while ( !stream.eof() ) {
+    while ( !stream.atEnd() ) {
       line = stream.readLine(); // line of text excluding '\n'
       lines += line;
     }
     file.close();
 
     if  ( !study )
-      study = getStudy();
+      study = (CAM_Study*)module()->application()->activeStudy();
     buildTree( study->root(), lines );
 
     return true;
@@ -202,13 +212,14 @@ bool LIGHTGUI_DataModel::loadFile ( const QString& theFileName, CAM_Study* study
   return false;
 }
 
-//=================================================================================
-// function : dumpFile()
-// purpose  : saves text data to the file
-//=================================================================================
-bool LIGHTGUI_DataModel::dumpFile ( const QString& theFileName )
+/*!
+  \brief Save text data to the file
+  \param filename file path
+  \return \c true if data is loaded successfully
+*/
+bool LIGHTGUI_DataModel::dumpFile( const QString& filename )
 {
-  QString aFileName = theFileName;
+  QString aFileName = filename;
   if ( aFileName.isEmpty() )
     aFileName = myFileName;
 
@@ -218,11 +229,11 @@ bool LIGHTGUI_DataModel::dumpFile ( const QString& theFileName )
   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
     LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
     if ( obj && obj->lineNb() > 0 )
-      lines.insert( lines.at( obj->lineNb()-1 ), obj->lineText() );
+      lines.insert( obj->lineNb()-1, obj->lineText() );
   }
 
   QFile file ( aFileName );
-  if ( file.open( IO_WriteOnly ) ) {
+  if ( file.open( QIODevice::WriteOnly ) ) {
     QTextStream stream ( &file );
     QStringList::Iterator it = lines.begin();
     for ( ; it != lines.end(); ++it ) {
@@ -237,42 +248,45 @@ bool LIGHTGUI_DataModel::dumpFile ( const QString& theFileName )
   return false;
 }
 
-//=================================================================================
-// function : fileName()
-// purpose  : gets a name of text file previously loaded or saved
-//=================================================================================
-QString LIGHTGUI_DataModel::fileName () const
+/*!
+  \brief Get latest loaded or saved text file's name.
+  \return file name (empty string if file has not been loaded or saved)
+*/
+QString LIGHTGUI_DataModel::fileName() const
 {
   return myFileName;
 }
 
-//=================================================================================
-// function : getLineText()
-// purpose  : gets text from the given line
-//=================================================================================
-QString LIGHTGUI_DataModel::getLineText ( const int thePosition ) const
+/*!
+  \brief Get text for the specified line.
+  \param id line identifier
+  \return string text for the line with identifier \a id
+          (empty string is \a id is invalid)
+*/
+QString LIGHTGUI_DataModel::getLineText( const int id ) const
 {
   QString aText;
 
-  LIGHTGUI_DataObject* obj = findObject( thePosition );
+  LIGHTGUI_DataObject* obj = findObject( id );
   if ( obj )
     aText = obj->lineText();
 
   return aText;
 }
 
-//=================================================================================
-// function : setLineText()
-// purpose  : sets new text to the given line
-//=================================================================================
-bool LIGHTGUI_DataModel::setLineText ( const int thePosition, const QString& theText )
+/*!
+  \brief Set text for the specified line.
+  \param id line identifier
+  \param txt new string text for the line
+  \return \c true on success or \c false if \a id is invalid
+*/
+bool LIGHTGUI_DataModel::setLineText( const int id, const QString& txt )
 {
-  if ( thePosition <= 0 ) return false;
-  LIGHTGUI_DataObject* obj = findObject( thePosition );
+  LIGHTGUI_DataObject* obj = findObject( id );
   if ( obj ) {
-    if ( theText.stripWhiteSpace().isEmpty() && !obj->lineText().stripWhiteSpace().isEmpty() ||
-       !theText.stripWhiteSpace().isEmpty() &&  obj->lineText().stripWhiteSpace().isEmpty() ) {
-      if ( obj->lineText().stripWhiteSpace().isEmpty() ) {
+    if ( txt.trimmed().isEmpty() && !obj->lineText().trimmed().isEmpty() ||
+       !txt.trimmed().isEmpty() &&  obj->lineText().trimmed().isEmpty() ) {
+      if ( obj->lineText().trimmed().isEmpty() ) {
        // paragraph becomes a text line
        SUIT_DataObject* newParent = obj->prevBrother();
        if ( newParent ) {
@@ -287,85 +301,98 @@ bool LIGHTGUI_DataModel::setLineText ( const int thePosition, const QString& the
        SUIT_DataObject* modelRoot = parent ? parent->parent() : 0;
        if ( modelRoot && parent ) {
          int pos = parent->childPos( obj );
-         modelRoot->insertChild( obj, modelRoot->childPos( parent )+1 );
+         modelRoot->insertChild( obj, modelRoot->childPos( parent ) + 1 );
          while ( SUIT_DataObject* next = parent->childObject( pos ) )
            obj->appendChild( next );
        }
       }
     }
-    obj->setLineText( theText );
+    obj->setLineText( txt );
     return true;
   }
   return false;
 }
 
-//=================================================================================
-// function : insertLineBefore()
-// purpose  : inserts the text line before the given one or appends a new line
-//=================================================================================
-bool LIGHTGUI_DataModel::insertLineBefore ( const int thePosition, const QString& theText )
+/*!
+  \brief Insert new text line.
+  \param id identifier of the line after which new one should be inserted
+         (if <=0, new line is added to the end)
+  \param txt string text
+  \return \c true on success or \c false if \a id is invalid
+*/
+bool LIGHTGUI_DataModel::insertLineBefore( const int id, const QString& txt )
 {
-  // Insert new line before the item at thePosition in the list,
-  // or at the end() if thePosition is out of range
-  LIGHTGUI_ModuleObject* modelRoot = dynamic_cast<LIGHTGUI_ModuleObject*>( root() );
-  if ( !modelRoot )
-    return false;
-  if ( thePosition > 0 ) {
-    LIGHTGUI_DataObject* obj = findObject( thePosition );
+  // Insert new line before the item at position in the list,
+  // or at the end() if position is out of range
+  LightApp_DataObject* modelRoot = dynamic_cast<LightApp_DataObject*>( root() );
+  LightApp_Study* study = dynamic_cast<LightApp_Study*>( module()->application()->activeStudy() );
+  if ( id > 0 ) {
+    if ( !modelRoot )
+      return false;
+    LIGHTGUI_DataObject* obj = findObject( id );
     if ( !obj || !obj->parent() )
       return false;
     SUIT_DataObject* parent = obj->parent();
-    if ( theText.stripWhiteSpace().isEmpty() ) {
+    if ( txt.trimmed().isEmpty() ) {
       // insert new paragraph
-      if ( obj->lineText().stripWhiteSpace().isEmpty() ) {
+      if ( obj->lineText().trimmed().isEmpty() ) {
         int pos = modelRoot->childPos( obj );
-       modelRoot->insertChild( new LIGHTGUI_DataObject( theText, 0 ), pos );
+       modelRoot->insertChild( new LIGHTGUI_DataObject( generateId(), txt, 0 ), pos );
       }
       else {
        int pos = parent->childPos( obj );
-       LIGHTGUI_DataObject* newObj = new LIGHTGUI_DataObject( theText, 0 );
-       modelRoot->insertChild( newObj, modelRoot->childPos( parent )+1 );
+       LIGHTGUI_DataObject* newObj = new LIGHTGUI_DataObject( generateId(), txt, 0 );
+       modelRoot->insertChild( newObj, modelRoot->childPos( parent ) + 1 );
        while ( SUIT_DataObject* next = parent->childObject( pos ) )
          newObj->appendChild( next );
       }
     }
     else {
       // insert new text line
-      if ( obj->lineText().stripWhiteSpace().isEmpty() ) {
+      if ( obj->lineText().trimmed().isEmpty() ) {
        SUIT_DataObject* prevParent = obj->prevBrother();
        if ( prevParent )
-         prevParent->appendChild( new LIGHTGUI_DataObject( theText, prevParent ) );
+         prevParent->appendChild( new LIGHTGUI_DataObject( generateId(), txt, prevParent ) );
       }
       else {
         int pos = parent->childPos( obj );
-       parent->insertChild( new LIGHTGUI_DataObject( theText, 0 ), pos );
+       parent->insertChild( new LIGHTGUI_DataObject( generateId(), txt, 0 ), pos );
       }
     }
   }
   else {
     // append new paragraph/line
-    theText.stripWhiteSpace().isEmpty() ? new LIGHTGUI_DataObject( theText, modelRoot ) : 
-                                          new LIGHTGUI_DataObject( theText, modelRoot->lastChild() );
+    if ( modelRoot )
+      txt.trimmed().isEmpty() ? new LIGHTGUI_DataObject( generateId(), txt, modelRoot ) : 
+                               new LIGHTGUI_DataObject( generateId(), txt, modelRoot->lastChild() );
+    else {
+      QStringList lines;
+      if ( !txt.trimmed().isEmpty() ) 
+       lines.append( txt );
+      buildTree( study->root(), lines );
+    }
+      
   }
   return true;
 }
 
-//=================================================================================
-// function : deleteTextLine()
-// purpose  : remove text line at the given position
-//=================================================================================
-bool LIGHTGUI_DataModel::deleteTextLine( const int thePosition )
+/*!
+  \brief Remove text line.
+  \param id line identifier
+  \return \c true on success or \c false if \a id is invalid
+*/
+bool LIGHTGUI_DataModel::deleteTextLine( const int id )
 {
-  LIGHTGUI_ModuleObject* modelRoot = dynamic_cast<LIGHTGUI_ModuleObject*>( root() );
+  LightApp_DataObject* modelRoot = dynamic_cast<LightApp_DataObject*>( root() );
+
   if ( !modelRoot )
     return false;
-  if ( thePosition <= 0 )
-    return false;
-  LIGHTGUI_DataObject* obj = findObject( thePosition );
+
+  LIGHTGUI_DataObject* obj = findObject( id );
   if ( !obj || !obj->parent() )
     return false;
   
-  if ( obj->lineText().stripWhiteSpace().isEmpty() ) {
+  if ( obj->lineText().trimmed().isEmpty() ) {
     // if paragraph : put all child lines to the previous paragraph
     SUIT_DataObject* newParent = obj->prevBrother();
     if ( newParent ) {
@@ -374,40 +401,118 @@ bool LIGHTGUI_DataModel::deleteTextLine( const int thePosition )
     }
   }
   obj->parent()->removeChild( obj );
+
   return true;
 }
 
-//=================================================================================
-// function : clearAll()
-// purpose  : removes all text lines
-//=================================================================================
+/*!
+  \brief Remove all lines.
+*/
 void LIGHTGUI_DataModel::clearAll()
 {
-  buildTree( getStudy()->root(), QStringList() );
+  CAM_Study* study = (CAM_Study*)module()->application()->activeStudy();
+  buildTree( study->root(), QStringList() );
+}
+
+/*!
+  \brief Getnerate unique line identifier.
+*/
+int LIGHTGUI_DataModel::generateId()
+{
+  return ++myMaxId;
 }
 
-//=================================================================================
-// function : buildTree()
-// purpose  : rebuilds data tree
-//=================================================================================
-void LIGHTGUI_DataModel::buildTree ( SUIT_DataObject* studyRoot, const QStringList& lines )
+/*!
+  \brief Get line identifier from the object entry.
+  \param entry object entry
+  \return object ID or -1 if \a entry is invalid
+*/
+int LIGHTGUI_DataModel::id( const QString& entry )
+{
+  int id = -1;
+  QStringList ids = entry.split( ":", QString::SkipEmptyParts );
+  if ( ids.count() == 2 && ids[0] == "LIGHTGUI" ) {
+    bool bOk;
+    int p = ids[1].toInt( &bOk );
+    if ( bOk ) 
+      id = p;
+  }
+  return id;
+}
+
+/*!
+  \brief Get object entry for the line with sepcified identifier.
+  \param id object ID
+  \return object entry corresponding to the given \a id
+*/
+QString LIGHTGUI_DataModel::entry( const int id )
+{
+  QString entry;
+  if ( id > 0 )
+    entry = QString( "LIGHTGUI:%1" ).arg( id );
+  return entry;
+}
+
+/*!
+  \brief Get line number for the object with the specified entry.
+  \param entry object entry
+  \return line number or 0 if \a entry is invalid
+*/
+int LIGHTGUI_DataModel::lineNb( const QString& entry )
+{
+  return lineNb( LIGHTGUI_DataModel::id( entry ) );
+}
+
+/*!
+  \brief Get line number for the specified identifier.
+  \param id line identifier
+  \return line number or 0 if \a id is invalid
+*/
+int LIGHTGUI_DataModel::lineNb( const int id )
+{
+  LIGHTGUI_DataObject* obj = findObject( id );
+  return obj ? obj->lineNb() : 0;
+}
+
+/*!
+  \brief Get all existing lines identifiers.
+  \return list of lines identifiers
+*/
+QList<int> LIGHTGUI_DataModel::getIds() const
+{
+  QList<int> l;
+  for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
+    LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
+    if ( obj )
+      l.append( obj->id() );
+  }
+  return l;
+}
+
+/*!
+  \brief Rebuild data tree.
+  \param studyRoot study root data object
+  \param lines string data
+*/
+void LIGHTGUI_DataModel::buildTree( SUIT_DataObject* studyRoot, const QStringList& lines )
 {
   if ( !studyRoot )
     return;
-  
-  LIGHTGUI_ModuleObject* modelRoot = new LIGHTGUI_ModuleObject( this, studyRoot );
-  CAM_DataObject* aParaObject, aLineObject;
 
-  aParaObject = new LIGHTGUI_DataObject ( "", modelRoot );
+  CAM_ModuleObject* modelRoot = createModuleObject( studyRoot );
+  LIGHTGUI_DataObject* aParaObject;
+  LIGHTGUI_DataObject* aLineObject;
+
+  aParaObject = new LIGHTGUI_DataObject ( generateId(), "", modelRoot );
 
   QStringList::ConstIterator it1 = lines.begin(),
                              it2 = lines.end();
   for ( ; it1 != it2; ++it1 ) {
-    if ( (*it1).stripWhiteSpace().isEmpty() ) {
-      aParaObject = new LIGHTGUI_DataObject ( *it1, modelRoot );
-    } 
+    if ( (*it1).trimmed().isEmpty() ) {
+      aParaObject = new LIGHTGUI_DataObject ( generateId(), *it1, modelRoot );
+    }
     else {
-      aLineObject = new LIGHTGUI_DataObject ( *it1, aParaObject );
+      aLineObject = new LIGHTGUI_DataObject ( generateId(), *it1, aParaObject );
     }
   }
 
@@ -415,15 +520,16 @@ void LIGHTGUI_DataModel::buildTree ( SUIT_DataObject* studyRoot, const QStringLi
   setRoot( modelRoot );
 }
 
-//=================================================================================
-// function : findObject()
-// purpose  : finds a data object corresponding to the given line number
-//=================================================================================
-LIGHTGUI_DataObject* LIGHTGUI_DataModel::findObject( const int thePosition ) const
+/*!
+  \brief Search data object corresponding to the specified line number.
+  \param id line identifier
+  \return data object or 0 if \a id is invalid
+*/
+LIGHTGUI_DataObject* LIGHTGUI_DataModel::findObject( const int id ) const
 {
   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
     LIGHTGUI_DataObject* obj = dynamic_cast<LIGHTGUI_DataObject*>( it.current() );
-    if ( obj && obj->lineNb() == thePosition )
+    if ( obj && obj->id() == id )
       return obj;
   }
   return 0;