Salome HOME
Fix for the "0051899: curves are not shown in opened study" issue.
[modules/visu.git] / src / VISU_I / VISU_Table_i.cc
index 80ce8c100ecd80b238b00fea647f5708fba52a64..6d7362637831c0b62c6701798fbd0426f4eb7ada 100644 (file)
@@ -1,47 +1,95 @@
-//  Copyright (C) 2003  CEA/DEN, EDF R&D
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
 //
+// Copyright (C) 2003-2007  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.
 //
+// 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
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+//  VISU OBJECT : interactive object for VISU entities implementation
 //  File   : VISU_Table_i.cc
 //  Author : Vadim SANDLER
 //  Module : VISU
+//
+#include "VISU_Table_i.hh"
+
+#include "VISU_Tools.h"
+#include "VISU_CutLinesBase_i.hh"
+#include "VISU_CutSegment_i.hh"
+#include "VISU_Result_i.hh"
+#include "VISU_ViewManager_i.hh"
+
+#include "SALOME_Event.h"
+#include "SPlot2d_Curve.h"
+
+#include "VISU_TableReader.hxx"
+#include "VISU_ConvertorUtils.hxx"
+
+#include "utilities.h"
+
+#include <Basics_Utils.hxx>
 
 using namespace std;
-#include "VISU_Table_i.hh"
 
-#include "QAD_Application.h"
-#include "QAD_Desktop.h"
-#include "QAD_Study.h"
-#include <fstream>     
-#include <strstream>
-#include <qfileinfo.h>
-#include <qstringlist.h>
-#include <memory>      
-
-#ifdef DEBUG
-static int MYDEBUG = 1;
+#ifdef _DEBUG_
+static int MYDEBUG = 0;
 #else
 static int MYDEBUG = 0;
 #endif
 
+//# Define delimeter
+#define TLT_DLM ":"
+
+//Absolute deviation
+#define D_MIN "min"
+#define D_MAX "max"
+
+//Percentage deviation
+#define D_PMIN "min%"
+#define D_PMAX "max%"
+
+#define D_EMIN "errmin"
+#define D_EMAX "errmax"
+
+#define D_EPMIN "errmin%"
+#define D_EPMAX "errmax%"
+
+#define D_ERR "error"
+#define D_ERRP "error%"
+
+
 //----------------------------------------------------------------
 //                      Table Object
 //----------------------------------------------------------------
 int VISU::Table_i::myNbPresent = 0;
 const string VISU::Table_i::myComment  = "TABLE";
-/*! 
+/*!
   Generate unique name
 */
-const char* VISU::Table_i::GenerateName() 
-{ 
-  return VISU::GenerateName( "Table", ++myNbPresent ); 
+QString VISU::Table_i::GenerateName()
+{
+  return VISU::GenerateName( "Table", ++myNbPresent );
 }
 /*!
   Gets comment string
 */
-const char* VISU::Table_i::GetComment() const 
-{ 
-  return myComment.c_str(); 
+const char* VISU::Table_i::GetComment() const
+{
+  return myComment.c_str();
 }
 /*!
   Constructor
@@ -49,27 +97,456 @@ const char* VISU::Table_i::GetComment() const
 VISU::Table_i::Table_i( SALOMEDS::Study_ptr theStudy, const char* theObjectEntry )
      : PrsObject_i(theStudy)
 {
-  myObjectEntry = theObjectEntry; 
+  MESSAGE("Table_i::Table_i - "<<this);
+  mySObj = theStudy->FindObjectID(theObjectEntry);
   myOrientation = VISU::Table::HORIZONTAL;
+  SetStudyDocument(theStudy);
+  BuildDeviationMap();
 }
 /*!
   Destructor
 */
 VISU::Table_i::~Table_i()
 {
+  MESSAGE("Table_i::~Table_i - "<<this);
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Table_i
+::SetTitle( const char* theTitle )
+{
+  SetName( theTitle, true );
+}
+
+//----------------------------------------------------------------------------
+char*
+VISU::Table_i
+::GetTitle()
+{
+  return CORBA::string_dup( GetName().c_str() );
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Table_i
+::SetOrientation( VISU::Table::Orientation theOrientation )
+{
+  myOrientation = theOrientation;
+}
+
+//----------------------------------------------------------------------------
+VISU::Table::Orientation
+VISU::Table_i
+::GetOrientation()
+{
+  return myOrientation;
 }
+
+
+//----------------------------------------------------------------------------
+void
+VISU::Table_i
+::SortRow(CORBA::Long theRow, VISU::SortOrder theSortOrder, VISU::SortPolicy theSortPolicy)
+{
+  SALOMEDS::SObject_var SO = mySObj;
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
+  if ( !SO->_is_nil() ) {
+    SALOMEDS::GenericAttribute_var anAttr;
+    if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
+      SALOMEDS::AttributeTableOfInteger_var anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
+      anInt->SortRow( theRow, (SALOMEDS::AttributeTable::SortOrder)theSortOrder,
+                      (SALOMEDS::AttributeTable::SortPolicy)theSortPolicy );
+    }
+    else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
+      SALOMEDS::AttributeTableOfReal_var aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
+      aReal->SortRow( theRow, (SALOMEDS::AttributeTable::SortOrder)theSortOrder,
+                      (SALOMEDS::AttributeTable::SortPolicy)theSortPolicy );
+    }
+    UpdateCurves( std::map<int, int>() );
+  }
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Table_i
+::SortColumn(CORBA::Long theColumn, VISU::SortOrder theSortOrder, VISU::SortPolicy theSortPolicy)
+{
+  SALOMEDS::SObject_var SO = mySObj;
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
+  if ( !SO->_is_nil() ) {
+    SALOMEDS::GenericAttribute_var anAttr;
+    if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
+      SALOMEDS::AttributeTableOfInteger_var anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
+      anInt->SortColumn( theColumn, (SALOMEDS::AttributeTable::SortOrder)theSortOrder,
+                         (SALOMEDS::AttributeTable::SortPolicy)theSortPolicy );
+    }
+    else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
+      SALOMEDS::AttributeTableOfReal_var aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
+      aReal->SortColumn( theColumn, (SALOMEDS::AttributeTable::SortOrder)theSortOrder,
+                         (SALOMEDS::AttributeTable::SortPolicy)theSortPolicy );
+    }
+    UpdateCurves( std::map<int, int>() );
+  }
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Table_i
+::SortByRow(CORBA::Long theRow, VISU::SortOrder theSortOrder, VISU::SortPolicy theSortPolicy)
+{
+  SALOMEDS::SObject_var SO = mySObj;
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
+  if ( !SO->_is_nil() ) {
+    SALOMEDS::GenericAttribute_var anAttr;
+    if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
+      SALOMEDS::AttributeTableOfInteger_var anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
+      anInt->SortByRow( theRow, (SALOMEDS::AttributeTable::SortOrder)theSortOrder,
+                        (SALOMEDS::AttributeTable::SortPolicy)theSortPolicy );
+    }
+    else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
+      SALOMEDS::AttributeTableOfReal_var aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
+      aReal->SortByRow( theRow, (SALOMEDS::AttributeTable::SortOrder)theSortOrder,
+                        (SALOMEDS::AttributeTable::SortPolicy)theSortPolicy );
+    }
+    UpdateCurves( std::map<int, int>() );
+  }
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Table_i
+::SortByColumn(CORBA::Long theColumn, VISU::SortOrder theSortOrder, VISU::SortPolicy theSortPolicy)
+{
+  SALOMEDS::SObject_var SO = mySObj;
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
+  if ( !SO->_is_nil() ) {
+    SALOMEDS::LongSeq_var aRowIndices;
+    SALOMEDS::GenericAttribute_var anAttr;
+    if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
+      SALOMEDS::AttributeTableOfInteger_var anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
+      aRowIndices = anInt->SortByColumn( theColumn, (SALOMEDS::AttributeTable::SortOrder)theSortOrder,
+                                         (SALOMEDS::AttributeTable::SortPolicy)theSortPolicy );
+    }
+    else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
+      SALOMEDS::AttributeTableOfReal_var aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
+      aRowIndices = aReal->SortByColumn( theColumn, (SALOMEDS::AttributeTable::SortOrder)theSortOrder,
+                                         (SALOMEDS::AttributeTable::SortPolicy)theSortPolicy );
+    }
+    std::map<int, int> aMixData;
+    for ( int i = 0, n = aRowIndices->length(); i < n; i++ )
+      aMixData[ aRowIndices[i] ] = i+1;
+    UpdateCurves( aMixData );
+  }
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Table_i
+::UpdateCurves(std::map<int,int> theMixData)
+{
+  SALOMEDS::SObject_var SO = mySObj;
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
+  SALOMEDS::ChildIterator_var CI = GetStudyDocument()->NewChildIterator( SO );
+  for ( CI->InitEx( true ); CI->More(); CI->Next() ) {
+    CORBA::Object_var anObj = SObjectToObject( CI->Value() );
+    VISU::Curve_var aCurve = VISU::Curve::_narrow( anObj );
+    if ( !aCurve->_is_nil() ) {
+      if ( VISU::Curve_i* pCurve = dynamic_cast<VISU::Curve_i*>( GetServant( aCurve ).in() ) ) {
+        int aHRow = pCurve->GetHRow(), aVRow = pCurve->GetVRow();
+        if ( theMixData.find( aHRow ) != theMixData.end() )
+          pCurve->SetHRow( theMixData[ aHRow ] );
+        if ( theMixData.find( aVRow ) != theMixData.end() )
+          pCurve->SetVRow( theMixData[ aVRow ] );
+        UpdatePlot2d( pCurve, eUpdateData );
+      }
+    }
+  }
+}
+//----------------------------------------------------------------------------
+bool 
+VISU::Table_i::parseTitle(const QString theTitle, 
+                          QString& theOutTitle,
+                          DeviationType& theType, 
+                          bool& isMin) {
+  QStringList lst = theTitle.split(TLT_DLM);
+  theType = NoneDvtn;
+  isMin = false;
+  theOutTitle.clear();
+  if(lst.size() >= 2) {
+    QString s1 = lst[0];
+    QString s2 = lst[1];
+    if(QString::compare(lst[0], D_MIN, Qt::CaseInsensitive) == 0){
+      theType = AbsoluteDvtn;
+      isMin = true;
+    } else if(QString::compare(lst[0], D_MAX, Qt::CaseInsensitive) == 0) {
+      theType = AbsoluteDvtn;
+      isMin = false;
+    } else if(QString::compare(lst[0], D_PMIN, Qt::CaseInsensitive) == 0) {
+      theType = PercentageDvtn;
+      isMin = true;
+    } else if(QString::compare(lst[0], D_PMAX, Qt::CaseInsensitive) == 0) {
+      theType = PercentageDvtn;
+      isMin = false;
+    } else if(QString::compare(lst[0], D_EMIN, Qt::CaseInsensitive) == 0) {
+      theType = ErrorDvtn;
+      isMin = true;
+    } else if(QString::compare(lst[0], D_EMAX, Qt::CaseInsensitive) == 0) {
+      theType = ErrorDvtn;
+      isMin = false;
+    } else if(QString::compare(lst[0], D_EPMIN, Qt::CaseInsensitive) == 0) {
+      theType = ErrorPercentageDvtn;
+      isMin = true;
+    } else if(QString::compare(lst[0], D_EPMAX, Qt::CaseInsensitive) == 0) {
+      theType = ErrorPercentageDvtn;
+      isMin = false;
+    } else if(QString::compare(lst[0], D_ERR, Qt::CaseInsensitive) == 0) {
+      theType = SimpleErrorDvtn;
+    } else if(QString::compare(lst[0], D_ERRP, Qt::CaseInsensitive) == 0) {
+      theType = SimpleErrorPercentageDvtn;
+    }
+  }
+  if(theType == NoneDvtn){
+    return false;
+  } else {
+    for(int i = 1; i < lst.size();i++ )
+      theOutTitle += lst[i];
+    return true;
+  }
+}
+//----------------------------------------------------------------------------
+double 
+VISU::Table_i 
+::calculateDeviation(DeviationType theType, double value,double deviationValue, bool isMin){
+  double result;
+  switch(theType) {
+    case AbsoluteDvtn: 
+      result = deviationValue;
+      break;
+    case PercentageDvtn: 
+      result = value*deviationValue;
+      break;
+    case SimpleErrorDvtn:
+    case ErrorDvtn: 
+      result = value + (isMin ? -1.0 : 1.0)*deviationValue; 
+      break;
+    case ErrorPercentageDvtn:   
+    case SimpleErrorPercentageDvtn: 
+      result = value *( 1 + (isMin ? -1.0 : 1.0)*deviationValue); 
+      break;
+    default: result = 0.;
+  }
+  return isMin ? value - result : result - value;
+}
+
+QString 
+VISU::Table_i
+::deviationLabel(DeviationData* info) {
+  QString lbl;
+  if(info) {
+      bool add = true;
+      switch(info->minDeviation()){
+        case SimpleErrorDvtn:
+          lbl = D_ERR;
+          add = false;
+          break;
+        case SimpleErrorPercentageDvtn:
+          lbl = D_ERRP;
+          add = false;
+          break;
+        case AbsoluteDvtn:
+          lbl = D_MIN;
+          break;
+        case PercentageDvtn:
+          lbl = D_PMIN;
+          break;
+        case ErrorDvtn:
+          lbl = D_EMIN;
+          break;
+        case ErrorPercentageDvtn:
+          lbl = D_EPMIN;
+          break;
+      }
+      if(add) {
+        lbl += " / ";
+        switch(info->maxDeviation()){
+          case AbsoluteDvtn:
+            lbl += D_MAX;
+            break;
+          case PercentageDvtn:
+            lbl += D_PMAX;
+            break;
+          case ErrorDvtn:
+            lbl += D_EMAX;
+            break;
+          case ErrorPercentageDvtn:
+            lbl += D_EPMAX;
+            break;
+        }
+      }
+  }
+  return lbl;
+}
+
+//----------------------------------------------------------------------------
+bool
+VISU::Table_i
+::hasDeviationData(const int row) {
+  return myDeviationMap.contains(row);
+}
+
+//----------------------------------------------------------------------------
+VISU::DeviationData* 
+VISU::Table_i::getDeviationInfo(const int row) {
+  if(hasDeviationData(row))
+    return &myDeviationMap[row];
+  return NULL;
+}
+
+//----------------------------------------------------------------------------
+bool
+VISU::Table_i
+::isDeviationRow(const int row) {
+  DeviationMap::const_iterator it = myDeviationMap.begin();
+  for( ; it != myDeviationMap.end(); it++) {
+    if((*it).minRow() == row || (*it).maxRow() == row)
+      return true;
+  }
+  return false;
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Table_i
+::BuildDeviationMap() {
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
+  SALOMEDS::GenericAttribute_var        anAttr;
+  SALOMEDS::AttributeTableOfInteger_var anInt;
+  SALOMEDS::AttributeTableOfReal_var    aReal;
+  SALOMEDS::StringSeq_var rowTitles = new SALOMEDS::StringSeq();
+  SALOMEDS::StringSeq_var rowUnits = new SALOMEDS::StringSeq();
+
+  if ( !mySObj->_is_nil() ) {
+    if ( Builder->FindAttribute( mySObj, anAttr, "AttributeTableOfInteger" ) ) {
+      anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
+      rowTitles = anInt->GetRowTitles();
+      rowUnits = anInt->GetRowUnits();
+    }
+    else if ( Builder->FindAttribute( mySObj, anAttr, "AttributeTableOfReal" ) ) {
+      aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
+      rowTitles = aReal->GetRowTitles();
+      rowUnits = aReal->GetRowUnits();
+      }
+   }
+   int nbTitles = rowTitles->length();
+   int nbUnits = rowUnits->length();
+
+   QString realTitle;
+   DeviationType deviationType; 
+   bool isMin;
+
+   //Deviation candidates map:
+   //Key - title without keyword, pair { "deviation type" , "id of row" }
+   QMap<QString, QPair<DeviationType,int> > minCandidatesMap;
+   QMap<QString, QPair<DeviationType,int> > maxCandidatesMap;
+   QMap<QString, QPair<DeviationType,int> > CandidatesMap;
+   if( nbTitles > 0 ) {
+     for(int i = 0; i < nbTitles; i++ ) {
+       if(parseTitle(rowTitles[i].in(), realTitle, deviationType, isMin)) {
+         if( deviationType == SimpleErrorDvtn || deviationType == SimpleErrorPercentageDvtn ){
+           if(!CandidatesMap.contains(realTitle)) {
+              CandidatesMap[realTitle] = QPair<DeviationType, int>(deviationType,i);
+           } else {
+            minCandidatesMap.remove(realTitle);
+            maxCandidatesMap.remove(realTitle);
+            CandidatesMap.remove(realTitle);
+           }
+            continue;
+         }
+         if(isMin) {
+           if(!minCandidatesMap.contains(realTitle)){
+              minCandidatesMap[realTitle] = QPair<DeviationType, int>(deviationType,i);
+           } else {
+            minCandidatesMap.remove(realTitle);
+            maxCandidatesMap.remove(realTitle);
+            CandidatesMap.remove(realTitle);
+           }
+         } else {
+           if(!maxCandidatesMap.contains(realTitle)){
+              maxCandidatesMap[realTitle] = QPair<DeviationType, int>(deviationType,i);
+           } else {
+            minCandidatesMap.remove(realTitle);
+            maxCandidatesMap.remove(realTitle);
+            CandidatesMap.remove(realTitle);
+           }
+         }
+       }
+     }
+     QString currentTitle;
+     for(int i = 0; i < nbTitles; i++ ) {
+      currentTitle = rowTitles[i].in();
+      if(minCandidatesMap.contains(currentTitle) && maxCandidatesMap.contains(currentTitle)) {
+        //check for the units
+        if(nbUnits > 0) {
+          if(i < nbUnits) {
+            const char* s1 = rowUnits[i].in();
+            const char* s2 = rowUnits[minCandidatesMap[currentTitle].second].in();
+            const char* s3 = rowUnits[maxCandidatesMap[currentTitle].second].in();
+            if(strcmp(s1,s2) != 0 || strcmp(s1,s3) != 0 ) continue;
+          } else continue;
+        }
+        myDeviationMap[i] = DeviationData(minCandidatesMap[currentTitle].second,
+                                          maxCandidatesMap[currentTitle].second,
+                                          minCandidatesMap[currentTitle].first,
+                                          maxCandidatesMap[currentTitle].first);
+      } else if(CandidatesMap.contains(currentTitle)) {
+          //check for the units
+          if(nbUnits > 0) {
+            if(i < nbUnits) {
+              const char* s1 = rowUnits[i].in();
+              const char* s2 = rowUnits[CandidatesMap[currentTitle].second].in();
+              if(strcmp(s1,s2) != 0) continue;
+            } else continue;
+          }
+          myDeviationMap[i] = DeviationData(CandidatesMap[currentTitle].second,
+                                          CandidatesMap[currentTitle].second,
+                                          CandidatesMap[currentTitle].first,
+                                          CandidatesMap[currentTitle].first);
+      }
+     }
+   }
+}
+
+//----------------------------------------------------------------------------
+SALOMEDS::SObject_var
+VISU::Table_i
+::GetSObject() const
+{
+  return mySObj;
+}
+
+//----------------------------------------------------------------------------
+std::string
+VISU::Table_i
+::GetObjectEntry() 
+{
+  CORBA::String_var anEntry = mySObj->GetID();
+  return anEntry.in(); 
+}
+
+//----------------------------------------------------------------------------
 /*!
   Gets number of rows in table
 */
 CORBA::Long VISU::Table_i::GetNbRows()
 {
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( myObjectEntry.c_str() );
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::SObject_var SO = mySObj;
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   if ( !SO->_is_nil() ) {
     SALOMEDS::GenericAttribute_var        anAttr;
     if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
       SALOMEDS::AttributeTableOfInteger_var anInt =  SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
-      return anInt->GetNbRows();
+       return anInt->GetNbRows();
     }
     else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
       SALOMEDS::AttributeTableOfReal_var aReal =  SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
@@ -83,8 +560,8 @@ CORBA::Long VISU::Table_i::GetNbRows()
 */
 CORBA::Long VISU::Table_i::GetNbColumns()
 {
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( myObjectEntry.c_str() );
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::SObject_var SO = mySObj;
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   if ( !SO->_is_nil() ) {
     SALOMEDS::GenericAttribute_var        anAttr;
     if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
@@ -103,71 +580,107 @@ CORBA::Long VISU::Table_i::GetNbColumns()
 */
 VISU::Storable* VISU::Table_i::Create()
 {
-  // generate name ... 
-  myName = GetTableTitle(); 
-  if ( myName == "" )
-    myName = GenerateName();
+  // generate name ...
+  SetName(GetTableTitle().toLatin1().data(), false);
+
+  // mpv (PAL 5357): if name attribute already exist at this label, use it as name of table
+  if ( GetName() == "" )
+    if ( !mySObj->_is_nil() ) {
+      CutLinesBase_i* pCutLines = NULL;
+      CORBA::Object_var anObj = SObjectToObject(mySObj);
+      if(!CORBA::is_nil(anObj)){
+       VISU::CutLinesBase_var aCutLines = VISU::CutLinesBase::_narrow(anObj);
+         if(!aCutLines->_is_nil())
+           pCutLines = dynamic_cast<CutLinesBase_i*>(GetServant(aCutLines).in());
+       }
+      if (!pCutLines)
+       if (mySObj->GetName()) SetName(mySObj->GetName(), false);
+    }
+
+  if ( GetName() == "" )
+    SetName(GenerateName().toLatin1().data(), false);
   // ... and build the object
   return Build( false );
 }
 /*!
   Builds presentation of table
 */
-VISU::Storable* VISU::Table_i::Build( int theRestoring ) 
+VISU::Storable* VISU::Table_i::Build( int theRestoring )
 {
+
   // look for reference SObject with table attribute
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( myObjectEntry.c_str() );
+  SALOMEDS::SObject_var SO = mySObj;
+
   if ( !SO->_is_nil() ) {
-    CutLines_i* pCutLines = NULL;
+    CutLinesBase_i* pCutLines = NULL;
     CORBA::Object_var anObj = SObjectToObject(SO);
     if(!CORBA::is_nil(anObj)){
-      VISU::CutLines_var aCutLines = VISU::CutLines::_narrow(anObj);
+      VISU::CutLinesBase_var aCutLines = VISU::CutLinesBase::_narrow(anObj);
       if(!aCutLines->_is_nil())
-       pCutLines = dynamic_cast<CutLines_i*>(GetServant(aCutLines));
+        pCutLines = dynamic_cast<CutLinesBase_i*>(GetServant(aCutLines).in());
     }
-    SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+    SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
     SALOMEDS::GenericAttribute_var anAttr;
-    if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) || 
-        Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) || pCutLines) {
-      // look for component
-      if ( !theRestoring ) {
-       SALOMEDS::SComponent_var SComponent = VISU::FindOrCreateVisuComponent( myStudy );
-       // create SObject and set attributes
-       QString aComment;
-       aComment.sprintf("myComment=%s;myType=%d",GetComment(),VISU::TTABLE);
-       string anEntry = CreateAttributes( myStudy, 
-                                          SComponent->GetID(),
-                                          "",
-                                          GetID(),
-                                          GetName(),
-                                          "",
-                                          aComment.latin1(), 
-                                          true );
-       // create SObject referenced to real table object
-       SALOMEDS::SObject_var newSO = myStudy->FindObjectID( anEntry.c_str() );
-       if(pCutLines) {
-         pCutLines->BuildTableOfReal(newSO);
-         myObjectEntry = anEntry;
-       }
-       SALOMEDS::SObject_var refSO = Builder->NewObject( newSO );
-       Builder->Addreference( refSO, SO );
+    // look for component
+    if ( !theRestoring ) {
+      SALOMEDS::SComponent_var SComponent = VISU::FindOrCreateVisuComponent( GetStudyDocument() );
+      // create SObject and set attributes
+      QString aComment;
+      if(pCutLines)
+        aComment.sprintf("myComment=%s;mySourceId=CutLines",GetComment());
+      else{
+        aComment.sprintf("myComment=%s;mySourceId=TableAttr",GetComment());
+        SALOMEDS::SObject_var aFatherSObject = SO->GetFather();
+        if(aFatherSObject->FindAttribute(anAttr,"AttributeString")){
+          SALOMEDS::AttributeString_var aCommentAttr =
+            SALOMEDS::AttributeString::_narrow(anAttr);
+          CORBA::String_var aValue = aCommentAttr->Value();
+          Storable::TRestoringMap aMap;
+          Storable::StringToMap(aValue.in(),aMap);
+          bool anIsExist;
+          QString aMethodName = VISU::Storable::FindValue(aMap,"myComment",&anIsExist);
+          if(anIsExist){
+            if( aMethodName == "ImportTables" ){
+              aComment.sprintf("myComment=%s;mySourceId=TableFile",GetComment());
+            }
+          }
+        }
       }
-      return this;
+
+      string anEntry = CreateAttributes( GetStudyDocument(),
+                                         SO->GetID(),//SComponent->GetID(),
+                                         "ICON_TREE_TABLE",
+                                         GetID(),
+                                         GetName(),
+                                         "",
+                                         aComment.toLatin1().data(),
+                                         pCutLines );
+      // create SObject referenced to real table object
+      mySObj = SALOMEDS::SObject::_duplicate(GetStudyDocument()->FindObjectID( anEntry.c_str() ));
+      if(pCutLines) {
+        bool isCutSegment = dynamic_cast<CutSegment_i*>(pCutLines);
+        pCutLines->BuildTableOfReal(mySObj, isCutSegment);
+      }
+      // mpv (PAL5357): reference attributes are unnecessary now
+      //SALOMEDS::SObject_var refSO = Builder->NewObject( mySObj );
+      //Builder->Addreference( refSO, SO );
     }
+
+    return this;
   }
   return NULL;
 }
 /*!
   Restores table object from stream
 */
-VISU::Storable* VISU::Table_i::Restore( const Storable::TRestoringMap& theMap )
-     throw( std::logic_error& )
+VISU::Storable* VISU::Table_i::Restore( const Storable::TRestoringMap& theMap, SALOMEDS::SObject_ptr SO)
 {
   if(MYDEBUG) MESSAGE(GetComment());
-  myName = (const char*)(VISU::Storable::FindValue(theMap,"myName"));
-  myObjectEntry = (const char *)(VISU::Storable::FindValue(theMap,"myObjectEntry"));
-  myTitle = (const char*)(VISU::Storable::FindValue(theMap,"myTitle"));
+  SetName(VISU::Storable::FindValue(theMap,"myName").toLatin1().data(), false);
+  myTitle = VISU::Storable::FindValue(theMap,"myTitle").toLatin1().data();
   myOrientation = ( VISU::Table::Orientation )( VISU::Storable::FindValue(theMap,"myOrientation").toInt() );
+  mySObj = SALOMEDS::SObject::_duplicate(SO);
+  mySObj->Register();
   return Build( true );
 }
 /*!
@@ -175,42 +688,67 @@ VISU::Storable* VISU::Table_i::Restore( const Storable::TRestoringMap& theMap )
 */
 void VISU::Table_i::ToStream( std::ostringstream& theStr )
 {
-  Storable::DataToStream( theStr, "myName",        myName.c_str() );
-  Storable::DataToStream( theStr, "myObjectEntry", myObjectEntry.c_str() );
+  Storable::DataToStream( theStr, "myName",        GetName().c_str() );
   Storable::DataToStream( theStr, "myTitle",       myTitle.c_str() );
   Storable::DataToStream( theStr, "myOrientation", myOrientation );
 }
 /*!
   Called from engine to restore table from the file
 */
-VISU::Storable* VISU::TableRestore(SALOMEDS::SObject_ptr theSObject, 
-                                  const string& thePrefix, const Storable::TRestoringMap& theMap)
+VISU::Storable* VISU::Table_i::StorableEngine(SALOMEDS::SObject_ptr theSObject,
+                                             const Storable::TRestoringMap& theMap,
+                                             const std::string& thePrefix,
+                                             CORBA::Boolean theIsMultiFile)
 {
   SALOMEDS::Study_var aStudy = theSObject->GetStudy();
   VISU::Table_i* pResent = new VISU::Table_i( aStudy, "" );
-  return pResent->Restore( theMap );
+  return pResent->Restore( theMap, theSObject);
 }
 /*!
   Gets title for the original table object
 */
-const char* VISU::Table_i::GetTableTitle()
+QString VISU::Table_i::GetTableTitle()
 {
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( GetObjectEntry() );
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::SObject_var SO = mySObj;
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   SALOMEDS::GenericAttribute_var        anAttr;
   SALOMEDS::AttributeTableOfInteger_var anInt;
   SALOMEDS::AttributeTableOfReal_var    aReal;
-  if ( !SO->_is_nil() ) { 
+  if ( !SO->_is_nil() ) {
     if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
       anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
-      return anInt->GetTitle();
+      CORBA::String_var aString = anInt->GetTitle();
+      return aString.in();
     }
     else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
       aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
-      return aReal->GetTitle();
+      CORBA::String_var aString = aReal->GetTitle();
+      return aString.in();
     }
   }
-  return ""; 
+  return "";
+}
+
+//---------------------------------------------------------------
+void VISU::Table_i::RemoveFromStudy()
+{
+  struct TRemoveFromStudy: public SALOME_Event
+  {
+    VISU::Table_i* myRemovable;
+    TRemoveFromStudy(VISU::Table_i* theRemovable):
+      myRemovable(theRemovable)
+    {}
+    
+    virtual
+    void
+    Execute()
+    {
+      VISU::RemoveFromStudy(myRemovable->GetSObject(),false);
+    }
+  };
+
+  // Remove the table with all curves
+  ProcessVoidEvent(new TRemoveFromStudy(this));
 }
 
 //----------------------------------------------------------------
@@ -219,89 +757,204 @@ const char* VISU::Table_i::GetTableTitle()
 /*!
   Restores table object from the stream [ static ]
 */
-static VISU::Table_i* GetTable( SALOMEDS::Study_var& theStudy, const VISU::Storable::TRestoringMap& theMap ) {
-  string anEntry = VISU::Storable::FindValue( theMap, "TableID" ).latin1();
-  SALOMEDS::SObject_var aSObject = theStudy->FindObjectID( anEntry.c_str() );
-  CORBA::Object_var anObject = VISU::SObjectToObject( aSObject );
+static VISU::Table_i* GetTable( SALOMEDS::Study_ptr theStudy, SALOMEDS::SObject_ptr theSO ) {
+  CORBA::Object_var anObject = VISU::SObjectToObject( theSO );
   if( !CORBA::is_nil( anObject ) ) {
     CORBA::Object_ptr aTable = VISU::Table::_narrow( anObject );
     if( !CORBA::is_nil( aTable ) )
-      return dynamic_cast<VISU::Table_i*>( VISU::GetServant( aTable ) );
+      return dynamic_cast<VISU::Table_i*>(VISU::GetServant(aTable).in());
   }
   return NULL;
 }
 
 int VISU::Curve_i::myNbPresent = 0;
 const string VISU::Curve_i::myComment  = "CURVE";
-/*! 
+/*!
   Generate unique name
 */
-const char* VISU::Curve_i::GenerateName() 
-{ 
-  return VISU::GenerateName( "Curve", ++myNbPresent )
+QString VISU::Curve_i::GenerateName()
+{
+  return VISU::GenerateName( "Curve", ++myNbPresent ).toLatin1().data();
 }
 /*!
   Gets comment string
 */
-const char* VISU::Curve_i::GetComment() const 
-{ 
-  return myComment.c_str(); 
+const char* VISU::Curve_i::GetComment() const
+{
+  return myComment.c_str();
 }
 /*!
   Constructor
   NB : theHRow, theVRow are the indexes of rows in the Table object and numbered from the 1 to GetNbRows()
 */
-VISU::Curve_i::Curve_i(SALOMEDS::Study_ptr theStudy, Table_i* theTable, CORBA::Long theHRow, CORBA::Long theVRow )
-     : PrsObject_i(theStudy), myTable( theTable ), myHRow( theHRow ), myVRow( theVRow )
+VISU::Curve_i::Curve_i( SALOMEDS::Study_ptr theStudy, Table_i* theTable,
+                       CORBA::Long theHRow, CORBA::Long theVRow,
+                       CORBA::Long theZRow, CORBA::Boolean theIsV2 )
+: PrsObject_i(theStudy), myTable( theTable ), myHRow( theHRow ),
+  myVRow( theVRow ), myZRow( theZRow ), myIsV2( theIsV2 ), myDeviationEnabled(false)
 {
   myAuto = true;
   myLine = VISU::Curve::SOLIDLINE;
   myLineWidth = 0;
   myMarker = VISU::Curve::CIRCLE;
   myColor.R = 0.0; myColor.G = 0.0; myColor.B = 0.0;
+  myScale = 1.0;
 }
 /*!
   Destructor
 */
 VISU::Curve_i::~Curve_i()
 {
+  MESSAGE("Curve_i::~Curve_i");
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Curve_i
+::SetTitle( const char* theTitle )
+{
+  SetName( theTitle, true );
+}
+
+//----------------------------------------------------------------------------
+char*
+VISU::Curve_i
+::GetTitle()
+{
+  return CORBA::string_dup( GetName().c_str() );
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Curve_i
+::SetColor( const SALOMEDS::Color& theColor )
+{
+  myColor = theColor; 
+  myAuto = false;
+}
+
+//----------------------------------------------------------------------------
+SALOMEDS::Color
+VISU::Curve_i
+::GetColor()
+{
+  return myColor;
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Curve_i
+::SetMarker( VISU::Curve::MarkerType theType )
+{
+  myMarker = theType; 
+  myAuto = false;
+}
+
+//----------------------------------------------------------------------------
+VISU::Curve::MarkerType
+VISU::Curve_i
+::GetMarker()
+{
+  return myMarker;
+}
+
+//----------------------------------------------------------------------------
+void
+VISU::Curve_i
+::SetLine( VISU::Curve::LineType theType, CORBA::Long theWidth )
+{
+  myLine = theType; 
+  myLineWidth = theWidth; 
+  myAuto = false;
+}
+
+//----------------------------------------------------------------------------
+VISU::Curve::LineType
+VISU::Curve_i
+::GetLine()
+{
+  return myLine;
+}
+
+//----------------------------------------------------------------------------
+CORBA::Long
+VISU::Curve_i
+::GetLineWidth()
+{
+  return myLineWidth;
 }
+
+//----------------------------------------------------------------------------
+void 
+VISU::Curve_i
+::SetScale( CORBA::Double theCoef )
+{
+  myScale = theCoef;  
+  UpdatePlot2d( this, eUpdateData );
+}
+
+//----------------------------------------------------------------------------
+CORBA::Double 
+VISU::Curve_i
+::GetScale()
+{
+  return myScale;    
+}
+
+//----------------------------------------------------------------------------
+void 
+VISU::Curve_i
+::RemoveScale()
+{
+  SetScale( 1.0 );
+}
+
+//----------------------------------------------------------------------------
 /*!
   Creates curve object
 */
 VISU::Storable* VISU::Curve_i::Create()
 {
-  // generate name ... 
-  myName = GetVerTitle(); 
-  if ( myName == "" )
-    myName = GenerateName();
+  // generate name ...
+  SetName(GetVerTitle(), false);
+  if ( GetName() == "" )
+    SetName(GenerateName().toLatin1().data(), false);
   // ... and build the object
   return Build( false );
 }
 /*!
   Builds presentation of curve
 */
-VISU::Storable* VISU::Curve_i::Build( int theRestoring ) 
+VISU::Storable* VISU::Curve_i::Build(int theRestoring )
 {
   if ( myTable != NULL ) {
     // getting table SObject by it's entry
-    SALOMEDS::SObject_var SO = myStudy->FindObjectID( myTable->GetEntry() );
     int nbRows = myTable->GetNbRows();
-    if ( !SO->_is_nil() && myHRow > 0 && myHRow <= nbRows && myVRow > 0 && myVRow <= nbRows ) {
+    if ( myHRow > 0 && myHRow <= nbRows && myVRow > 0 && myVRow <= nbRows ) {
       if ( !theRestoring ) {
        // look for component
-       SALOMEDS::SComponent_var SComponent = VISU::FindOrCreateVisuComponent( myStudy );
+       SALOMEDS::SComponent_var SComponent = VISU::FindOrCreateVisuComponent( GetStudyDocument() );
        // create SObject and set attributes
        QString aComment;
-       aComment.sprintf("myComment=%s;myType=%d",GetComment(),VISU::TCURVE);
-       string anEntry = CreateAttributes( myStudy, 
-                                          myTable->GetEntry(),
-                                          "",
-                                          GetID(),
-                                          GetName(),
-                                          "",
-                                          aComment.latin1(),
-                                          true );
+       aComment.sprintf("myComment=%s",GetComment());
+       string anEntry = CreateAttributes( GetStudyDocument(),
+                                         myTable->GetObjectEntry(),
+                                         "",
+                                         GetID(),
+                                         GetName(),
+                                         "",
+                                         aComment.toLatin1().data(),
+                                         true );
+       // create SObject referenced to real table object
+       mySObj = SALOMEDS::SObject::_duplicate(GetStudyDocument()->FindObjectID(anEntry.c_str()));
+
+       // Set icon
+       SALOMEDS::StudyBuilder_var aStudyBuilder = GetStudyDocument()->NewBuilder();
+       SALOMEDS::GenericAttribute_var anAttr;
+       SALOMEDS::AttributePixMap_var  aPixmap;
+       anAttr  = aStudyBuilder->FindOrCreateAttribute( mySObj, "AttributePixMap" );
+       aPixmap = SALOMEDS::AttributePixMap::_narrow( anAttr );
+       aPixmap ->SetPixMap("ICON_TREE_CURVE");
       }
       return this;
     }
@@ -315,12 +968,12 @@ VISU::Storable* VISU::Curve_i::Build( int theRestoring )
 CORBA::Boolean VISU::Curve_i::IsValid()
 {
   // getting table SObject by it's entry
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( myTable->GetObjectEntry() );
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID(myTable->GetObjectEntry().c_str());
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   SALOMEDS::GenericAttribute_var        anAttr;
   SALOMEDS::AttributeTableOfInteger_var anInt;
   SALOMEDS::AttributeTableOfReal_var    aReal;
-  if ( !SO->_is_nil() ) { 
+  if ( !SO->_is_nil() ) {
     if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
       anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
       if ( myHRow > 0 && myHRow <= anInt->GetNbRows() && myVRow > 0 && myVRow <= anInt->GetNbRows() ) {
@@ -343,24 +996,24 @@ string VISU::Curve_i::GetHorTitle()
 {
   string title;
   // getting table SObject by it's entry
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( myTable->GetObjectEntry() );
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID(myTable->GetObjectEntry().c_str());
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   SALOMEDS::GenericAttribute_var        anAttr;
   SALOMEDS::AttributeTableOfInteger_var anInt;
   SALOMEDS::AttributeTableOfReal_var    aReal;
-  if ( !SO->_is_nil() ) { 
+  if ( !SO->_is_nil() ) {
     if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
       anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
       SALOMEDS::StringSeq_var rowTitles = anInt->GetRowTitles();
       if ( rowTitles->length() > 0 && myHRow > 0 && myHRow <= anInt->GetNbRows() ) {
-       title = strdup( rowTitles[ myHRow-1 ] );
+       title = rowTitles[ myHRow-1 ];
       }
     }
     else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
       aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
       SALOMEDS::StringSeq_var rowTitles = aReal->GetRowTitles();
       if ( rowTitles->length() > 0 && myHRow > 0 && myHRow <= aReal->GetNbRows() ) {
-       title = strdup( rowTitles[ myHRow-1 ] );
+       title = rowTitles[ myHRow-1 ];
       }
     }
   }
@@ -373,23 +1026,23 @@ string VISU::Curve_i::GetVerTitle()
 {
   string title;
   // getting table SObject by it's entry
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( myTable->GetObjectEntry() );
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID(myTable->GetObjectEntry().c_str());
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   SALOMEDS::GenericAttribute_var        anAttr;
   SALOMEDS::AttributeTableOfInteger_var anInt;
   SALOMEDS::AttributeTableOfReal_var    aReal;
-  if ( !SO->_is_nil() ) { 
+  if ( !SO->_is_nil() ) {
     if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
       anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
       SALOMEDS::StringSeq_var rowTitles = anInt->GetRowTitles();
       if ( rowTitles->length() > 0 && myVRow > 0 && myVRow <= anInt->GetNbRows() )
-       title = strdup( rowTitles[ myVRow-1 ] );
+       title = rowTitles[ myVRow-1 ];
     }
     else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
       aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
       SALOMEDS::StringSeq_var rowTitles = aReal->GetRowTitles();
       if ( rowTitles->length() > 0 && myVRow > 0 && myVRow <= aReal->GetNbRows() )
-       title = strdup( rowTitles[ myVRow-1 ] );
+       title = rowTitles[ myVRow-1 ];
     }
   }
   return title;
@@ -401,23 +1054,23 @@ string VISU::Curve_i::GetHorUnits()
 {
   string units;
   // getting table SObject by it's entry
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( myTable->GetObjectEntry() );
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID(myTable->GetObjectEntry().c_str());
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   SALOMEDS::GenericAttribute_var        anAttr;
   SALOMEDS::AttributeTableOfInteger_var anInt;
   SALOMEDS::AttributeTableOfReal_var    aReal;
-  if ( !SO->_is_nil()  ) { 
+  if ( !SO->_is_nil()  ) {
     if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
       anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
       SALOMEDS::StringSeq_var rowUnits = anInt->GetRowUnits();
       if ( rowUnits->length() > 0 && myHRow > 0 && myHRow <= anInt->GetNbRows() )
-       units = strdup( rowUnits[ myHRow-1 ] );
+       units = rowUnits[ myHRow-1 ];
     }
     else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
       aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
       SALOMEDS::StringSeq_var rowUnits = aReal->GetRowUnits();
       if ( rowUnits->length() > 0 && myHRow > 0 && myHRow <= aReal->GetNbRows() )
-       units = strdup( rowUnits[ myHRow-1 ] );
+       units = rowUnits[ myHRow-1 ];
     }
   }
   return units;
@@ -429,23 +1082,23 @@ string VISU::Curve_i::GetVerUnits()
 {
   string units;
   // getting table SObject by it's entry
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( myTable->GetObjectEntry() );
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID(myTable->GetObjectEntry().c_str());
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   SALOMEDS::GenericAttribute_var        anAttr;
   SALOMEDS::AttributeTableOfInteger_var anInt;
   SALOMEDS::AttributeTableOfReal_var    aReal;
-  if ( !SO->_is_nil() ) { 
+  if ( !SO->_is_nil() ) {
     if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
       anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
       SALOMEDS::StringSeq_var rowUnits = anInt->GetRowUnits();
       if ( rowUnits->length() > 0 && myVRow > 0 && myVRow <= anInt->GetNbRows() )
-       units = strdup( rowUnits[ myVRow-1] );
+       units = rowUnits[ myVRow-1];
     }
     else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
       aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
       SALOMEDS::StringSeq_var rowUnits = aReal->GetRowUnits();
       if ( rowUnits->length() > 0 && myVRow > 0 && myVRow <= aReal->GetNbRows() )
-       units = strdup( rowUnits[ myVRow-1 ] );
+       units = rowUnits[ myVRow-1 ];
     }
   }
   return units;
@@ -453,19 +1106,22 @@ string VISU::Curve_i::GetVerUnits()
 /*!
   Gets curve data
 */
-int VISU::Curve_i::GetData( double*& theHorList, double*& theVerList )
+int VISU::Curve_i::GetData( double*& theHorList, double*& theVerList, QStringList& zList )
 {
   theHorList = 0; theVerList = 0;
   // getting table SObject by it's entry
-  SALOMEDS::SObject_var SO = myStudy->FindObjectID( myTable->GetObjectEntry() );
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID(myTable->GetObjectEntry().c_str());
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   SALOMEDS::GenericAttribute_var        anAttr;
   SALOMEDS::AttributeTableOfInteger_var anInt;
   SALOMEDS::AttributeTableOfReal_var    aReal;
-  if ( !SO->_is_nil() ) { 
+
+  QString tip = "%1: %2", z_data;
+
+  if ( !SO->_is_nil() ) {
     if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
       anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
-      int nbCols = anInt->GetNbColumns() ; 
+      int nbCols = anInt->GetNbColumns(), nbRows = anInt->GetNbRows();
       if ( nbCols > 0 && myHRow > 0 && myHRow <= anInt->GetNbRows() && myVRow > 0 && myVRow <= anInt->GetNbRows() ) {
        int nbPoints = 0;
        for ( int j = 1; j <= nbCols; j++ ) {
@@ -476,10 +1132,24 @@ int VISU::Curve_i::GetData( double*& theHorList, double*& theVerList )
          theHorList = new double[ nbPoints ];
          theVerList = new double[ nbPoints ];
          int k = 0;
+
+         SALOMEDS::StringSeq_var rowTitles = anInt->GetRowTitles();
+
          for ( int j = 1; j <= nbCols; j++ ) {
            if ( anInt->HasValue( myHRow, j ) && anInt->HasValue( myVRow, j ) ) {
              theHorList[k] = anInt->GetValue( myHRow, j );
              theVerList[k] = anInt->GetValue( myVRow, j );
+
+             z_data = tip.arg( GetHorTitle().c_str() ).arg( theHorList[k] ) + "\n";
+             z_data += tip.arg( GetVerTitle().c_str() ).arg( theVerList[k] );
+
+             if( myZRow>0 && myZRow<=nbRows && anInt->HasValue( myZRow, j ) )
+             {
+               string title;
+               title = rowTitles[ myZRow-1 ];
+               z_data += "\n" + tip.arg( title.c_str() ).arg( anInt->GetValue( myZRow, j ) );
+             }
+             zList.append( z_data );
              k++;
            }
          }
@@ -489,7 +1159,7 @@ int VISU::Curve_i::GetData( double*& theHorList, double*& theVerList )
     }
     else if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
       aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
-      int nbCols = aReal->GetNbColumns() ; 
+      int nbCols = aReal->GetNbColumns(), nbRows = aReal->GetNbRows();
       if ( nbCols > 0 && myHRow > 0 && myHRow <= aReal->GetNbRows() && myVRow > 0 && myVRow <= aReal->GetNbRows() ) {
        int nbPoints = 0;
        for ( int j = 1; j <= nbCols; j++ ) {
@@ -500,10 +1170,24 @@ int VISU::Curve_i::GetData( double*& theHorList, double*& theVerList )
          theHorList = new double[ nbPoints ];
          theVerList = new double[ nbPoints ];
          int k = 0;
+
+         SALOMEDS::StringSeq_var rowTitles = aReal->GetRowTitles();
+
          for ( int j = 1; j <= nbCols; j++ ) {
            if ( aReal->HasValue( myHRow, j ) && aReal->HasValue( myVRow, j ) ) {
              theHorList[k] = aReal->GetValue( myHRow, j );
              theVerList[k] = aReal->GetValue( myVRow, j );
+
+             z_data = tip.arg( GetHorTitle().c_str() ).arg( theHorList[k] ) + "\n";
+             z_data += tip.arg( GetVerTitle().c_str() ).arg( theVerList[k] );
+
+             if( myZRow>0 && myZRow<=nbRows && aReal->HasValue( myZRow, j ) )
+             {
+               string title;
+               title = rowTitles[ myZRow-1 ];
+               z_data += "\n" + tip.arg( title.c_str() ).arg( aReal->GetValue( myZRow, j ) );
+             }
+             zList.append( z_data );
              k++;
            }
          }
@@ -514,14 +1198,97 @@ int VISU::Curve_i::GetData( double*& theHorList, double*& theVerList )
   }
   return 0;
 }
+
+int VISU::Curve_i::GetDeviationData( double*& theMin, double*& theMax, QList<int>& theIndexes) {
+  if(!hasDeviation())
+    return 0;
+
+  theIndexes.clear();
+
+  DeviationData *info = myTable->getDeviationInfo(myVRow - 1);
+  int minRow = info->minRow() + 1;
+  int maxRow = info->maxRow() + 1;
+
+  SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID(myTable->GetObjectEntry().c_str());
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
+  SALOMEDS::GenericAttribute_var        anAttr;
+  SALOMEDS::AttributeTableOfInteger_var anInt;
+  SALOMEDS::AttributeTableOfReal_var    aReal;
+
+  int nbPoints = 0;
+  if ( !SO->_is_nil() ) {
+    if ( Builder->FindAttribute( SO, anAttr, "AttributeTableOfInteger" ) ) {
+      anInt = SALOMEDS::AttributeTableOfInteger::_narrow( anAttr );
+      int nbCols = anInt->GetNbColumns();
+      int nbRows = anInt->GetNbRows();
+      if ( nbCols > 0 && myHRow > 0 && myVRow && minRow > 0 && maxRow > 0 && 
+           myHRow <= nbRows &&  myVRow <= nbRows && minRow <= nbRows && maxRow <= nbRows ) {
+        for ( int j = 1; j <= nbCols; j++ ) {
+               if ( anInt->HasValue( myHRow, j ) && anInt->HasValue( myVRow, j ) && 
+               anInt->HasValue( minRow, j ) && anInt->HasValue( maxRow, j ) )
+                 nbPoints++;
+        }
+
+         if ( nbPoints > 0 ) {
+               theMin = new double[ nbPoints ];
+               theMax = new double[ nbPoints ];
+           int k = 0;
+          int value;
+               for ( int j = 1; j <= nbCols; j++ ) {
+                 if ( anInt->HasValue( myHRow, j ) && anInt->HasValue( myVRow, j ) &&
+                 anInt->HasValue( minRow, j ) && anInt->HasValue( maxRow, j )) {
+                 value = anInt->GetValue(myVRow,j);
+              theMin[k] = Table_i::calculateDeviation(info->minDeviation(),value, anInt->GetValue(minRow,j), true);
+                   theMax[k] = Table_i::calculateDeviation(info->maxDeviation(),value, anInt->GetValue(maxRow,j), false);
+              k++;
+              theIndexes.push_back(j-1);
+            }
+          } // for ( ...
+        } // nbPoints > 0
+      } // nbCols > 0 && myHRow > 0 && myVRow ...
+    } // Builder->FindAttribute(...
+    else if( Builder->FindAttribute( SO, anAttr, "AttributeTableOfReal" ) ) {
+      aReal = SALOMEDS::AttributeTableOfReal::_narrow( anAttr );
+      int nbCols = aReal->GetNbColumns();
+      int nbRows = aReal->GetNbRows();
+      if ( nbCols > 0 && myHRow > 0 && myVRow && minRow > 0 && maxRow > 0 && 
+           myHRow <= nbRows &&  myVRow <= nbRows && minRow <= nbRows && maxRow <= nbRows) {
+        for ( int j = 1; j <= nbCols; j++ ) {
+               if ( aReal->HasValue( myHRow, j ) && aReal->HasValue( myVRow, j ) && 
+               aReal->HasValue( minRow, j ) && aReal->HasValue( maxRow, j ) )
+                 nbPoints++;
+        }
+
+         if ( nbPoints > 0 ) {
+               theMin = new double[ nbPoints ];
+               theMax = new double[ nbPoints ];
+           int k = 0;
+          double value;
+               for ( int j = 1; j <= nbCols; j++ ) {
+                 if ( aReal->HasValue( myHRow, j ) && aReal->HasValue( myVRow, j ) &&
+                 aReal->HasValue( minRow, j ) && aReal->HasValue( maxRow, j )) {
+              value =  aReal->GetValue(myVRow,j);
+              theMin[k] = Table_i::calculateDeviation(info->minDeviation(),value, aReal->GetValue(minRow,j), true);
+              theMax[k] = Table_i::calculateDeviation(info->maxDeviation(),value, aReal->GetValue(maxRow,j), false);
+              k++;
+              theIndexes.push_back(j-1);
+            }
+          } // for ( ..
+        } // nbPoints > 0
+      } // nbCols > 0 && myHRow > 0 && myVRow ...
+    } // Builder->FindAttribute( ...
+  } // !SO->_is_nil()
+  return nbPoints;
+}
 /*!
   Creates curve Plot2d presentation object
 */
-Plot2d_Curve* VISU::Curve_i::CreatePresentation()
+SPlot2d_Curve* VISU::Curve_i::CreatePresentation()
 {
-  Plot2d_Curve* crv = new Plot2d_Curve();
+  SPlot2d_Curve* crv = new SPlot2d_Curve();
+  crv->setYAxis( myIsV2 ? QwtPlot::yRight : QwtPlot::yLeft );
   crv->setHorTitle( GetHorTitle().c_str() );
-  string tlt = GetTitle(); 
+  string tlt = GetTitle();
   if ( tlt.length() <= 0 )
     tlt = GetVerTitle();
   //crv->setVerTitle( strdup( GetVerTitle().c_str() ) );
@@ -531,39 +1298,56 @@ Plot2d_Curve* VISU::Curve_i::CreatePresentation()
   crv->setVerUnits( GetVerUnits().c_str() );
   double* xList = 0;
   double* yList = 0;
-  int     nbPoints = GetData( xList, yList );
+  QStringList zList;
+  int     nbPoints = GetData( xList, yList, zList );
   if ( nbPoints > 0 && xList && yList ) {
-    crv->setData( xList, yList, nbPoints );
+    crv->setData( xList, yList, nbPoints, zList );
   }
   //cout << "********** Number of points: " << nbPoints <<endl;
   //for ( int i =0 ; i < nbPoints; i++ ) {
   //  cout << i<<"\t"<<xList[i] << "\t"<< yList[i] << endl;
   //}
-  crv->setLine( (Plot2d_Curve::LineType)GetLine(), GetLineWidth() );
-  crv->setMarker( (Plot2d_Curve::MarkerType)GetMarker() ); 
+  crv->setLine( (Plot2d::LineType)GetLine(), GetLineWidth() );
+  crv->setMarker( (Plot2d::MarkerType)GetMarker() );
   SALOMEDS::Color color = GetColor();
   crv->setColor( QColor( (int)(color.R*255.), (int)(color.G*255.), (int)(color.B*255.) ) );
   crv->setAutoAssign( IsAuto() );
-  crv->setIO(new SALOME_InteractiveObject(strdup(GetEntry()),"VISU",strdup(GetName()))); 
+  CORBA::String_var aString = mySObj->GetID();
+  crv->setIO(new SALOME_InteractiveObject(aString.in(), "VISU", GetName().c_str()));
   if ( myTable )
-    crv->setTableIO(new SALOME_InteractiveObject(strdup(myTable->GetEntry()),"VISU",strdup(myTable->GetName()))); 
+    crv->setTableIO(new SALOME_InteractiveObject(myTable->GetObjectEntry().c_str(), "VISU", myTable->GetName().c_str()));
+
+  if(!myContainers.isEmpty())     
+    crv->addOwners(myContainers);
   return crv;
 }
 /*!
   Restores curve object from stream
 */
-VISU::Storable* VISU::Curve_i::Restore( const Storable::TRestoringMap& theMap )
-     throw( std::logic_error& )
+VISU::Storable* VISU::Curve_i::Restore( const Storable::TRestoringMap& theMap, SALOMEDS::SObject_ptr theSO)
 {
   if(MYDEBUG) MESSAGE(GetComment());
-  myName = (const char*)(VISU::Storable::FindValue(theMap,"myName"));
+  mySObj = SALOMEDS::SObject::_duplicate(theSO);
+  mySObj->Register();
+  SetName(VISU::Storable::FindValue(theMap,"myName").toLatin1().data(), false);
   myHRow = VISU::Storable::FindValue(theMap,"myHRow").toInt();
   myVRow = VISU::Storable::FindValue(theMap,"myVRow").toInt();
+  bool ok = false;
+  QString z_str = VISU::Storable::FindValue(theMap,"myZRow", &ok);
+  myZRow = ok ? z_str.toInt() : 0;
+  ok = false;
+  QString v2_str = VISU::Storable::FindValue(theMap,"myIsV2", &ok);
+  myIsV2 = ok ? v2_str.toInt() : false;
+
+  QString scale_str = VISU::Storable::FindValue(theMap,"myScale", &ok);
+  myScale = ok ? scale_str.toDouble() : 1.0;
   myColor.R = VISU::Storable::FindValue(theMap,"myColor.R").toDouble();
   myColor.G = VISU::Storable::FindValue(theMap,"myColor.G").toDouble();
   myColor.B = VISU::Storable::FindValue(theMap,"myColor.B").toDouble();
   myMarker = ( VISU::Curve::MarkerType )( VISU::Storable::FindValue(theMap,"myMarker").toInt() );
   myLine = ( VISU::Curve::LineType )( VISU::Storable::FindValue(theMap,"myLine").toInt() );
+  myLineWidth = VISU::Storable::FindValue(theMap,"myLineWidth").toInt();
+  myAuto = VISU::Storable::FindValue(theMap,"myAuto").toInt();
   return Build( true );
 }
 /*!
@@ -571,55 +1355,150 @@ VISU::Storable* VISU::Curve_i::Restore( const Storable::TRestoringMap& theMap )
 */
 void VISU::Curve_i::ToStream( std::ostringstream& theStr )
 {
-  Storable::DataToStream( theStr, "TableID",   GetTableID());
-  Storable::DataToStream( theStr, "myName",    myName.c_str() );
-  Storable::DataToStream( theStr, "myHRow",    myHRow );
-  Storable::DataToStream( theStr, "myVRow",    myVRow );
-  Storable::DataToStream( theStr, "myColor.R", myColor.R );
-  Storable::DataToStream( theStr, "myColor.G", myColor.G );
-  Storable::DataToStream( theStr, "myColor.B", myColor.B );
-  Storable::DataToStream( theStr, "myMarker",  myMarker );
-  Storable::DataToStream( theStr, "myLine",    myLine );
+  Storable::DataToStream( theStr, "myName",      GetName().c_str() );
+  Storable::DataToStream( theStr, "myHRow",      myHRow );
+  Storable::DataToStream( theStr, "myVRow",      myVRow );
+  Storable::DataToStream( theStr, "myZRow",      myZRow );
+  Storable::DataToStream( theStr, "myIsV2",      myIsV2 );
+  Storable::DataToStream( theStr, "myScale",     myScale );
+  Storable::DataToStream( theStr, "myColor.R",   myColor.R );
+  Storable::DataToStream( theStr, "myColor.G",   myColor.G );
+  Storable::DataToStream( theStr, "myColor.B",   myColor.B );
+  Storable::DataToStream( theStr, "myMarker",    myMarker );
+  Storable::DataToStream( theStr, "myLine",      myLine );
+  Storable::DataToStream( theStr, "myLineWidth", myLineWidth );
+  Storable::DataToStream( theStr, "myAuto",      myAuto );
 }
 /*!
   Gets reference table's entry
 */
-const char* VISU::Curve_i::GetTableID() { 
-  return CORBA::string_dup(myTable->GetEntry());
+std::string VISU::Curve_i::GetTableID() {
+  return myTable->GetObjectEntry();
 }
 /*!
   Called from engine to restore curve from the file
 */
-VISU::Storable* VISU::CurveRestore(SALOMEDS::SObject_ptr theSObject, 
-                                  const string& thePrefix, const Storable::TRestoringMap& theMap)
+VISU::Storable* VISU::Curve_i::StorableEngine(SALOMEDS::SObject_ptr theSObject,
+                                             const Storable::TRestoringMap& theMap,
+                                             const std::string& thePrefix,
+                                             CORBA::Boolean theIsMultiFile)
 {
   SALOMEDS::Study_var aStudy = theSObject->GetStudy();
-  VISU::Table_i* pTable = GetTable( aStudy, theMap );
+  VISU::Table_i* pTable = GetTable(aStudy, theSObject->GetFather());
   if( pTable != NULL ) {
-    VISU::Curve_i* pResent = new VISU::Curve_i( aStudy, pTable, 0, 0 );
-    return pResent->Restore( theMap );
+    VISU::Curve_i* pResent = new VISU::Curve_i( aStudy, pTable, 0, 0, 0, false );
+    return pResent->Restore( theMap, theSObject);
   }
   return NULL;
 }
 
+void VISU::Curve_i::RemoveFromStudy()
+{
+  
+  //remove curve from containers
+  PortableServer::POA_ptr aPOA = GetPOA();
+  ContainerSet::ConstIterator it = myContainers.begin();
+  for ( ; it != myContainers.end(); it++ ) {    
+    SALOMEDS::SObject_var aSObject =  GetStudyDocument()->FindObjectID( (*it).toLatin1().data() );
+    if ( aSObject->_is_nil() ) continue;
+    
+    CORBA::Object_var anObj = VISU::SObjectToObject( aSObject );
+    if ( CORBA::is_nil( anObj ) ) continue;
+    VISU::Container_i* aContainer = dynamic_cast<VISU::Container_i*>( VISU::GetServant( anObj.in() ).in() );
+    if ( !aContainer ) continue;
+    aContainer->RemoveCurve(VISU::Curve::_narrow(aPOA->servant_to_reference(this)));
+  }
+
+  struct TRemoveFromStudy: public SALOME_Event
+  {
+    VISU::Curve_i* myRemovable;
+    TRemoveFromStudy(VISU::Curve_i* theRemovable):
+      myRemovable(theRemovable)
+    {}
+    
+    virtual
+    void
+    Execute()
+    {
+      VISU::DeleteActors(myRemovable);
+      VISU::RemoveFromStudy(myRemovable->GetSObject(),false);
+    }
+  };
+
+  ProcessVoidEvent(new TRemoveFromStudy(this));
+}
+
+SALOMEDS::SObject_var VISU::Curve_i::GetSObject()
+{
+  return mySObj;
+}
+
+
+/*!
+  Add container.
+  id  - owner of the curve
+*/
+void VISU::Curve_i::addContainer(const QString& id) {
+  myContainers.insert(id);
+}
+
+/*!
+  Remove Container
+  id  - entry of the container
+*/
+void VISU::Curve_i::removeContainer(const QString& id) {
+  myContainers.insert(id);
+}
+
+/*!
+  Get all owners of the curve.
+  \return owners of the curve.
+*/
+VISU::ContainerSet VISU::Curve_i::getContainers() const {
+  return myContainers;
+}
+
+/*!
+  Return true if on the curve were assigned deviation data
+*/
+bool VISU::Curve_i::hasDeviation() {
+  return myTable && myTable->hasDeviationData(myVRow-1);
+}
+
+/*!
+  Enable/disable deviation data displaying.
+*/
+void  VISU::Curve_i::ShowDeviation(CORBA::Boolean flag) {
+  if(flag && hasDeviation())
+    myDeviationEnabled = flag;
+  else
+    myDeviationEnabled = false;
+}
+/*!
+  Return enable deviation flag
+*/
+bool VISU::Curve_i::isDeviationShown() {
+  return myDeviationEnabled;
+}
+
 //----------------------------------------------------------------
 //                      Container Object
 //----------------------------------------------------------------
 int VISU::Container_i::myNbPresent = 0;
 const string VISU::Container_i::myComment  = "CONTAINER";
-/*! 
+/*!
   Generate unique name
 */
-const char* VISU::Container_i::GenerateName() 
-{ 
-  return VISU::GenerateName( "Container", ++myNbPresent ); 
+QString VISU::Container_i::GenerateName()
+{
+  return VISU::GenerateName( "Plot2DView", ++myNbPresent ).toLatin1().data();
 }
 /*!
   Gets comment string
 */
-const char* VISU::Container_i::GetComment() const 
-{ 
-  return myComment.c_str(); 
+const char* VISU::Container_i::GetComment() const
+{
+  return myComment.c_str();
 }
 /*!
   Constructor
@@ -633,6 +1512,7 @@ VISU::Container_i::Container_i( SALOMEDS::Study_ptr theStudy )
 */
 VISU::Container_i::~Container_i()
 {
+  MESSAGE("Container_i::~Container_i");
   myCurves.clear();
 }
 /*!
@@ -640,21 +1520,22 @@ VISU::Container_i::~Container_i()
 */
 void VISU::Container_i::AddCurve( Curve_ptr theCurve )
 {
-  if ( myStudy->_is_nil() )
+  if ( GetStudyDocument()->_is_nil() )
     return;
-  SALOMEDS::SObject_var mySO = myStudy->FindObjectID( GetEntry() );
+  SALOMEDS::SObject_var mySO = GetStudyDocument()->FindObjectID( GetEntry().c_str() );
   if ( mySO->_is_nil() )
     return;
   PortableServer::POA_ptr aPOA = GetPOA();
   Curve_i* pCurve = dynamic_cast<Curve_i*>( aPOA->reference_to_servant( theCurve ) );
   if( pCurve ) {
-    QString entry = pCurve->GetEntry();
-    SALOMEDS::SObject_var SO = myStudy->FindObjectID( entry.latin1() );
-    if ( !SO->_is_nil() && myCurves.find( entry ) == myCurves.end() ) {
+    QString entry( pCurve->GetEntry().c_str() );
+    SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID( entry.toLatin1().data() );
+    if ( !SO->_is_nil() && myCurves.indexOf( entry ) == -1 ) {
       myCurves.append( entry );
-      SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+      SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
       SALOMEDS::SObject_var newSO = Builder->NewObject( mySO );
       Builder->Addreference( newSO, SO );
+      pCurve->addContainer(GetEntry().c_str());
     }
   }
 }
@@ -663,20 +1544,20 @@ void VISU::Container_i::AddCurve( Curve_ptr theCurve )
 */
 void VISU::Container_i::RemoveCurve( Curve_ptr theCurve )
 {
-  if ( myStudy->_is_nil() )
+  if ( GetStudyDocument()->_is_nil() )
     return;
-  SALOMEDS::SObject_var mySO = myStudy->FindObjectID( GetEntry() );
+  SALOMEDS::SObject_var mySO = GetStudyDocument()->FindObjectID( GetEntry().c_str() );
   if ( mySO->_is_nil() )
     return;
   PortableServer::POA_ptr aPOA = GetPOA();
   Curve_i* pCurve = dynamic_cast<Curve_i*>( aPOA->reference_to_servant( theCurve ) );
   if( pCurve ) {
-    QString entry = pCurve->GetEntry();
-    if ( myCurves.find( entry ) != myCurves.end() ) {
+    QString entry( pCurve->GetEntry().c_str() );
+    if ( myCurves.indexOf( entry ) != -1 ) {
       // found !!!
-      myCurves.remove( entry );
-      SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
-      SALOMEDS::ChildIterator_var CI = myStudy->NewChildIterator( mySO );
+      myCurves.removeAll( entry );
+      SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
+      SALOMEDS::ChildIterator_var CI = GetStudyDocument()->NewChildIterator( mySO );
       for ( ; CI->More(); CI->Next() ) {
        SALOMEDS::SObject_var childSO = CI->Value();
        SALOMEDS::SObject_var refSO;
@@ -684,6 +1565,7 @@ void VISU::Container_i::RemoveCurve( Curve_ptr theCurve )
          Builder->RemoveObject( childSO );
        }
       }
+      pCurve->removeContainer(GetEntry().c_str());
     }
   }
 }
@@ -692,6 +1574,7 @@ void VISU::Container_i::RemoveCurve( Curve_ptr theCurve )
 */
 CORBA::Long VISU::Container_i::GetNbCurves()
 {
+  //  Update();
   return myCurves.count();
 }
 /*!
@@ -699,19 +1582,19 @@ CORBA::Long VISU::Container_i::GetNbCurves()
 */
 void VISU::Container_i::Clear()
 {
-  if ( myStudy->_is_nil() )
+  if ( GetStudyDocument()->_is_nil() )
     return;
-  SALOMEDS::SObject_var mySO = myStudy->FindObjectID( GetEntry() );
+  SALOMEDS::SObject_var mySO = GetStudyDocument()->FindObjectID( GetEntry().c_str() );
   if ( mySO->_is_nil() )
     return;
   QStringList toDelete;
-  SALOMEDS::ChildIterator_var CI = myStudy->NewChildIterator( mySO );
+  SALOMEDS::ChildIterator_var CI = GetStudyDocument()->NewChildIterator( mySO );
   for ( ; CI->More(); CI->Next() ) {
     toDelete.append( CI->Value()->GetID() );
   }
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
   for ( int i = 0; i < toDelete.count(); i++ ) {
-    SALOMEDS::SObject_var SO = myStudy->FindObjectID( toDelete[i].latin1() );
+    SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID( toDelete[i].toLatin1().data() );
     Builder->RemoveObject( SO );
   }
   myCurves.clear();
@@ -721,30 +1604,39 @@ void VISU::Container_i::Clear()
 */
 VISU::Storable* VISU::Container_i::Create()
 {
-  // generate name ... 
-  myName = GenerateName();
+  // generate name ...
+  SetName(GenerateName().toLatin1().data(), false);
   // ... and build the object
   return Build( false );
 }
 /*!
   Builds presentation of container
 */
-VISU::Storable* VISU::Container_i::Build( int theRestoring ) 
+VISU::Storable* VISU::Container_i::Build( int theRestoring )
 {
   if ( !theRestoring ) {
     // looking for component
-    SALOMEDS::SComponent_var SComponent = VISU::FindOrCreateVisuComponent( myStudy );
+    SALOMEDS::SComponent_var SComponent = VISU::FindOrCreateVisuComponent( GetStudyDocument() );
     // create SObject and set attributes
     QString aComment;
-    aComment.sprintf("myComment=%s;myType=%d",GetComment(),VISU::TCONTAINER);
-    string anEntry = CreateAttributes( myStudy, 
+    aComment.sprintf("myComment=%s",GetComment());
+    string anEntry = CreateAttributes( GetStudyDocument(),
                                       SComponent->GetID(),
                                       "",
                                       GetID(),
                                       GetName(),
                                       "",
-                                      aComment.latin1(),
+                                      aComment.toLatin1().data(),
                                       true );
+    mySObj = SALOMEDS::SObject::_duplicate(GetStudyDocument()->FindObjectID(anEntry.c_str()));
+
+    // Set icon
+    SALOMEDS::StudyBuilder_var aStudyBuilder = GetStudyDocument()->NewBuilder();
+    SALOMEDS::GenericAttribute_var anAttr;
+    SALOMEDS::AttributePixMap_var  aPixmap;
+    anAttr  = aStudyBuilder->FindOrCreateAttribute( mySObj, "AttributePixMap" );
+    aPixmap = SALOMEDS::AttributePixMap::_narrow( anAttr );
+    aPixmap ->SetPixMap("ICON_TREE_CONTAINER");
   }
   return this;
 }
@@ -753,19 +1645,19 @@ VISU::Storable* VISU::Container_i::Build( int theRestoring )
 */
 void VISU::Container_i::Update()
 {
-  if ( myStudy->_is_nil() )
+  if ( GetStudyDocument()->_is_nil() )
     return;
-  SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
-  SALOMEDS::SObject_var mySO = myStudy->FindObjectID( GetEntry() );
+  SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
+  SALOMEDS::SObject_var mySO = GetStudyDocument()->FindObjectID( GetEntry().c_str() );
   SALOMEDS::GenericAttribute_var anAttr;
   if ( !mySO->_is_nil() ) {
     QStringList toDelete;
     int i;
     for ( i = 0; i < myCurves.count(); i++ ) {
-      SALOMEDS::SObject_var SO = myStudy->FindObjectID( myCurves[i].latin1() );
+      SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID( myCurves[i].toLatin1().data() );
       if ( !SO->_is_nil() && Builder->FindAttribute( SO, anAttr, "AttributeIOR" ) ) {
-       // if real Curve Object still exists 
-       SALOMEDS::ChildIterator_var CI = myStudy->NewChildIterator( mySO );
+       // if real Curve Object still exists
+       SALOMEDS::ChildIterator_var CI = GetStudyDocument()->NewChildIterator( mySO );
        bool bFound = false;
        for ( ; CI->More(); CI->Next() ) {
          SALOMEDS::SObject_var childSO = CI->Value();
@@ -785,21 +1677,21 @@ void VISU::Container_i::Update()
        toDelete.append( myCurves[i] );
       }
     }
-    for ( i = 0; i < toDelete.count(); i++ ) { 
-      myCurves.remove( toDelete[i] );
+    for ( i = 0; i < toDelete.count(); i++ ) {
+      myCurves.removeAll( toDelete[i] );
     }
     toDelete.clear();
-    SALOMEDS::ChildIterator_var CI = myStudy->NewChildIterator( mySO );
+    SALOMEDS::ChildIterator_var CI = GetStudyDocument()->NewChildIterator( mySO );
     for ( ; CI->More(); CI->Next() ) {
       SALOMEDS::SObject_var childSO = CI->Value();
       SALOMEDS::SObject_var refSO;
       if ( childSO->ReferencedObject( refSO ) && ( refSO->_is_nil() || !Builder->FindAttribute( refSO, anAttr, "AttributeIOR" ) ||
-                                                  myCurves.find( refSO->GetID() ) == myCurves.end() ) ) {
+                                                  myCurves.indexOf( refSO->GetID() ) == -1 ) ) {
        toDelete.append( childSO->GetID() );
       }
     }
-    for ( i = 0; i < toDelete.count(); i++ ) { 
-      SALOMEDS::ChildIterator_var CI = myStudy->NewChildIterator( mySO );
+    for ( i = 0; i < toDelete.count(); i++ ) {
+      SALOMEDS::ChildIterator_var CI = GetStudyDocument()->NewChildIterator( mySO );
       for ( ; CI->More(); CI->Next() ) {
        SALOMEDS::SObject_var childSO = CI->Value();
        if ( toDelete[i] == CI->Value()->GetID() ) {
@@ -816,15 +1708,15 @@ void VISU::Container_i::Update()
 VISU::Curve_i* VISU::Container_i::GetCurve( CORBA::Long theIndex )
 {
   if ( theIndex > 0 && theIndex <= myCurves.count()  ) {
-    SALOMEDS::StudyBuilder_var Builder = myStudy->NewBuilder();
+    SALOMEDS::StudyBuilder_var Builder = GetStudyDocument()->NewBuilder();
     SALOMEDS::GenericAttribute_var anAttr;
-    SALOMEDS::SObject_var SO = myStudy->FindObjectID( myCurves[  theIndex-1 ].latin1() );
+    SALOMEDS::SObject_var SO = GetStudyDocument()->FindObjectID(myCurves[ theIndex-1 ].toLatin1().data() );
     CORBA::Object_var anObject = VISU::SObjectToObject( SO );
     if( !CORBA::is_nil( anObject ) ) {
-      // if real Curve Object exists 
+      // if real Curve Object exists
       CORBA::Object_ptr aCurve = VISU::Curve::_narrow( anObject );
       if( !CORBA::is_nil( aCurve ) )
-      return dynamic_cast<VISU::Curve_i*>(VISU::GetServant( aCurve ) );
+      return dynamic_cast<VISU::Curve_i*>(VISU::GetServant(aCurve).in());
     }
   }
   return NULL;
@@ -832,13 +1724,13 @@ VISU::Curve_i* VISU::Container_i::GetCurve( CORBA::Long theIndex )
 /*!
   Restores container data from the stream
 */
-VISU::Storable* VISU::Container_i::Restore( const Storable::TRestoringMap& theMap )
-     throw( std::logic_error& )
+VISU::Storable* VISU::Container_i::Restore( const Storable::TRestoringMap& theMap, SALOMEDS::SObject_ptr SO )
 {
   if(MYDEBUG) MESSAGE(GetComment());
-  myName = (const char*)(VISU::Storable::FindValue( theMap, "myName" )); 
+  mySObj = SALOMEDS::SObject::_duplicate(SO);
+  SetName(VISU::Storable::FindValue( theMap, "myName" ).toLatin1().data(), false);
   QString val = VISU::Storable::FindValue( theMap, "myCurves" );
-  myCurves = QStringList::split( QString( "*" ), val, false );
+  myCurves = val.split( "*", QString::SkipEmptyParts );
   return Build( true );
 }
 /*!
@@ -846,7 +1738,7 @@ VISU::Storable* VISU::Container_i::Restore( const Storable::TRestoringMap& theMa
 */
 void VISU::Container_i::ToStream( std::ostringstream& theStr )
 {
-  Storable::DataToStream( theStr, "myName",   myName.c_str() );
+  Storable::DataToStream( theStr, "myName",   GetName().c_str() );
   Storable::DataToStream( theStr, "myCurves", myCurves.join( QString( "*" ) ) );
 //  theStr<<" myName "<<myName;
 //  theStr<<" myCurves "<<myCurves.join( QString( "*" ) ).latin1()<<"* ";
@@ -854,247 +1746,351 @@ void VISU::Container_i::ToStream( std::ostringstream& theStr )
 /*!
   Called from engine to restore container from the file
 */
-VISU::Storable* VISU::ContainerRestore(SALOMEDS::SObject_ptr theSObject, 
-                                      const string& thePrefix, const Storable::TRestoringMap& theMap)
+VISU::Storable* VISU::Container_i::StorableEngine(SALOMEDS::SObject_ptr theSObject,
+                                                 const Storable::TRestoringMap& theMap,
+                                                 const std::string& thePrefix,
+                                                 CORBA::Boolean theIsMultiFile)
 {
   SALOMEDS::Study_var aStudy = theSObject->GetStudy();
   VISU::Container_i* pResent = new VISU::Container_i( aStudy );
-  return pResent->Restore( theMap );
-}
-
-//-------------------------------------------------------------
-//             Implementation of reading from file
-//-------------------------------------------------------------
-typedef vector<float> TValues;
-
-struct TRow{
-  string myTitle;
-  string myUnit;
-  TValues myValues;
-};
-
-typedef vector<TRow> TRows;
-
-struct TTable2D{
-  string myTitle;
-  vector<string> myColumnUnits;
-  vector<string> myColumnTitles;
-  TRows myRows;
-  int Check(){
-    if(myRows.empty()) return 0;
-    int iEnd = myRows[0].myValues.size();
-    if(iEnd == 0) return 0;
-    if(myColumnTitles.size() != iEnd) myColumnTitles.resize(iEnd);
-    if(myColumnUnits.size() != iEnd) myColumnUnits.resize(iEnd);
-    int jEnd = myRows.size();
-    for(int j = 0; j < jEnd; j++)
-      if(myRows[j].myValues.size() != iEnd) return 0;
-    return 1;
-  }
-  void getColumns(TTable2D& theTable2D) const {
-    TRows& aRows = theTable2D.myRows;
-    aRows.clear();
-    if(myRows.empty()) return;
-    int jEnd = myRows.size();
-    //Define Titles & Units
-    theTable2D.myColumnTitles.resize(jEnd);
-    theTable2D.myColumnUnits.resize(jEnd);
-    for(int j = 0; j < jEnd; j++){
-      theTable2D.myColumnTitles[j] = myRows[j].myTitle;
-      theTable2D.myColumnUnits[j] = myRows[j].myUnit;
-    }
-    //Define Rows
-    int iEnd = myRows[0].myValues.size();
-    for(int i = 0; i < iEnd; i++){
-      TRow aNewRow;
-      aNewRow.myTitle = myColumnTitles[i];
-      aNewRow.myUnit = myColumnUnits[i];
-      aNewRow.myValues.resize(jEnd);
-      for(int j = 0; j < jEnd; j++){
-       aNewRow.myValues[j] = myRows[j].myValues[i];
-      }
-      aRows.push_back(aNewRow);
+  return pResent->Restore( theMap, theSObject );
+}
+
+void VISU::Container_i::RemoveFromStudy()
+{
+  struct TRemoveFromStudy: public SALOME_Event
+  {
+    VISU::Container_i* myRemovable;
+    TRemoveFromStudy(VISU::Container_i* theRemovable):
+      myRemovable(theRemovable)
+    {}
+    
+    virtual
+    void
+    Execute()
+    {
+      VISU::RemoveFromStudy(myRemovable->GetSObject(),false);
     }
-  }
-};
+  };
 
-typedef vector<TTable2D> TTableCont;
+  ProcessVoidEvent(new TRemoveFromStudy(this));
+}
 
-int getLine(ifstream& theStmIn, QString& theString){
-  char tmp;
-  ostrstream aStrOut;
-  while(theStmIn.get(tmp)){
-    aStrOut<<tmp;
-    if(tmp == '\n') break;
-  }
-  aStrOut<<ends;
-  auto_ptr<char> aRet(aStrOut.str());
-  theString = aRet.get();
-  return !theStmIn.eof();
-}
-
-void ImportTables(const char* theFileName, TTableCont& theTableCont){
-  ifstream aStmIn;
-  aStmIn.open(theFileName);
-  QString aTmp;
-  do{
-    //Find beginning of Table
-    while(getLine(aStmIn,aTmp) && aTmp == "\n");
-    //cout<<"\n There is new Table2D with Title = ";
-    TTable2D aTable2D;
-    while(!aStmIn.eof() && aTmp != "\n"){
-      if(aTmp.find("#TITLE:") == 0){
-       int aLen = aTmp.find(":") + 1;
-       aTmp.remove(0,aLen);
-       QString aTitle = aTmp.stripWhiteSpace();
-       aTable2D.myTitle = (const char*)aTitle;
-       //cout<<aTitle<<endl;
-      }else if(aTmp.find("#COLUMN_TITLES:") == 0){
-       int aLen = aTmp.find(":") + 1;
-       aTmp.remove(0,aLen);
-       QStringList aStrList = QStringList::split("|",aTmp);
-       //cout<<"Its Column Titles : ";
-       for(int i = 0; i < aStrList.count(); i++){
-         aTmp = aStrList[i].stripWhiteSpace();
-         aTable2D.myColumnTitles.push_back(aTmp.latin1());
-         //cout<<"\t"<<aTmp;
-       }
-       //cout<<endl;
-      }else if(aTmp.find("#COLUMN_UNITS:") == 0){
-       int aLen = aTmp.find(":") + 1;
-       aTmp.remove(0,aLen);
-       QStringList aStrList = QStringList::split(" ",aTmp);
-       //cout<<"Its Column Units : ";
-       for(int i = 0; i < aStrList.count(); i++){
-         aTmp = aStrList[i].stripWhiteSpace();
-         aTable2D.myColumnUnits.push_back(aTmp.latin1());
-         //cout<<"\t"<<aTmp;
-       }
-       //cout<<endl;
-      }else if(aTmp.find("#") == 0){
-       //It is a comment
-      }else if(aTmp.find("#TITLE:") > 0){
-       QStringList aStrList = QStringList::split("#TITLE:",aTmp);
-       QString aTitle = aStrList[1].stripWhiteSpace();
-       TRow aRow; 
-       aRow.myTitle = (const char*)aTitle;
-       //cout<<aTitle<<" : ";
-       QStringList aValList = QStringList::split(" ",aStrList[0]);
-       for(int i = 0; i < aValList.count(); i++){
-         float aVal = aValList[i].toFloat();
-         aRow.myValues.push_back(aVal);
-         //cout<<"\t"<<aVal;
-       }
-       aTable2D.myRows.push_back(aRow);
-       //cout<<endl;
-      }else{
-       QStringList aValList = QStringList::split(" ",aTmp);
-       TRow aRow; 
-       for(int i = 0; i < aValList.count(); i++){
-         float aVal = aValList[i].toFloat();
-         aRow.myValues.push_back(aVal);
-         //cout<<"\t"<<aVal;
-       }
-       aTable2D.myRows.push_back(aRow);
-       //cout<<endl;
-      }
-      getLine(aStmIn,aTmp);
-    }
-    if(aTable2D.Check()){
-      //cout<<"aTable2D checked "<<aTable2D.myTitle<<endl;
-      theTableCont.push_back(aTable2D);
-    }
-  }while(!aStmIn.eof());
-  aStmIn.close();
-  //cout<<"After close"<<endl;
+SALOMEDS::SObject_var VISU::Container_i::GetSObject()
+{
+  return mySObj;
 }
 
-SALOMEDS::SObject_var VISU::ImportTables(const char* theFileName, SALOMEDS::Study_ptr theStudy){
-  TTableCont aTableCont;
-  ImportTables(theFileName,aTableCont);
-  if(aTableCont.empty()) return SALOMEDS::SObject::_nil();
+SALOMEDS::SObject_var
+VISU::ImportTables(const char* theFileName, SALOMEDS::Study_ptr theStudy,
+                   bool theFirstStrAsTitle)
+{
+  // Set "C" numeric locale to import numbers correctly
+  Kernel_Utils::Localizer loc;
+
+  TTableContainer aContainer;
+  ImportTables( theFileName, aContainer, theFirstStrAsTitle );
+  if ( aContainer.empty() ) 
+    return SALOMEDS::SObject::_nil();
+
   SALOMEDS::StudyBuilder_var aStudyBuilder = theStudy->NewBuilder();
   SALOMEDS::SComponent_var theSComponent = VISU::FindOrCreateVisuComponent(theStudy);
   SALOMEDS::SObject_var aFileObject = aStudyBuilder->NewObject(theSComponent);
-  SALOMEDS::GenericAttribute_var anAttr = 
+  SALOMEDS::GenericAttribute_var anAttr =
     aStudyBuilder->FindOrCreateAttribute(aFileObject, "AttributeName");
   SALOMEDS::AttributeName_var aName = SALOMEDS::AttributeName::_narrow(anAttr);
   QFileInfo aFileInfo(theFileName);
-  aName->SetValue(aFileInfo.fileName().latin1());
-  int iEnd = aTableCont.size();
-  /*
-  for(int i = 0, iEnd = aTableCont.size(); i < iEnd; i++){
-    const TTable2D& aTable2D = aTableCont[i];
+  aName->SetValue( aFileInfo.fileName().toLatin1().data());
+  anAttr = aStudyBuilder->FindOrCreateAttribute(aFileObject, "AttributeString");
+  SALOMEDS::AttributeString_var aComment = SALOMEDS::AttributeString::_narrow(anAttr);
+  QString aString;
+  aString.sprintf("myComment=ImportTables;myFileName=%s;myFirstStrAsTitle=%d",
+                 aFileInfo.absoluteFilePath().toLatin1().data(),theFirstStrAsTitle);
+  aComment->SetValue(aString.toLatin1().data());
+  for(int i = 0, iEnd = aContainer.size(); i < iEnd; i++) {
+    PTableIDMapper aTableIDMapper = aContainer[i];
+    const TTable2D& aTable2D = *aTableIDMapper;
     SALOMEDS::SObject_var aRealObject = aStudyBuilder->NewObject(aFileObject);
     anAttr = aStudyBuilder->FindOrCreateAttribute(aRealObject, "AttributeName");
     aName = SALOMEDS::AttributeName::_narrow(anAttr);
-    cout<<"aTable2D.myTitle = "<<aTable2D.myTitle<<endl;
-    if(aTable2D.myTitle != "")
+    if(MYDEBUG) MESSAGE("aTable2D.myTitle = "<<aTable2D.myTitle);
+    if ( aTable2D.myTitle != "" ) {
       aName->SetValue(aTable2D.myTitle.c_str());
-    else{
-      QString aNewName;
-      aNewName.sprintf("Table:%d",i);
-      aName->SetValue(aNewName.latin1());
     }
-    anAttr = aStudyBuilder->FindOrCreateAttribute(aRealObject, "AttributeTableOfReal");
-    SALOMEDS::AttributeTableOfReal_var aTableOfReal = SALOMEDS::AttributeTableOfReal::_narrow(anAttr);
-    aTableOfReal->SetTitle(aTable2D.myTitle.c_str());
-    const TRows& aRows = aTable2D.myRows;
-    //aTable2D.getColumns(aRows);
-    int kEnd = aRows[0].myValues.size();
-    aTableOfReal->SetNbColumns(kEnd);
-    for(int j = 0, jEnd = aRows.size(); j < jEnd; j++){
-      cout<<"j = "<<j<<endl;
-      const TRow& aRow = aRows[j];
-      SALOMEDS::DoubleSeq_var aDoubleSeq = new SALOMEDS::DoubleSeq();
-      int kEnd = aRow.myValues.size();
-      aDoubleSeq->length(kEnd);
-      cout<<"kEnd = "<<kEnd<<endl;
-      for(int k = 0; k < kEnd; k++) aDoubleSeq[k] = aRow.myValues[k];
-      aTableOfReal->AddRow(aDoubleSeq.in());
-      aTableOfReal->SetRowTitle(j+1,aRow.myTitle.c_str());
-      aTableOfReal->SetRowUnit(j+1,aRow.myUnit.c_str());
-    }
-    for(int k = 0; k < kEnd; k++){
-      aTableOfReal->SetColumnTitle(k+1,aTable2D.myColumnTitles[k].c_str());
-      //aTableOfReal->SetColumnUnit(k+1,aTable2D.myColumnUnits[k].c_str());
-    }
-  }
-  */
-  for(int i = 0, iEnd = aTableCont.size(); i < iEnd; i++){
-    const TTable2D& aTable2D = aTableCont[i];
-    SALOMEDS::SObject_var aRealObject = aStudyBuilder->NewObject(aFileObject);
-    anAttr = aStudyBuilder->FindOrCreateAttribute(aRealObject, "AttributeName");
-    aName = SALOMEDS::AttributeName::_narrow(anAttr);
-    //cout<<"aTable2D.myTitle = "<<aTable2D.myTitle<<endl;
-    if(aTable2D.myTitle != "")
-      aName->SetValue(aTable2D.myTitle.c_str());
-    else{
+    else {
       QString aNewName;
       aNewName.sprintf("Table:%d",i);
-      aName->SetValue(aNewName.latin1());
+      aName->SetValue(aNewName.toLatin1().data());
     }
+
     anAttr = aStudyBuilder->FindOrCreateAttribute(aRealObject, "AttributeTableOfReal");
     SALOMEDS::AttributeTableOfReal_var aTableOfReal = SALOMEDS::AttributeTableOfReal::_narrow(anAttr);
     aTableOfReal->SetTitle(aTable2D.myTitle.c_str());
     TTable2D aNewTable2D;
     aTable2D.getColumns(aNewTable2D);
     int kEnd = aNewTable2D.myRows[0].myValues.size();
-    aTableOfReal->SetNbColumns(kEnd);
-    for(int j = 0, jEnd = aNewTable2D.myRows.size(); j < jEnd; j++){
-      //cout<<"j = "<<j<<endl;
-      SALOMEDS::DoubleSeq_var aDoubleSeq = new SALOMEDS::DoubleSeq();
-      aDoubleSeq->length(kEnd);
-      //cout<<"kEnd = "<<kEnd<<endl;
-      for(int k = 0; k < kEnd; k++) aDoubleSeq[k] = aNewTable2D.myRows[j].myValues[k];
-      aTableOfReal->AddRow(aDoubleSeq.in());
-      aTableOfReal->SetRowTitle(j+1,aNewTable2D.myRows[j].myTitle.c_str());
-      aTableOfReal->SetRowUnit(j+1,aNewTable2D.myRows[j].myUnit.c_str());
+    // check empty columns
+    TColStd_MapOfInteger EmptyColumns;
+    for(int j = 0, jEnd = aNewTable2D.myRows.size(); j < jEnd; j++) {
+      bool hasVal = false;
+      for(int k = 0; k < kEnd; k++) {
+       QString aVal = aNewTable2D.myRows[j].myValues[k].c_str();
+       bool anIsOk = false;
+       double aValue = aVal.toDouble(&anIsOk);
+        if(anIsOk) {
+          hasVal = true;
+          break;
+        }
+      }
+      if(!hasVal) {
+        EmptyColumns.Add(j);
+      }
     }
-    for(int k = 0; k < kEnd; k++){
-      aTableOfReal->SetColumnTitle(k+1,aNewTable2D.myColumnTitles[k].c_str());
-      //aTableOfReal->SetColumnUnit(k+1,aTable2D.myColumnUnits[k].c_str());
+    // create table of real
+    aTableOfReal->SetNbColumns( kEnd - EmptyColumns.Extent() );
+    int currNum = -1;
+    for(int j = 0, jEnd = aNewTable2D.myRows.size(); j < jEnd; j++) {
+      if( EmptyColumns.Contains(j) ) continue;
+      currNum++;
+      if(MYDEBUG) MESSAGE("j = "<<j<<"; kEnd = "<<kEnd);
+      for(int k = 0; k < kEnd; k++) {
+       QString aVal = aNewTable2D.myRows[j].myValues[k].c_str();
+       bool anIsOk = false;
+       double aValue = aVal.toDouble(&anIsOk);
+       if( anIsOk && !aVal.contains("NAN",Qt::CaseInsensitive) &&
+            !aVal.contains("INF",Qt::CaseInsensitive) ) {
+         aTableOfReal->PutValue(aValue,currNum+1,k+1);
+        }
+      }
+      aTableOfReal->SetRowTitle(currNum+1,aNewTable2D.myRows[j].myTitle.c_str());
+      aTableOfReal->SetRowUnit(currNum+1,aNewTable2D.myRows[j].myUnit.c_str());
     }
+    for(int k = 0; k < kEnd; k++)
+      aTableOfReal->SetColumnTitle(k+1,aNewTable2D.myColumnTitles[k].c_str());
   }
   return aFileObject;
 }
+
+
+//=======================================================================
+//function : updateStrForCSV
+//purpose  : auxilary for ExportTableToFile
+//=======================================================================
+void updateStrForCSV(QString& aStr, const char aSep)
+{
+  int index = aStr.indexOf('"');
+  while(index>=0) {
+    aStr.insert(index,'"');
+    if( index+2 >= aStr.size() ) break;
+    index = aStr.indexOf('"',index+2);
+  }
+  index = aStr.indexOf(aSep);
+  if(index>=0) {
+    // current string contains separator => need to use "..."
+    aStr.insert(0,'"');
+    aStr.push_back('"');
+  }
+}
+
+
+//=======================================================================
+//function : ExportTableToFile
+//purpose  : 
+//=======================================================================
+template<class TTableAttr> bool ExportTableToFile(const TTableAttr& aTabAttr,
+                                                 const char* theFileName)
+{
+  if (CORBA::is_nil(aTabAttr))
+    return false;
+
+  // Set "C" numeric locale to save numbers correctly
+  Kernel_Utils::Localizer loc;
+
+  QFile aFile(theFileName);
+  aFile.open(QIODevice::WriteOnly);
+
+  /* extract the table info and write it into file */
+
+  QString aTitle(aTabAttr->GetTitle()); /*Table title*/
+  int aRowsNb = aTabAttr->GetNbRows();
+  int aColNb  = aTabAttr->GetNbColumns();
+
+  SALOMEDS::StringSeq_var aRowTitles = aTabAttr->GetRowTitles();
+  SALOMEDS::StringSeq_var aRowUnits = aTabAttr->GetRowUnits();
+  SALOMEDS::StringSeq_var aColumnTitles = aTabAttr->GetColumnTitles();
+
+  //--------------------------------------------------
+  //    write as *.csv file if it is needed
+  //--------------------------------------------------
+  QString tmp(theFileName);
+  tmp = tmp.trimmed();
+  tmp = tmp.right(3).trimmed();
+  if( tmp == QString("csv") ) {
+    const char aSep = ',';
+    // write column titles
+    QString aLine(aRowTitles[0]);
+    updateStrForCSV(aLine,aSep);
+    for(int i=1; i<aRowsNb; i++) {
+      aLine += aSep;
+      QString aTmp(aRowTitles[i]);
+      updateStrForCSV(aTmp,aSep);
+      aLine += aTmp;
+    }
+    aLine += "\n";
+    aFile.write(aLine.toLatin1() );
+    // write table data
+    QString aValue;
+    for (int j = 1; j <= aColNb; j++) {
+      QString aLine = "";
+      if(aTabAttr->HasValue(1,j)) {
+        aLine = aValue.sprintf("%.16g",(double)aTabAttr->GetValue(1,j));
+      }
+      for (int i = 2; i <= aRowsNb; i++) {
+        if(aTabAttr->HasValue(i,j)) {
+          aLine += aSep + aValue.sprintf("%.16g",(double)aTabAttr->GetValue(i,j));
+        }
+        else aLine += aSep;
+      }
+      aLine += "\n";
+      aFile.write(aLine.toLatin1() );
+    }
+
+    aFile.close();
+    return true;
+  }
+  //--------------------------------------------------
+  //       end of writing as *.csv file
+  //--------------------------------------------------
+
+  /* The given table is rare (some cells is empty) or not? */
+  bool isRareTable = false;
+  for (int i = 1; i <= aRowsNb; i++)
+    for (int j = 1; j <= aColNb && !isRareTable; j++)
+      isRareTable = !aTabAttr->HasValue(i,j);
+
+  QString aLine;
+  if (isRareTable) {
+    /* Separate the given table to 2D tables and write these ones to the file */
+    QString anAbscissTitle(aRowTitles[0]); /*Absciss row title (X coord)*/
+    anAbscissTitle.trimmed();
+    QString anAbscissUnit(aRowUnits[0]);
+    anAbscissUnit.trimmed();
+    if (aRowsNb > 2 && aTitle.length() )  aTitle = aTitle + " - ";
+
+    for (int i = 2; i <= aRowsNb; i++ )
+      {
+       /* TITLE */
+       QString anOrdinate(aRowTitles[i-1]), aTail;
+       anOrdinate.trimmed();
+
+       aLine = "#TITLE: " + aTitle +
+         ((anOrdinate.length())?  anOrdinate :
+                                 (aRowsNb>2)? aTail.sprintf("%d",i-1) : aTail.sprintf("") ) + "\n";
+       aFile.write(aLine.toLatin1() );
+
+       /* COLUMN_TITLES */
+       if ( anAbscissTitle.length() || anOrdinate.length() ) {
+         aLine = "#COLUMN_TITLES: " + anAbscissTitle + " | " + anOrdinate;
+          int tmpind = aLine.indexOf("\n");
+          while(tmpind>=0) {
+            aLine.remove(tmpind,1);
+            tmpind = aLine.indexOf("\n");
+          }
+         aLine += "\n";
+         aFile.write(aLine.toLatin1() );
+       }
+
+       /* COLUMN_UNITS */
+       aLine = anAbscissUnit + " " +aRowUnits[i-1];
+       if (!aLine.trimmed().isEmpty()) {
+         aLine = "#COLUMN_UNITS: " + aLine  + "\n";
+         aFile.write(aLine.toLatin1() );
+       }
+
+       /* CURVE COORDINATES */
+       for (int j = 1; j <= aColNb; j++)
+         {
+           if ( aTabAttr -> HasValue(i,j) &&  aTabAttr -> HasValue(1, j)) {
+             aLine = aLine.sprintf("%.16g %.16g",
+                                   (double)(aTabAttr->GetValue(1,j)),
+                                   (double)(aTabAttr->GetValue(i,j)));  /* aTabAttr->GetValue(1,j) - X coord */
+             if ( !aLine.trimmed().isEmpty() ) {
+               QString aColTitle(aColumnTitles[j-1]);
+               if ( !aColTitle.trimmed().isEmpty() )
+                 aLine = aLine + "  #TITLE: " + aColTitle ;
+               aFile.write(QString(aLine + "\n").toLatin1() );
+             }
+           }
+         }
+       aFile.write("\n", 1);
+      }
+  }//end of if (isRareTable)
+  else {
+    /* Write the table in the file without separating */
+    /* TITLE */
+    aLine = "#TITLE: " + aTitle + "\n";
+    aFile.write(aLine.toLatin1());
+
+    /* COLUMN_TITLES  and COLUMN_UNITS */
+    QString aTitlesSep = "";
+    QString aUnitsSep  = "";
+    QString aTitlesStr = "#COLUMN_TITLES: ";
+    QString aUnitsStr  = "#COLUMN_UNITS: ";
+    for (int i = 1; i <= aRowsNb; i++) {
+      if (!QString(aRowTitles[i-1]).trimmed().isEmpty()) {
+        aTitlesStr += (aTitlesSep + aRowTitles[i-1]);
+        if (aTitlesSep.isEmpty()) aTitlesSep = " | ";
+      }
+      if (!QString(aRowUnits[i-1]).trimmed().isEmpty()) {
+        aUnitsStr += (aUnitsSep + aRowUnits[i-1]);
+        if (aUnitsSep.isEmpty()) aUnitsSep = " ";
+      }
+    }
+    int tmpind = aTitlesStr.indexOf("\n");
+    while(tmpind>=0) {
+      aTitlesStr.remove(tmpind,1);
+      tmpind = aTitlesStr.indexOf("\n");
+    }
+    aTitlesStr += "\n";
+    aUnitsStr  += "\n";
+    aFile.write(aTitlesStr.toLatin1());
+    aFile.write(aUnitsStr.toLatin1());
+
+    /* CURVE COORDINATES */
+    QString aSep, aValue, aColTitle;
+    for (int j = 1; j <= aColNb; j++) {
+      aLine = ""; aSep  = "";
+      for (int i = 1; i <= aRowsNb; i++) {
+        aLine += (aSep + aValue.sprintf("%.16g", (double)(aTabAttr->GetValue(i,j))));
+        if (aSep.isEmpty()) aSep = " ";
+      }
+      if (!aLine.trimmed().isEmpty()) {
+        aColTitle = aColumnTitles[j-1];
+        if (!aColTitle.trimmed().isEmpty())
+          aLine = aLine + "  #TITLE: " + aColTitle;
+        aLine += "\n";
+        aFile.write(aLine.toLatin1());
+      }
+    }
+  } //end of else
+
+  aFile.close();
+  return true;
+}
+
+bool VISU::ExportTableToFile(SALOMEDS::SObject_ptr theTable, const char* theFileName)
+{
+  //Find table
+  SALOMEDS::GenericAttribute_var anAttr ;
+  if (theTable->FindAttribute(anAttr, "AttributeTableOfReal")) {
+    SALOMEDS::AttributeTableOfReal_var aTabAttr =
+      SALOMEDS::AttributeTableOfReal ::_narrow(anAttr);
+    return ExportTableToFile ( aTabAttr , theFileName);
+  }
+  else if (theTable->FindAttribute(anAttr, "AttributeTableOfInteger")) {
+    SALOMEDS::AttributeTableOfInteger_var aTabAttr =
+      SALOMEDS::AttributeTableOfInteger ::_narrow(anAttr);
+    return ExportTableToFile ( aTabAttr , theFileName);
+  }
+  return false;
+}