Salome HOME
0023614: EDF 16256 - Coordinates of a group
authoreap <eap@opencascade.com>
Mon, 28 Jan 2019 12:04:53 +0000 (15:04 +0300)
committereap <eap@opencascade.com>
Mon, 28 Jan 2019 12:04:53 +0000 (15:04 +0300)
17 files changed:
idl/SMESH_Filter.idl
src/Controls/SMESH_Controls.cxx
src/Controls/SMESH_ControlsDef.hxx
src/SMESHGUI/CMakeLists.txt
src/SMESHGUI/SMESHGUI_FilterDlg.cxx
src/SMESHGUI/SMESHGUI_MeshInfo.cxx
src/SMESHGUI/SMESHGUI_MeshInfo.h
src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx
src/SMESHGUI/SMESHGUI_SelectionProxy.cxx [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_SelectionProxy.h [new file with mode: 0644]
src/SMESHGUI/SMESH_msg_en.ts
src/SMESHGUI/SMESH_msg_fr.ts
src/SMESHGUI/SMESH_msg_ja.ts
src/SMESH_I/SMESH_Filter_i.cxx
src/SMESH_I/SMESH_Filter_i.hxx
src/SMESH_I/SMESH_Mesh_i.cxx
src/SMESH_I/SMESH_PythonDump.cxx

index 85ae6dc..9d45d6e 100644 (file)
@@ -61,6 +61,7 @@ module SMESH
     FT_MultiConnection2D,
     FT_Length,
     FT_Length2D,
+    FT_Length3D,
     FT_Deflection2D,
     FT_NodeConnectivityNumber,
     FT_BelongToMeshGroup,
@@ -118,7 +119,8 @@ module SMESH
   */
   interface NumericalFunctor: Functor
   {
-    double GetValue( in long theElementId );
+    double  GetValue    ( in long theElementId );
+    boolean IsApplicable( in long theElementId );
 
     Histogram GetHistogram     ( in short nbIntervals, in boolean isLogarithmic );
     Histogram GetLocalHistogram( in short nbIntervals, in boolean isLogarithmic,
@@ -151,6 +153,7 @@ module SMESH
     typedef sequence<Value> Values;
     Values GetValues();
   };
+  interface Length3D          : NumericalFunctor{};
   interface Deflection2D      : NumericalFunctor{};
   interface MultiConnection   : NumericalFunctor{};
   interface MultiConnection2D : NumericalFunctor
@@ -588,6 +591,7 @@ module SMESH
     MaxElementLength3D CreateMaxElementLength3D();
     Length             CreateLength();
     Length2D           CreateLength2D();
+    Length3D           CreateLength3D();
     Deflection2D       CreateDeflection2D();
     MultiConnection    CreateMultiConnection();
     MultiConnection2D  CreateMultiConnection2D();
index 719cd64..ae66e14 100644 (file)
@@ -233,7 +233,7 @@ bool NumericalFunctor::GetPoints(const int       theId,
     return false;
 
   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
-  if ( !anElem || anElem->GetType() != this->GetType() )
+  if ( !IsApplicable( anElem ))
     return false;
 
   return GetPoints( anElem, theRes );
@@ -294,6 +294,24 @@ double NumericalFunctor::Round( const double & aVal )
 
 //================================================================================
 /*!
+ * \brief Return true if a value can be computed for a given element.
+ *        Some NumericalFunctor's are meaningful for elements of a certain
+ *        geometry only.
+ */
+//================================================================================
+
+bool NumericalFunctor::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return element && element->GetType() == this->GetType();
+}
+
+bool NumericalFunctor::IsApplicable( long theElementId ) const
+{
+  return IsApplicable( myMesh->FindElement( theElementId ));
+}
+
+//================================================================================
+/*!
  * \brief Return histogram of functor values
  *  \param nbIntervals - number of intervals
  *  \param nbEvents - number of mesh elements having values within i-th interval
@@ -901,6 +919,11 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P )
   return 0;
 }
 
+bool AspectRatio::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) && !element->IsPoly() );
+}
+
 double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const
 {
   // the aspect ratio is in the range [1.0,infinity]
@@ -1007,6 +1030,11 @@ double AspectRatio3D::GetValue( long theId )
   return aVal;
 }
 
+bool AspectRatio3D::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) && !element->IsPoly() );
+}
+
 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
 {
   double aQuality = 0.0;
@@ -1015,11 +1043,11 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
   int nbNodes = P.size();
 
   if( myCurrElement->IsQuadratic() ) {
-    if(nbNodes==10) nbNodes=4; // quadratic tetrahedron
+    if     (nbNodes==10) nbNodes=4; // quadratic tetrahedron
     else if(nbNodes==13) nbNodes=5; // quadratic pyramid
     else if(nbNodes==15) nbNodes=6; // quadratic pentahedron
     else if(nbNodes==20) nbNodes=8; // quadratic hexahedron
-    else if(nbNodes==27) nbNodes=8; // quadratic hexahedron
+    else if(nbNodes==27) nbNodes=8; // tri-quadratic hexahedron
     else return aQuality;
   }
 
@@ -1296,6 +1324,11 @@ SMDSAbs_ElementType AspectRatio3D::GetType() const
 */
 //================================================================================
 
+bool Warping::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return NumericalFunctor::IsApplicable( element ) && element->NbNodes() == 4;
+}
+
 double Warping::GetValue( const TSequenceOfXYZ& P )
 {
   if ( P.size() != 4 )
@@ -1360,6 +1393,11 @@ SMDSAbs_ElementType Warping::GetType() const
 */
 //================================================================================
 
+bool Taper::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) && element->NbNodes() == 4 );
+}
+
 double Taper::GetValue( const TSequenceOfXYZ& P )
 {
   if ( P.size() != 4 )
@@ -1418,6 +1456,11 @@ static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ
   return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0. : v1.Angle( v2 );
 }
 
+bool Skew::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) && element->NbNodes() <= 4 );
+}
+
 double Skew::GetValue( const TSequenceOfXYZ& P )
 {
   if ( P.size() != 3 && P.size() != 4 )
@@ -1534,11 +1577,34 @@ SMDSAbs_ElementType Length::GetType() const
 
 //================================================================================
 /*
+  Class       : Length3D
+  Description : Functor for calculating minimal length of element edge
+*/
+//================================================================================
+
+Length3D::Length3D():
+  Length2D ( SMDSAbs_Volume )
+{
+}
+
+//================================================================================
+/*
   Class       : Length2D
-  Description : Functor for calculating minimal length of edge
+  Description : Functor for calculating minimal length of element edge
 */
 //================================================================================
 
+Length2D::Length2D( SMDSAbs_ElementType type ):
+  myType ( type )
+{
+}
+
+bool Length2D::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) &&
+           element->GetEntityType() != SMDSEntity_Polyhedra );
+}
+
 double Length2D::GetValue( const TSequenceOfXYZ& P )
 {
   double aVal = 0;
@@ -1783,7 +1849,7 @@ double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
 
 SMDSAbs_ElementType Length2D::GetType() const
 {
-  return SMDSAbs_Face;
+  return myType;
 }
 
 Length2D::Value::Value(double theLength,long thePntId1, long thePntId2):
@@ -1805,84 +1871,90 @@ bool Length2D::Value::operator<(const Length2D::Value& x) const
 
 void Length2D::GetValues(TValues& theValues)
 {
-  TValues aValues;
-  for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
+  if ( myType == SMDSAbs_Face )
   {
-    const SMDS_MeshFace* anElem = anIter->next();
-    if ( anElem->IsQuadratic() )
+    for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
     {
-      // use special nodes iterator
-      SMDS_NodeIteratorPtr anIter = anElem->interlacedNodesIterator();
-      long aNodeId[4] = { 0,0,0,0 };
-      gp_Pnt P[4];
-
-      double aLength = 0;
-      if ( anIter->more() )
-      {
-        const SMDS_MeshNode* aNode = anIter->next();
-        P[0] = P[1] = SMESH_NodeXYZ( aNode );
-        aNodeId[0] = aNodeId[1] = aNode->GetID();
-        aLength = 0;
-      }
-      for ( ; anIter->more(); )
+      const SMDS_MeshFace* anElem = anIter->next();
+      if ( anElem->IsQuadratic() )
       {
-        const SMDS_MeshNode* N1 = anIter->next();
-        P[2] = SMESH_NodeXYZ( N1 );
-        aNodeId[2] = N1->GetID();
-        aLength = P[1].Distance(P[2]);
-        if(!anIter->more()) break;
-        const SMDS_MeshNode* N2 = anIter->next();
-        P[3] = SMESH_NodeXYZ( N2 );
-        aNodeId[3] = N2->GetID();
-        aLength += P[2].Distance(P[3]);
+        // use special nodes iterator
+        SMDS_NodeIteratorPtr anIter = anElem->interlacedNodesIterator();
+        long aNodeId[4] = { 0,0,0,0 };
+        gp_Pnt P[4];
+
+        double aLength = 0;
+        if ( anIter->more() )
+        {
+          const SMDS_MeshNode* aNode = anIter->next();
+          P[0] = P[1] = SMESH_NodeXYZ( aNode );
+          aNodeId[0] = aNodeId[1] = aNode->GetID();
+          aLength = 0;
+        }
+        for ( ; anIter->more(); )
+        {
+          const SMDS_MeshNode* N1 = anIter->next();
+          P[2] = SMESH_NodeXYZ( N1 );
+          aNodeId[2] = N1->GetID();
+          aLength = P[1].Distance(P[2]);
+          if(!anIter->more()) break;
+          const SMDS_MeshNode* N2 = anIter->next();
+          P[3] = SMESH_NodeXYZ( N2 );
+          aNodeId[3] = N2->GetID();
+          aLength += P[2].Distance(P[3]);
+          Value aValue1(aLength,aNodeId[1],aNodeId[2]);
+          Value aValue2(aLength,aNodeId[2],aNodeId[3]);
+          P[1] = P[3];
+          aNodeId[1] = aNodeId[3];
+          theValues.insert(aValue1);
+          theValues.insert(aValue2);
+        }
+        aLength += P[2].Distance(P[0]);
         Value aValue1(aLength,aNodeId[1],aNodeId[2]);
-        Value aValue2(aLength,aNodeId[2],aNodeId[3]);
-        P[1] = P[3];
-        aNodeId[1] = aNodeId[3];
+        Value aValue2(aLength,aNodeId[2],aNodeId[0]);
         theValues.insert(aValue1);
         theValues.insert(aValue2);
       }
-      aLength += P[2].Distance(P[0]);
-      Value aValue1(aLength,aNodeId[1],aNodeId[2]);
-      Value aValue2(aLength,aNodeId[2],aNodeId[0]);
-      theValues.insert(aValue1);
-      theValues.insert(aValue2);
-    }
-    else {
-      SMDS_NodeIteratorPtr aNodesIter = anElem->nodeIterator();
-      long aNodeId[2] = {0,0};
-      gp_Pnt P[3];
+      else {
+        SMDS_NodeIteratorPtr aNodesIter = anElem->nodeIterator();
+        long aNodeId[2] = {0,0};
+        gp_Pnt P[3];
+
+        double aLength;
+        const SMDS_MeshElement* aNode;
+        if ( aNodesIter->more())
+        {
+          aNode = aNodesIter->next();
+          P[0] = P[1] = SMESH_NodeXYZ( aNode );
+          aNodeId[0] = aNodeId[1] = aNode->GetID();
+          aLength = 0;
+        }
+        for( ; aNodesIter->more(); )
+        {
+          aNode = aNodesIter->next();
+          long anId = aNode->GetID();
 
-      double aLength;
-      const SMDS_MeshElement* aNode;
-      if ( aNodesIter->more())
-      {
-        aNode = aNodesIter->next();
-        P[0] = P[1] = SMESH_NodeXYZ( aNode );
-        aNodeId[0] = aNodeId[1] = aNode->GetID();
-        aLength = 0;
-      }
-      for( ; aNodesIter->more(); )
-      {
-        aNode = aNodesIter->next();
-        long anId = aNode->GetID();
+          P[2] = SMESH_NodeXYZ( aNode );
+
+          aLength = P[1].Distance(P[2]);
 
-        P[2] = SMESH_NodeXYZ( aNode );
+          Value aValue(aLength,aNodeId[1],anId);
+          aNodeId[1] = anId;
+          P[1] = P[2];
+          theValues.insert(aValue);
+        }
 
-        aLength = P[1].Distance(P[2]);
+        aLength = P[0].Distance(P[1]);
 
-        Value aValue(aLength,aNodeId[1],anId);
-        aNodeId[1] = anId;
-        P[1] = P[2];
+        Value aValue(aLength,aNodeId[0],aNodeId[1]);
         theValues.insert(aValue);
       }
-
-      aLength = P[0].Distance(P[1]);
-
-      Value aValue(aLength,aNodeId[0],aNodeId[1]);
-      theValues.insert(aValue);
     }
   }
+  else
+  {
+    // not implemented
+  }
 }
 
 //================================================================================
index 4f717d3..359ffe1 100644 (file)
@@ -136,6 +136,8 @@ namespace SMESH{
                         const std::vector<int>& elements,
                         const double*           minmax=0,
                         const bool              isLogarithmic = false);
+      bool IsApplicable( long theElementId ) const;
+      virtual bool IsApplicable( const SMDS_MeshElement* element ) const;
       virtual SMDSAbs_ElementType GetType() const = 0;
       virtual double GetBadRate( double Value, int nbNodes ) const = 0;
       long  GetPrecision() const;
@@ -176,8 +178,8 @@ namespace SMESH{
       virtual double GetBadRate( double Value, int nbNodes ) const;
       virtual SMDSAbs_ElementType GetType() const;
     };
-  
-  
+
+
     /*
       Class       : MaxElementLength3D
       Description : Functor calculating maximum length of 3D element
@@ -212,6 +214,7 @@ namespace SMESH{
       virtual double GetValue( const TSequenceOfXYZ& thePoints );
       virtual double GetBadRate( double Value, int nbNodes ) const;
       virtual SMDSAbs_ElementType GetType() const;
+      virtual bool IsApplicable( const SMDS_MeshElement* element ) const;
     };
   
   
@@ -225,6 +228,7 @@ namespace SMESH{
       virtual double GetValue( const TSequenceOfXYZ& thePoints );
       virtual double GetBadRate( double Value, int nbNodes ) const;
       virtual SMDSAbs_ElementType GetType() const;
+      virtual bool IsApplicable( const SMDS_MeshElement* element ) const;
     };
   
   
@@ -237,7 +241,8 @@ namespace SMESH{
       virtual double GetValue( const TSequenceOfXYZ& thePoints );
       virtual double GetBadRate( double Value, int nbNodes ) const;
       virtual SMDSAbs_ElementType GetType() const;
-      
+      virtual bool IsApplicable( const SMDS_MeshElement* element ) const;
+
     private:
       double ComputeA( const gp_XYZ&, const gp_XYZ&, const gp_XYZ&, const gp_XYZ& ) const;
     };
@@ -252,6 +257,7 @@ namespace SMESH{
       virtual double GetValue( const TSequenceOfXYZ& thePoints );
       virtual double GetBadRate( double Value, int nbNodes ) const;
       virtual SMDSAbs_ElementType GetType() const;
+      virtual bool IsApplicable( const SMDS_MeshElement* element ) const;
     };
 
     /*
@@ -263,6 +269,7 @@ namespace SMESH{
       virtual double GetValue( const TSequenceOfXYZ& thePoints );
       virtual double GetBadRate( double Value, int nbNodes ) const;
       virtual SMDSAbs_ElementType GetType() const;
+      virtual bool IsApplicable( const SMDS_MeshElement* element ) const;
     };
 
 
@@ -291,10 +298,12 @@ namespace SMESH{
 
     /*
       Class       : Length2D
-      Description : Functor for calculating minimal length of edge
+      Description : Functor for calculating minimal length of edges of element
     */
     class SMESHCONTROLS_EXPORT Length2D: public virtual NumericalFunctor{
     public:
+      Length2D( SMDSAbs_ElementType type = SMDSAbs_Face );
+      virtual bool   IsApplicable( const SMDS_MeshElement* element ) const;
       virtual double GetValue( const TSequenceOfXYZ& thePoints );
       virtual double GetBadRate( double Value, int nbNodes ) const;
       virtual SMDSAbs_ElementType GetType() const;
@@ -306,10 +315,23 @@ namespace SMESH{
       };
       typedef std::set<Value> TValues;
       void GetValues(TValues& theValues);
+
+    private:
+      SMDSAbs_ElementType myType;
     };
     typedef boost::shared_ptr<Length2D> Length2DPtr;
 
     /*
+      Class       : Length2D
+      Description : Functor for calculating minimal length of edges of 3D element
+    */
+    class SMESHCONTROLS_EXPORT Length3D: public virtual Length2D {
+    public:
+      Length3D();
+    };
+    typedef boost::shared_ptr<Length3D> Length3DPtr;
+
+    /*
       Class       : Deflection2D
       Description : Functor for calculating distance between a face and geometry
     */
index 497d419..1b82686 100644 (file)
@@ -165,6 +165,7 @@ SET(_other_HEADERS
   SMESHGUI_MeshEditPreview.h
   SMESHGUI_IdValidator.h
   SMESHGUI_FileValidator.h
+  SMESHGUI_SelectionProxy.h
   SMESH_SMESHGUI.hxx
 )
 
@@ -189,6 +190,7 @@ SET(_other_SOURCES
   SMESHGUI_GroupDlg.cxx
   SMESHGUI_RemoveNodesDlg.cxx
   SMESHGUI_RemoveElementsDlg.cxx
+  SMESHGUI_SelectionProxy.cxx
   SMESHGUI_MeshInfo.cxx
   SMESHGUI_Measurements.cxx
   SMESHGUI_Preferences_ScalarBarDlg.cxx
index c153396..29505d1 100755 (executable)
@@ -1571,6 +1571,7 @@ void SMESHGUI_FilterTable::updateAdditionalWidget()
                  aCriterion == SMESH::FT_MaxElementLength3D ||
                  aCriterion == SMESH::FT_Length             ||
                  aCriterion == SMESH::FT_Length2D           ||
+                 aCriterion == SMESH::FT_Length3D           ||
                  aCriterion == SMESH::FT_Deflection2D       ||
                  aCriterion == SMESH::FT_BallDiameter );
 
@@ -1618,6 +1619,7 @@ const char* SMESHGUI_FilterTable::getPrecision( const int aType )
     retval = "len_tol_precision"; break;
   case SMESH::FT_Length:
   case SMESH::FT_Length2D:
+  case SMESH::FT_Length3D:
   case SMESH::FT_Deflection2D:
   case SMESH::FT_MaxElementLength2D:
   case SMESH::FT_MaxElementLength3D:
@@ -1830,6 +1832,7 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con
 
   case SMESH::FT_Length:
   case SMESH::FT_Length2D:
+  case SMESH::FT_Length3D:
   case SMESH::FT_Deflection2D: anIsDoubleCriterion = true; break;
 
   case SMESH::FT_BelongToMeshGroup: break;
@@ -2270,6 +2273,7 @@ const QMap<int, QString>& SMESHGUI_FilterTable::getCriteria (const int theType)
       aCriteria[ SMESH::FT_BadOrientedVolume    ] = tr("BAD_ORIENTED_VOLUME");
       aCriteria[ SMESH::FT_BareBorderVolume     ] = tr("BARE_BORDER_VOLUME");
       aCriteria[ SMESH::FT_OverConstrainedVolume] = tr("OVER_CONSTRAINED_VOLUME");
+      aCriteria[ SMESH::FT_Length3D             ] = tr("LENGTH3D");
       aCriteria[ SMESH::FT_Volume3D             ] = tr("VOLUME_3D");
       aCriteria[ SMESH::FT_MaxElementLength3D   ] = tr("MAX_ELEMENT_LENGTH_3D");
       aCriteria[ SMESH::FT_LinearOrQuadratic    ] = tr("LINEAR");
index 9c1fb88..bcbd1b8 100644 (file)
 //
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
-//  File   : SMESHGUI_MeshInfo.cxx
-//  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
 
 #include "SMESHGUI_MeshInfo.h"
 
-#include "SMDSAbs_ElementType.hxx"
-#include "SMDS_BallElement.hxx"
-#include "SMDS_EdgePosition.hxx"
-#include "SMDS_FacePosition.hxx"
 #include "SMDS_Mesh.hxx"
-#include "SMDS_VolumeTool.hxx"
-#include "SMESHDS_Mesh.hxx"
+#include "SMESH_Actor.h"
 #include "SMESHGUI.h"
 #include "SMESHGUI_FilterUtils.h"
 #include "SMESHGUI_IdPreview.h"
 #include "SMESHGUI_SpinBox.h"
 #include "SMESHGUI_Utils.h"
 #include "SMESHGUI_VTKUtils.h"
-#include "SMESH_Actor.h"
 
-#include <LightApp_SelectionMgr.h>
 #include <SUIT_FileDlg.h>
 #include <SUIT_OverrideCursor.h>
 #include <SUIT_ResourceMgr.h>
 #include <SUIT_Session.h>
 #include <SVTK_ViewWindow.h>
+#include <LightApp_SelectionMgr.h>
 
 #include <SALOMEDSClient_Study.hxx>
-#include <SalomeApp_Study.h>
 
 #include <QApplication>
 #include <QButtonGroup>
 #include <QCheckBox>
+#include <QComboBox>
 #include <QContextMenuEvent>
 #include <QGridLayout>
 #include <QHBoxLayout>
 #include <QLineEdit>
 #include <QMenu>
 #include <QPushButton>
-#include <QToolButton>
 #include <QRadioButton>
-#include <QTextStream>
+#include <QStackedWidget>
+#include <QStandardItemModel>
 #include <QTabWidget>
 #include <QTextBrowser>
+#include <QTextStream>
+#include <QToolButton>
+#include <QTreeWidget>
 #include <QVBoxLayout>
 
-#include "utilities.h"
+////////////////////////////////////////////////////////////////////////////////
+/// \class Field
+/// \brief Field widget.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
+class Field : public QLabel
+{
+public:
+  Field( QWidget*, const QString& = QString() );
+  bool event( QEvent* );
+};
+
+/*!
+  \brief Constructor.
+  \param parent Parent widget.
+  \param name Field name. Defauls to null string.
+*/
+Field::Field( QWidget* parent, const QString& name ): QLabel( parent )
+{
+  setFrameStyle( QLabel::StyledPanel | QLabel::Sunken );
+  setAlignment( Qt::AlignCenter );
+  setAutoFillBackground( true );
+  QPalette pal = palette();
+  QColor base = QApplication::palette().color( QPalette::Active, QPalette::Base );
+  pal.setColor( QPalette::Window, base );
+  setPalette( pal );
+  setMinimumWidth( 60 );
+  if ( !name.isEmpty() )
+    setObjectName( name );
+}
+
+/*!
+  \brief Event handler. Redefined from QLabel.
+*/
+bool Field::event( QEvent* e )
+{
+  if ( e->type() == QEvent::DynamicPropertyChange )
+  {
+    QDynamicPropertyChangeEvent* ce = (QDynamicPropertyChangeEvent*)e;
+    if ( ce->propertyName() == "value" && property( "value" ).isValid() )
+    {
+      setText( QString::number( property( "value" ).toInt() ) );
+      setProperty( "value", QVariant() );
+      return true;
+    }
+  }
+  return QLabel::event( e );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class TreeItemCreator
+/// \brief Generic tree item creator.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
 
-#include <SALOMEconfig.h>
-#include CORBA_SERVER_HEADER(GEOM_Gen)
+class TreeItemCreator
+{
+public:
+  TreeItemCreator() {}
+  virtual ~TreeItemCreator() {}
+  virtual QTreeWidgetItem* createItem( QTreeWidgetItem*, int ) = 0;
+};
 
-namespace {
+////////////////////////////////////////////////////////////////////////////////
+// General purpose services.
+////////////////////////////////////////////////////////////////////////////////
 
-  const int SPACING      = 6;
-  const int MARGIN       = 9;
-  const int MAXITEMS     = 10;
-  const int GROUPS_ID    = 100;
-  const int SUBMESHES_ID = 200;
-  const int SPACING_INFO = 2;
+namespace
+{
+  const int SPACING = 6;
+  const int MARGIN = 9;
+
+  enum
+  {
+    Bold = 0x01,
+    Italic = 0x02,
+    AllColumns = 0x04,
+    Expanded = 0x08,
+    Editable = 0x10
+  };
 
-  const char* id_preview_resource = "id_preview_resource";
+  enum
+  {
+    GroupsId = 100,
+    SubMeshesId
+  };
 
-  enum InfoRole {
+  enum
+  {
     TypeRole = Qt::UserRole + 10,
     IdRole,
   };
 
-  enum InfoType {
+  enum
+  {
     NodeConnectivity = 100,
     ElemConnectivity,
   };
-} // namesapce
+
+  /*!
+    \brief Get item's depth in the tree.
+    \param item Tree widget item.
+    \return Item's depth in the tree widget (top-level item has zero depth).
+    \internal
+  */
+  int itemDepth( QTreeWidgetItem* item )
+  {
+    QList<QTreeWidgetItem*> parents;
+    parents << item;
+    while ( parents.last()->parent() )
+      parents << parents.last()->parent();
+    return parents.size()-1;
+  }
+
+  /*!
+    \brief Get chunk size.
+    \return Chunk size.
+    \internal
+  */
+  int blockSize()
+  {
+    return 10;
+  }
+
+  /*!
+    \brief Get spacer.
+    \return Spacer string.
+    \internal
+  */
+  QString spacing()
+  {
+    static int size = 1;
+    static QChar spacer = ' ';
+    return QString( size, spacer );
+  }
+
+  /*!
+    \brief Get indent.
+    \param length Indent size. Defaults to 1.
+    \return Indentation string.
+    \internal
+  */
+  QString indent( int length = 1 )
+  {
+    static int size = 4;
+    static QChar spacer = ' ';
+    return QString( size * length, spacer );
+  }
+
+  /*!
+    \brief Get indent.
+    \param spacer Spacer.
+    \param length Indent size. Defaults to 1.
+    \return Indentation string.
+    \internal
+  */
+  QString indent( const QString& spacer, uint length = 1 )
+  {
+    QString result;
+    while( length-- > 0 )
+      result += spacer;
+    return result;
+  }
+
+  /*!
+    \brief Get group separator.
+    \param length Length of ruler (number of symbols). Defaults to 80.
+    \return Ruler string.
+    \internal
+  */
+  QString ruler( int length = 80 )
+  {
+    static QChar ruler = '-';
+    return QString( length, ruler );
+  }
+
+  /*!
+    \brief Get text value from label.
+    \param w Widget (QLabel).
+    \return Value string.
+    \internal
+  */
+  QString widgetValue( QWidget* w )
+  {
+    QString v;
+    if ( qobject_cast<QLabel*>( w ) )
+      v = qobject_cast<QLabel*>( w )->text();
+    return v;
+  }
+
+  /*!
+    \brief Get font for given options.
+    \param font Initial font.
+    \param options Font attributes.
+    \return Font.
+  */
+  QFont fontFromOptions( const QFont& font, int options )
+  {
+    QFont f = font;
+    f.setBold( options & Bold );
+    f.setItalic( options & Italic );
+    return f;
+  }
+
+  /*!
+    \brief Set font attributes to given widget.
+    \param w Widget.
+    \param options Font attributes.
+  */
+  void setFontAttributes( QWidget* w, int options )
+  {
+    if ( w )
+      w->setFont( fontFromOptions( w->font(), options ) );
+  }
+
+  /*!
+    \brief Set attributes to given tree item.
+    \param item Tree widget item.
+    \param options Item attributes.
+  */
+  void setTreeItemAttributes( QTreeWidgetItem* item, int options )
+  {
+    if ( item && item->treeWidget() )
+    {
+      for ( int i = 0; i < item->treeWidget()->columnCount(); i++ )
+      {
+        if ( i == 0 || options & AllColumns )
+          item->setFont( i, fontFromOptions( item->font( 0 ), options) );
+      }
+    }
+    if ( options & Expanded )
+      item->setExpanded( true );
+    if ( options & Editable )
+      item->setFlags( item->flags() | Qt::ItemIsEditable );
+  }
+
+  /*!
+    \brief Create label.
+    \param parent Parent widget.
+    \param options Label options. Defaults to 0 (none).
+    \return New label.
+  */
+  QLabel* createLabel( QWidget* parent, int options = 0 )
+  {
+    QLabel* lab = new QLabel( parent );
+    setFontAttributes( lab, options );
+    return lab;
+  }
+
+  /*!
+    \brief Create label.
+    \param text Label text.
+    \param parent Parent widget.
+    \param options Label options. Defaults to 0 (none).
+    \return New label.
+  */
+  QLabel* createLabel( const QString& text, QWidget* parent, int options = 0 )
+  {
+    QLabel* lab = createLabel( parent, options );
+    lab->setText( text );
+    return lab;
+  }
+
+  /*!
+    \brief Create information field.
+    \param parent Parent widget.
+    \param name Field's object. Default to null string.
+    \return New field.
+  */
+  QLabel* createField( QWidget* parent, const QString& name = QString() )
+  {
+    return new Field( parent, name );
+  }
+
+  /*!
+    \brief Create information field.
+    \param parent Parent widget.
+    \param options Label options.
+    \param name Field's object. Default to null string.
+    \return New field.
+  */
+  QLabel* createField( QWidget* parent, int options, const QString& name = QString() )
+  {
+    QLabel* field = createField( parent, name );
+    setFontAttributes( field, options );
+    return field;
+  }
+
+  /*!
+    \brief Create ruler.
+    \param parent Parent widget.
+    \param orientation Ruler orientation. Defaults to horizontal.
+    \return New ruler.
+  */
+  QWidget* createSeparator( QWidget* parent, Qt::Orientation orientation = Qt::Horizontal )
+  {
+    QFrame* line = new QFrame( parent );
+    line->setFrameShape( orientation == Qt::Horizontal ? QFrame::HLine : QFrame::HLine );
+    line->setFrameShadow( QFrame::Sunken );
+    return line;
+  }
+
+  /*!
+    \brief Decorate text as bold.
+    \param text Initial text.
+    \return Decorated text.
+  */
+  QString bold( const QString& text )
+  {
+    return QString("<b>%1</b>").arg( text );
+  }
+
+  /*!
+    \brief Format connectivity data to string representation.
+    \param connectivity Connectivity map.
+    \param type Element type or face index if negative
+    \return Stringifed representation of the connectivity.
+  */
+  QString formatConnectivity( SMESH::Connectivity connectivity, int type )
+  {
+    QStringList str;
+    QString     result;
+    bool isNodal = ( type == SMDSAbs_Node || type < 0 );
+    type = qAbs( type );
+    if ( connectivity.contains( type ))
+    {
+      QList<int> elements = connectivity[ type ];
+      if ( !isNodal ) // order of nodes is important
+        qSort( elements );
+      foreach( int id, elements )
+        str << QString::number( id );
+
+      // wrap IDs into an html link, to be treated by QTextBrowser used by SMESHGUI_SimpleElemInfo
+      QString s = str.join( " " );
+      result = ( "<a href = \"" +                                 // URL:
+                 QString( isNodal ? "nodes" : "elems" ) + "://" + // protocol
+                 QString( "host.com/") + // QUrl return nothing if host missing
+                 s + "\">" +                                      // path
+                 s + "</a>" );                                    // anchor text
+    }
+    return result;
+  }
+} // end of anonymous namespace
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_Info
+/// \brief Base widget for all information panes.
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
-  \class ExtraWidget
-  \internal
+  \brief Constructor.
+  \param parent Parent widget. Defaults to 0.
 */
+SMESHGUI_Info::SMESHGUI_Info( QWidget* parent ): QWidget( parent )
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class ExtraWidget
+/// \brief Auxiliary widget to browse between chunks of information.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
 class ExtraWidget : public QWidget
 {
 public:
   ExtraWidget( QWidget*, bool = false );
-  ~ExtraWidget();
-
-  void updateControls( int, int, int = MAXITEMS );
+  void updateControls( int, int );
 
 public:
-  QLabel*      current;
+  QLabel* current;
   QPushButton* prev;
   QPushButton* next;
-  bool         brief;
+  bool brief;
 };
 
-ExtraWidget::ExtraWidget( QWidget* parent, bool b ) : QWidget( parent ), brief( b )
+/*
+  \brief Constructor.
+  \param parent Parent widget.
+  \param briefSummary Show summary in brief format. Defaults to \c false.
+*/
+ExtraWidget::ExtraWidget( QWidget* parent, bool briefSummary ): QWidget( parent ), brief( briefSummary )
 {
   current = new QLabel( this );
   current->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
-  prev = new QPushButton( tr( "<<" ), this );
-  next = new QPushButton( tr( ">>" ), this );
+  prev = new QPushButton( "<<", this );
+  next = new QPushButton( ">>", this );
   QHBoxLayout* hbl = new QHBoxLayout( this );
-  hbl->setContentsMargins( 0, SPACING, 0, 0 );
+  hbl->setMargin( 0 );
   hbl->setSpacing( SPACING );
   hbl->addStretch();
   hbl->addWidget( current );
@@ -131,884 +462,1047 @@ ExtraWidget::ExtraWidget( QWidget* parent, bool b ) : QWidget( parent ), brief(
   hbl->addWidget( next );
 }
 
-ExtraWidget::~ExtraWidget()
-{
-}
-
-void ExtraWidget::updateControls( int total, int index, int blockSize )
+/*
+  \brief Update controls.
+  \param total Total number of items.
+  \param index Current index.
+*/
+void ExtraWidget::updateControls( int total, int index )
 {
-  setVisible( total > blockSize );
+  setVisible( total > blockSize() );
   QString format = brief ? QString( "%1-%2 / %3" ) : SMESHGUI_MeshInfoDlg::tr( "X_FROM_Y_ITEMS_SHOWN" );
-  current->setText( format.arg( index*blockSize+1 ).arg( qMin( index*blockSize+blockSize, total )).arg( total ));
+  current->setText( format.arg( index*blockSize()+1 ).arg( qMin( index*blockSize()+blockSize(), total ) ).arg( total ) );
   prev->setEnabled( index > 0 );
-  next->setEnabled( (index+1)*blockSize < total );
+  next->setEnabled( (index+1)*blockSize() < total );
 }
 
-/*!
-  \class DumpFileDlg
-  \brief Customization of standard "Save file" dialog box for dump info operation
-  \internal
-*/
+////////////////////////////////////////////////////////////////////////////////
+/// \class DumpFileDlg
+/// \brief Standard Save File dialog box, customized for dump info operation.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
 
 class DumpFileDlg : public SUIT_FileDlg
 {
+  QMap<int, QCheckBox*> myControls;
 public:
-  DumpFileDlg( QWidget* parent );
-
-  QCheckBox* myBaseChk;
-  QCheckBox* myElemChk;
-  QCheckBox* myAddChk;
-  QCheckBox* myCtrlChk;
+  DumpFileDlg( QWidget*, bool = true );
+  bool isChecked( int ) const;
+  void setChecked( int, bool );
 };
 
 /*!
-  \brief Constructor
+  \brief Constructor.
+  \param parent Parent widget.
+  \param showControls Show additional controls. Defaults to \c true.
   \internal
 */
-DumpFileDlg::DumpFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
+DumpFileDlg::DumpFileDlg( QWidget* parent, bool showControls ): SUIT_FileDlg( parent, false, true, true )
 {
-  QGridLayout* grid = ::qobject_cast<QGridLayout *>( layout() );
-  if ( grid ) {
+  if ( showControls )
+  {
     QWidget* hB = new QWidget( this );
-    myBaseChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_BASE_INFO" ), hB );
-    myElemChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ELEM_INFO" ), hB );
-    myAddChk  = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ADD_INFO" ),  hB );
-    myCtrlChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_CTRL_INFO" ), hB );
+    myControls[SMESHGUI_MeshInfoDlg::BaseInfo] = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_BASE_INFO" ), hB );
+    myControls[SMESHGUI_MeshInfoDlg::ElemInfo] = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ELEM_INFO" ), hB );
+    myControls[SMESHGUI_MeshInfoDlg::AddInfo] = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ADD_INFO" ),  hB );
+    myControls[SMESHGUI_MeshInfoDlg::CtrlInfo] = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_CTRL_INFO" ), hB );
 
     QGridLayout* layout = new QGridLayout( hB );
-    layout->addWidget( myBaseChk, 0, 0 );
-    layout->addWidget( myElemChk, 0, 1 );
-    layout->addWidget( myAddChk, 1, 0 );
-    layout->addWidget( myCtrlChk, 1, 1 );
-
-    QPushButton* pb = new QPushButton( this );
+    layout->setMargin( 0 );
+    layout->addWidget( myControls[SMESHGUI_MeshInfoDlg::BaseInfo], 0, 0 );
+    layout->addWidget( myControls[SMESHGUI_MeshInfoDlg::ElemInfo], 0, 1 );
+    layout->addWidget( myControls[SMESHGUI_MeshInfoDlg::AddInfo], 1, 0 );
+    layout->addWidget( myControls[SMESHGUI_MeshInfoDlg::CtrlInfo], 1, 1 );
 
-    int row = grid->rowCount();
-    grid->addWidget( new QLabel( "", this ), row, 0 );
-    grid->addWidget( hB, row, 1, 1, 3 );
-    grid->addWidget( pb, row, 5 );
-
-    pb->hide();
+    addWidgets( 0, hB, 0 );
   }
 }
 
 /*!
-  \brief Get depth of the tree item
+  \brief Get control's value.
+  \param option Control identifier.
+  \return Control value.
   \internal
-  \param theItem tree widget item
-  \return item's depth in tree widget (where top-level items have zero depth)
 */
-static int itemDepth( QTreeWidgetItem* item )
+bool DumpFileDlg::isChecked( int option ) const
 {
-  int d = 0;
-  QTreeWidgetItem* p = item->parent();
-  while ( p ) {
-    d++;
-    p = p->parent();
-  }
-  return d;
+  return myControls.contains( option ) ? myControls[option]->isChecked() : false;
 }
 
 /*!
-  \class SMESHGUI_MeshInfo
-  \brief Base mesh information widget
-  
-  Displays the base information about mesh object: mesh, sub-mesh, group or arbitrary ID source.
+  \brief Set control's initial value.
+  \param option Control identifier.
+  \param value Control value.
+  \internal
 */
+void DumpFileDlg::setChecked( int option, bool value )
+{
+  if ( myControls.contains( option ) ) 
+    myControls[option]->setChecked( value );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_BaseInfo
+/// \brief Show basic information on selected object.
+///
+/// Displays the base information about selected object: mesh, sub-mesh, group
+/// or arbitrary ID source.
+/// \todo Hide unnecessary widgets (e.g. for mesh group).
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
   \brief Constructor.
-  \param parent parent widget
+  \param parent Parent widget. Defaults to 0.
 */
-SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent )
-  : QFrame( parent ), myWidgets( iElementsEnd )
+SMESHGUI_BaseInfo::SMESHGUI_BaseInfo( QWidget* parent ): SMESHGUI_Info( parent )
 {
-  setFrameStyle( StyledPanel | Sunken );
-
   QGridLayout* l = new QGridLayout( this );
   l->setMargin( MARGIN );
   l->setSpacing( SPACING );
 
-  int index = 0;
-
-  // object
-  QLabel* aNameLab     = new QLabel( tr( "NAME_LAB" ), this );
-  QLabel* aName        = createField();
-  aName->setObjectName("meshName");
-  aName->setMinimumWidth( 150 );
-  QLabel* aObjLab      = new QLabel( tr( "OBJECT_LAB" ), this );
-  QLabel* aObj         = createField();
-  aObj->setObjectName("meshType");
-  aObj->setMinimumWidth( 150 );
-  myWidgets[ index++ ] << aNameLab << aName;
-  myWidgets[ index++ ] << aObjLab  << aObj;
-
-  // nodes
-  QWidget* aNodesLine  = createLine();
-  QLabel*  aNodesLab   = new QLabel( tr( "NODES_LAB" ), this );
-  QLabel*  aNodes      = createField();
-  aNodes->setObjectName("nbNodes");
-  myWidgets[ index++ ] << aNodesLine;
-  myWidgets[ index++ ] << aNodesLab << aNodes;
-
-  // elements
-  QWidget* aElemLine   = createLine();
-  QLabel*  aElemLab    = new QLabel( tr( "ELEMENTS_LAB" ),     this );
-  QLabel*  aElemTotal  = new QLabel( tr( "TOTAL_LAB" ),        this );
-  QLabel*  aElemLin    = new QLabel( tr( "LINEAR_LAB" ),       this );
-  QLabel*  aElemQuad   = new QLabel( tr( "QUADRATIC_LAB" ),    this );
-  QLabel*  aElemBiQuad = new QLabel( tr( "BI_QUADRATIC_LAB" ), this );
-  myWidgets[ index++ ] << aElemLine;
-  myWidgets[ index++ ] << aElemLab << aElemTotal << aElemLin << aElemQuad << aElemBiQuad;
-
-  // ... Number elements
-  QWidget* aNbLine     = createLine(); 
-  QLabel*  aNbTotal    = createField();
-  aNbTotal->setObjectName("totalNbElems");
-  QLabel*  aNbLin      = createField();
-  aNbLin->setObjectName("totalNbLinearElems");
-  QLabel*  aNbQuad     = createField();
-  aNbQuad->setObjectName("totalNbQuadraticElems");
-  QLabel*  aNbBiQuad   = createField();
-  aNbBiQuad->setObjectName("totalNbBiQuadraticElems");
-  myWidgets[ index++ ] << aNbLine;
-  myWidgets[ index++ ] << new QLabel( "", this ) << aNbTotal << aNbLin << aNbQuad << aNbBiQuad;
-
-  // ... 0D elements
-  QWidget* a0DLine     = createLine();
-  QLabel*  a0DLab      = new QLabel( tr( "0D_LAB" ), this );
-  QLabel*  a0DTotal    = createField();
-  a0DTotal->setObjectName("nb0D");
-
-  myWidgets[ index++ ] << a0DLine;
-  myWidgets[ index++ ] << a0DLab << a0DTotal;
-
-  // ... Ball elements
-  QWidget* aBallLine     = createLine();
-  QLabel*  aBallLab      = new QLabel( tr( "BALL_LAB" ), this );
-  QLabel*  aBallTotal    = createField();
-  aBallTotal->setObjectName("nbBall");
-  myWidgets[ index++ ] << aBallLine;
-  myWidgets[ index++ ] << aBallLab << aBallTotal;
-
-  // ... 1D elements
-  QWidget* a1DLine     = createLine();
-  QLabel*  a1DLab      = new QLabel( tr( "1D_LAB" ), this );
-  QLabel*  a1DTotal    = createField();
-  a1DTotal->setObjectName("nb1D");
-  QLabel*  a1DLin      = createField();
-  a1DLin->setObjectName("nbLinear1D");
-  QLabel*  a1DQuad     = createField();
-  a1DQuad->setObjectName("nbQuadratic1D");
-  myWidgets[ index++ ] << a1DLine;
-  myWidgets[ index++ ] << a1DLab << a1DTotal << a1DLin << a1DQuad;
-
-  // ... 2D elements
-  QWidget* a2DLine      = createLine();
-  QLabel*  a2DLab       = new QLabel( tr( "2D_LAB" ), this );
-  QLabel*  a2DTotal     = createField();
-  a2DTotal->setObjectName("nb2D");
-  QLabel*  a2DLin       = createField();
-  a2DLin->setObjectName("nbLinear2D");
-  QLabel*  a2DQuad      = createField();
-  a2DQuad->setObjectName("nbQuadratic2D");
-  QLabel*  a2DBiQuad    = createField();
-  a2DBiQuad->setObjectName("nbBiQuadratic2D");
-  QLabel*  a2DTriLab    = new QLabel( tr( "TRIANGLES_LAB" ), this );
-  QLabel*  a2DTriTotal  = createField();
-  a2DTriTotal->setObjectName("nbTriangle");
-  QLabel*  a2DTriLin    = createField();
-  a2DTriLin->setObjectName("nbLinearTriangle");
-  QLabel*  a2DTriQuad   = createField();
-  a2DTriQuad->setObjectName("nbQuadraticTriangle");
-  QLabel*  a2DTriBiQuad = createField();
-  a2DTriBiQuad->setObjectName("nbBiQuadraticTriangle");
-  QLabel*  a2DQuaLab    = new QLabel( tr( "QUADRANGLES_LAB" ), this );
-  QLabel*  a2DQuaTotal  = createField();
-  a2DQuaTotal->setObjectName("nbQuadrangle");
-  QLabel*  a2DQuaLin    = createField();
-  a2DQuaLin->setObjectName("nbLinearQuadrangle");
-  QLabel*  a2DQuaQuad   = createField();
-  a2DQuaQuad->setObjectName("nbQuadraticQuadrangle");
-  QLabel*  a2DQuaBiQuad = createField();
-  a2DQuaBiQuad->setObjectName("nbBiQuadraticQuadrangle");
-  QLabel*  a2DPolLab    = new QLabel( tr( "POLYGONS_LAB" ), this );
-  QLabel*  a2DPolTotal  = createField();
-  a2DPolTotal->setObjectName("nbPolygon");
-  QLabel*  a2DPolLin    = createField();
-  a2DPolLin->setObjectName("nbLinearPolygon");
-  QLabel*  a2DPolQuad   = createField();
-  a2DPolQuad->setObjectName("nbQuadraticPolygon");
-  myWidgets[ index++ ] << a2DLine;
-  myWidgets[ index++ ] << a2DLab    << a2DTotal    << a2DLin    << a2DQuad    << a2DBiQuad;
-  myWidgets[ index++ ] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad << a2DTriBiQuad;
-  myWidgets[ index++ ] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad << a2DQuaBiQuad;
-  myWidgets[ index++ ] << a2DPolLab << a2DPolTotal << a2DPolLin << a2DPolQuad;
-
-  // ... 3D elements
-  QWidget* a3DLine      = createLine();
-  QLabel*  a3DLab       = new QLabel( tr( "3D_LAB" ), this );
-  QLabel*  a3DTotal     = createField();
-  a3DTotal->setObjectName("nb3D");
-  QLabel*  a3DLin       = createField();
-  a3DLin->setObjectName("nbLinear3D");
-  QLabel*  a3DQuad      = createField();
-  a3DQuad->setObjectName("nbQuadratic3D");
-  QLabel*  a3DBiQuad    = createField();
-  a3DBiQuad->setObjectName("nbBiQuadratic3D");
-  QLabel*  a3DTetLab    = new QLabel( tr( "TETRAHEDRONS_LAB" ), this );
-  QLabel*  a3DTetTotal  = createField();
-  a3DTetTotal->setObjectName("nbTetrahedron");
-  QLabel*  a3DTetLin    = createField();
-  a3DTetLin->setObjectName("nbLinearTetrahedron");
-  QLabel*  a3DTetQuad   = createField();
-  a3DTetQuad->setObjectName("nbQudraticTetrahedron");
-  QLabel*  a3DHexLab    = new QLabel( tr( "HEXAHEDONRS_LAB" ), this );
-  QLabel*  a3DHexTotal  = createField();
-  a3DHexTotal->setObjectName("nbHexahedron");
-  QLabel*  a3DHexLin    = createField();
-  a3DHexLin->setObjectName("nbLinearHexahedron");
-  QLabel*  a3DHexQuad   = createField();
-  a3DHexQuad->setObjectName("nbQuadraticHexahedron");
-  QLabel*  a3DHexBiQuad = createField();
-  a3DHexBiQuad->setObjectName("nbBiQuadraticHexahedron");
-  QLabel*  a3DPyrLab    = new QLabel( tr( "PYRAMIDS_LAB" ), this );
-  QLabel*  a3DPyrTotal  = createField();
-  a3DPyrTotal->setObjectName("nbPyramid");
-  QLabel*  a3DPyrLin    = createField();
-  a3DPyrLin->setObjectName("nbLinearPyramid");
-  QLabel*  a3DPyrQuad   = createField();
-  a3DPyrQuad->setObjectName("nbQuadraticPyramid");
-  QLabel*  a3DPriLab    = new QLabel( tr( "PRISMS_LAB" ), this );
-  QLabel*  a3DPriTotal  = createField();
-  a3DPriTotal->setObjectName("nbPrism");
-  QLabel*  a3DPriLin    = createField();
-  a3DPriLin->setObjectName("nbLinearPrism");
-  QLabel*  a3DPriQuad   = createField();
-  a3DPriQuad->setObjectName("nbQuadraticPrism");
-  QLabel*  a3DPriBiQuad   = createField();
-  a3DPriBiQuad->setObjectName("nbBiQuadraticPrism");
-  QLabel*  a3DHexPriLab   = new QLabel( tr( "HEX_PRISMS_LAB" ), this );
-  QLabel*  a3DHexPriTotal = createField();
-  a3DHexPriTotal->setObjectName("nbHexagonalPrism");
-  QLabel*  a3DPolLab    = new QLabel( tr( "POLYHEDRONS_LAB" ), this );
-  QLabel*  a3DPolTotal  = createField();
-  a3DPolTotal->setObjectName("nbPolyhedron");
-  myWidgets[ index++ ] << a3DLine;
-  myWidgets[ index++ ] << a3DLab    << a3DTotal    << a3DLin    << a3DQuad    << a3DBiQuad;
-  myWidgets[ index++ ] << a3DTetLab << a3DTetTotal << a3DTetLin << a3DTetQuad;
-  myWidgets[ index++ ] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad << a3DHexBiQuad;
-  myWidgets[ index++ ] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad;
-  myWidgets[ index++ ] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad << a3DPriBiQuad;
-  myWidgets[ index++ ] << a3DHexPriLab << a3DHexPriTotal;
-  myWidgets[ index++ ] << a3DPolLab << a3DPolTotal;
-
-  myLoadBtn = new QPushButton( tr( "BUT_LOAD_MESH" ), this );
-  myLoadBtn->setAutoDefault( true );
-  connect( myLoadBtn, SIGNAL( clicked() ), this, SLOT( loadMesh() ));
-  
-  setFontAttributes( aNameLab,    Bold );
-  setFontAttributes( aObjLab,     Bold );
-  setFontAttributes( aNodesLab,   Bold );
-  setFontAttributes( aElemLab,    Bold );
-  setFontAttributes( aElemTotal,  Italic );
-  setFontAttributes( aElemLin,    Italic );
-  setFontAttributes( aElemQuad,   Italic );
-  setFontAttributes( aElemBiQuad, Italic );
-  setFontAttributes( a0DLab,      Bold );
-  setFontAttributes( aBallLab,    Bold );
-  setFontAttributes( a1DLab,      Bold );
-  setFontAttributes( a2DLab,      Bold );
-  setFontAttributes( a3DLab,      Bold );
-
-  l->addWidget( aNameLab,     0, 0 );
-  l->addWidget( aName,        0, 1, 1, 4 );
-  l->addWidget( aObjLab,      1, 0 );
-  l->addWidget( aObj,         1, 1, 1, 4 );
-  l->addWidget( aNodesLine,   2, 0, 1, 5 );
-  l->addWidget( aNodesLab,    3, 0 );
-  l->addWidget( aNodes,       3, 1 );
-  l->addWidget( aElemLine,    4, 0, 1, 5 );
-  l->addWidget( aElemLab,     5, 0 );
-  l->addWidget( aElemTotal,   5, 1 );
-  l->addWidget( aElemLin,     5, 2 );
-  l->addWidget( aElemQuad,    5, 3 );
-  l->addWidget( aElemBiQuad,  5, 4 );
-  l->addWidget( aNbLine,      6, 1, 1, 4 );
-  l->addWidget( aNbTotal,     7, 1 );
-  l->addWidget( aNbLin,       7, 2 );
-  l->addWidget( aNbQuad,      7, 3 );
-  l->addWidget( aNbBiQuad,    7, 4 );
-  l->addWidget( a0DLine,      8, 1, 1, 4 );
-  l->addWidget( a0DLab,       9, 0 );
-  l->addWidget( a0DTotal,     9, 1 );
-  l->addWidget( aBallLine,    10, 1, 1, 4 );
-  l->addWidget( aBallLab,     11, 0 );
-  l->addWidget( aBallTotal,   11, 1 );
-  l->addWidget( a1DLine,      12, 1, 1, 4 );
-  l->addWidget( a1DLab,       13, 0 );
-  l->addWidget( a1DTotal,     13, 1 );
-  l->addWidget( a1DLin,       13, 2 );
-  l->addWidget( a1DQuad,      13, 3 );
-  l->addWidget( a2DLine,      14, 1, 1, 4 );
-  l->addWidget( a2DLab,       15, 0 );
-  l->addWidget( a2DTotal,     15, 1 );
-  l->addWidget( a2DLin,       15, 2 );
-  l->addWidget( a2DQuad,      15, 3 );
-  l->addWidget( a2DBiQuad,    15, 4 );
-  l->addWidget( a2DTriLab,    16, 0 );
-  l->addWidget( a2DTriTotal,  16, 1 );
-  l->addWidget( a2DTriLin,    16, 2 );
-  l->addWidget( a2DTriQuad,   16, 3 );
-  l->addWidget( a2DTriBiQuad, 16, 4 );
-  l->addWidget( a2DQuaLab,    17, 0 );
-  l->addWidget( a2DQuaTotal,  17, 1 );
-  l->addWidget( a2DQuaLin,    17, 2 );
-  l->addWidget( a2DQuaQuad,   17, 3 );
-  l->addWidget( a2DQuaBiQuad, 17, 4 );
-  l->addWidget( a2DPolLab,    18, 0 );
-  l->addWidget( a2DPolTotal,  18, 1 );
-  l->addWidget( a2DPolLin,    18, 2 );
-  l->addWidget( a2DPolQuad,   18, 3 );
-  l->addWidget( a3DLine,      19, 1, 1, 4 );
-  l->addWidget( a3DLab,       20, 0 );
-  l->addWidget( a3DTotal,     20, 1 );
-  l->addWidget( a3DLin,       20, 2 );
-  l->addWidget( a3DQuad,      20, 3 );
-  l->addWidget( a3DBiQuad,    20, 4 );
-  l->addWidget( a3DTetLab,    21, 0 );
-  l->addWidget( a3DTetTotal,  21, 1 );
-  l->addWidget( a3DTetLin,    21, 2 );
-  l->addWidget( a3DTetQuad,   21, 3 );
-  l->addWidget( a3DHexLab,    22, 0 );
-  l->addWidget( a3DHexTotal,  22, 1 );
-  l->addWidget( a3DHexLin,    22, 2 );
-  l->addWidget( a3DHexQuad,   22, 3 );
-  l->addWidget( a3DHexBiQuad, 22, 4 );
-  l->addWidget( a3DPyrLab,    23, 0 );
-  l->addWidget( a3DPyrTotal,  23, 1 );
-  l->addWidget( a3DPyrLin,    23, 2 );
-  l->addWidget( a3DPyrQuad,   23, 3 );
-  l->addWidget( a3DPriLab,    24, 0 );
-  l->addWidget( a3DPriTotal,  24, 1 );
-  l->addWidget( a3DPriLin,    24, 2 );
-  l->addWidget( a3DPriQuad,   24, 3 );
-  l->addWidget( a3DPriBiQuad, 24, 4 );
-  l->addWidget( a3DHexPriLab,   25, 0 );
-  l->addWidget( a3DHexPriTotal, 25, 1 );
-  l->addWidget( a3DPolLab,    26, 0 );
-  l->addWidget( a3DPolTotal,  26, 1 );
-  l->addWidget( myLoadBtn,    28, 1, 1, 4 );
-
-  l->setColumnStretch( 0, 0 );
-  l->setColumnStretch( 1, 5 );
-  l->setColumnStretch( 2, 5 );
-  l->setColumnStretch( 3, 5 );
-  l->setColumnStretch( 4, 5 );
-  l->setRowStretch( 27, 5 );
-
+  // object info
+  // - name
+  addWidget( createLabel( tr( "NAME_LAB" ), this, Bold ), iName, iLabel );
+  addWidget( createField( this, "meshName" ), iName, iSingle, 4 )->setMinimumWidth( 150 );
+  // - type
+  addWidget( createLabel( tr( "OBJECT_LAB" ), this, Bold ), iObject, iLabel );
+  addWidget( createField( this, "meshType" ), iObject, iSingle, 4 )->setMinimumWidth( 150 );
+  // - --- (separator)
+  addWidget( createSeparator( this ), iObjectEnd, iLabel, 5 );
+
+  // node info
+  // - info
+  addWidget( createLabel( tr( "NODES_LAB" ), this, Bold ), iNodes, iLabel );
+  addWidget( createField( this, "nbNodes" ), iNodes, iTotal );
+  // - --- (separator)
+  addWidget( createSeparator( this ), iNodesEnd, iLabel, 5 );
+
+  // element info
+  // - title
+  addWidget( createLabel( tr( "ELEMENTS_LAB" ), this, Bold ), iElementsTitle, iLabel );
+  addWidget( createLabel( tr( "TOTAL_LAB" ), this, Italic ), iElementsTitle, iTotal );
+  addWidget( createLabel( tr( "LINEAR_LAB" ), this, Italic ), iElementsTitle, iLinear );
+  addWidget( createLabel( tr( "QUADRATIC_LAB" ), this, Italic ), iElementsTitle, iQuadratic );
+  addWidget( createLabel( tr( "BI_QUADRATIC_LAB" ), this, Italic ), iElementsTitle, iBiQuadratic );
+  // - --- (separator)
+  addWidget( createSeparator( this ), iElementsTitleEnd, iTotal, 4 );
+  // - summary
+  addWidget( createField( this, "totalNbElems" ), iElementsTotal, iTotal );
+  addWidget( createField( this, "totalNbLinearElems" ), iElementsTotal, iLinear );
+  addWidget( createField( this, "totalNbQuadraticElems" ), iElementsTotal, iQuadratic );
+  addWidget( createField( this, "totalNbBiQuadraticElems" ), iElementsTotal, iBiQuadratic );
+  // - --- (separator)
+  addWidget( createSeparator( this ), iElementsTotalEnd, iTotal, 4 );
+  // - 0D elements info
+  addWidget( createLabel( tr( "0D_LAB" ), this, Bold | Italic ), i0D, iLabel );
+  addWidget( createField( this, "nb0D" ), i0D, iTotal );
+  // - --- (separator)
+  addWidget( createSeparator( this ), i0DEnd, iTotal, 4 );
+  // - balls info
+  addWidget( createLabel( tr( "BALL_LAB" ), this, Bold | Italic ), iBalls, iLabel );
+  addWidget( createField( this, "nbBall" ), iBalls, iTotal );
+  // - --- (separator)
+  addWidget( createSeparator( this ), iBallsEnd, iTotal, 4 );
+  // - 1D elements info
+  addWidget( createLabel( tr( "1D_LAB" ), this, Bold | Italic ), i1D, iLabel );
+  addWidget( createField( this, "nb1D" ), i1D, iTotal );
+  addWidget( createField( this, "nbLinear1D" ), i1D, iLinear );
+  addWidget( createField( this, "nbQuadratic1D" ), i1D, iQuadratic );
+  // - --- (separator)
+  addWidget( createSeparator( this ), i1DEnd, iTotal, 4 );
+  // - 2D elements info
+  // --+ summary
+  addWidget( createLabel( tr( "2D_LAB" ), this, Bold | Italic ), i2D, iLabel );
+  addWidget( createField( this, "nb2D" ), i2D, iTotal );
+  addWidget( createField( this, "nbLinear2D" ), i2D, iLinear );
+  addWidget( createField( this, "nbQuadratic2D" ), i2D, iQuadratic );
+  addWidget( createField( this, "nbBiQuadratic2D" ), i2D, iBiQuadratic );
+  // --+ triangles
+  addWidget( createLabel( tr( "TRIANGLES_LAB" ), this, Italic ), i2DTriangles, iLabel );
+  addWidget( createField( this, Italic, "nbTriangle" ), i2DTriangles, iTotal );
+  addWidget( createField( this, Italic, "nbLinearTriangle" ), i2DTriangles, iLinear );
+  addWidget( createField( this, Italic, "nbQuadraticTriangle" ), i2DTriangles, iQuadratic );
+  addWidget( createField( this, Italic, "nbBiQuadraticTriangle" ), i2DTriangles, iBiQuadratic );
+  // --+ quadrangles
+  addWidget( createLabel( tr( "QUADRANGLES_LAB" ), this, Italic ), i2DQuadrangles, iLabel );
+  addWidget( createField( this, Italic, "nbQuadrangle" ), i2DQuadrangles, iTotal );
+  addWidget( createField( this, Italic, "nbLinearQuadrangle" ), i2DQuadrangles, iLinear );
+  addWidget( createField( this, Italic, "nbQuadraticQuadrangle" ), i2DQuadrangles, iQuadratic );
+  addWidget( createField( this, Italic, "nbBiQuadraticQuadrangle" ), i2DQuadrangles, iBiQuadratic );
+  // --+ polygons
+  addWidget( createLabel( tr( "POLYGONS_LAB" ), this, Italic ), i2DPolygons, iLabel );
+  addWidget( createField( this, Italic, "nbPolygon" ), i2DPolygons, iTotal );
+  addWidget( createField( this, Italic, "nbLinearPolygon" ), i2DPolygons, iLinear );
+  addWidget( createField( this, Italic, "nbQuadraticPolygon" ), i2DPolygons, iQuadratic );
+  // - --- (separator)
+  addWidget( createSeparator( this ), i2DEnd, iTotal, 4 );
+  // - 3D elements info
+  // --+ summary
+  addWidget( createLabel( tr( "3D_LAB" ), this, Bold | Italic ), i3D, iLabel );
+  addWidget( createField( this, "nb3D" ), i3D, iTotal );
+  addWidget( createField( this, "nbLinear3D" ), i3D, iLinear );
+  addWidget( createField( this, "nbQuadratic3D" ), i3D, iQuadratic );
+  addWidget( createField( this, "nbBiQuadratic3D" ), i3D, iBiQuadratic );
+  // --+ tetras
+  addWidget( createLabel( tr( "TETRAHEDRONS_LAB" ), this, Italic ), i3DTetrahedrons, iLabel );
+  addWidget( createField( this, Italic, "nbTetrahedron" ), i3DTetrahedrons, iTotal );
+  addWidget( createField( this, Italic, "nbLinearTetrahedron" ), i3DTetrahedrons, iLinear );
+  addWidget( createField( this, Italic, "nbQudraticTetrahedron" ), i3DTetrahedrons, iQuadratic );
+  // --+ hexas
+  addWidget( createLabel( tr( "HEXAHEDONRS_LAB" ), this, Italic ), i3DHexahedrons, iLabel );
+  addWidget( createField( this, Italic, "nbHexahedron" ), i3DHexahedrons, iTotal );
+  addWidget( createField( this, Italic, "nbLinearHexahedron" ), i3DHexahedrons, iLinear );
+  addWidget( createField( this, Italic, "nbQuadraticHexahedron" ), i3DHexahedrons, iQuadratic );
+  addWidget( createField( this, Italic, "nbBiQuadraticHexahedron" ), i3DHexahedrons, iBiQuadratic );
+  // --+ pyramids
+  addWidget( createLabel( tr( "PYRAMIDS_LAB" ), this, Italic ), i3DPyramids, iLabel );
+  addWidget( createField( this, Italic, "nbPyramid" ), i3DPyramids, iTotal );
+  addWidget( createField( this, Italic, "nbLinearPyramid" ), i3DPyramids, iLinear );
+  addWidget( createField( this, Italic, "nbQuadraticPyramid" ), i3DPyramids, iQuadratic );
+  // --+ prisms
+  addWidget( createLabel( tr( "PRISMS_LAB" ), this, Italic ), i3DPrisms, iLabel );
+  addWidget( createField( this, Italic, "nbPrism" ), i3DPrisms, iTotal );
+  addWidget( createField( this, Italic, "nbLinearPrism" ), i3DPrisms, iLinear );
+  addWidget( createField( this, Italic, "nbQuadraticPrism" ), i3DPrisms, iQuadratic );
+  addWidget( createField( this, Italic, "nbBiQuadraticPrism" ), i3DPrisms, iBiQuadratic );
+  // --+ hexagonal prisms
+  addWidget( createLabel( tr( "HEX_PRISMS_LAB" ), this, Italic ), i3DHexaPrisms, iLabel );
+  addWidget( createField( this, Italic, "nbHexagonalPrism" ), i3DHexaPrisms, iTotal );
+  // --+ polyhedrons
+  addWidget( createLabel( tr( "POLYHEDRONS_LAB" ), this, Italic ), i3DPolyhedrons, iLabel );
+  addWidget( createField( this, Italic, "nbPolyhedron" ), i3DPolyhedrons, iTotal );
+
+  // load button
+  QPushButton* loadBtn = new QPushButton( tr( "BUT_LOAD_MESH" ), this );
+  loadBtn->setAutoDefault( true );
+  connect( loadBtn, SIGNAL( clicked() ), this, SLOT( loadMesh() ) );
+  addWidget( loadBtn, iEnd, iSingle, 4 );
+
+  // additional layout set-up
+  l->setColumnStretch( iLabel, 0 );
+  l->setColumnStretch( iTotal, 5 );
+  l->setColumnStretch( iLinear, 5 );
+  l->setColumnStretch( iQuadratic, 5 );
+  l->setColumnStretch( iBiQuadratic, 5 );
+  l->setRowStretch( iElementsEnd, 5 );
+
+  // set initial values
   clear();
 }
 
 /*!
-  \brief Destructor
+  \brief Destructor.
 */
-SMESHGUI_MeshInfo::~SMESHGUI_MeshInfo()
+SMESHGUI_BaseInfo::~SMESHGUI_BaseInfo()
 {
 }
 
 /*!
-  \brief Show information on the mesh object.
-  \param obj object being processed (mesh, sub-mesh, group, ID source)
+  \brief Show information on given object.
+  \param proxy Object to show information on (mesh, sub-mesh, group, ID source).
 */
-void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
+void SMESHGUI_BaseInfo::showInfo( const SMESH::SelectionProxy& proxy )
 {
+  // reset panel
   clear();
-  if ( !CORBA::is_nil( obj )) {
-    _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
-    if ( sobj ) 
-      myWidgets[iName][iSingle]->setProperty( "text", sobj->GetName().c_str() );
-    SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
-    SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
-    SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
-    if ( !aMesh->_is_nil() ) {
-      myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_MESH" ));
+
+  // then fill panel with data if object is not null
+  if ( proxy )
+  {
+    myProxy = proxy;
+
+    SMESH::MeshInfo info = proxy.meshInfo();
+
+    // object info
+    // - name
+    widget( iName, iSingle )->setProperty( "text", proxy.name() );
+    // - type
+    QString typeName;
+    SMESH::SelectionProxy::Type type = proxy.type();
+    if ( type == SMESH::SelectionProxy::Mesh )
+    {
+      typeName = tr( "OBJECT_MESH" );
     }
-    else if ( !aSubMesh->_is_nil() ) {
-      myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_SUBMESH" ));
+    else if ( type == SMESH::SelectionProxy::Submesh )
+    {
+      typeName = tr( "OBJECT_SUBMESH" );
     }
-    else if ( !aGroup->_is_nil() ) {
-      QString objType;
-      switch( aGroup->GetType() ) {
-      case SMESH::NODE:  objType = tr( "OBJECT_GROUP_NODES"   );break;
-      case SMESH::EDGE:  objType = tr( "OBJECT_GROUP_EDGES"   );break;
-      case SMESH::FACE:  objType = tr( "OBJECT_GROUP_FACES"   );break;
-      case SMESH::VOLUME:objType = tr( "OBJECT_GROUP_VOLUMES" );break;
-      case SMESH::ELEM0D:objType = tr( "OBJECT_GROUP_0DELEMS" );break;
-      case SMESH::BALL:  objType = tr( "OBJECT_GROUP_BALLS"   );break;
-      default:           objType = tr( "OBJECT_GROUP"         );break;
+    else if ( type >= SMESH::SelectionProxy::Group )
+    {
+      switch( proxy.groupElementType() )
+      {
+      case SMESH::NODE:   typeName = tr( "OBJECT_GROUP_NODES"   ); break;
+      case SMESH::EDGE:   typeName = tr( "OBJECT_GROUP_EDGES"   ); break;
+      case SMESH::FACE:   typeName = tr( "OBJECT_GROUP_FACES"   ); break;
+      case SMESH::VOLUME: typeName = tr( "OBJECT_GROUP_VOLUMES" ); break;
+      case SMESH::ELEM0D: typeName = tr( "OBJECT_GROUP_0DELEMS" ); break;
+      case SMESH::BALL:   typeName = tr( "OBJECT_GROUP_BALLS"   ); break;
+      default:            typeName = tr( "OBJECT_GROUP"         ); break;
       }
-      myWidgets[iObject][iSingle]->setProperty( "text", objType );
+      QString subType;
+      if ( type == SMESH::SelectionProxy::GroupStd )
+        subType = tr( "OBJECT_GROUP_STANDALONE" );
+      else if ( type == SMESH::SelectionProxy::GroupGeom )
+        subType = tr( "OBJECT_GROUP_GEOM" );
+      else if ( type == SMESH::SelectionProxy::GroupFilter )
+        subType = tr( "OBJECT_GROUP_FILTER" );
+      if ( !subType.isEmpty() )
+        typeName = QString( "%1 %2" ).arg( typeName, subType );
     }
-    SMESH::long_array_var info = obj->GetMeshInfo();
-    myWidgets[iNodes][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Node] ));
-    myWidgets[i0D][iTotal]    ->setProperty( "text", QString::number( info[SMDSEntity_0D] ));
-    myWidgets[iBalls][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Ball] ));
-    long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge];
-    myWidgets[i1D][iTotal]    ->setProperty( "text", QString::number( nbEdges ));
-    myWidgets[i1D][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Edge] ));
-    myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ));
-    long nbTriangles     = info[SMDSEntity_Triangle]   + info[SMDSEntity_Quad_Triangle]   + info[SMDSEntity_BiQuad_Triangle];
-    long nbQuadrangles   = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
-    long nb2DPolygons    = info[SMDSEntity_Polygon]    + info[SMDSEntity_Quad_Polygon];
-    long nb2DLinear      = info[SMDSEntity_Triangle]        + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon];
-    long nb2DQuadratic   = info[SMDSEntity_Quad_Triangle]   + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_Quad_Polygon];
-    long nb2DBiQuadratic = info[SMDSEntity_BiQuad_Triangle] + info[SMDSEntity_BiQuad_Quadrangle];
-    long nb2DTotal       = nb2DLinear + nb2DQuadratic + nb2DBiQuadratic;
-
-    myWidgets[i2D][iTotal]                  ->setProperty( "text", QString::number( nb2DTotal ));
-    myWidgets[i2D][iLinear]                 ->setProperty( "text", QString::number( nb2DLinear ));
-    myWidgets[i2D][iQuadratic]              ->setProperty( "text", QString::number( nb2DQuadratic ));
-    myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", QString::number( nb2DBiQuadratic ));
-    myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", QString::number( nbTriangles ));
-    myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", QString::number( info[SMDSEntity_Triangle] ));
-    myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Triangle] ));
-    myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Triangle] ));
-    myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", QString::number( nbQuadrangles ));
-    myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ));
-    myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] ));
-    myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Quadrangle] ));
-    myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", QString::number( nb2DPolygons ));
-    myWidgets[i2DPolygons][iLinear]         ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ));
-    myWidgets[i2DPolygons][iQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Polygon] ));
-    long nbTetrahedrons  = info[SMDSEntity_Tetra]   + info[SMDSEntity_Quad_Tetra];
-    long nbHexahedrons   = info[SMDSEntity_Hexa]    + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa];
-    long nbPyramids      = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid];
-    long nbPrisms        = info[SMDSEntity_Penta]   + info[SMDSEntity_Quad_Penta] + info[SMDSEntity_BiQuad_Penta];
-    long nb3DLinear      = info[SMDSEntity_Tetra]   + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra] + info[SMDSEntity_Hexagonal_Prism];
-    long nb3DQuadratic   = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta];
-    long nb3DBiQuadratic = info[SMDSEntity_TriQuad_Hexa] + info[SMDSEntity_BiQuad_Penta];
-    long nb3DTotal       = nb3DLinear + nb3DQuadratic + nb3DBiQuadratic;
-    myWidgets[i3D][iTotal]                  ->setProperty( "text", QString::number( nb3DTotal ));
-    myWidgets[i3D][iLinear]                 ->setProperty( "text", QString::number( nb3DLinear ));
-    myWidgets[i3D][iQuadratic]              ->setProperty( "text", QString::number( nb3DQuadratic ));
-    myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", QString::number( nb3DBiQuadratic ));
-    myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", QString::number( nbTetrahedrons ));
-    myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ));
-    myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Tetra] ));
-    myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", QString::number( nbHexahedrons ));
-    myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", QString::number( info[SMDSEntity_Hexa] ));
-    myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Hexa] ));
-    myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_TriQuad_Hexa] ));
-    myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", QString::number( nbPyramids ));
-    myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", QString::number( info[SMDSEntity_Pyramid] ));
-    myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Pyramid] ));
-    myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", QString::number( nbPrisms ));
-    myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", QString::number( info[SMDSEntity_Penta] ));
-    myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ));
-    myWidgets[i3DPrisms][iBiQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Penta] ));
-    myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ));
-    myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ));
-    long nbElemTotal       = info[SMDSEntity_0D] + info[SMDSEntity_Ball] + nbEdges + nb2DTotal + nb3DTotal;
-    long nbElemLinearial   = info[SMDSEntity_Edge] + nb2DLinear + nb3DLinear;
-    long nbElemQuadratic   = info[SMDSEntity_Quad_Edge] + nb2DQuadratic + nb3DQuadratic;
-    long nbElemBiQuadratic = nb2DBiQuadratic + nb3DBiQuadratic;
-    myWidgets[iNb][iTotal]      ->setProperty( "text", QString::number( nbElemTotal ));
-    myWidgets[iNb][iLinear]     ->setProperty( "text", QString::number( nbElemLinearial ));
-    myWidgets[iNb][iQuadratic]  ->setProperty( "text", QString::number( nbElemQuadratic ));
-    myWidgets[iNb][iBiQuadratic]->setProperty( "text", QString::number( nbElemBiQuadratic ));
-    // before full loading from study file, type of elements in a sub-mesh can't be defined
-    // in some cases
-    bool infoOK = obj->IsMeshInfoCorrect();
-    myLoadBtn->setVisible( !infoOK );
-    if ( !infoOK )
+    widget( iObject, iSingle )->setProperty( "text", typeName );
+
+    // node info
+    uint nbNodes = info[SMDSEntity_Node];
+    widget( iNodes, iTotal )->setProperty( "value", nbNodes );
+
+    // element info
+    // - 0D elements info
+    uint nb0d = info[SMDSEntity_0D];
+    widget( i0D, iTotal )->setProperty( "value", nb0d );
+    // - balls info
+    uint nbBalls = info[SMDSEntity_Ball];
+    widget( iBalls, iTotal )->setProperty( "value", nbBalls );
+    // - 1D elements info
+    uint nb1dLin = info[SMDSEntity_Edge];
+    uint nb1dQua = info[SMDSEntity_Quad_Edge];
+    uint nb1d = nb1dLin + nb1dQua;
+    widget( i1D, iLinear )->setProperty( "value", nb1dLin );
+    widget( i1D, iQuadratic )->setProperty( "value", nb1dQua );
+    widget( i1D, iTotal )->setProperty( "value", nb1d );
+    // - 2D elements info
+    // --+ triangles
+    uint nbTriLin = info[SMDSEntity_Triangle];
+    uint nbTriQua = info[SMDSEntity_Quad_Triangle];
+    uint nbTriBiq = info[SMDSEntity_BiQuad_Triangle];
+    uint nbTri = nbTriLin + nbTriQua + nbTriBiq;
+    widget( i2DTriangles, iLinear )->setProperty( "value", nbTriLin );
+    widget( i2DTriangles, iQuadratic )->setProperty( "value", nbTriQua );
+    widget( i2DTriangles, iBiQuadratic )->setProperty( "value", nbTriBiq );
+    widget( i2DTriangles, iTotal )->setProperty( "value", nbTri );
+    // --+ quadrangles
+    uint nbQuadLin = info[SMDSEntity_Quadrangle];
+    uint nbQuadQua = info[SMDSEntity_Quad_Quadrangle];
+    uint nbQuadBiq = info[SMDSEntity_BiQuad_Quadrangle];
+    uint nbQuad = nbQuadLin + nbQuadQua + nbQuadBiq;
+    widget( i2DQuadrangles, iLinear )->setProperty( "value", nbQuadLin );
+    widget( i2DQuadrangles, iQuadratic )->setProperty( "value", nbQuadQua );
+    widget( i2DQuadrangles, iBiQuadratic )->setProperty( "value", nbQuadBiq );
+    widget( i2DQuadrangles, iTotal )->setProperty( "value", nbQuad );
+    // --+ polygons
+    uint nbPolyLin = info[SMDSEntity_Polygon];
+    uint nbPolyQua = info[SMDSEntity_Quad_Polygon];
+    uint nbPoly = nbPolyLin + nbPolyQua;
+    widget( i2DPolygons, iLinear )->setProperty( "value", nbPolyLin );
+    widget( i2DPolygons, iQuadratic )->setProperty( "value", nbPolyQua );
+    widget( i2DPolygons, iTotal )->setProperty( "value", nbPoly );
+    // --+ summary
+    uint nb2dLin = nbTriLin + nbQuadLin + nbPolyLin;
+    uint nb2dQua = nbTriQua + nbQuadQua + nbPolyQua;
+    uint nb2dBiq = nbTriBiq + nbQuadBiq;
+    uint nb2d = nb2dLin + nb2dQua + nb2dBiq;
+    widget( i2D, iLinear )->setProperty( "value", nb2dLin );
+    widget( i2D, iQuadratic )->setProperty( "value", nb2dQua );
+    widget( i2D, iBiQuadratic )->setProperty( "value", nb2dBiq );
+    widget( i2D, iTotal )->setProperty( "value", nb2d );
+    // - 3D elements info
+    // --+ tetras
+    uint nbTetraLin = info[SMDSEntity_Tetra];
+    uint nbTetraQua = info[SMDSEntity_Quad_Tetra];
+    uint nbTetra = nbTetraLin + nbTetraQua;
+    widget( i3DTetrahedrons, iLinear )->setProperty( "value", nbTetraLin );
+    widget( i3DTetrahedrons, iQuadratic )->setProperty( "value", nbTetraQua );
+    widget( i3DTetrahedrons, iTotal )->setProperty( "value", nbTetra );
+    // --+ hexas
+    uint nbHexaLin = info[SMDSEntity_Hexa];
+    uint nbHexaQua = info[SMDSEntity_Quad_Hexa];
+    uint nbHexaBiq = info[SMDSEntity_TriQuad_Hexa];
+    uint nbHexa = nbHexaLin + nbHexaQua + nbHexaBiq;
+    widget( i3DHexahedrons, iLinear )->setProperty( "value", nbHexaLin );
+    widget( i3DHexahedrons, iQuadratic )->setProperty( "value", nbHexaQua );
+    widget( i3DHexahedrons, iBiQuadratic )->setProperty( "value", nbHexaBiq );
+    widget( i3DHexahedrons, iTotal )->setProperty( "value", nbHexa );
+    // --+ pyramids
+    uint nbPyraLin = info[SMDSEntity_Pyramid];
+    uint nbPyraQua = info[SMDSEntity_Quad_Pyramid];
+    uint nbPyra = nbPyraLin + nbPyraQua;
+    widget( i3DPyramids, iLinear )->setProperty( "value", nbPyraLin );
+    widget( i3DPyramids, iQuadratic )->setProperty( "value", nbPyraQua );
+    widget( i3DPyramids, iTotal )->setProperty( "value", nbPyra );
+    // --+ prisms
+    uint nbPentaLin = info[SMDSEntity_Penta];
+    uint nbPentaQua = info[SMDSEntity_Quad_Penta];
+    uint nbPentaBiq = info[SMDSEntity_BiQuad_Penta];
+    uint nbPenta = nbPentaLin + nbPentaQua + nbPentaBiq;
+    widget( i3DPrisms, iLinear )->setProperty( "value", nbPentaLin );
+    widget( i3DPrisms, iQuadratic )->setProperty( "value", nbPentaQua );
+    widget( i3DPrisms, iBiQuadratic )->setProperty( "value", nbPentaBiq );
+    widget( i3DPrisms, iTotal )->setProperty( "value", nbPenta );
+    // --+ hexagonal prisms
+    uint nbHexaPri = info[SMDSEntity_Hexagonal_Prism];
+    widget( i3DHexaPrisms, iTotal )->setProperty( "value", nbHexaPri );
+    // --+ polyhedrons
+    uint nbPolyhedra = info[SMDSEntity_Polyhedra];
+    widget( i3DPolyhedrons, iTotal )->setProperty( "value", nbPolyhedra );
+    // --+ summary
+    uint nb3dLin = nbTetraLin + nbHexaLin + nbPyraLin + nbPentaLin + nbHexaPri + nbPolyhedra;
+    uint nb3dQua = nbTetraQua + nbHexaQua + nbPyraQua + nbPentaQua;
+    uint nb3dBiq = nbHexaBiq + nbPentaBiq;
+    uint nb3d = nb3dLin + nb3dQua + nb3dBiq;
+    widget( i3D, iLinear )->setProperty( "value", nb3dLin );
+    widget( i3D, iQuadratic )->setProperty( "value", nb3dQua );
+    widget( i3D, iBiQuadratic )->setProperty( "value", nb3dBiq );
+    widget( i3D, iTotal )->setProperty( "value", nb3d );
+    // - summary
+    uint nbElemLin = nb1dLin + nb2dLin + nb3dLin;
+    uint nbElemQua = nb1dQua + nb2dQua + nb3dQua;
+    uint nbElemBiq = nb2dBiq + nb3dBiq;
+    uint nbElem = nb0d + nbBalls + nb1d + nb2d + nb3d;
+    widget( iElementsTotal, iLinear )->setProperty( "value", nbElemLin );
+    widget( iElementsTotal, iQuadratic )->setProperty( "value", nbElemQua );
+    widget( iElementsTotal, iBiQuadratic )->setProperty( "value", nbElemBiq );
+    widget( iElementsTotal, iTotal )->setProperty( "value", nbElem );
+
+    // show 'Load' button if data was not loaded yet
+    widget( iEnd, iSingle )->setVisible( !proxy.isValid() );
+
+    // until data is loaded from study file, type of elements in a sub-mesh or group
+    // can be undefined in some cases
+    if ( !proxy.isValid() )
     {
-      // two options:
-      // 1. Type of 2D or 3D elements is unknown but their nb is OK (for a sub-mesh)
-      // 2. No info at all (for a group on geom or filter)
-      bool hasAnyInfo = false;
-      for ( size_t i = 0; i < info->length() && !hasAnyInfo; ++i )
-        hasAnyInfo = info[i];
-      if ( hasAnyInfo ) // believe it is a sub-mesh
+      // two cases are possible:
+      // 1. type of 2D or 3D elements is unknown but their nb is OK (for a sub-mesh)
+      // 2. there is no info at all (for a group on geom or on filter)
+      if ( info.count( SMDSEntity_Node, SMDSEntity_Last ) > 0 ) // believe it is a sub-mesh
       {
-        if ( nb2DLinear + nb2DQuadratic + nb2DBiQuadratic > 0 )
+        if ( nb2dLin + nb2dQua + nb2dBiq > 0 )
         {
-          myWidgets[i2D][iLinear]                 ->setProperty( "text", "?" );
-          myWidgets[i2D][iQuadratic]              ->setProperty( "text", "?" );
-          myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", "?" );
-          myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", "?" );
-          myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", "?" );
-          myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", "?" );
-          myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", "?" );
-          myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", "?" );
-          myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", "?" );
-          myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", "?" );
-          myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", "?" );
-          myWidgets[i2DPolygons][iLinear]         ->setProperty( "text", "?" );
-          myWidgets[i2DPolygons][iQuadratic]      ->setProperty( "text", "?" );
-          myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", "?" );
-          myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
-          myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
-          myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
-          myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
+          // we know nothing about triangles, quadranges and polygons
+          for ( int i = i2DTriangles; i < i2DEnd; i++ )
+          {
+            for ( int j = iTotal; j < iNbColumns; j++ )
+            {
+              if ( widget( i, j ) )
+                widget( i, j )->setProperty( "text", "?" );
+            }
+          }
+          // we don't know if elements are linear, quadratic or bi-quadratic
+          for ( int j = iLinear; j < iNbColumns; j++ )
+          {
+            if ( widget( i2D, j ) )
+              widget( i2D, j )->setProperty( "text", "?" );
+            if ( widget( iElementsTotal, j ) )
+              widget( iElementsTotal, j )->setProperty( "text", "?" );
+          }
         }
-        else if ( nb3DLinear + nb3DQuadratic + nb3DBiQuadratic > 0 )
+        else if ( nb3dLin + nb3dQua + nb3dBiq > 0 )
         {
-          myWidgets[i3D][iLinear]                 ->setProperty( "text", "?" );
-          myWidgets[i3D][iQuadratic]              ->setProperty( "text", "?" );
-          myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", "?" );
-          myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", "?" );
-          myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", "?" );
-          myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", "?" );
-          myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", "?" );
-          myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", "?" );
-          myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", "?" );
-          myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", "?" );
-          myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", "?" );
-          myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", "?" );
-          myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", "?" );
-          myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", "?" );
-          myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", "?" );
-          myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", "?" );
-          myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", "?" );
-          myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", "?" );
-          myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
-          myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
-          myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
-          myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
+          // we know nothing about tetras, hexas, etc.
+          for ( int i = i3DTetrahedrons; i < i3DEnd; i++ )
+          {
+            for ( int j = iTotal; j < iNbColumns; j++ )
+            {
+              if ( widget( i, j ) )
+                widget( i, j )->setProperty( "text", "?" );
+            }
+          }
+          // we don't know if elements are linear, quadratic or bi-quadratic
+          for ( int j = iLinear; j < iNbColumns; j++ )
+          {
+            if ( widget( i3D, j ) )
+              widget( i3D, j )->setProperty( "text", "?" );
+            if ( widget( iElementsTotal, j ) )
+              widget( iElementsTotal, j )->setProperty( "text", "?" );
+          }
         }
       }
       else
       {
-        myWidgets[iNodes][iTotal]               ->setProperty( "text", "?" );
-        myWidgets[i0D][iTotal]                  ->setProperty( "text", "?" );
-        myWidgets[iBalls][iTotal]               ->setProperty( "text", "?" );
-        myWidgets[i1D][iTotal]                  ->setProperty( "text", "?" );
-        myWidgets[i1D][iLinear]                 ->setProperty( "text", "?" );
-        myWidgets[i1D][iQuadratic]              ->setProperty( "text", "?" );
-        myWidgets[i2D][iTotal]                  ->setProperty( "text", "?" );
-        myWidgets[i2D][iLinear]                 ->setProperty( "text", "?" );
-        myWidgets[i2D][iQuadratic]              ->setProperty( "text", "?" );
-        myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", "?" );
-        myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", "?" );
-        myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", "?" );
-        myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", "?" );
-        myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", "?" );
-        myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", "?" );
-        myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", "?" );
-        myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", "?" );
-        myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", "?" );
-        myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", "?" );
-        myWidgets[i3D][iTotal]                  ->setProperty( "text", "?" );
-        myWidgets[i3D][iLinear]                 ->setProperty( "text", "?" );
-        myWidgets[i3D][iQuadratic]              ->setProperty( "text", "?" );
-        myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", "?" );
-        myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", "?" );
-        myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", "?" );
-        myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", "?" );
-        myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", "?" );
-        myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", "?" );
-        myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", "?" );
-        myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", "?" );
-        myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", "?" );
-        myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", "?" );
-        myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", "?" );
-        myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", "?" );
-        myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", "?" );
-        myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", "?" );
-        myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", "?" );
-        myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
-        myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
-        myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
-        myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
+        // we know nothing about nodes :(
+        widget( iNodes, iTotal )->setProperty( "text", "?" );
+        // we know nothing about elements :(
+        for ( int i = iElementsTotal; i < iElementsEnd; i++ )
+        {
+          for ( int j = iTotal; j < iNbColumns; j++ )
+          {
+            if ( widget( i, j ) )
+              widget( i, j )->setProperty( "text", "?" );
+          }
+        }
       }
     }
   }
 }
 
 /*!
-  \brief Load mesh from a study file
+  \brief Update information in panel.
 */
-void SMESHGUI_MeshInfo::loadMesh()
+void SMESHGUI_BaseInfo::updateInfo()
 {
-  SUIT_OverrideCursor wc;
+  showInfo( myProxy );
+}
 
-  SALOME_ListIO selected;
-  SMESHGUI::selectionMgr()->selectedObjects( selected );
+/*!
+  \brief Load mesh from a study file.
+*/
+void SMESHGUI_BaseInfo::loadMesh()
+{
+  SUIT_OverrideCursor wc;
+  if ( myProxy )
+  {
+    myProxy.load();
+    updateInfo();
+  }
+}
 
-  if ( selected.Extent() == 1 ) {
-    Handle(SALOME_InteractiveObject) IO = selected.First();
-    SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
-    if ( !CORBA::is_nil( obj )) {
-      SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
-      if ( !mesh->_is_nil() )
-      {
-        mesh->Load();
-        showInfo( obj );
-      }
+/*!
+  \brief Reset panel (clear all data).
+*/
+void SMESHGUI_BaseInfo::clear()
+{
+  // - name
+  widget( iName, iSingle )->setProperty( "text", QString() );
+  // - type
+  widget( iObject, iSingle )->setProperty( "text", QString() );
+  // - nodes
+  widget( iNodes, iTotal )->setProperty( "value", 0 );
+  // - elements
+  for ( int i = iElementsTotal; i < iElementsEnd; i++ )
+  {
+    for ( int j = iTotal; j < iNbColumns; j++ )
+    {
+      if ( widget( i, j ) )
+        widget( i, j )->setProperty( "value", 0 );
     }
   }
 }
 
 /*!
-  \brief Reset the widget to the initial state (nullify all fields).
+  \brief Register widget in a grid.
+  \param w Widget being added.
+  \param row Row index in a grid.
+  \param column Column index in a grid.
+  \param colspan Number of columns to span in a grid. Defaults to 1.
+  \return Just added widget.
 */
-void SMESHGUI_MeshInfo::clear()
+QWidget* SMESHGUI_BaseInfo::addWidget( QWidget* w, int row, int column, int colspan )
 {
-  myWidgets[iName][iSingle]               ->setProperty( "text", QString() );
-  myWidgets[iObject][iSingle]             ->setProperty( "text", QString() );
-  myWidgets[iNodes][iTotal]               ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i0D][iTotal]                  ->setProperty( "text", QString::number( 0 ));
-  myWidgets[iBalls][iTotal]               ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i1D][iTotal]                  ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i1D][iLinear]                 ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i1D][iQuadratic]              ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2D][iTotal]                  ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2D][iLinear]                 ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2D][iQuadratic]              ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DPolygons][iLinear]         ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DPolygons][iQuadratic]      ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3D][iTotal]                  ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3D][iLinear]                 ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3D][iQuadratic]              ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", QString::number( 0 ));
-  myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", QString::number( 0 ));
-  myWidgets[iNb][iTotal]                  ->setProperty( "text", QString::number( 0 ));
-  myWidgets[iNb][iLinear]                 ->setProperty( "text", QString::number( 0 ));
-  myWidgets[iNb][iQuadratic]              ->setProperty( "text", QString::number( 0 ));
-  myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ));
-}
-
-/*!
-  \brief Create info field
-  \return new info field
-*/
-QLabel* SMESHGUI_MeshInfo::createField()
-{
-  QLabel* lab = new QLabel( this );
-  lab->setFrameStyle( StyledPanel | Sunken );
-  lab->setAlignment( Qt::AlignCenter );
-  lab->setAutoFillBackground( true );
-  QPalette pal = lab->palette();
-  pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ));
-  lab->setPalette( pal );
-  lab->setMinimumWidth( 70 );
-  return lab;
-}
-
-/*!
-  \brief Create horizontal rule.
-  \return new line object
-*/
-QWidget* SMESHGUI_MeshInfo::createLine()
-{
-  QFrame* line = new QFrame( this );
-  line->setFrameStyle( HLine | Sunken );
-  return line;
-}
-
-/*!
-  \brief Change widget font attributes (bold, italic, ...).
-  \param w widget
-  \param attr font attributes (XORed flags)
-  \param val value to be set to attributes
-*/
-void SMESHGUI_MeshInfo::setFontAttributes( QWidget* w, int attr, bool val )
-{
-  if ( w && attr ) {
-    QFont f = w->font();
-    if ( attr & Bold   ) f.setBold( val );
-    if ( attr & Italic ) f.setItalic( val );
-    w->setFont( f );
-  }
-}
-
-/*!
-  \brief Show/hide group(s) of fields.
-  \param start beginning of the block
-  \param end end of the block
-  \param on visibility flag
-*/
-void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on )
-{
-  start = qMax( 0, start );
-  end   = qMin( end, (int)iElementsEnd );
-  for ( int i = start; i < end; i++ ) {
-    wlist wl = myWidgets[i];
-    foreach ( QWidget* w, wl ) w->setVisible( on );
-  }
-}
-
-void SMESHGUI_MeshInfo::saveInfo( QTextStream &out )
-{
-  out << QString( 9, '-' ) << "\n";
-  out << tr( "BASE_INFO" ) << "\n";
-  out << QString( 9, '-' ) << "\n";
-  out <<                                   tr( "NAME_LAB" )         << "  " << ( myWidgets[iName][iSingle]->property( "text" )).toString() << "\n";
-  out <<                                   tr( "OBJECT_LAB" )       << "  " << ( myWidgets[iObject][iSingle]->property( "text" )).toString() << "\n";
-  out <<                                   tr( "NODES_LAB" )        << "  " << ( myWidgets[iNodes][iTotal]->property( "text" )).toString() << "\n";
-  out <<                                   tr( "ELEMENTS_LAB" )     << "\n";
-  out << QString( SPACING_INFO,   ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iNb][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO,   ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[iNb][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO,   ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[iNb][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO,   ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[iNb][iBiQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO,   ' ' ) << tr( "0D_LAB" )           << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i0D][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO,   ' ' ) << tr( "BALL_LAB" )         << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iBalls][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO,   ' ' ) << tr( "1D_LAB" )           << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i1D][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i1D][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i1D][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO,   ' ' ) << tr( "2D_LAB" )           << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2D][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2D][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2D][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2D][iBiQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "TRIANGLES_LAB" )    << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DTriangles][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DTriangles][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DTriangles][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DTriangles][iBiQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRANGLES_LAB" )  << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DQuadrangles][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DQuadrangles][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DQuadrangles][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DQuadrangles][iBiQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYGONS_LAB" )     << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DPolygons][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DPolygons][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DPolygons][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO,   ' ' ) << tr( "3D_LAB" )           << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3D][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3D][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3D][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i3D][iBiQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "TETRAHEDRONS_LAB" ) << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DTetrahedrons][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DTetrahedrons][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DTetrahedrons][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "HEXAHEDONRS_LAB" )  << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexahedrons][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DHexahedrons][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DHexahedrons][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i3DHexahedrons][iBiQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "PYRAMIDS_LAB" )     << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPyramids][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPyramids][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPyramids][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "PRISMS_LAB" )       << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPrisms][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPrisms][iLinear]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPrisms][iQuadratic]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "HEX_PRISMS_LAB" )   << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexaPrisms][iTotal]->property( "text" )).toString() << "\n";
-  out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYHEDRONS_LAB" )  << "\n";
-  out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPolyhedrons][iTotal]->property( "text" )).toString() << "\n" << "\n";
-}
-
-/*!
-  \class SMESHGUI_ElemInfo
-  \brief Base class for the mesh element information widget.
+  if ( !myWidgets.contains( row ) )
+    myWidgets[row] = wlist();
+  myWidgets[row][column] = w;
+  dynamic_cast<QGridLayout*>( layout() )->addWidget( w, row, column, 1, colspan );
+  return w;
+}
+
+/*!
+  \brief Get registered widget.
+  \param row Row index in a grid.
+  \param column Column index in a grid.
+  \return Widget stored in a given grid cell (0 if there's no widget).
 */
+QWidget* SMESHGUI_BaseInfo::widget( int row, int column ) const
+{
+  return myWidgets.contains( row ) && myWidgets[row].contains( column ) ? myWidgets[row][column] : 0;
+}
 
 /*!
-  \brief Constructor
-  \param parent parent widget
+  \brief Get text value from registered widget.
+  \param row Row index in a grid.
+  \param column Column index in a grid.
+  \return Value string (empty string if no label in given cell).
+*/
+QString SMESHGUI_BaseInfo::value( int row, int column ) const
+{
+  return widgetValue( widget( row, column ) );
+}
+
+/*!
+  \brief Show/hide group(s) of widgets.
+  \param startRow Starting grid row.
+  \param lastRow Last grid row.
+  \param on Visibility flag.
+*/
+void SMESHGUI_BaseInfo::setFieldsVisible( int startRow, int lastRow, bool on )
+{
+  startRow = qMax( 0, startRow );
+  lastRow = qMin( lastRow, (int)iEnd );
+  for ( int i = startRow; i <= lastRow; i++ )
+  {
+    wlist widgets = myWidgets[i];
+    foreach ( QWidget* w, widgets )
+      w->setVisible( on );
+  }
+}
+
+/*!
+  \brief Write information from panel to ouput stream.
+  \param out Text stream output.
+*/
+void SMESHGUI_BaseInfo::saveInfo( QTextStream& out )
+{
+  // title
+  QString title = tr( "BASE_INFO" );
+  out << ruler( title.size() ) << endl;
+  out << title << endl;
+  out << ruler( title.size() ) << endl;
+  out << endl;
+
+  // object info
+  // - name
+  out << tr( "NAME_LAB" ) << spacing() << value( iName, iSingle ) << endl;
+  // - type
+  out << tr( "OBJECT_LAB" ) << spacing() << value( iObject, iSingle ) << endl;
+  // - --- (separator)
+  out << endl;
+
+  // node info
+  out << tr( "NODES_LAB" ) << spacing() << value( iNodes, iTotal ) << endl;
+  // - --- (separator)
+  out << endl;
+
+  // element info
+  QString lin = tr( "LINEAR_LAB" ) + ":" + spacing();
+  QString qua = tr( "QUADRATIC_LAB" ) + ":" + spacing();
+  QString biq = tr( "BI_QUADRATIC_LAB" ) + ":" + spacing();
+  // - summary
+  out << tr( "ELEMENTS_LAB" ) << spacing() << value( iElementsTotal, iTotal ) << endl;
+  out << indent(1) << lin << value( iElementsTotal, iLinear ) << endl;
+  out << indent(1) << qua << value( iElementsTotal, iQuadratic ) << endl;
+  out << indent(1) << biq << value( iElementsTotal, iBiQuadratic ) << endl;
+  // - --- (separator)
+  out << endl;
+  // - 0D elements info
+  out << indent(1) << tr( "0D_LAB" ) << spacing() << value( i0D, iTotal ) << endl;
+  // - --- (separator)
+  out << endl;
+  // - balls info
+  out << indent(1) << tr( "BALL_LAB" ) << spacing() << value( iBalls, iTotal ) << endl;
+  // - --- (separator)
+  out << endl;
+  // - 1D elements info
+  out << indent(1) << tr( "1D_LAB" ) << spacing() << value( i1D, iTotal ) << endl;
+  out << indent(2) << lin << value( i1D, iLinear ) << endl;
+  out << indent(2) << qua << value( i1D, iQuadratic ) << endl;
+  // - --- (separator)
+  out << endl;
+  // - 2D elements info
+  // - summary
+  out << indent(1) << tr( "2D_LAB" ) << spacing() << value( i2D, iTotal ) << endl;
+  out << indent(2) << lin << value( i2D, iLinear ) << endl;
+  out << indent(2) << qua << value( i2D, iQuadratic ) << endl;
+  out << indent(2) << biq << value( i2D, iBiQuadratic ) << endl;
+  // - --- (separator)
+  out << endl;
+  // --+ triangles
+  out << indent(2) << tr( "TRIANGLES_LAB" ) << spacing() << value( i2DTriangles, iTotal ) << endl;
+  out << indent(3) << lin << value( i2DTriangles, iLinear ) << endl;
+  out << indent(3) << qua << value( i2DTriangles, iQuadratic ) << endl;
+  out << indent(3) << biq << value( i2DTriangles, iBiQuadratic ) << endl;
+  // --+ quadrangles
+  out << indent(2) << tr( "QUADRANGLES_LAB" ) << spacing() << value( i2DQuadrangles, iTotal ) << endl;
+  out << indent(3) << lin << value( i2DQuadrangles, iLinear ) << endl;
+  out << indent(3) << qua << value( i2DQuadrangles, iQuadratic ) << endl;
+  out << indent(3) << biq << value( i2DQuadrangles, iBiQuadratic ) << endl;
+  // --+ polygons
+  out << indent(2) << tr( "POLYGONS_LAB" ) << spacing() << value( i2DPolygons, iTotal ) << endl;
+  out << indent(3) << lin << value( i2DPolygons, iLinear ) << endl;
+  out << indent(3) << qua << value( i2DPolygons, iQuadratic ) << endl;
+  // - --- (separator)
+  out << endl;
+  // - 3D elements info
+  // --+ summary
+  out << indent(1) << tr( "3D_LAB" ) << spacing() << value( i3D, iTotal ) << endl;
+  out << indent(2) << lin << value( i3D, iLinear ) << endl;
+  out << indent(2) << qua << value( i3D, iQuadratic ) << endl;
+  out << indent(2) << biq << value( i3D, iBiQuadratic ) << endl;
+  // - --- (separator)
+  out << endl;
+  // --+ tetras
+  out << indent(2) << tr( "TETRAHEDRONS_LAB" ) << spacing() << value( i3DTetrahedrons, iTotal ) << endl;
+  out << indent(3) << lin << value( i3DTetrahedrons, iLinear ) << endl;
+  out << indent(3) << qua << value( i3DTetrahedrons, iQuadratic ) << endl;
+  // --+ hexas
+  out << indent(2) << tr( "HEXAHEDONRS_LAB" ) << spacing() << value( i3DHexahedrons, iTotal ) << endl;
+  out << indent(3) << lin << value( i3DHexahedrons, iLinear ) << endl;
+  out << indent(3) << qua << value( i3DHexahedrons, iQuadratic ) << endl;
+  out << indent(3) << biq << value( i3DHexahedrons, iBiQuadratic ) << endl;
+  // --+ pyramids
+  out << indent(2) << tr( "PYRAMIDS_LAB" ) << spacing() << value( i3DPyramids, iTotal ) << endl;
+  out << indent(3) << lin << value( i3DPyramids, iLinear ) << endl;
+  out << indent(3) << qua << value( i3DPyramids, iQuadratic ) << endl;
+  // --+ prisms
+  out << indent(2) << tr( "PRISMS_LAB" ) << spacing() << value( i3DPrisms, iTotal ) << endl;
+  out << indent(3) << lin << value( i3DPrisms, iLinear ) << endl;
+  out << indent(3) << qua << value( i3DPrisms, iQuadratic ) << endl;
+  out << indent(3) << biq << value( i3DPrisms, iBiQuadratic ) << endl;
+  // --+ hexagonal prisms
+  out << indent(2) << tr( "HEX_PRISMS_LAB" ) << spacing() << value( i3DHexaPrisms, iTotal ) << endl;
+  // --+ polyhedrons
+  out << indent(2) << tr( "POLYHEDRONS_LAB" ) << spacing() << value( i3DPolyhedrons, iTotal ) << endl;
+  // - --- (separator)
+  out << endl;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class InfoWriter
+/// \brief Base info writer class.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
+class InfoWriter
+{
+protected:
+  int myPrecision;
+  bool myRecursive;
+public:
+  InfoWriter( bool = false );
+  void write( const QString&, bool = false );
+  void write( const QString&, const QString&, bool = false );
+  void write( const QString&, int, bool = false );
+  void write( const QString&, double, bool = false );
+  void write( const QString&, const SMESH::XYZ&, bool = false );
+  virtual void indent() {}
+  virtual void unindent() {}
+  virtual void separator() {}
+protected:
+  virtual void put( const QString&, const QString&, bool = false ) = 0;
+};
+
+InfoWriter::InfoWriter( bool r ): myRecursive(r)
+{
+  myPrecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
+}
+
+void InfoWriter::write( const QString& key, bool emphasize )
+{
+  put( key, QString(), emphasize );
+}
+
+void InfoWriter::write( const QString& key, const QString& value, bool emphasize )
+{
+  put( key, value, emphasize );
+}
+
+void InfoWriter::write( const QString& key, int value, bool emphasize )
+{
+  put( key, QString::number( value ), emphasize );
+}
+
+void InfoWriter::write( const QString& key, double value, bool emphasize )
+{
+  put( key, QString::number( value, myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) ), emphasize );
+}
+
+void InfoWriter::write( const QString& key, const SMESH::XYZ& value, bool emphasize )
+{
+  if ( myRecursive )
+  {
+    write( key, emphasize );
+    indent();
+    write( "X", value.x() );
+    write( "Y", value.y() );
+    write( "Z", value.z() );
+    unindent(); 
+  }
+  else
+  {
+    QStringList vl;
+    vl << QString::number( value.x(), myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) );
+    vl << QString::number( value.y(), myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) );
+    vl << QString::number( value.z(), myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) );
+    put( key, vl.join( ", " ), emphasize );
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SimpleWriter
+/// \brief Base text writer.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
+class SimpleWriter: public InfoWriter
+{
+protected:
+  int myIndent;
+public:
+  SimpleWriter();
+  void indent();
+  void unindent();
+  void separator();
+protected:
+  void put( const QString&, const QString&, bool );
+  virtual QString spacer() const;
+  virtual QString decorate( const QString& ) const;
+  virtual void dumpLine( const QString& ) = 0;
+};
+
+SimpleWriter::SimpleWriter(): InfoWriter(false), myIndent(0)
+{
+}
+
+void SimpleWriter::indent()
+{
+  myIndent += 1;
+}
+
+void SimpleWriter::unindent()
+{
+  myIndent = qMax( myIndent-1, 0 );
+}
+
+void SimpleWriter::separator()
+{
+  write( "" );
+}
+
+QString SimpleWriter::spacer() const
+{
+  return " ";
+}
+
+QString SimpleWriter::decorate( const QString& s ) const
+{
+  return s;
+}
+
+void SimpleWriter::put( const QString& key, const QString& value, bool emphasize )
+{
+  QString line;
+  line += ::indent( spacer(), myIndent*4 );
+  line += decorate( key );
+  if ( !value.isEmpty() )
+  {
+    line += ":";
+    line += emphasize ? decorate( value ) : value;
+  }
+  dumpLine( line );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class StreamWriter
+/// \brief Writer for QTextStream.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
+class StreamWriter: public SimpleWriter
+{
+  QTextStream& myOut;
+public:
+  StreamWriter( QTextStream& );
+protected:
+  void dumpLine( const QString& );
+};
+
+StreamWriter::StreamWriter( QTextStream& out ): SimpleWriter(), myOut(out)
+{
+}
+
+void StreamWriter::dumpLine( const QString& line )
+{
+  myOut << line;
+  myOut << endl;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class TextWriter
+/// \brief Writer for QTextBrowser.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
+class TextWriter: public SimpleWriter
+{
+  QTextBrowser* myInfo;
+public:
+  TextWriter( QTextBrowser* );
+protected:
+  QString spacer() const;
+  QString decorate( const QString& ) const;
+  void dumpLine( const QString& );
+};
+
+TextWriter::TextWriter( QTextBrowser* w ): SimpleWriter(), myInfo(w)
+{
+}
+
+QString TextWriter::spacer() const
+{
+  return "&nbsp;";
+}
+
+QString TextWriter::decorate( const QString& s ) const
+{
+  return bold( s );
+}
+
+void TextWriter::dumpLine( const QString& line )
+{
+  myInfo->append( line );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class TreeWriter
+/// \brief Writer for QTreeWidget.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
+class TreeWriter: public InfoWriter
+{
+  QTreeWidget* myInfo;
+  QTreeWidgetItem* myCurrentItem;
+  TreeItemCreator* myCreator;
+public:
+  TreeWriter( QTreeWidget*, TreeItemCreator* );
+  ~TreeWriter();
+  void indent();
+  void unindent();
+protected:
+  void put( const QString&, const QString&, bool = false );
+};
+
+TreeWriter::TreeWriter( QTreeWidget* w, TreeItemCreator* c ):
+  InfoWriter(true), myInfo(w), myCurrentItem(0), myCreator(c)
+{
+}
+
+TreeWriter::~TreeWriter()
+{
+  delete myCreator;
+}
+
+void TreeWriter::put( const QString& key, const QString& value, bool emphasize )
+{
+  //std::string sss = myCurrentItem ? myCurrentItem->text(0).toStdString() : "";
+  int options = Bold;
+  if ( emphasize ) options |= AllColumns;
+  QTreeWidgetItem* item = myCreator->createItem( myCurrentItem, options );
+  item->setText( 0, key );
+  if ( !value.isEmpty() )
+  {
+    QString val = value;
+    if ( value.startsWith( "<a href" )) // connectivity encoded as: <a href = "nodes://host/1 2">1 2</a>
+    {
+      int role = ( value[11] == 'n' ) ? NodeConnectivity : ElemConnectivity;
+      val = value.mid( value.lastIndexOf( '>', -5 ) + 1 ); // ==>   1 2</a>
+      val.chop( 4 );
+      item->setData( 1, TypeRole, role );
+    }
+    item->setText( 1, val );
+  }
+}
+
+void TreeWriter::indent()
+{
+  QTreeWidgetItem* item = myCurrentItem ? myCurrentItem : myInfo->invisibleRootItem();
+  if ( item->childCount() > 0 )
+    myCurrentItem = item->child( item->childCount()-1 );
+}
+
+void TreeWriter::unindent()
+{
+  if ( myCurrentItem )
+    myCurrentItem = myCurrentItem->parent();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_ElemInfo
+/// \brief Base class for the mesh element information widget.
+///
+/// Displays the detail information about given mesh node(s) or element(s).
+/// Default class does not provide working implementation but onle general
+/// functionalities; main work is done in sub-classes.
+////////////////////////////////////////////////////////////////////////////////
+
+/*!
+  \brief Constructor.
+  \param parent Parent widget. Defaults to 0.
 */
-SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent )
-  : QWidget( parent ), myActor( 0 ), myIsElement( -1 )
+SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent ): SMESHGUI_Info( parent ), myWhat( ShowNone )
 {
   myFrame = new QWidget( this );
   myExtra = new ExtraWidget( this );
+
   QVBoxLayout* vbl = new QVBoxLayout( this );
   vbl->setMargin( 0 );
-  vbl->setSpacing( 0 );
+  vbl->setSpacing( SPACING );
   vbl->addWidget( myFrame );
   vbl->addWidget( myExtra );
-  connect( myExtra->prev, SIGNAL( clicked() ), this, SLOT( showPrevious() ));
-  connect( myExtra->next, SIGNAL( clicked() ), this, SLOT( showNext() ));
+
+  connect( myExtra->prev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) );
+  connect( myExtra->next, SIGNAL( clicked() ), this, SLOT( showNext() ) );
+
   clear();
 }
 
 /*!
-  \brief Destructor
+  \brief Destructor.
 */
 SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo()
 {
 }
 
 /*!
-  \brief Set mesh data source (actor)
-  \param actor mesh object actor
+  \brief Show information on given node / element.
+  \param proxy Object to compute information on (mesh, sub-mesh, group, ID source).
+  \param id Mesh node / element ID.
+  \param isElement If \c true, show element info; otherwise show node info.
 */
-void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor, SMESH::SMESH_IDSource_var obj )
+void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy, uint id, bool isElement )
 {
-  if ( myActor != actor ) {
-    myActor = actor;
-    myIsElement = -1;
-    SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
-    myMeshHasShape = ( !mesh->_is_nil() && mesh->HasShapeToMesh() );
-    clear();
-  }
-}
-
-/*!
-  \brief Show mesh element information
-  \param id mesh node / element ID
-  \param isElem show mesh element information if \c true or mesh node information if \c false
-*/
-void SMESHGUI_ElemInfo::showInfo( long id, bool isElem )
-{
-  QSet<long> ids;
+  QSet<uint> ids;
   ids << id;
-  showInfo( ids, isElem );
+  showInfo( proxy, ids, isElement );
 }
 
 /*!
-  \brief Show mesh element information
-  \param ids mesh nodes / elements identifiers
-  \param isElem show mesh element information if \c true or mesh node information if \c false
+  \brief Show information on given nodes / elements.
+  \param proxy Object to compute information on (mesh, sub-mesh, group, ID source).
+  \param ids Mesh nodes / elements IDs.
+  \param isElement If \c true, show element info; otherwise show node info.
 */
-void SMESHGUI_ElemInfo::showInfo( QSet<long> ids, bool isElem )
+void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy, QSet<uint> ids, bool isElement )
 {
-  QList<long> newIds = ids.toList();
+  if ( !proxy )
+  {
+    clear();
+    return;
+  }
+
+  QList<uint> newIds = ids.toList();
   qSort( newIds );
-  if ( myIDs == newIds && myIsElement == isElem ) return;
+  int what = isElement ? ShowElements : ShowNodes;
+  
+  if ( myProxy == proxy && myIDs == newIds && myWhat == what )
+    return;
+  
+  myProxy = proxy;
+  myProxy.refresh(); // try to re-initialize actor
+
+  clear();
 
   myIDs = newIds;
-  myIsElement = isElem;
+  myWhat = what;
   myIndex = 0;
+  
   updateControls();
-  information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ));
+  information( myIDs.mid( myIndex*blockSize(), blockSize() ) );
 }
 
 /*!
-  \brief Clear mesh element information widget
+  \brief Show information on given group.
+  \param proxy Object to compute information on (group).
+*/
+void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy )
+{
+  if ( !proxy || proxy.groupElementType() == SMESH::ALL ) // null proxy or not a group
+  {
+    clear();
+    return;
+  }
+
+  showInfo( proxy, proxy.ids(), proxy.groupElementType() != SMESH::NODE );
+}
+
+/*!
+  \brief Reset panel (clear all data).
 */
 void SMESHGUI_ElemInfo::clear()
 {
@@ -1019,136 +1513,483 @@ void SMESHGUI_ElemInfo::clear()
 }
 
 /*!
-  \brief Get central area widget
-  \return central widget
+  \brief Get central area widget.
+  \return Central widget.
 */
-QWidget* SMESHGUI_ElemInfo::frame() const
+QWidget* SMESHGUI_ElemInfo::centralWidget() const
 {
   return myFrame;
 }
 
 /*!
-  \brief Get actor
-  \return actor being used
+  \brief Get current mesh proxy object information is shown on.
+  \return Current proxy.
 */
-SMESH_Actor* SMESHGUI_ElemInfo::actor() const
+SMESH::SelectionProxy SMESHGUI_ElemInfo::proxy() const
 {
-  return myActor;
+  return myProxy;
 }
 
 /*!
   \brief Get current info mode.
-  \return \c true if mesh element information is shown or \c false if node information is shown
+  \return Current panel mode.
 */
-bool SMESHGUI_ElemInfo::isElements() const
+int SMESHGUI_ElemInfo::what() const
 {
-  return myIsElement;
+  return myWhat;
 }
 
 /*!
-  \fn void SMESHGUI_ElemInfo::information( const QList<long>& ids )
-  \brief Show information on the specified nodes / elements
-
-  This function is to be redefined in sub-classes.
-
-  \param ids nodes / elements identifiers information is to be shown on
+  \brief Get title for given element type.
+  \param type Mesh element type.
+  \param multiple Use plural form. Defaults to \c false.
+  \return Element type's title.
 */
+QString SMESHGUI_ElemInfo::type2str( int type, bool multiple )
+{
+  QString title;
+  switch ( type )
+  {
+  case SMDSAbs_Edge:
+    title = multiple ? tr( "EDGES" ) : tr( "EDGE" ) ; break;
+  case SMDSAbs_Face:
+    title = multiple ? tr( "FACES" ) : tr( "FACE" ); break;
+  case SMDSAbs_Volume:
+    title = multiple ? tr( "VOLUMES" ) : tr( "VOLUME" ); break;
+  case SMDSAbs_0DElement:
+    title = multiple ? tr( "0D_ELEMENTS" ) : tr( "0D_ELEMENT" ); break;
+  case SMDSAbs_Ball:
+    title = multiple ? tr( "BALL_ELEMENTS" ) : tr( "BALL" ); break;
+  default:
+    break;
+  }
+  return title;
+}
 
 /*!
-  \brief Internal clean-up (reset widget)
+  \brief Get title for given shape type.
+  \param type Shape type.
+  \return Shape type's title.
 */
-void SMESHGUI_ElemInfo::clearInternal()
+QString SMESHGUI_ElemInfo::stype2str( int type )
 {
+  QString title;
+  switch ( type )
+  {
+  case GEOM::VERTEX:
+    title = tr( "GEOM_VERTEX" ); break;
+  case GEOM::EDGE:
+    title = tr( "GEOM_EDGE" ); break;
+  case GEOM::FACE:
+    title = tr( "GEOM_FACE" ); break;
+  case GEOM::SOLID:
+  default:
+    title = tr( "GEOM_SOLID" ); break;
+    break;
+  }
+  return title;
 }
 
 /*!
-  \brief Get node connectivity
-  \param node mesh node
-  \return node connectivity map
+  \brief Get title for given element type.
+  \param type Mesh element type.
+  \return Element type's title.
 */
-SMESHGUI_ElemInfo::Connectivity SMESHGUI_ElemInfo::nodeConnectivity( const SMDS_MeshNode* node )
+QString SMESHGUI_ElemInfo::etype2str( int type )
 {
-  Connectivity elmap;
-  if ( node ) {
-    SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
-    while ( it && it->more() ) {
-      const SMDS_MeshElement* ne = it->next();
-      elmap[ ne->GetType() ] << ne->GetID();
-    }
+  QString title;
+  switch ( type )
+  {
+  case SMESH::Entity_0D:
+    title = tr( "SMESH_ELEM0D" ); break;
+  case SMESH::Entity_Edge:
+    title = tr( "SMESH_EDGE" ); break;
+  case SMESH::Entity_Quad_Edge:
+    title = tr( "SMESH_QUADRATIC_EDGE" ); break;
+  case SMESH::Entity_Triangle:
+    title = tr( "SMESH_TRIANGLE" ); break;
+  case SMESH::Entity_Quad_Triangle:
+    title = tr( "SMESH_QUADRATIC_TRIANGLE" ); break;
+  case SMESH::Entity_BiQuad_Triangle:
+    title = tr( "SMESH_BIQUADRATIC_TRIANGLE" ); break;
+  case SMESH::Entity_Quadrangle:
+    title = tr( "SMESH_QUADRANGLE" ); break;
+  case SMESH::Entity_Quad_Quadrangle:
+    title = tr( "SMESH_QUADRATIC_QUADRANGLE" ); break;
+  case SMESH::Entity_BiQuad_Quadrangle:
+    title = tr( "SMESH_BIQUADRATIC_QUADRANGLE" ); break;
+  case SMESH::Entity_Polygon:
+    title = tr( "SMESH_POLYGON" ); break;
+  case SMESH::Entity_Quad_Polygon:
+    title = tr( "SMESH_QUADRATIC_POLYGON" ); break;
+  case SMESH::Entity_Tetra:
+    title = tr( "SMESH_TETRAHEDRON" ); break;
+  case SMESH::Entity_Quad_Tetra:
+    title = tr( "SMESH_QUADRATIC_TETRAHEDRON" ); break;
+  case SMESH::Entity_Pyramid:
+    title = tr( "SMESH_PYRAMID" ); break;
+  case SMESH::Entity_Quad_Pyramid:
+    title = tr( "SMESH_QUADRATIC_PYRAMID" ); break;
+  case SMESH::Entity_Hexa:
+    title = tr( "SMESH_HEXAHEDRON" ); break;
+  case SMESH::Entity_Quad_Hexa:
+    title = tr( "SMESH_QUADRATIC_HEXAHEDRON" ); break;
+  case SMESH::Entity_TriQuad_Hexa:
+    title = tr( "SMESH_TRIQUADRATIC_HEXAHEDRON" ); break;
+  case SMESH::Entity_Penta:
+    title = tr( "SMESH_PENTA" ); break;
+  case SMESH::Entity_Quad_Penta:
+    title = tr( "SMESH_QUADRATIC_PENTAHEDRON" ); break;
+  case SMESH::Entity_BiQuad_Penta:
+    title = tr( "SMESH_BIQUADRATIC_PENTAHEDRON" ); break;
+  case SMESH::Entity_Hexagonal_Prism:
+    title = tr( "SMESH_HEX_PRISM" ); break;
+  case SMESH::Entity_Polyhedra:
+    title = tr( "SMESH_POLYEDRON" ); break;
+  case SMESH::Entity_Quad_Polyhedra:
+    title = tr( "SMESH_QUADRATIC_POLYEDRON" ); break;
+  case SMESH::Entity_Ball:
+    title = tr( "SMESH_BALL" ); break;
+  default:
+    break;
   }
-  return elmap;
+  return title;
 }
 
 /*!
-  \brief Format connectivity data to string representation
-  \param connectivity connetivity map
-  \param type element type
-  \return string representation of the connectivity
+  \brief Get title for given quality control.
+  \param type Mesh control type.
+  \return Quality control's title.
 */
-QString SMESHGUI_ElemInfo::formatConnectivity( Connectivity connectivity, int type )
+QString SMESHGUI_ElemInfo::ctrl2str( int control )
 {
-  QStringList str;
-  if ( connectivity.contains( type )) {
-    QList<int> elements = connectivity[ type ];
-    qSort( elements );
-    foreach( int id, elements )
-      str << QString::number( id );
+  QString title;
+  switch ( control )
+  {
+  case SMESH::FT_AspectRatio:
+    title = tr( "ASPECTRATIO_ELEMENTS" ); break;
+  case SMESH::FT_AspectRatio3D:
+    title = tr( "ASPECTRATIO_3D_ELEMENTS" ); break;
+  case SMESH::FT_Warping:
+    title = tr( "WARP_ELEMENTS" ); break;
+  case SMESH::FT_MinimumAngle:
+    title = tr( "MINIMUMANGLE_ELEMENTS" ); break;
+  case SMESH::FT_Taper:
+    title = tr( "TAPER_ELEMENTS" ); break;
+  case SMESH::FT_Skew:
+    title = tr( "SKEW_ELEMENTS" ); break;
+  case SMESH::FT_Area:
+    title = tr( "AREA_ELEMENTS" ); break;
+  case SMESH::FT_Volume3D:
+    title = tr( "VOLUME_3D_ELEMENTS" ); break;
+  case SMESH::FT_MaxElementLength2D:
+    title = tr( "MAX_ELEMENT_LENGTH_2D" ); break;
+  case SMESH::FT_MaxElementLength3D:
+    title = tr( "MAX_ELEMENT_LENGTH_3D" ); break;
+  case SMESH::FT_Length:
+    title = tr( "LENGTH_EDGES" ); break;
+  case SMESH::FT_Length2D:
+  case SMESH::FT_Length3D:
+    title = tr( "MIN_ELEM_EDGE" ); break;
+  case SMESH::FT_BallDiameter:
+    title = tr( "BALL_DIAMETER" ); break;
+  default:
+    break;
   }
-  return str.join( " " );
+  return title;
 }
 
 /*!
-  \brief Calculate gravity center of the mesh element
-  \param element mesh element
+  \brief Write information on given mesh nodes / elements.
+  \param writer Information writer.
+  \param ids Nodes / elements IDs.
 */
-SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement* element )
+void SMESHGUI_ElemInfo::writeInfo( InfoWriter* writer, const QList<uint>& ids )
 {
-  XYZ xyz;
-  if ( element ) {
-    SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
-    while ( nodeIt->more() ) {
-      const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-      xyz.add( node->X(), node->Y(), node->Z() );
+  if ( !proxy() )
+    return;
+
+  bool grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
+  int cprecision = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ? 
+    SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 ) : -1;
+
+  SMESH::XYZ xyz;
+  SMESH::Connectivity connectivity;
+  SMESH::Position position;
+  bool ok;
+
+  foreach ( uint id, ids )
+  {
+    writer->separator();
+
+    if ( what() == ShowNodes )
+    {
+      // show node info
+      // - check that node exists
+      if ( !proxy().hasNode( id ) )
+        continue;
+      // - id
+      writer->write( tr( "NODE" ), (int)id, true );
+      writer->indent();
+      // - coordinates
+      ok = proxy().nodeCoordinates( id, xyz );
+      if ( ok )
+      {
+        writer->write( tr( "COORDINATES" ), xyz );
+      }
+      // - connectivity
+      ok = proxy().nodeConnectivity( id, connectivity );
+      if ( ok )
+      {
+        if ( !connectivity.isEmpty() )
+        {
+          writer->write( tr( "CONNECTIVITY" ) );
+          writer->indent();
+          for ( int i = SMDSAbs_Edge; i <= SMDSAbs_Ball; i++ )
+          {
+            QString formatted = formatConnectivity( connectivity, i );
+            if ( !formatted.isEmpty() )
+              writer->write( type2str( i, true ), formatted );
+          }
+          writer->unindent();
+        }
+        else
+        {
+          writer->write( tr( "CONNECTIVITY" ), tr( "FREE_NODE" ) );
+        }
+      }
+      // - position
+      ok = proxy().nodePosition( id, position );
+      if ( ok && position.isValid() )
+      {
+        writer->write( tr( "POSITION" ), (stype2str( position.shapeType() ) + " #%1").arg( position.shapeId() ) );
+        writer->indent();
+        if ( position.hasU() )
+          writer->write( tr("U_POSITION"), position.u() );
+        if ( position.hasV() )
+          writer->write( tr("V_POSITION"), position.v() );
+        writer->unindent();
+      }
+      // - groups node belongs to
+      QList<SMESH::SelectionProxy> groups = proxy().nodeGroups( id );
+      bool topCreated = false;
+      foreach( SMESH::SelectionProxy group, groups )
+      {
+        if ( group && !group.name().isEmpty() )
+        {
+          if ( !topCreated )
+          {
+            writer->write( SMESHGUI_AddInfo::tr( "GROUPS" ) );
+            writer->indent();
+            topCreated = true;
+          }
+          writer->write( group.name().trimmed() ); // trim name
+          if ( grp_details )
+          {
+            writer->indent();
+            int type = group.type();
+            if ( type == SMESH::SelectionProxy::GroupStd )
+            {
+              writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
+            }
+            else if ( type == SMESH::SelectionProxy::GroupGeom )
+            {
+              writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
+              writer->write( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ), group.shapeName() );
+            }
+            else if ( type == SMESH::SelectionProxy::GroupFilter )
+            {
+              writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
+            }
+            int size = group.size();
+            if ( size != -1 );
+            writer->write( SMESHGUI_AddInfo::tr( "SIZE" ), size );
+            QColor color = group.color();
+            if ( color.isValid() )
+              writer->write( SMESHGUI_AddInfo::tr( "COLOR" ), color.name() );
+            writer->unindent();
+          }
+        }
+      }
+      if ( topCreated )
+        writer->unindent();
+      writer->unindent();
     }
-    xyz.divide( element->NbNodes() );
-  }
-  return xyz;
+    else if ( what() == ShowElements )
+    {
+      // show element info
+      // - check that element exists
+      if ( !proxy().hasElement( id ) )
+        continue;
+      // - id & type
+      int type = proxy().elementType( id );
+      if  ( type == SMESH::ALL )
+        continue;
+      writer->write( type2str( type ), (int)id, true );
+      writer->indent();
+      // - geometry type
+      type = proxy().elementEntityType( id );
+      writer->write( tr( "TYPE" ), etype2str( type ) );
+      // - connectivity
+      if ( type == SMESH::Entity_Polyhedra ||
+           type == SMESH::Entity_Quad_Polyhedra )
+      {
+        int nbNodes;
+        ok = proxy().perFaceConnectivity( id, connectivity, nbNodes );
+        if ( ok && !connectivity.isEmpty() )
+        {
+          writer->write( tr( "NB_NODES" ), nbNodes );
+          writer->write( tr( "CONNECTIVITY" ) );
+          writer->indent();
+          int nbFaces = connectivity.size();
+          for ( int iF = 1; iF <= nbFaces; ++iF )
+          {
+            QString formatted = formatConnectivity( connectivity, -iF );
+            writer->write(( type2str( SMDSAbs_Face, 0 ) + " %1 / %2" ).arg( iF ).arg( nbFaces ),
+                          formatted );
+          }
+          writer->unindent();
+        }
+      }
+      else
+      {
+        ok = proxy().elementConnectivity( id, connectivity );
+        if ( ok && !connectivity.isEmpty() )
+        {
+          QString formatted = formatConnectivity( connectivity, SMDSAbs_Node );
+          if ( !formatted.isEmpty() )
+          {
+            writer->write( tr( "NB_NODES" ), connectivity[ SMDSAbs_Node ].size() );
+            writer->write( tr( "CONNECTIVITY" ), formatted ); //todo: TypeRole: ElemConnectivity
+          }
+        }
+      }
+      // - position
+      ok = proxy().elementPosition( id, position );
+      if ( ok && position.isValid() )
+      {
+        writer->write( tr( "POSITION" ), (stype2str( position.shapeType() ) + " #%1").arg( position.shapeId() ) );
+      }
+      // - gravity center
+      ok = proxy().elementGravityCenter( id, xyz );
+      if ( ok )
+      {
+        writer->write( tr( "GRAVITY_CENTER" ), xyz );
+      }
+      // - normal vector
+      ok = proxy().elementNormal( id, xyz );
+      if ( ok )
+      {
+        writer->write( tr( "NORMAL_VECTOR" ), xyz );
+      }
+      // - controls
+      bool topCreated = false;
+      for ( int i = SMESH::FT_AspectRatio; i < SMESH::FT_Undefined; i++ )
+      {
+        QString ctrlTitle = ctrl2str( i );
+        if ( ctrlTitle.isEmpty() )
+          continue;
+        if ( !topCreated )
+        {
+          writer->write( tr( "CONTROLS" ) );
+          writer->indent();
+          topCreated = true;
+        }
+        double value;
+        if ( proxy().elementControl( id, i, cprecision, value ) )
+          writer->write( ctrlTitle, value );
+      }
+      if ( topCreated )
+        writer->unindent();
+      // - groups element belongs to
+      QList<SMESH::SelectionProxy> groups = proxy().elementGroups( id );
+      topCreated = false;
+      foreach( SMESH::SelectionProxy group, groups )
+      {
+        if ( group && !group.name().isEmpty() )
+        {
+          if ( !topCreated )
+          {
+            writer->write( SMESHGUI_AddInfo::tr( "GROUPS" ) );
+            writer->indent();
+            topCreated = true;
+          }
+          writer->write( group.name().trimmed() ); // trim name
+          if ( grp_details )
+          {
+            writer->indent();
+            int type = group.type();
+            if ( type == SMESH::SelectionProxy::GroupStd )
+            {
+              writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
+            }
+            else if ( type == SMESH::SelectionProxy::GroupGeom )
+            {
+              writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
+              writer->write( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ), group.shapeName() );
+            }
+            else if ( type == SMESH::SelectionProxy::GroupFilter )
+            {
+              writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
+            }
+            int size = group.size();
+            if ( size != -1 );
+              writer->write( SMESHGUI_AddInfo::tr( "SIZE" ), size );
+            QColor color = group.color();
+            if ( color.isValid() )
+              writer->write( SMESHGUI_AddInfo::tr( "COLOR" ), color.name() );
+            writer->unindent();
+          }
+        }
+      }
+      if ( topCreated )
+        writer->unindent();
+      writer->unindent();
+    }
+  }  
 }
 
 /*!
-  \brief Calculate normal vector to the mesh face
-  \param element mesh face
+  \fn void SMESHGUI_ElemInfo::information( const QList<uint>& ids )
+  \brief Show information on given mesh nodes / elements.
+
+  This function has to be redefined in sub-classes.
+
+  \param ids Nodes / elements IDs.
 */
-SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::normal( const SMDS_MeshElement* element )
+
+/*!
+  \brief Internal clean-up (reset panel).
+
+  Default implementation does nothing; the method has to be redefined
+  in sub-classes to perform internal clean-up.
+*/
+void SMESHGUI_ElemInfo::clearInternal()
 {
-  gp_XYZ n = SMESH::getNormale( SMDS_Mesh::DownCast<SMDS_MeshFace>( element ));
-  return XYZ(n.X(), n.Y(), n.Z());
 }
 
 /*!
-  \brief This slot is called from "Show Previous" button click.
-  Shows information on the previous group of the items.
+  \brief Show previous chunk of information.
 */
 void SMESHGUI_ElemInfo::showPrevious()
 {
   myIndex = qMax( 0, myIndex-1 );
   updateControls();
-  information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ));
+  information( myIDs.mid( myIndex*blockSize(), blockSize() ) );
 }
 
 /*!
-  \brief This slot is called from "Show Next" button click.
-  Shows information on the next group of the items.
+  \brief Show next chunk of information.
 */
 void SMESHGUI_ElemInfo::showNext()
 {
-  myIndex = qMin( myIndex+1, myIDs.count() / MAXITEMS );
+  myIndex = qMin( myIndex+1, myIDs.count() / blockSize() );
   updateControls();
-  information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ));
+  information( myIDs.mid( myIndex*blockSize(), blockSize() ) );
 }
 
 /*!
-  \brief Update widgets state
+  \brief Update control widget state.
 */
 void SMESHGUI_ElemInfo::updateControls()
 {
@@ -1156,448 +1997,53 @@ void SMESHGUI_ElemInfo::updateControls()
 }
 
 /*!
-  \class SMESHGUI_SimpleElemInfo
-  \brief Represents mesh element information in the simple text area.
+  \brief Write information from panel to ouput stream.
+  \param out Text stream output.
 */
+void SMESHGUI_ElemInfo::saveInfo( QTextStream &out )
+{
+  // title
+  QString title = tr( "ELEM_INFO" );
+  out << ruler( title.size() ) << endl;
+  out << title << endl;
+  out << ruler( title.size() ) << endl;
+  //  out << endl;
+
+  // info
+  StreamWriter writer( out );
+  writeInfo( &writer, myIDs );
+  out << endl;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_SimpleElemInfo
+/// \brief Show mesh element information in the simple text area.
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
-  \brief Constructor
-  \param parent parent widget
+  \brief Constructor.
+  \param parent Parent widget. Defaults to 0.
 */
 SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
   : SMESHGUI_ElemInfo( parent )
 {
-  myInfo = new QTextBrowser( frame() );
-  QVBoxLayout* l = new QVBoxLayout( frame() );
+  myInfo = new QTextBrowser( centralWidget() );
+  QVBoxLayout* l = new QVBoxLayout( centralWidget() );
   l->setMargin( 0 );
   l->addWidget( myInfo );
+
+  connect( myInfo, SIGNAL( anchorClicked(QUrl)), this, SLOT( connectivityClicked( QUrl )));
 }
 
 /*!
-  \brief Show mesh element information
-  \param ids mesh nodes / elements identifiers
+  \brief Show mesh element information.
+  \param ids Nodes / elements IDs.
 */
-void SMESHGUI_SimpleElemInfo::information( const QList<long>& ids )
+void SMESHGUI_SimpleElemInfo::information( const QList<uint>& ids )
 {
   clearInternal();
-
-  if ( actor() ) {
-    int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
-    int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
-    int cprecision = -1;
-    if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ))
-      cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
-    foreach ( long id, ids ) {
-      if ( !isElements() ) {
-        //
-        // show node info
-        //
-        const SMDS_MeshNode* node = actor()->GetObject()->GetMesh()->FindNode( id );
-        if ( !node ) return;
-
-        // node ID
-        myInfo->append( QString( "<b>%1 #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "NODE" )).arg( id ));
-        // separator
-        myInfo->append( "" );
-        // coordinates
-        myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" )).
-                        arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision )).
-                        arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision )).
-                        arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision )) );
-        // separator
-        myInfo->append( "" );
-        // connectivity
-        Connectivity connectivity = nodeConnectivity( node );
-        if ( !connectivity.isEmpty() ) {
-          myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" )) );
-          QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
-          if ( !con.isEmpty() )
-            myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" )).arg( con ));
-          con = formatConnectivity( connectivity, SMDSAbs_Edge );
-          if ( !con.isEmpty() )
-            myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" )).arg( con ));
-          con = formatConnectivity( connectivity, SMDSAbs_Ball );
-          if ( !con.isEmpty() )
-            myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" )).arg( con ));
-          con = formatConnectivity( connectivity, SMDSAbs_Face );
-          if ( !con.isEmpty() )
-            myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" )).arg( con ));
-          con = formatConnectivity( connectivity, SMDSAbs_Volume );
-          if ( !con.isEmpty() )
-            myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" )).arg( con ));
-        }
-        else {
-          myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" )).arg( id ));
-        }
-        // node position
-        SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();
-        if ( !CORBA::is_nil( aMeshPtr )) {
-          SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
-          int shapeID = pos->shapeID;
-          if ( shapeID > 0 ) {
-            QString shapeType;
-            double u = 0, v = 0;
-            switch ( pos->shapeType ) {
-            case GEOM::EDGE:
-              shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );
-              if ( pos->params.length() == 1 )
-                u = pos->params[0];
-              break;
-            case GEOM::FACE:
-              shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );
-              if ( pos->params.length() == 2 ) {
-                u = pos->params[0];
-                v = pos->params[1];
-              }
-              break;
-            case GEOM::VERTEX:
-              shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" );
-              break;
-            default:
-              shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );
-              break;
-            }
-            // separator
-            myInfo->append( "" );
-            myInfo->append( QString( "<b>%1:" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" )) );
-            myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( shapeType ).arg( shapeID ));
-            if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) {
-              myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "U_POSITION" )).
-                              arg( QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )) ));
-              if ( pos->shapeType == GEOM::FACE ) {
-                myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "V_POSITION" )).
-                                arg( QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )) ));
-              }
-            }
-          }
-        }
-        // groups node belongs to
-        SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
-        if ( !CORBA::is_nil( aMesh )) {
-          SMESH::ListOfGroups_var groups = aMesh->GetGroups();
-          myInfo->append( "" ); // separator
-          bool top_created = false;
-          for ( CORBA::ULong i = 0; i < groups->length(); i++ ) {
-            SMESH::SMESH_GroupBase_var aGrp = groups[i];
-            if ( CORBA::is_nil( aGrp )) continue;
-            QString aName = aGrp->GetName();
-            if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id )) {
-              if ( !top_created ) {
-                myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" )) );
-                top_created = true;
-              }
-              myInfo->append( QString( "+ <b>%1:</b>" ).arg( aName.trimmed() ));
-              if ( grp_details ) {
-                SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
-                SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
-                SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
-
-                // type : group on geometry, standalone group, group on filter
-                if ( !CORBA::is_nil( aStdGroup )) {
-                  myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" )).
-                                  arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" )) );
-                }
-                else if ( !CORBA::is_nil( aGeomGroup )) {
-                  myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" )).
-                                  arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" )) );
-                  GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
-                  _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
-                  if ( sobj ) {
-                    myInfo->append( QString( "  - <b>%1:</b> %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" )).
-                                    arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" )).arg( sobj->GetName().c_str() ));
-                  }
-                }
-                else if ( !CORBA::is_nil( aFltGroup )) {
-                  myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" )).
-                                  arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" )) );
-                }
-
-                // size
-                myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" )).
-                                arg( QString::number( aGrp->Size() )) );
-
-                // color
-                SALOMEDS::Color color = aGrp->GetColor();
-                myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" )).
-                                arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ));
-              }
-            }
-          }
-        }
-      }
-      else {
-        //
-        // show element info
-        //
-        const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
-        SMESH::Controls::NumericalFunctorPtr afunctor;
-        if ( !e ) return;
-
-        // Element ID && Type
-        QString stype;
-        switch( e->GetType() ) {
-        case SMDSAbs_0DElement:
-          stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break;
-        case SMDSAbs_Ball:
-          stype = SMESHGUI_ElemInfo::tr( "BALL" ); break;
-        case SMDSAbs_Edge:
-          stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break;
-        case SMDSAbs_Face:
-          stype = SMESHGUI_ElemInfo::tr( "FACE" ); break;
-        case SMDSAbs_Volume:
-          stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break;
-        default:
-          break;
-        }
-        if ( stype.isEmpty() ) return;
-        myInfo->append( QString( "<b>%1 #%2</b>" ).arg( stype ).arg( id ));
-        // separator
-        myInfo->append( "" );
-
-        // Geometry type
-        QString gtype;
-        switch( e->GetEntityType() ) {
-        case SMDSEntity_Triangle:
-        case SMDSEntity_Quad_Triangle:
-        case SMDSEntity_BiQuad_Triangle:
-          gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
-        case SMDSEntity_Quadrangle:
-        case SMDSEntity_Quad_Quadrangle:
-        case SMDSEntity_BiQuad_Quadrangle:
-          gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
-        case SMDSEntity_Polygon:
-        case SMDSEntity_Quad_Polygon:
-          gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
-        case SMDSEntity_Tetra:
-        case SMDSEntity_Quad_Tetra:
-          gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
-        case SMDSEntity_Pyramid:
-        case SMDSEntity_Quad_Pyramid:
-          gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
-        case SMDSEntity_Hexa:
-        case SMDSEntity_Quad_Hexa:
-        case SMDSEntity_TriQuad_Hexa:
-          gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
-        case SMDSEntity_Penta:
-        case SMDSEntity_Quad_Penta:
-        case SMDSEntity_BiQuad_Penta:
-          gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
-        case SMDSEntity_Hexagonal_Prism:
-          gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
-        case SMDSEntity_Polyhedra:
-        case SMDSEntity_Quad_Polyhedra:
-          gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
-        default:
-          break;
-        }
-        if ( !gtype.isEmpty() )
-          myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "TYPE" )).arg( gtype ));
-
-        // Quadratic flag (any element except 0D)
-        if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) {
-          myInfo->append( QString( "<b>%1?</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "QUADRATIC" )).arg( e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" )) );
-        }
-        if ( const SMDS_BallElement* ball = SMDS_Mesh::DownCast<SMDS_BallElement>( e )) {
-          // Ball diameter
-          myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" )).arg( ball->GetDiameter() ));
-        }
-        // separator
-        myInfo->append( "" );
-
-        // Connectivity
-        SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
-        for ( int idx = 1; nodeIt->more(); idx++ ) {
-          const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-          // node number and ID
-          myInfo->append( QString( "<b>%1 %2/%3</b> - #%4" ).arg( SMESHGUI_ElemInfo::tr( "NODE" )).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ));
-          // node coordinates
-          myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" )).
-                          arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision )).
-                          arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision )).
-                          arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision )) );
-          // node connectivity
-          Connectivity connectivity = nodeConnectivity( node );
-          if ( !connectivity.isEmpty() ) {
-            myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" )) );
-            QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
-            if ( !con.isEmpty() )
-              myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" )).arg( con ));
-            con = formatConnectivity( connectivity, SMDSAbs_Edge );
-            if ( !con.isEmpty() )
-              myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" )).arg( con ));
-            con = formatConnectivity( connectivity, SMDSAbs_Face );
-            if ( !con.isEmpty() )
-              myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" )).arg( con ));
-            con = formatConnectivity( connectivity, SMDSAbs_Volume );
-            if ( !con.isEmpty() )
-              myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" )).arg( con ));
-          }
-          else {
-            myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" )).arg( id ));
-          }
-        }
-        // separator
-        myInfo->append( "" );
-
-        // Controls
-        myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONTROLS" )) );
-        //Length
-        if ( e->GetType() == SMDSAbs_Edge ) {
-          afunctor.reset( new SMESH::Controls::Length() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "LENGTH_EDGES" )).arg( afunctor->GetValue( id )) );
-        }
-        if( e->GetType() == SMDSAbs_Face ) {
-          //Area
-          afunctor.reset(  new SMESH::Controls::Area() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "AREA_ELEMENTS" )).arg( afunctor->GetValue( id )) );
-          //Taper
-          afunctor.reset( new SMESH::Controls::Taper() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "TAPER_ELEMENTS" )).arg( afunctor->GetValue( id )) );
-          //AspectRatio2D
-          afunctor.reset( new SMESH::Controls::AspectRatio() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_ELEMENTS" )).arg( afunctor->GetValue( id )) );
-          //Minimum angle
-          afunctor.reset( new SMESH::Controls::MinimumAngle() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MINIMUMANGLE_ELEMENTS" )).arg( afunctor->GetValue( id )) );
-          //Warping angle
-          afunctor.reset( new SMESH::Controls::Warping() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "WARP_ELEMENTS" )).arg( afunctor->GetValue( id )) );
-          //Skew
-          afunctor.reset( new SMESH::Controls::Skew() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "SKEW_ELEMENTS" )).arg( afunctor->GetValue( id )) );
-          //ElemDiam2D
-          afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_2D" )).arg( afunctor->GetValue( id )) );
-          //min edge length
-          afunctor.reset( new SMESH::Controls::Length2D() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MIN_ELEM_EDGE" )).arg( afunctor->GetValue( id )) );
-        }
-        if( e->GetType() == SMDSAbs_Volume ) {
-          //AspectRatio3D
-          afunctor.reset(  new SMESH::Controls::AspectRatio3D() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_3D_ELEMENTS" )).arg( afunctor->GetValue( id )) );
-          //Volume
-          afunctor.reset(  new SMESH::Controls::Volume() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUME_3D_ELEMENTS" )).arg( afunctor->GetValue( id )) );
-          //ElementDiameter3D
-          afunctor.reset(  new SMESH::Controls::Volume() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_3D" )).arg( afunctor->GetValue( id )) );
-        }
-        // separator
-        myInfo->append( "" );
-
-        // Gravity center
-        XYZ gc = gravityCenter( e );
-        myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" )).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ));
-
-        // Normal vector
-        if( e->GetType() == SMDSAbs_Face ) {
-          XYZ gc = normal( e );
-          myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "NORMAL_VECTOR" )).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ));
-        }
-
-        // Element position
-        if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
-          SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
-          if ( !CORBA::is_nil( aMesh )) {
-            SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
-            int shapeID = pos.shapeID;
-            if ( shapeID > 0 ) {
-              myInfo->append( "" ); // separator
-              QString shapeType;
-              switch ( pos.shapeType ) {
-              case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
-              case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
-              case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
-              case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
-              case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
-              default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
-              }
-              myInfo->append( QString( "<b>%1:</b> %2 #%3" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" )).arg( shapeType ).arg( shapeID ));
-            }
-          }
-        }
-
-        // Groups the element belongs to
-        SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
-        if ( !CORBA::is_nil( aMesh )) {
-          SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
-          myInfo->append( "" ); // separator
-          bool top_created = false;
-          for ( CORBA::ULong i = 0; i < groups->length(); i++ ) {
-            SMESH::SMESH_GroupBase_var aGrp = groups[i];
-            if ( CORBA::is_nil( aGrp )) continue;
-            QString aName = aGrp->GetName();
-            if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id )) {
-              if ( !top_created ) {
-                myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" )) );
-                top_created = true;
-              }
-              myInfo->append( QString( "+ <b>%1:</b>" ).arg( aName.trimmed() ));
-              if ( grp_details ) {
-                SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
-                SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
-                SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
-
-                // type : group on geometry, standalone group, group on filter
-                if ( !CORBA::is_nil( aStdGroup )) {
-                  myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" )).
-                                  arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" )) );
-                }
-                else if ( !CORBA::is_nil( aGeomGroup )) {
-                  myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" )).
-                                  arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" )) );
-                  GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
-                  _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
-                  if ( sobj ) {
-                    myInfo->append( QString( "  - <b>%1:</b> %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" )).
-                                    arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" )).arg( sobj->GetName().c_str() ));
-                  }
-                }
-                else if ( !CORBA::is_nil( aFltGroup )) {
-                  myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" )).
-                                  arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" )) );
-                }
-
-                myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" )).
-                                arg( QString::number( aGrp->Size() )) );
-
-                // color
-                SALOMEDS::Color color = aGrp->GetColor();
-                myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" )).
-                                arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ));
-              }
-            }
-          }
-        }
-      }
-      // separator
-      if ( ids.count() > 1 ) {
-        myInfo->append( "" );
-        myInfo->append( "------" );
-        myInfo->append( "" );
-      }
-    }
-  }
+  TextWriter writer( myInfo );
+  writeInfo( &writer, ids );
 }
 
 /*!
@@ -1608,21 +2054,19 @@ void SMESHGUI_SimpleElemInfo::clearInternal()
   myInfo->clear();
 }
 
-void SMESHGUI_SimpleElemInfo::saveInfo( QTextStream &out )
+void SMESHGUI_SimpleElemInfo::connectivityClicked(const QUrl & url)
 {
-  out << QString( 12, '-' ) << "\n";
-  out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
-  out << QString( 12, '-' ) << "\n";
-  out << myInfo->toPlainText();
-  out << "\n";
+  int type = ( url.scheme()[0] == 'n' ) ? NodeConnectivity : ElemConnectivity;
+  QString ids = url.path(); // excess chars will be filtered off by SMESHGUI_IdValidator
+  emit( itemInfo( type, ids ));
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_TreeElemInfo::ItemDelegate
+/// \brief Item delegate for tree mesh info widget.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
 
-/*!
-  \class SMESHGUI_TreeElemInfo::ItemDelegate
-  \brief Item delegate for tree mesh info widget
-  \internal
-*/
 class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate
 {
 public:
@@ -1631,571 +2075,99 @@ public:
 };
 
 /*!
-  \brief Constructor
+  \brief Constructor.
   \internal
 */
-SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent )
+SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ): QItemDelegate( parent )
 {
 }
 
 /*!
-  \brief Create item editor widget
+  \brief Redefined from QItemDelegate.
   \internal
 */
 QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
 {
   QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index );
-  if ( qobject_cast<QLineEdit*>( w )) qobject_cast<QLineEdit*>( w )->setReadOnly(  true );
+  if ( qobject_cast<QLineEdit*>( w ) )
+    qobject_cast<QLineEdit*>( w )->setReadOnly( true );
   return w;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_TreeElemInfo::ItemCreator
+/// \brief Item creator for tree mesh info widget.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
+class SMESHGUI_TreeElemInfo::ItemCreator : public TreeItemCreator
+{
+  SMESHGUI_TreeElemInfo* myView;
+public:
+  ItemCreator( SMESHGUI_TreeElemInfo* );
+  QTreeWidgetItem* createItem( QTreeWidgetItem*, int );
+};
+
+/*!
+  \brief Constructor.
+  \param view Parent view.
+  \internal
+*/
+SMESHGUI_TreeElemInfo::ItemCreator::ItemCreator( SMESHGUI_TreeElemInfo* view ): TreeItemCreator(), myView( view )
+{
+}
+
 /*!
-  \class SMESHGUI_TreeElemInfo
-  \brief Represents mesh element information in the tree-like form.
+  \brief Create new tree item.
+  \param parent Parent tree item.
+  \param options Item options.
+  \return New tree widget item.
+  \internal
 */
+QTreeWidgetItem* SMESHGUI_TreeElemInfo::ItemCreator::createItem( QTreeWidgetItem* parent, int options )
+{
+  return myView->createItem( parent, options );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_TreeElemInfo
+/// \brief Show mesh element information as the tree.
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
-  \brief Constructor
-  \param parent parent widget
+  \brief Constructor.
+  \param parent Parent widget. Defaults to 0.
 */
 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
   : SMESHGUI_ElemInfo( parent )
 {
-  myInfo = new QTreeWidget( frame() );
+  myInfo = new QTreeWidget( centralWidget() );
   myInfo->setColumnCount( 2 );
-  myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ));
+  myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
   myInfo->header()->setStretchLastSection( true );
 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
   myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
 #else
   myInfo->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
 #endif
-  myInfo->setItemDelegate( new ItemDelegate( myInfo ));
-  QVBoxLayout* l = new QVBoxLayout( frame() );
+  myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
+  QVBoxLayout* l = new QVBoxLayout( centralWidget() );
   l->setMargin( 0 );
   l->addWidget( myInfo );
-  connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int )), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int )) );
+  connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int ) ) );
   connect( myInfo, SIGNAL( itemCollapsed( QTreeWidgetItem* )), this, SLOT( saveExpanded( QTreeWidgetItem* )) );
   connect( myInfo, SIGNAL( itemExpanded( QTreeWidgetItem* )), this, SLOT( saveExpanded( QTreeWidgetItem* )) );
 }
 
 /*!
-  \brief Show mesh element information
-  \param ids mesh nodes / elements identifiers
+  \brief Show mesh element information.
+  \param ids Nodes / elements IDs.
 */
-void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
+void SMESHGUI_TreeElemInfo::information( const QList<uint>& ids )
 {
   clearInternal();
-
-  if ( actor() ) {
-    int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
-    int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
-    int cprecision = -1;
-    if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false )) 
-      cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
-    foreach ( long id, ids ) {
-      if ( !isElements() ) {
-        //
-        // show node info
-        //
-        const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindNode( id );
-        if ( !e ) return;
-        const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
-      
-        // node ID
-        QTreeWidgetItem* nodeItem = createItem( 0, Bold | All );
-        nodeItem->setText( 0, SMESHGUI_ElemInfo::tr( "NODE" ));
-        nodeItem->setText( 1, QString( "#%1" ).arg( id ));
-        // coordinates
-        QTreeWidgetItem* coordItem = createItem( nodeItem, Bold );
-        coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ));
-        QTreeWidgetItem* xItem = createItem( coordItem );
-        xItem->setText( 0, "X" );
-        xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-        QTreeWidgetItem* yItem = createItem( coordItem );
-        yItem->setText( 0, "Y" );
-        yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-        QTreeWidgetItem* zItem = createItem( coordItem );
-        zItem->setText( 0, "Z" );
-        zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-        // connectivity
-        QTreeWidgetItem* conItem = createItem( nodeItem, Bold );
-        conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ));
-        Connectivity connectivity = nodeConnectivity( node );
-        if ( !connectivity.isEmpty() ) {
-          QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
-          if ( !con.isEmpty() ) {
-            QTreeWidgetItem* i = createItem( conItem );
-            i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ));
-            i->setText( 1, con );
-          }
-          con = formatConnectivity( connectivity, SMDSAbs_Ball );
-          if ( !con.isEmpty() ) {
-            QTreeWidgetItem* i = createItem( conItem );
-            i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ));
-            i->setText( 1, con );
-            i->setData( 1, TypeRole, NodeConnectivity );
-          }
-          con = formatConnectivity( connectivity, SMDSAbs_Edge );
-          if ( !con.isEmpty() ) {
-            QTreeWidgetItem* i = createItem( conItem );
-            i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ));
-            i->setText( 1, con );
-            i->setData( 1, TypeRole, NodeConnectivity );
-          }
-          con = formatConnectivity( connectivity, SMDSAbs_Face );
-          if ( !con.isEmpty() ) {
-            QTreeWidgetItem* i = createItem( conItem );
-            i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ));
-            i->setText( 1, con );
-            i->setData( 1, TypeRole, NodeConnectivity );
-          }
-          con = formatConnectivity( connectivity, SMDSAbs_Volume );
-          if ( !con.isEmpty() ) {
-            QTreeWidgetItem* i = createItem( conItem );
-            i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ));
-            i->setText( 1, con );
-            i->setData( 1, TypeRole, NodeConnectivity );
-          }
-        }
-        else {
-          conItem->setText( 1, SMESHGUI_ElemInfo::tr( "FREE_NODE" ));
-        }
-        // node position
-        SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();   
-        if ( !CORBA::is_nil( aMeshPtr )) {
-          SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
-          int shapeID = pos->shapeID;
-          if ( shapeID > 0 ) {
-            QString shapeType;
-            double u = 0, v = 0;
-            switch ( pos->shapeType ) {
-            case GEOM::EDGE:
-              shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );
-              if ( pos->params.length() == 1 )
-                u = pos->params[0];
-              break;
-            case GEOM::FACE:
-              shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );
-              if ( pos->params.length() == 2 ) {
-                u = pos->params[0];
-                v = pos->params[1];
-              }
-              break;
-            case GEOM::VERTEX:
-              shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" );
-              break;
-            default:
-              shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );
-              break;
-            }
-            QTreeWidgetItem* posItem = createItem( nodeItem, Bold );
-            posItem->setText( 0, SMESHGUI_ElemInfo::tr("POSITION") );
-            posItem->setText( 1, (shapeType + " #%1").arg( shapeID ));
-            if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) {
-              QTreeWidgetItem* uItem = createItem( posItem );
-              uItem->setText( 0, SMESHGUI_ElemInfo::tr("U_POSITION") );
-              uItem->setText( 1, QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )));
-              if ( pos->shapeType == GEOM::FACE ) {
-                QTreeWidgetItem* vItem = createItem( posItem );
-                vItem->setText( 0, SMESHGUI_ElemInfo::tr("V_POSITION") );
-                vItem->setText( 1, QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )));
-              }
-            }
-          }
-        }
-        // groups node belongs to
-        SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
-        if ( !CORBA::is_nil( aMesh )) {
-          SMESH::ListOfGroups_var groups = aMesh->GetGroups();
-          QTreeWidgetItem* groupsItem = 0;
-          for ( CORBA::ULong i = 0; i < groups->length(); i++ ) {
-            SMESH::SMESH_GroupBase_var aGrp = groups[i];
-            if ( CORBA::is_nil( aGrp )) continue;
-            QString aName = aGrp->GetName();
-            if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id )) {
-              if ( !groupsItem ) {
-                groupsItem = createItem( nodeItem, Bold );
-                groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ));
-              }
-              QTreeWidgetItem* it = createItem( groupsItem, Bold );
-              it->setText( 0, aName.trimmed() );
-              if ( grp_details ) {
-                SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
-                SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
-                SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
-                
-                // type : group on geometry, standalone group, group on filter
-                QTreeWidgetItem* typeItem = createItem( it );
-                typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ));
-                if ( !CORBA::is_nil( aStdGroup )) {
-                  typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ));
-                }
-                else if ( !CORBA::is_nil( aGeomGroup )) {
-                  typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ));
-                  GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
-                  _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
-                  if ( sobj ) {
-                    QTreeWidgetItem* gobjItem = createItem( typeItem );
-                    gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ));
-                    gobjItem->setText( 1, sobj->GetName().c_str() );
-                  }
-                }
-                else if ( !CORBA::is_nil( aFltGroup )) {
-                  typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ));
-                }
-                
-                // size
-                QTreeWidgetItem* sizeItem = createItem( it );
-                sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ));
-                sizeItem->setText( 1, QString::number( aGrp->Size() ));
-                
-                // color
-                SALOMEDS::Color color = aGrp->GetColor();
-                QTreeWidgetItem* colorItem = createItem( it );
-                colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ));
-                colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ));
-              }
-            }
-          }
-        }
-      }
-      else {
-        //
-        // show element info
-        // 
-        const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
-        SMESH::Controls::NumericalFunctorPtr afunctor;
-        if ( !e ) return;
-        
-        // element ID && type
-        QString stype;
-        switch( e->GetType() ) {
-        case SMDSAbs_0DElement: stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break;
-        case SMDSAbs_Ball:      stype = SMESHGUI_ElemInfo::tr( "BALL" ); break;
-        case SMDSAbs_Edge:      stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break;
-        case SMDSAbs_Face:      stype = SMESHGUI_ElemInfo::tr( "FACE" ); break;
-        case SMDSAbs_Volume:    stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break;
-        default:;
-        }
-        if ( stype.isEmpty() ) return;
-        QTreeWidgetItem* elemItem = createItem( 0, Bold | All );
-        elemItem->setText( 0, stype );
-        elemItem->setText( 1, QString( "#%1" ).arg( id ));
-        // geometry type
-        QString gtype;
-        switch( e->GetEntityType() ) {
-        case SMDSEntity_Triangle:
-        case SMDSEntity_Quad_Triangle:
-        case SMDSEntity_BiQuad_Triangle:
-          gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
-        case SMDSEntity_Quadrangle:
-        case SMDSEntity_Quad_Quadrangle:
-        case SMDSEntity_BiQuad_Quadrangle:
-          gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
-        case SMDSEntity_Polygon:
-        case SMDSEntity_Quad_Polygon:
-          gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
-        case SMDSEntity_Tetra:
-        case SMDSEntity_Quad_Tetra:
-          gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
-        case SMDSEntity_Pyramid:
-        case SMDSEntity_Quad_Pyramid:
-          gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
-        case SMDSEntity_Hexa:
-        case SMDSEntity_Quad_Hexa:
-        case SMDSEntity_TriQuad_Hexa:
-          gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
-        case SMDSEntity_Penta:
-        case SMDSEntity_Quad_Penta:
-        case SMDSEntity_BiQuad_Penta:
-          gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
-        case SMDSEntity_Hexagonal_Prism:
-          gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
-        case SMDSEntity_Polyhedra:
-        case SMDSEntity_Quad_Polyhedra:
-          gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
-        default:
-          break;
-        }
-        if ( !gtype.isEmpty() ) {
-          QTreeWidgetItem* typeItem = createItem( elemItem, Bold );
-          typeItem->setText( 0, SMESHGUI_ElemInfo::tr( "TYPE" ));
-          typeItem->setText( 1, gtype );
-        }
-        // quadratic flag (for edges, faces and volumes)
-        if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
-          // quadratic flag
-          QTreeWidgetItem* quadItem = createItem( elemItem, Bold );
-          quadItem->setText( 0, SMESHGUI_ElemInfo::tr( "QUADRATIC" ));
-          quadItem->setText( 1, e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ));
-        }
-        if ( const SMDS_BallElement* ball = SMDS_Mesh::DownCast< SMDS_BallElement >( e )) {
-          // ball diameter
-          QTreeWidgetItem* diamItem = createItem( elemItem, Bold );
-          diamItem->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ));
-          diamItem->setText( 1, QString( "%1" ).arg( ball->GetDiameter() ));
-        }
-        // connectivity
-        QTreeWidgetItem* conItem = createItem( elemItem, Bold );
-        conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ));
-
-
-        if( e->GetGeomType() != SMDSGeom_POLYHEDRA ) {
-          SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
-          for ( int idx = 1; nodeIt->more(); idx++ ) {
-            const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-            nodeInfo( node, idx, e->NbNodes(), conItem );
-          }
-        }
-        else {
-          SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
-          std::set< const SMDS_MeshNode* > addedNodes;
-          QList<const SMDS_MeshElement*> uniqueNodes;
-          while ( nodeIt->more() ) {
-            const SMDS_MeshNode* node = nodeIt->next();
-            if ( addedNodes.insert( node ).second )
-              uniqueNodes.append( nodeIt->next() );
-          }
-          SMDS_VolumeTool vtool( e );
-          const int nbFaces = vtool.NbFaces();
-          for( int face_id = 0; face_id < nbFaces; face_id++ ) {
-            QTreeWidgetItem* faceItem = createItem( conItem, Bold );
-            faceItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "FACE" )).arg( face_id + 1 ).arg( nbFaces ));
-            faceItem->setExpanded( true );
-
-            const SMDS_MeshNode** aNodeIds = vtool.GetFaceNodes( face_id );
-            const int              nbNodes = vtool.NbFaceNodes ( face_id );
-            for( int node_id = 0; node_id < nbNodes; node_id++ ) {
-              const SMDS_MeshNode* node = aNodeIds[node_id];
-              nodeInfo( node, uniqueNodes.indexOf(node) + 1, uniqueNodes.size(), faceItem );
-            }
-          }
-        }
-        //Controls
-        QTreeWidgetItem* cntrItem = createItem( elemItem, Bold );
-        cntrItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONTROLS" ));
-        //Length
-        if( e->GetType()==SMDSAbs_Edge){
-          afunctor.reset( new SMESH::Controls::Length() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          QTreeWidgetItem* lenItem = createItem( cntrItem, Bold );
-          lenItem->setText( 0, tr( "LENGTH_EDGES" ));
-          lenItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-        }
-        if( e->GetType() == SMDSAbs_Face ) {
-          //Area
-          afunctor.reset( new SMESH::Controls::Area() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          QTreeWidgetItem* areaItem = createItem( cntrItem, Bold );
-          areaItem->setText( 0, tr( "AREA_ELEMENTS" ));
-          areaItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue(id) ));
-          //Taper
-          if ( e->NbNodes() == 4 ) // see SMESH_Controls.cxx
-          {
-            afunctor.reset( new SMESH::Controls::Taper() );
-            afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-            afunctor->SetPrecision( cprecision );
-            QTreeWidgetItem* taperlItem = createItem( cntrItem, Bold );
-            taperlItem->setText( 0, tr( "TAPER_ELEMENTS" ));
-            taperlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-            //Warping angle
-            afunctor.reset( new SMESH::Controls::Warping() );
-            afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-            afunctor->SetPrecision( cprecision );
-            QTreeWidgetItem* warpItem = createItem( cntrItem, Bold );
-            warpItem->setText( 0, tr( "WARP_ELEMENTS" ));
-            warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-          }
-          //AspectRatio2D
-          if ( !e->IsPoly() )
-          {
-            afunctor.reset( new SMESH::Controls::AspectRatio() );
-            afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-            QTreeWidgetItem* ratlItem = createItem( cntrItem, Bold );
-            ratlItem->setText( 0, tr( "ASPECTRATIO_ELEMENTS" ));
-            ratlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-          }
-          //Minimum angle
-          afunctor.reset( new SMESH::Controls::MinimumAngle() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          afunctor->SetPrecision( cprecision );
-          QTreeWidgetItem* minanglItem = createItem( cntrItem, Bold );
-          minanglItem->setText( 0, tr( "MINIMUMANGLE_ELEMENTS" ));
-          minanglItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-          //Skew
-          if ( e->NbNodes() == 3 || e->NbNodes() == 4 )
-          {
-            afunctor.reset( new SMESH::Controls::Skew() );
-            afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-            afunctor->SetPrecision( cprecision );
-            QTreeWidgetItem* skewItem = createItem( cntrItem, Bold );
-            skewItem->setText( 0, tr( "SKEW_ELEMENTS" ));
-            skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-          }
-          //Deflection
-          if ( hasShapeToMesh() )
-          {
-            afunctor.reset( new SMESH::Controls::Deflection2D() );
-            afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-            QTreeWidgetItem* deflItem = createItem( cntrItem, Bold );
-            deflItem->setText( 0, tr( "DEFLECTION_2D" ));
-            deflItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-          }
-          //ElemDiam2D
-          if ( !e->IsPoly() )
-          {
-            afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
-            afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-            QTreeWidgetItem* diamItem = createItem( cntrItem, Bold );
-            diamItem->setText( 0, tr( "MAX_ELEMENT_LENGTH_2D" ));
-            diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-          }
-        }
-        if( e->GetType() == SMDSAbs_Volume ) {
-          if ( !e->IsPoly() )
-          {
-            //AspectRatio3D
-            afunctor.reset( new SMESH::Controls::AspectRatio3D() );
-            afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-            QTreeWidgetItem* ratlItem3 = createItem( cntrItem, Bold );
-            ratlItem3->setText( 0, tr( "ASPECTRATIO_3D_ELEMENTS" ));
-            ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-          }
-          //Volume
-          afunctor.reset( new SMESH::Controls::Volume() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          QTreeWidgetItem* volItem = createItem( cntrItem, Bold );
-          volItem->setText( 0, tr( "VOLUME_3D_ELEMENTS" ));
-          volItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-          //ElementDiameter3D
-          afunctor.reset( new SMESH::Controls::MaxElementLength3D() );
-          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-          QTreeWidgetItem* diam3Item = createItem( cntrItem, Bold );
-          diam3Item->setText( 0, tr( "MAX_ELEMENT_LENGTH_3D" ));
-          diam3Item->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
-        }
-
-        //min edge length
-        afunctor.reset( new SMESH::Controls::Length2D() );
-        afunctor->SetMesh( actor()->GetObject()->GetMesh() );
-        QTreeWidgetItem* minEdgeItem = createItem( cntrItem, Bold );
-        minEdgeItem->setText( 0, tr( "MIN_ELEM_EDGE" ));
-        SMESH::Controls::TSequenceOfXYZ points;
-        afunctor->GetPoints( e, points ); // "non-standard" way, to make it work for all elem types
-        minEdgeItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( points )) );
-
-        // gravity center
-        XYZ gc = gravityCenter( e );
-        QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
-        gcItem->setText( 0, SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ));
-        QTreeWidgetItem* xItem = createItem( gcItem );
-        xItem->setText( 0, "X" );
-        xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-        QTreeWidgetItem* yItem = createItem( gcItem );
-        yItem->setText( 0, "Y" );
-        yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-        QTreeWidgetItem* zItem = createItem( gcItem );
-        zItem->setText( 0, "Z" );
-        zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-
-        // normal vector
-        if( e->GetType() == SMDSAbs_Face ) {
-          XYZ gc = normal( e );
-          QTreeWidgetItem* nItem = createItem( elemItem, Bold );
-          nItem->setText( 0, SMESHGUI_ElemInfo::tr( "NORMAL_VECTOR" ));
-          QTreeWidgetItem* xItem = createItem( nItem );
-          xItem->setText( 0, "X" );
-          xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-          QTreeWidgetItem* yItem = createItem( nItem );
-          yItem->setText( 0, "Y" );
-          yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-          QTreeWidgetItem* zItem = createItem( nItem );
-          zItem->setText( 0, "Z" );
-          zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-        }
-
-        // element position
-        SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
-        if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
-          if ( !CORBA::is_nil( aMesh )) {
-            SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
-            int shapeID = pos.shapeID;
-            if ( shapeID > 0 ) {
-              QTreeWidgetItem* shItem = createItem( elemItem, Bold );
-              QString shapeType;
-              switch ( pos.shapeType ) {
-              case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
-              case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
-              case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
-              case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
-              case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
-              default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
-              }
-              shItem->setText( 0, SMESHGUI_ElemInfo::tr( "POSITION" ));
-              shItem->setText( 1, QString( "%1 #%2" ).arg( shapeType ).arg( shapeID ));
-            }
-          }
-        }
-        // groups element belongs to
-        if ( !CORBA::is_nil( aMesh )) {
-          SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
-          QTreeWidgetItem* groupsItem = 0;
-          for ( CORBA::ULong i = 0; i < groups->length(); i++ ) {
-            SMESH::SMESH_GroupBase_var aGrp = groups[i];
-            if ( CORBA::is_nil( aGrp )) continue;
-            QString aName = aGrp->GetName();
-            if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id )) {
-              if ( !groupsItem ) {
-                groupsItem = createItem( elemItem, Bold );
-                groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ));
-              }
-              QTreeWidgetItem* it = createItem( groupsItem, Bold );
-              it->setText( 0, aName.trimmed() );
-              if ( grp_details ) {
-                SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
-                SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
-                SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
-                
-                // type : group on geometry, standalone group, group on filter
-                QTreeWidgetItem* typeItem = createItem( it );
-                typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ));
-                if ( !CORBA::is_nil( aStdGroup )) {
-                  typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ));
-                }
-                else if ( !CORBA::is_nil( aGeomGroup )) {
-                  typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ));
-                  GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
-                  _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
-                  if ( sobj ) {
-                    QTreeWidgetItem* gobjItem = createItem( typeItem );
-                    gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ));
-                    gobjItem->setText( 1, sobj->GetName().c_str() );
-                  }
-                }
-                else if ( !CORBA::is_nil( aFltGroup )) {
-                  typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ));
-                }
-                
-                // size
-                QTreeWidgetItem* sizeItem = createItem( it );
-                sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ));
-                sizeItem->setText( 1, QString::number( aGrp->Size() ));
-                
-                // color
-                SALOMEDS::Color color = aGrp->GetColor();
-                QTreeWidgetItem* colorItem = createItem( it );
-                colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ));
-                colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ));
-              }
-            }
-          }
-        }
-      }
-    }
-  }
+  TreeWriter writer( myInfo, new ItemCreator( this ) );
+  writeInfo( &writer, ids );
 }
 
 /*!
@@ -2208,66 +2180,66 @@ void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
 void SMESHGUI_TreeElemInfo::nodeInfo( const SMDS_MeshNode* node, int index,
                                       int nbNodes, QTreeWidgetItem* parentItem )
 {
-  int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
-  // node number and ID
-  QTreeWidgetItem* nodeItem = createItem( parentItem, Bold );
-  nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" )).arg( index ).arg( nbNodes ));
-  nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ));
-  nodeItem->setData( 1, TypeRole, ElemConnectivity );
-  nodeItem->setData( 1, IdRole, node->GetID() );
-  nodeItem->setExpanded( false );
-  // node coordinates
-  QTreeWidgetItem* coordItem = createItem( nodeItem );
-  coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ));
-  QTreeWidgetItem* xItem = createItem( coordItem );
-  xItem->setText( 0, "X" );
-  xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-  QTreeWidgetItem* yItem = createItem( coordItem );
-  yItem->setText( 0, "Y" );
-  yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-  QTreeWidgetItem* zItem = createItem( coordItem );
-  zItem->setText( 0, "Z" );
-  zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
-  // node connectivity
-  QTreeWidgetItem* nconItem = createItem( nodeItem );
-  nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ));
-  Connectivity connectivity = nodeConnectivity( node );
-  if ( !connectivity.isEmpty() ) {
-    QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
-    if ( !con.isEmpty() ) {
-      QTreeWidgetItem* i = createItem( nconItem );
-      i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ));
-      i->setText( 1, con );
-    }
-    con = formatConnectivity( connectivity, SMDSAbs_Edge );
-    if ( !con.isEmpty() ) {
-      QTreeWidgetItem* i = createItem( nconItem );
-      i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ));
-      i->setText( 1, con );
-      i->setData( 1, TypeRole, NodeConnectivity );
-    }
-    con = formatConnectivity( connectivity, SMDSAbs_Ball );
-    if ( !con.isEmpty() ) {
-      QTreeWidgetItem* i = createItem( nconItem );
-      i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ));
-      i->setText( 1, con );
-      i->setData( 1, TypeRole, NodeConnectivity );
-    }
-    con = formatConnectivity( connectivity, SMDSAbs_Face );
-    if ( !con.isEmpty() ) {
-      QTreeWidgetItem* i = createItem( nconItem );
-      i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ));
-      i->setText( 1, con );
-      i->setData( 1, TypeRole, NodeConnectivity );
-    }
-    con = formatConnectivity( connectivity, SMDSAbs_Volume );
-    if ( !con.isEmpty() ) {
-      QTreeWidgetItem* i = createItem( nconItem );
-      i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ));
-      i->setText( 1, con );
-      i->setData( 1, TypeRole, NodeConnectivity );
-    }
-  }
+  // int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
+  // // node number and ID
+  // QTreeWidgetItem* nodeItem = createItem( parentItem, Bold );
+  // nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" )).arg( index ).arg( nbNodes ));
+  // nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ));
+  // nodeItem->setData( 1, TypeRole, ElemConnectivity );
+  // nodeItem->setData( 1, IdRole, node->GetID() );
+  // nodeItem->setExpanded( false );
+  // // node coordinates
+  // QTreeWidgetItem* coordItem = createItem( nodeItem );
+  // coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ));
+  // QTreeWidgetItem* xItem = createItem( coordItem );
+  // xItem->setText( 0, "X" );
+  // xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
+  // QTreeWidgetItem* yItem = createItem( coordItem );
+  // yItem->setText( 0, "Y" );
+  // yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
+  // QTreeWidgetItem* zItem = createItem( coordItem );
+  // zItem->setText( 0, "Z" );
+  // zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
+  // // node connectivity
+  // QTreeWidgetItem* nconItem = createItem( nodeItem );
+  // nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ));
+  // Connectivity connectivity = nodeConnectivity( node );
+  // if ( !connectivity.isEmpty() ) {
+  //   QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
+  //   if ( !con.isEmpty() ) {
+  //     QTreeWidgetItem* i = createItem( nconItem );
+  //     i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ));
+  //     i->setText( 1, con );
+  //   }
+  //   con = formatConnectivity( connectivity, SMDSAbs_Edge );
+  //   if ( !con.isEmpty() ) {
+  //     QTreeWidgetItem* i = createItem( nconItem );
+  //     i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ));
+  //     i->setText( 1, con );
+  //     i->setData( 1, TypeRole, NodeConnectivity );
+  //   }
+  //   con = formatConnectivity( connectivity, SMDSAbs_Ball );
+  //   if ( !con.isEmpty() ) {
+  //     QTreeWidgetItem* i = createItem( nconItem );
+  //     i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ));
+  //     i->setText( 1, con );
+  //     i->setData( 1, TypeRole, NodeConnectivity );
+  //   }
+  //   con = formatConnectivity( connectivity, SMDSAbs_Face );
+  //   if ( !con.isEmpty() ) {
+  //     QTreeWidgetItem* i = createItem( nconItem );
+  //     i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ));
+  //     i->setText( 1, con );
+  //     i->setData( 1, TypeRole, NodeConnectivity );
+  //   }
+  //   con = formatConnectivity( connectivity, SMDSAbs_Volume );
+  //   if ( !con.isEmpty() ) {
+  //     QTreeWidgetItem* i = createItem( nconItem );
+  //     i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ));
+  //     i->setText( 1, con );
+  //     i->setData( 1, TypeRole, NodeConnectivity );
+  //   }
+  // }
 }
 /*!
   \brief Internal clean-up (reset widget)
@@ -2279,35 +2251,22 @@ void SMESHGUI_TreeElemInfo::clearInternal()
 }
 
 /*!
-  \brief Create new tree item.
-  \param parent parent tree widget item
-  \param flags item flag
-  \return new tree widget item
+  \brief Create new item and add it to the tree.
+  \param parent Parent tree widget item. Defaults to 0 (top-level item).
+  \param options Item flags. Defaults to 0 (none).
+  \return New tree widget item.
 */
-QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int flags )
+QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int options )
 {
-  QTreeWidgetItem* item;
-  if ( parent )
-    item = new QTreeWidgetItem( parent );
-  else
-    item = new QTreeWidgetItem( myInfo );
-
-  item->setFlags( item->flags() | Qt::ItemIsEditable );
-
-  QFont f = item->font( 0 );
-  f.setBold( true );
-  for ( int i = 0; i < myInfo->columnCount(); i++ ) {
-    if ( ( flags & Bold ) && ( i == 0 || flags & All ))
-      item->setFont( i, f );
-  }
+  QTreeWidgetItem* item = new QTreeWidgetItem( parent ? parent : myInfo->invisibleRootItem() );
+  setTreeItemAttributes( item, options | Expanded | Editable );
 
   if ( parent && parent->childCount() == 1 && itemDepth( parent ) == 1 )
   {
     QString resName = expandedResource( parent );
     parent->setExpanded( SMESHGUI::resourceMgr()->booleanValue("SMESH", resName, true ));
   }
-
-  item->setExpanded( true );
+  
   return item;
 }
 
@@ -2317,24 +2276,21 @@ void SMESHGUI_TreeElemInfo::contextMenuEvent( QContextMenuEvent* e )
   if ( widgets.isEmpty() ) return;
   QTreeWidgetItem* aTreeItem = widgets.first();
   int type = aTreeItem->data( 1, TypeRole ).toInt();
-  int id   = aTreeItem->data( 1, IdRole ).toInt();
-  QMenu menu;
-  QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" ));
-  if ( type == ElemConnectivity && id > 0 && menu.exec( e->globalPos() ) == a )
-    emit( itemInfo( id ));
-  else if ( type == NodeConnectivity && menu.exec( e->globalPos() ) == a )
-    emit( itemInfo( aTreeItem->text( 1 )) );
+  if (( type == ElemConnectivity || type == NodeConnectivity ) &&
+      ( !aTreeItem->text( 1 ).isEmpty() ))
+  {
+    QMenu menu;
+    QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" ));
+    if ( menu.exec( e->globalPos() ) == a )
+      emit( itemInfo( type, aTreeItem->text( 1 )) );
+  }
 }
 
 void SMESHGUI_TreeElemInfo::itemDoubleClicked( QTreeWidgetItem* theItem, int theColumn )
 {
   if ( theItem ) {
     int type = theItem->data( 1, TypeRole ).toInt();
-    int id   = theItem->data( 1, IdRole ).toInt();
-    if ( type == ElemConnectivity && id > 0 )
-      emit( itemInfo( id ));
-    else if ( type == NodeConnectivity )
-      emit( itemInfo( theItem->text( 1 )) );
+    emit( itemInfo( type, theItem->text( 1 )) );
   }
 }
 
@@ -2346,482 +2302,527 @@ void SMESHGUI_TreeElemInfo::saveExpanded( QTreeWidgetItem* theItem )
 
 QString SMESHGUI_TreeElemInfo::expandedResource( QTreeWidgetItem* theItem )
 {
-  return QString("Expanded_") + ( isElements() ? "E_" : "N_" ) + theItem->text(0);
+  return QString("Expanded_") + ( what()==ShowElements ? "E_" : "N_" ) + theItem->text(0);
 }
 
-void SMESHGUI_TreeElemInfo::saveInfo( QTextStream &out )
-{
-  out << QString( 12, '-' ) << "\n";
-  out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
-  out << QString( 12, '-' ) << "\n";
-
-  QTreeWidgetItemIterator it( myInfo );
-  while ( *it ) {
-    if ( !( *it )->text(0).isEmpty() ) {
-      out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
-      if ( !( *it )->text(1).isEmpty() ) out << ": " << ( *it )->text(1);
-      out << "\n";
-    }
-    ++it;
-  }
-  out << "\n";
-}
+////////////////////////////////////////////////////////////////////////////////
+/// \class InfoComputor
+/// \brief Mesh information computor.
+/// \internal
+///
+/// The class is created for different computation operations. Currently it is
+/// used to compute size and number of underlying nodes for given group.
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
-  \class GrpComputor
-  \brief Mesh information computer
+  \brief Constructor.
+  \param parent Parent object.
+  \param proxy Object to compute information on (group).
+  \param item Tree widget item, referenced by this computer.
+  \param operation Value to compute.
   \internal
-  
-  The class is created for different computation operation. Currently it is used
-  to compute number of underlying nodes for the groups.
-*/
-
-/*!
-  \brief Constructor
 */
-GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp,
-                          QTreeWidgetItem*           item,
-                          QObject*                   parent,
-                          bool                       toComputeSize)
-  : QObject( parent ), myItem( item ), myToComputeSize( toComputeSize )
+InfoComputor::InfoComputor( QObject* parent, const SMESH::SelectionProxy& proxy, int operation )
+  : QObject( parent ), myProxy( proxy ), myOperation( operation )
 {
-  myGroup = SMESH::SMESH_GroupBase::_narrow( grp );
 }
 
 /*!
-  \brief Compute function
+  \brief Compute requested information.
+  \internal
 */
-void GrpComputor::compute()
+void InfoComputor::compute()
 {
-  if ( !CORBA::is_nil( myGroup ) && myItem ) {
+  if ( myProxy )
+  {
     SUIT_OverrideCursor wc;
-    QTreeWidgetItem* item = myItem;
-    myItem = 0;
-    int nb = myToComputeSize ? myGroup->Size() : myGroup->GetNumberOfNodes();
-    item->treeWidget()->removeItemWidget( item, 1 );
-    item->setText( 1, QString::number( nb ));
+    switch ( myOperation )
+    {
+    case GrpSize:
+      myProxy.size( true ); // force size computation
+      emit computed();
+      break;
+    case GrpNbNodes:
+      myProxy.nbNodes( true ); // force size computation
+      emit computed();
+      break;
+    default:
+      break;
+    }
   }
 }
 
-/*!
-  \class SMESHGUI_AddInfo
-  \brief The wigdet shows additional information on the mesh object.
-*/
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_AddInfo
+/// \brief Show additional information on selected object.
+///
+/// Displays an additional information about selected object: mesh, sub-mesh
+/// or group.
+///
+/// \todo Rewrite saveInfo() method to print all data, not currently shown only.
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
-  \brief Constructor
-  \param parent parent widget
+  \brief Constructor.
+  \param parent Parent widget. Defaults to 0.
 */
-SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
-  : QTreeWidget( parent )
+SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent ): SMESHGUI_Info( parent )
 {
-  setColumnCount( 2 );
-  header()->setStretchLastSection( true );
+  QVBoxLayout* l = new QVBoxLayout( this );
+  l->setMargin( 0 );
+  l->setSpacing( SPACING );
+
+  myTree = new QTreeWidget( this );
+
+  myTree->setColumnCount( 2 );
+  myTree->header()->setStretchLastSection( true );
 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
-  header()->setResizeMode( 0, QHeaderView::ResizeToContents );
+  myTree->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
 #else
-  header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
+  myTree->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
 #endif
-  header()->hide();
+  myTree->header()->hide();
+
+  l->addWidget( myTree );
 }
 
 /*!
-  \brief Destructor
+  \brief Destructor.
 */
 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
 {
 }
 
 /*!
-  \brief Show additional information on the selected object
-  \param obj object being processed (mesh, sub-mesh, group, ID source)
+  \brief Show information on given object.
+  \param proxy Object to show information on (mesh, sub-mesh, group).
 */
-void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
+void SMESHGUI_AddInfo::showInfo( const SMESH::SelectionProxy& proxy )
 {
+  // reset panel
   setProperty( "group_index", 0 );
   setProperty( "submesh_index",  0 );
   myComputors.clear();
-  clear();
-
-  if ( CORBA::is_nil( obj )) return;
-
-  _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
-  if ( !sobj ) return;
+  myTree->clear();
 
-  // name
-  QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
-  nameItem->setText( 0, tr( "NAME" ));
-  nameItem->setText( 1, sobj->GetName().c_str() );
-  
-  SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
-  SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
-  SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
-  
-  if ( !aMesh->_is_nil() )
-    meshInfo( aMesh, nameItem );
-  else if ( !aSubMesh->_is_nil() )
-    subMeshInfo( aSubMesh, nameItem );
-  else if ( !aGroup->_is_nil() )
-    groupInfo( aGroup.in(), nameItem );
+  // then fill panel with data if object is not null
+  if ( proxy )
+  {
+    myProxy = proxy;
+
+    // name
+    QTreeWidgetItem* nameItem = createItem( 0, Bold | AllColumns );
+    nameItem->setText( 0, tr( "NAME" ) );
+    nameItem->setText( 1, proxy.name() );
+
+    // object info
+    if ( proxy.type() == SMESH::SelectionProxy::Mesh )
+      meshInfo( proxy, nameItem );
+    else if ( proxy.type() == SMESH::SelectionProxy::Submesh )
+      subMeshInfo( proxy, nameItem );
+    else if ( proxy.type() >= SMESH::SelectionProxy::Group )
+      groupInfo( proxy, nameItem );
+  }
 }
 
 /*!
-  \brief Create new tree item.
-  \param parent parent tree widget item
-  \param flags item flag
-  \return new tree widget item
+  \brief Update information in panel.
 */
-QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
+void SMESHGUI_AddInfo::updateInfo()
 {
-  QTreeWidgetItem* item;
-
-  if ( parent )
-    item = new QTreeWidgetItem( parent );
-  else
-    item = new QTreeWidgetItem( this );
-
-  //item->setFlags( item->flags() | Qt::ItemIsEditable );
+  showInfo( myProxy );
+}
 
-  QFont f = item->font( 0 );
-  f.setBold( true );
-  for ( int i = 0; i < columnCount(); i++ ) {
-    if ( ( flags & Bold ) && ( i == 0 || flags & All ))
-      item->setFont( i, f );
-  }
+/*!
+  \brief Reset panel (clear all data).
+*/
+void SMESHGUI_AddInfo::clear()
+{
+  myTree->clear();
+}
 
-  item->setExpanded( true );
+/*!
+  \brief Create new item and add it to the tree.
+  \param parent Parent tree widget item. Defaults to 0 (top-level item).
+  \param options Item flags. Defaults to 0 (none).
+  \return New tree widget item.
+*/
+QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int options )
+{
+  QTreeWidgetItem* item = parent ? new QTreeWidgetItem( parent ) : 
+    new QTreeWidgetItem( myTree->invisibleRootItem() );
+  setTreeItemAttributes( item, options | Expanded );
   return item;
 }
 
 /*!
-  \brief Show mesh info
-  \param mesh mesh object
-  \param parent parent tree item
+  \brief Show information on mesh.
+  \param proxy Proxy object (mesh).
+  \param parent Parent tree item.
 */
-void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
+void SMESHGUI_AddInfo::meshInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent )
 {
+  if ( !proxy )
+    return;
+
+  QString shapeName = proxy.shapeName();
+  SMESH::MedInfo inf = proxy.medFileInfo();
+
   // type
-  GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
-  SMESH::MedFileInfo_var inf = mesh->GetMEDFileInfo();
   QTreeWidgetItem* typeItem = createItem( parent, Bold );
-  typeItem->setText( 0, tr( "TYPE" ));
-  if ( !CORBA::is_nil( shape )) {
-    typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ));
-    _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
-    if ( sobj ) {
-      QTreeWidgetItem* gobjItem = createItem( typeItem );
-      gobjItem->setText( 0, tr( "GEOM_OBJECT" ));
-      gobjItem->setText( 1, sobj->GetName().c_str() );
-    }
+  typeItem->setText( 0, tr( "TYPE" ) );
+  if ( !shapeName.isEmpty() )
+  {
+    typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
+    // shape
+    QTreeWidgetItem* gobjItem = createItem( parent, Bold );
+    gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
+    gobjItem->setText( 1, shapeName );
   }
-  else if ( strlen( (char*)inf->fileName ) > 0 ) {
-    typeItem->setText( 1, tr( "MESH_FROM_FILE" ));
-    QTreeWidgetItem* fileItem = createItem( typeItem );
-    fileItem->setText( 0, tr( "FILE_NAME" ));
-    fileItem->setText( 1, (char*)inf->fileName );
+  else if ( inf.isValid() )
+  {
+    typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
+    // med file information
+    QTreeWidgetItem* fileItem = createItem( parent, Bold );
+    fileItem->setText( 0, tr( "FILE_NAME" ) );
+    fileItem->setText( 1, inf.fileName() );
+    QTreeWidgetItem* sizeItem = createItem( parent, Bold );
+    sizeItem->setText( 0, tr( "FILE_SIZE" ) );
+    sizeItem->setText( 1, QString::number( inf.size() ) );
+    QTreeWidgetItem* versionItem = createItem( parent, Bold );
+    versionItem->setText( 0, tr( "FILE_VERSION" ) );
+    versionItem->setText( 1, inf.version() != "0" ? inf.version() : tr( "VERSION_UNKNOWN" ) );
   }
-  else {
-    typeItem->setText( 1, tr( "STANDALONE_MESH" ));
+  else
+  {
+    typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
   }
   
   // groups
-  myGroups = mesh->GetGroups();
+  myGroups = proxy.groups();
   showGroups();
 
   // sub-meshes
-  mySubMeshes = mesh->GetSubMeshes();
+  mySubMeshes = proxy.submeshes();
   showSubMeshes();
 }
 
 /*!
-  \brief Show sub-mesh info
-  \param subMesh sub-mesh object
-  \param parent parent tree item
+  \brief Show information on sub-mesh.
+  \param proxy Proxy object (sub-mesh).
+  \param parent Parent tree item.
 */
-void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
+void SMESHGUI_AddInfo::subMeshInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent )
 {
+  if ( !proxy )
+    return;
+
   bool isShort = parent->parent() != 0;
 
-  if ( !isShort ) {
+  if ( !isShort )
+  {
     // parent mesh
-    _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
-    if ( sobj ) {
+    SMESH::SelectionProxy meshProxy = proxy.mesh();
+    if ( meshProxy )
+    {
       QTreeWidgetItem* nameItem = createItem( parent, Bold );
-      nameItem->setText( 0, tr( "PARENT_MESH" ));
-      nameItem->setText( 1, sobj->GetName().c_str() );
+      nameItem->setText( 0, tr( "PARENT_MESH" ) );
+      nameItem->setText( 1, meshProxy.name() );
     }
   }
   
   // shape
-  GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
-  _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
-  if ( sobj ) {
+  QString shapeName = proxy.shapeName();
+  if ( !shapeName.isEmpty() )
+  {
     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
-    gobjItem->setText( 0, tr( "GEOM_OBJECT" ));
-    gobjItem->setText( 1, sobj->GetName().c_str() );
+    gobjItem->setText( 1, shapeName );
   }
 }
 
 /*!
-  \brief Show group info
-  \param grp mesh group object
-  \param parent parent tree item
+  \brief Show information on group.
+  \param proxy Proxy object (group).
+  \param parent Parent tree item.
 */
-void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
+void SMESHGUI_AddInfo::groupInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent )
 {
-  bool isShort = parent->parent() != 0;
+  if ( !proxy )
+    return;
 
-  SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
-  SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
-  SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
+  bool isShort = parent->parent() != 0;
 
-  if ( !isShort ) {
+  if ( !isShort )
+  {
     // parent mesh
-    _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
-    if ( sobj ) {
+    SMESH::SelectionProxy meshProxy = proxy.mesh();
+    if ( meshProxy )
+    {
       QTreeWidgetItem* nameItem = createItem( parent, Bold );
-      nameItem->setText( 0, tr( "PARENT_MESH" ));
-      nameItem->setText( 1, sobj->GetName().c_str() );
+      nameItem->setText( 0, tr( "PARENT_MESH" ) );
+      nameItem->setText( 1, meshProxy.name() );
     }
   }
 
-  // type : group on geometry, standalone group, group on filter
+  // type
+  SMESH::SelectionProxy::Type type = proxy.type();
   QTreeWidgetItem* typeItem = createItem( parent, Bold );
-  typeItem->setText( 0, tr( "TYPE" ));
-  if ( !CORBA::is_nil( aStdGroup )) {
-    typeItem->setText( 1, tr( "STANDALONE_GROUP" ));
-  }
-  else if ( !CORBA::is_nil( aGeomGroup )) {
-    typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ));
-    GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
-    _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
-    if ( sobj ) {
-      QTreeWidgetItem* gobjItem = createItem( typeItem );
-      gobjItem->setText( 0, tr( "GEOM_OBJECT" ));
-      gobjItem->setText( 1, sobj->GetName().c_str() );
-    }
+  typeItem->setText( 0, tr( "TYPE" ) );
+  if ( type == SMESH::SelectionProxy::GroupStd )
+  {
+    typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
+  }
+  else if ( type == SMESH::SelectionProxy::GroupGeom )
+  {
+    typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
+    // shape
+    QTreeWidgetItem* gobjItem = createItem( parent, Bold );
+    gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
+    gobjItem->setText( 1, proxy.shapeName() );
   }
-  else if ( !CORBA::is_nil( aFltGroup )) {
-    typeItem->setText( 1, tr( "GROUP_ON_FILTER" ));
+  else if ( type == SMESH::SelectionProxy::GroupFilter )
+  {
+    typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
   }
 
-  if ( !isShort ) {
-    // entity type
-    QString etype = tr( "UNKNOWN" );
-    switch( grp->GetType() ) {
+  // element type
+  int etype = proxy.groupElementType();
+  if ( !isShort )
+  {
+    QString typeName = tr( "UNKNOWN" );
+    switch( etype )
+    {
     case SMESH::NODE:
-      etype = tr( "NODE" );
+      typeName = tr( "NODE" );
       break;
     case SMESH::EDGE:
-      etype = tr( "EDGE" );
+      typeName = tr( "EDGE" );
       break;
     case SMESH::FACE:
-      etype = tr( "FACE" );
+      typeName = tr( "FACE" );
       break;
     case SMESH::VOLUME:
-      etype = tr( "VOLUME" );
+      typeName = tr( "VOLUME" );
       break;
     case SMESH::ELEM0D:
-      etype = tr( "0DELEM" );
+      typeName = tr( "0DELEM" );
       break;
     case SMESH::BALL:
-      etype = tr( "BALL" );
+      typeName = tr( "BALL" );
       break;
     default:
       break;
     }
     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
-    etypeItem->setText( 0, tr( "ENTITY_TYPE" ));
-    etypeItem->setText( 1, etype );
+    etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
+    etypeItem->setText( 1, typeName );
   }
 
-  SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
-  bool            meshLoaded = mesh->IsLoaded();
-
-  // size. Don't call grp->Size() for GroupOnFilter - issue IPAL52831
-  int groupSize = -1;
-  if ( grp->IsNodeInfoAvailable() || CORBA::is_nil( aFltGroup ))
-    groupSize = grp->Size();
+  // size
+  // note: size is not computed for group on filter for performance reasons, see IPAL52831
+  bool meshLoaded = proxy.isMeshLoaded();
+  int size = proxy.size();
 
   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
-  sizeItem->setText( 0, tr( "SIZE" ));
-  if ( groupSize > -1 ) {
-    sizeItem->setText( 1, QString::number( groupSize ));
+  sizeItem->setText( 0, tr( "SIZE" ) );
+  if ( size >= 0 )
+  {
+    sizeItem->setText( 1, QString::number( size ) );
   }
-  else {
-    QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
-    setItemWidget( sizeItem, 1, btn );
-    GrpComputor* comp = new GrpComputor( grp, sizeItem, this, /*size=*/true );
-    connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ));
+  else
+  {
+    QPushButton* btn = new QPushButton( meshLoaded ? tr( "COMPUTE" ) : tr( "LOAD" ), this );
+    myTree->setItemWidget( sizeItem, 1, btn );
+    InfoComputor* comp = new InfoComputor( this, proxy, InfoComputor::GrpSize );
+    connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
+    connect( comp, SIGNAL( computed() ), this, SLOT( updateInfo() ) );
     myComputors.append( comp );
-    if ( !meshLoaded )
-      connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ));
   }
 
   // color
-  SALOMEDS::Color color = grp->GetColor();
   QTreeWidgetItem* colorItem = createItem( parent, Bold );
-  colorItem->setText( 0, tr( "COLOR" ));
-  colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ));
+  colorItem->setText( 0, tr( "COLOR" ) );
+  colorItem->setBackground( 1, proxy.color() );
 
   // nb of underlying nodes
-  if ( grp->GetType() != SMESH::NODE) {
+  if ( etype != SMESH::NODE )
+  {
     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
-    nodesItem->setText( 0, tr( "NB_NODES" ));
-    int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
-    bool toShowNodes = groupSize >= 0 ? ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || groupSize <= nbNodesLimit ) : false;
-    if ( toShowNodes && meshLoaded ) {
-      // already calculated and up-to-date
-      nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ));
+    nodesItem->setText( 0, tr( "NB_NODES" ) );
+
+    int nbNodes = proxy.nbNodes();
+    if ( nbNodes >= 0 )
+    {
+      nodesItem->setText( 1, QString::number( nbNodes ) );
     }
-    else {
-      QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
-      setItemWidget( nodesItem, 1, btn );
-      GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
-      connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ));
+    else
+    {
+      QPushButton* btn = new QPushButton( meshLoaded ? tr( "COMPUTE" ) : tr( "LOAD" ), this );
+      myTree->setItemWidget( nodesItem, 1, btn );
+      InfoComputor* comp = new InfoComputor( this, proxy, InfoComputor::GrpNbNodes ); 
+      connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
+      connect( comp, SIGNAL( computed() ), this, SLOT( updateInfo() ) );
       myComputors.append( comp );
-      if ( !meshLoaded )
-        connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ));
     }
   }
 }
 
+/*!
+  \brief Update information on child groups.
+*/
 void SMESHGUI_AddInfo::showGroups()
 {
+  // remove all computors
   myComputors.clear();
 
-  QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
-  if ( !parent ) return;
+  // tree root should be the first top level item
+  QTreeWidgetItem* parent = myTree->topLevelItemCount() > 0 ? myTree->topLevelItem( 0 ) : 0;
+  if ( !parent )
+    return;
 
   int idx = property( "group_index" ).toInt();
 
+  // find sub-meshes top-level container item
   QTreeWidgetItem* itemGroups = 0;
-  for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) {
-    if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) {
+  for ( int i = 0; i < parent->childCount() && !itemGroups; i++ )
+  {
+    if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GroupsId )
+    {
       itemGroups = parent->child( i );
-      ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemGroups, 1 ));
+      // update controls
+      ExtraWidget* extra = dynamic_cast<ExtraWidget*>( myTree->itemWidget( itemGroups, 1 ) );
       if ( extra )
-        extra->updateControls( myGroups->length(), idx );
-      while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items
+        extra->updateControls( myGroups.count(), idx );
+      // clear: remove all group items
+      while ( itemGroups->childCount() )
+        delete itemGroups->child( 0 );
     }
   }
 
   QMap<int, QTreeWidgetItem*> grpItems;
-  for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) {
-    SMESH::SMESH_GroupBase_var grp = myGroups[i];
-    if ( CORBA::is_nil( grp )) continue;
-    _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
-    if ( !grpSObj ) continue;
-
-    int grpType = grp->GetType();
-
-    if ( !itemGroups ) {
-      // create top-level groups container item
-      itemGroups = createItem( parent, Bold | All );
-      itemGroups->setText( 0, tr( "GROUPS" ));
-      itemGroups->setData( 0, Qt::UserRole, GROUPS_ID );
-
-      // total number of groups > 10, show extra widgets for info browsing
-      if ((int) myGroups->length() > MAXITEMS ) {
+  for ( int i = idx*blockSize() ; i < qMin( (idx+1)*blockSize(), (int)myGroups.count() ); i++ )
+  {
+    SMESH::SelectionProxy grp = myGroups[i];
+    if ( !grp )
+      continue;
+
+    int grpType = grp.groupElementType();
+
+    // create top-level groups container item if it does not exist
+    if ( !itemGroups )
+    {
+      itemGroups = createItem( parent, Bold | AllColumns );
+      itemGroups->setText( 0, tr( "GROUPS" ) );
+      itemGroups->setData( 0, Qt::UserRole, GroupsId );
+
+      // if necessary, create extra widget to show information by chunks
+      if ( myGroups.count() > blockSize() )
+      {
         ExtraWidget* extra = new ExtraWidget( this, true );
-        connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ));
-        connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ));
-        setItemWidget( itemGroups, 1, extra );
-        extra->updateControls( myGroups->length(), idx );
+        connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
+        connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
+        myTree->setItemWidget( itemGroups, 1, extra );
+        extra->updateControls( myGroups.count(), idx );
       }
     }
 
-    if ( grpItems.find( grpType ) == grpItems.end() ) {
-      grpItems[ grpType ] = createItem( itemGroups, Bold | All );
-      grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ));
-      itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
+    // create container item corresponding to particular element type
+    if ( !grpItems.contains( grpType ) )
+    {
+      grpItems[ grpType ] = createItem( itemGroups, Bold | AllColumns );
+      grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
+      itemGroups->insertChild( grpType-1, grpItems[ grpType ] ); // -1 needed since 0 corresponds to SMESH::ALL
     }
   
-    // group name
-    QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
-    grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed
+    // name
+    QTreeWidgetItem* nameItem = createItem( grpItems[ grpType ] );
+    nameItem->setText( 0, grp.name().trimmed() ); // trim name
 
     // group info
-    groupInfo( grp.in(), grpNameItem );
+    groupInfo( grp, nameItem );
   }
 }
 
+/*!
+  \brief Update information on child sub-meshes.
+*/
 void SMESHGUI_AddInfo::showSubMeshes()
 {
-  QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
-  if ( !parent ) return;
+  // tree root should be the first top level item
+  QTreeWidgetItem* parent = myTree->topLevelItemCount() > 0 ? myTree->topLevelItem( 0 ) : 0;
+  if ( !parent )
+    return;
 
   int idx = property( "submesh_index" ).toInt();
 
+  // find sub-meshes top-level container item
   QTreeWidgetItem* itemSubMeshes = 0;
-  for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) {
-    if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) {
+  for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ )
+  {
+    if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SubMeshesId )
+    {
       itemSubMeshes = parent->child( i );
-      ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemSubMeshes, 1 ));
+      // update controls
+      ExtraWidget* extra = dynamic_cast<ExtraWidget*>( myTree->itemWidget( itemSubMeshes, 1 ) );
       if ( extra )
-        extra->updateControls( mySubMeshes->length(), idx );
-      while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items
+        extra->updateControls( mySubMeshes.count(), idx );
+      // clear: remove all sub-mesh items
+      while ( itemSubMeshes->childCount() )
+        delete itemSubMeshes->child( 0 );
     }
   }
 
   QMap<int, QTreeWidgetItem*> smItems;
-  for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) {
-    SMESH::SMESH_subMesh_var sm = mySubMeshes[i];
-    if ( CORBA::is_nil( sm )) continue;
-    _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
-    if ( !smSObj ) continue;
-    
-    GEOM::GEOM_Object_var gobj = sm->GetSubShape();
-    if ( CORBA::is_nil(gobj )) continue;
+  for ( int i = idx*blockSize() ; i < qMin( (idx+1)*blockSize(), mySubMeshes.count() ); i++ )
+  {
+    SMESH::SelectionProxy sm = mySubMeshes[i];
+    if ( !sm )
+      continue;
     
-    int smType = gobj->GetShapeType();
-    if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
-
-    if ( !itemSubMeshes ) {
-      itemSubMeshes = createItem( parent, Bold | All );
-      itemSubMeshes->setText( 0, tr( "SUBMESHES" ));
-      itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID );
+    int smType = sm.shapeType();
+    if ( smType < 0 )
+      continue;
+    else if ( smType == GEOM::COMPSOLID )
+      smType = GEOM::COMPOUND;
+
+    // create top-level sub-meshes container item if it does not exist
+    if ( !itemSubMeshes )
+    {
+      itemSubMeshes = createItem( parent, Bold | AllColumns );
+      itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
+      itemSubMeshes->setData( 0, Qt::UserRole, SubMeshesId );
 
-      // total number of sub-meshes > 10, show extra widgets for info browsing
-      if ((int) mySubMeshes->length() > MAXITEMS ) {
+      // if necessary, create extra widget to show information by chunks
+      if ( mySubMeshes.count() > blockSize() )
+      {
         ExtraWidget* extra = new ExtraWidget( this, true );
-        connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ));
-        connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ));
-        setItemWidget( itemSubMeshes, 1, extra );
-        extra->updateControls( mySubMeshes->length(), idx );
+        connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
+        connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
+        myTree->setItemWidget( itemSubMeshes, 1, extra );
+        extra->updateControls( mySubMeshes.count(), idx );
       }
-    }
-         
-    if ( smItems.find( smType ) == smItems.end() ) {
-      smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
-      smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ));
-      itemSubMeshes->insertChild( smType, smItems[ smType ] );
-    }
-    
-    // submesh name
-    QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
-    smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed
-    
-    // submesh info
-    subMeshInfo( sm.in(), smNameItem );
-  }
-}
-
-/*!
- * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
- */
-void SMESHGUI_AddInfo::changeLoadToCompute()
-{
-  for ( int i = 0; i < myComputors.count(); ++i )
-  {
-    if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
+    }
+
+    // create container item corresponding to particular shape type
+    if ( !smItems.contains( smType ) )
     {
-      if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 )) )
-        btn->setText( tr("COMPUTE") );
+      smItems[ smType ] = createItem( itemSubMeshes, Bold | AllColumns );
+      smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
+      itemSubMeshes->insertChild( smType, smItems[ smType ] );
     }
+    
+    // name
+    QTreeWidgetItem* nameItem = createItem( smItems[ smType ] );
+    nameItem->setText( 0, sm.name().trimmed() ); // trim name
+    
+    // submesh info
+    subMeshInfo( sm, nameItem );
   }
 }
 
+/*!
+  \brief Show previous chunk of information on child groups.
+*/
 void SMESHGUI_AddInfo::showPreviousGroups()
 {
   int idx = property( "group_index" ).toInt();
@@ -2829,6 +2830,9 @@ void SMESHGUI_AddInfo::showPreviousGroups()
   showGroups();
 }
 
+/*!
+  \brief Show next chunk of information on child groups.
+*/
 void SMESHGUI_AddInfo::showNextGroups()
 {
   int idx = property( "group_index" ).toInt();
@@ -2836,6 +2840,9 @@ void SMESHGUI_AddInfo::showNextGroups()
   showGroups();
 }
 
+/*!
+  \brief Show previous chunk of information on child sub-meshes.
+*/
 void SMESHGUI_AddInfo::showPreviousSubMeshes()
 {
   int idx = property( "submesh_index" ).toInt();
@@ -2843,6 +2850,9 @@ void SMESHGUI_AddInfo::showPreviousSubMeshes()
   showSubMeshes();
 }
 
+/*!
+  \brief Show next chunk of information on child sub-meshes.
+*/
 void SMESHGUI_AddInfo::showNextSubMeshes()
 {
   int idx = property( "submesh_index" ).toInt();
@@ -2850,50 +2860,161 @@ void SMESHGUI_AddInfo::showNextSubMeshes()
   showSubMeshes();
 }
 
+/*!
+  \brief Write information from panel to ouput stream.
+  \param out Text stream output.
+*/
 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
 {
-  out << QString( 15, '-')       << "\n";
-  out << tr( "ADDITIONAL_INFO" ) << "\n";
-  out << QString( 15, '-' )      << "\n";
-  QTreeWidgetItemIterator it( this );
-  while ( *it ) {
-    if ( !( ( *it )->text(0) ).isEmpty() ) {
-      out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
-      if ( ( *it )->text(0)  == tr( "COLOR" )) {
-        out << ": " << ( ( ( *it )->background(1) ).color() ).name();
-      }
-      else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1);
-      out << "\n";
+  // title
+  QString title = tr( "ADDITIONAL_INFO" );
+  out << ruler( title.size() ) << endl;
+  out << title << endl;
+  out << ruler( title.size() ) << endl;
+  out << endl;
+
+  // info
+  QTreeWidgetItemIterator it( myTree );
+  while ( *it )
+  {
+    if ( !( ( *it )->text(0) ).isEmpty() )
+    {
+      out << indent( itemDepth( *it ) ) << ( *it )->text(0);
+      if ( ( *it )->text(0)  == tr( "COLOR" ) )
+        out << ":" << spacing() << ( ( ( *it )->background(1) ).color() ).name();
+      else if ( !( ( *it )->text(1) ).isEmpty() )
+        out << ":" << spacing() << ( *it )->text(1);
+      out << endl;
     }
     ++it;
   }
-  out << "\n";
+  out << endl;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class GroupCombo
+/// \brief Customized combo box to manage list of mesh groups.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
+class GroupCombo: public QComboBox
+{
+  class Item: public QStandardItem
+  {
+  public:
+    SMESH::SelectionProxy myGroup;
+    Item( const SMESH::SelectionProxy& group )
+    {
+      myGroup = group;
+      setText( myGroup.name() );
+    }
+    SMESH::SelectionProxy group()
+    {
+      return myGroup;
+    }
+  };
+
+  SMESH::SelectionProxy myProxy;
+
+public:
+  GroupCombo( QWidget* );
+  void setSource( const SMESH::SelectionProxy& );
+  SMESH::SelectionProxy currentGroup() const;
+};
+
+/*!
+  \brief Contructor.
+  \param parent Parent widget.
+  \internal
+*/
+GroupCombo::GroupCombo( QWidget* parent ): QComboBox( parent )
+{
+  setModel( new QStandardItemModel( this ) );
+}
+
+/*!
+  \brief Set mesh source.
+  \param obj Mesh source.
+  \internal
+*/
+void GroupCombo::setSource( const SMESH::SelectionProxy& proxy )
+{
+  if ( myProxy == proxy )
+    return;
+
+  myProxy = proxy;
+
+  bool blocked = blockSignals( true );
+  QStandardItemModel* m = dynamic_cast<QStandardItemModel*>( model() );
+  m->clear();
+
+  if ( myProxy )
+  {
+    if ( myProxy.type() == SMESH::SelectionProxy::Mesh )
+    {
+      QList<SMESH::SelectionProxy> groups = myProxy.groups();
+      for ( int i = 0; i < groups.count(); ++i )
+      {
+        if ( groups[i] )
+        {
+          QString name = groups[i].name();
+          if ( !name.isEmpty() )
+            m->appendRow( new Item( groups[i] ) );
+        }
+      }
+      setCurrentIndex( -1 ); // for performance reasons
+    }
+    else if ( myProxy.type() >= SMESH::SelectionProxy::Group )
+    {
+      m->appendRow( new Item( myProxy ) );
+      setCurrentIndex( 0 );
+    }
+  }
+
+  blockSignals( blocked );
 }
 
 /*!
-  \class SMESHGUI_MeshInfoDlg
-  \brief Mesh information dialog box
+  \brief Get currently selected group.
+  \return Selected group.
+  \internal
 */
+SMESH::SelectionProxy GroupCombo::currentGroup() const
+{
+  SMESH::SelectionProxy group;
+  QStandardItemModel* m = dynamic_cast<QStandardItemModel*>( model() );
+  if ( currentIndex() >= 0 )
+    group = dynamic_cast<Item*>( m->item( currentIndex() ) )->group();
+  return group;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_MeshInfoDlg
+/// \brief Mesh information dialog box
+///
+/// \todo Move all business logic for element info to SMESHGUI_ElemInfo class.
+/// \todo Add selection button to reactivate selection on move from other dlg.
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
   \brief Constructor
-  \param parent parent widget
-  \param page specifies the dialog page to be shown at the start-up
+  \param parent Parent widget.
+  \param page Dialog page to show at start-up. Defaults to \c BaseInfo.
 */
 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
-  : QDialog( parent ), myActor( 0 )
+  : QDialog( parent )
 {
   setModal( false );
   setAttribute( Qt::WA_DeleteOnClose, true );
-  setWindowTitle( tr( "MESH_INFO" ));
+  setWindowTitle( tr( "MESH_INFO" ) );
   setSizeGripEnabled( true );
 
   myTabWidget = new QTabWidget( this );
 
   // base info
 
-  myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
-  myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ));
+  myBaseInfo = new SMESHGUI_BaseInfo( myTabWidget );
+  myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
 
   // elem info 
 
@@ -2902,40 +3023,47 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
   myMode = new QButtonGroup( this );
   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
+  myMode->addButton( new QRadioButton( tr( "GROUP_MODE" ), w ), GroupMode );
   myMode->button( NodeMode )->setChecked( true );
   myID = new QLineEdit( w );
-  myID->setValidator( new SMESHGUI_IdValidator( this ));
+  myID->setValidator( new SMESHGUI_IdValidator( this ) );
+  myGroups = new GroupCombo( w );
+  QStackedWidget* stack = new QStackedWidget( w );
+  stack->addWidget( myID );
+  stack->addWidget( myGroups );
   myIDPreviewCheck = new QCheckBox( tr( "SHOW_IDS" ), w );
-  myIDPreview = new SMESHGUI_IdPreview( SMESH::GetViewWindow( SMESHGUI::GetSMESHGUI() ));
+  myIDPreview = new SMESHGUI_IdPreview( SMESH::GetViewWindow( SMESHGUI::GetSMESHGUI() ) );
 
   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
-  mode = qMin( 1, qMax( 0, mode ));
+  mode = qMin( 1, qMax( 0, mode ) );
 
   if ( mode == 0 )
     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
   else
     myElemInfo = new SMESHGUI_TreeElemInfo( w );
+  stack->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
 
   QGridLayout* elemLayout = new QGridLayout( w );
   elemLayout->setMargin( MARGIN );
   elemLayout->setSpacing( SPACING );
   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
-  elemLayout->addWidget( myID,                       0, 2 );
-  elemLayout->addWidget( myIDPreviewCheck,           1, 0, 1, 2 );
-  elemLayout->addWidget( myElemInfo,                 2, 0, 1, 3 );
+  elemLayout->addWidget( myMode->button( GroupMode ), 0, 2 );
+  elemLayout->addWidget( stack, 0, 3 );
+  elemLayout->addWidget( myIDPreviewCheck, 1, 0, 1, 4 );
+  elemLayout->addWidget( myElemInfo, 2, 0, 1, 4 );
 
-  myTabWidget->addTab( w, tr( "ELEM_INFO" ));
+  myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
 
   // additional info
 
   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
-  myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ));
+  myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
 
   // controls info
 
   myCtrlInfo = new SMESHGUI_CtrlInfo( myTabWidget );
-  myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ));
+  myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ) );
 
   // buttons
 
@@ -2957,33 +3085,41 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
   btnLayout->addStretch( 10 );
   btnLayout->addWidget( helpBtn );
 
+  // arrange widgets
+
   QVBoxLayout* l = new QVBoxLayout ( this );
   l->setMargin( MARGIN );
   l->setSpacing( SPACING );
   l->addWidget( myTabWidget );
   l->addLayout( btnLayout );
 
-  myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page )));
+  // set initial page
+
+  myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
 
-  connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ));
-  connect( dumpBtn,     SIGNAL( clicked() ),              this, SLOT( dump() ));
-  connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ));
-  connect( myTabWidget, SIGNAL( currentChanged( int  )), this, SLOT( updateSelection() ));
-  connect( myMode,      SIGNAL( buttonClicked( int  )),  this, SLOT( modeChanged() ));
-  connect( myID,        SIGNAL( textChanged( QString )), this, SLOT( idChanged() ));
-  connect( myIDPreviewCheck,         SIGNAL( toggled(bool) ), this, SLOT( idPreviewChange(bool) ));
-  connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ));
-  connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ));
-  connect( myElemInfo,  SIGNAL( itemInfo( int )),     this, SLOT( showItemInfo( int )));
-  connect( myElemInfo,  SIGNAL( itemInfo( QString )), this, SLOT( showItemInfo( QString )));
+  // set-up connections
 
-  myIDPreviewCheck->setChecked( SMESHGUI::resourceMgr()->booleanValue( "SMESH", id_preview_resource, false ));
+  connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
+  connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
+  connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
+  connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) );
+  connect( myMode, SIGNAL( buttonClicked( int ) ), this, SLOT( modeChanged() ) );
+  connect( myGroups, SIGNAL( currentIndexChanged( int ) ), this, SLOT( modeChanged() ) );
+  connect( myID, SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) );
+  connect( myIDPreviewCheck, SIGNAL( toggled( bool ) ), this, SLOT( idPreviewChange( bool ) ) );
+  connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
+  connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) );
+  connect( myElemInfo, SIGNAL( itemInfo( int, QString ) ), this, SLOT( showItemInfo( int, QString ) ) );
+  connect( this, SIGNAL( switchMode( int ) ), stack, SLOT( setCurrentIndex( int ) ) );
 
+  // initialize
+
+  myIDPreviewCheck->setChecked( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "id_preview_resource", false ) );
   updateSelection();
 }
 
 /*!
-  \brief Destructor
+  \brief Destructor.
 */
 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
 {
@@ -2991,66 +3127,105 @@ SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
 }
 
 /*!
-  \brief Show mesh information
-  \param IO interactive object
+  \brief Show mesh information on given object.
+  \param io Interactive object.
 */
-void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
+void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& io )
 {
-  if ( !IO.IsNull() )
-    myIO = IO;
+  if ( !io.IsNull() )
+    showInfo( SMESH::SelectionProxy( io ) );
+}
 
-  SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
-  if ( !CORBA::is_nil( obj ))
-  {
-    myAddInfo->showInfo( obj );  // nb of nodes in a group can be computed by myAddInfo,
-    myBaseInfo->showInfo( obj ); // and it will be used by myBaseInfo (IPAL52871)
-    if ( myTabWidget->currentIndex() == CtrlInfo )
-      myCtrlInfo->showInfo( obj );
+/*!
+  \brief Show mesh information on given object.
+  \param proxy Selection proxy.
+*/
+void SMESHGUI_MeshInfoDlg::showInfo( const SMESH::SelectionProxy& proxy )
+{
+  SUIT_OverrideCursor wc;
 
-    {
-      myActor = SMESH::FindActorByEntry( IO->getEntry() );
-      SVTK_Selector* selector = SMESH::GetSelector();
-      QString ID;
-      int nb = 0;
-      if ( myActor && selector ) {
-        nb = myMode->checkedId() == NodeMode ?
-          SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
-          SMESH::GetNameOfSelectedNodes( selector, IO, ID );
-      }
-      myElemInfo->setSource( myActor, obj ) ;
-      if ( nb > 0 ) {
-        myID->setText( ID.trimmed() );
-        QSet<long> ids;
-        QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
-        foreach ( ID, idTxt )
-          ids << ID.trimmed().toLong();
-        myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
-      }
-      else {
-        myID->clear();
-        myElemInfo->clear();
-      }
+  if ( !proxy )
+    return;
+
+  myProxy = proxy;
+
+  SMESH::SMESH_IDSource_var obj = myProxy.object();
+
+  // "Base info" tab
+  myBaseInfo->showInfo( proxy );
+
+  // "Additional info" tab
+  myAddInfo->showInfo( proxy );
+
+  // "Quality info" tab
+  // Note: for performance reasons we update it only if it is currently active
+  if ( myTabWidget->currentIndex() == CtrlInfo )
+    myCtrlInfo->showInfo( proxy );
+
+  // "Element info" tab
+  myGroups->setSource( proxy );
+  if ( myMode->checkedId() == GroupMode ) {
+    SMESH::SelectionProxy group = myGroups->currentGroup();
+    if ( group )
+      myElemInfo->showInfo( group );
+    else
+      myElemInfo->clear();
+  }
+  else {
+    SVTK_Selector* selector = SMESH::GetSelector();
+    QString ID;
+    int nb = 0;
+    if ( myProxy.actor() && selector ) { //todo: actor()?
+      nb = myMode->checkedId() == NodeMode ?
+        SMESH::GetNameOfSelectedElements( selector, myProxy.io(), ID ) :
+        SMESH::GetNameOfSelectedNodes( selector, myProxy.io(), ID );
+    }
+    if ( nb > 0 ) {
+      myID->setText( ID.trimmed() );
+      QSet<uint> ids;
+      QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
+      foreach ( ID, idTxt )
+        ids << ID.trimmed().toUInt();
+      myElemInfo->showInfo( proxy, ids, myMode->checkedId() == ElemMode );
+    }
+    else {
+      myID->clear();
+      myElemInfo->clear();
     }
   }
 }
 
 /*!
-  \brief Perform clean-up actions on the dialog box closing.
+  \brief Update information.
+*/
+void SMESHGUI_MeshInfoDlg::updateInfo()
+{
+  SALOME_ListIO selected;
+  SMESHGUI::selectionMgr()->selectedObjects( selected );
+
+  if ( selected.Extent() == 1 )
+    showInfo( selected.First() );
+  else
+    showInfo( myProxy );
+}
+
+/*!
+  \brief Clean-up on dialog closing.
 */
 void SMESHGUI_MeshInfoDlg::reject()
 {
   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
   selMgr->clearFilters();
   SMESH::SetPointRepresentation( false );
-  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
-    aViewWindow->SetSelectionMode( ActorSelection );
+  if ( SVTK_ViewWindow* viewWindow = SMESH::GetViewWindow() )
+    viewWindow->SetSelectionMode( ActorSelection );
   QDialog::reject();
-  myIDPreview->SetPointsLabeled(false);
+  myIDPreview->SetPointsLabeled( false );
 }
 
 /*!
-  \brief Process keyboard event
-  \param e key press event
+  \brief Process keyboard event.
+  \param e Key press event.
 */
 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
 {
@@ -3062,15 +3237,7 @@ void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
 }
 
 /*!
-  \brief Reactivate dialog box, when mouse pointer goes into it.
-*/
-void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* )
-{
-  //activate();
-}
-
-/*!
-  \brief Setup selection mode depending on the current dialog box state.
+  \brief Set-up selection mode for currently selected page.
 */
 void SMESHGUI_MeshInfoDlg::updateSelection()
 {
@@ -3079,86 +3246,60 @@ void SMESHGUI_MeshInfoDlg::updateSelection()
   disconnect( selMgr, 0, this, 0 );
   selMgr->clearFilters();
 
-  if ( myTabWidget->currentIndex() == BaseInfo ||
-       myTabWidget->currentIndex() == AddInfo ||
-       myTabWidget->currentIndex() == CtrlInfo ) {
-    SMESH::SetPointRepresentation( false );
-    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
-      aViewWindow->SetSelectionMode( ActorSelection );
-  }
-  else {
-    if ( myMode->checkedId() == NodeMode ) {
-      SMESH::SetPointRepresentation( true );
-      if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
-        aViewWindow->SetSelectionMode( NodeSelection );
-    }
-    else {
-      SMESH::SetPointRepresentation( false );
-      if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
-        aViewWindow->SetSelectionMode( CellSelection );
-    }
-  }
+  int selMode = ActorSelection;
+  if ( myTabWidget->currentIndex() == ElemInfo && myMode->checkedId() == NodeMode )
+    selMode = NodeSelection;
+  else if ( myTabWidget->currentIndex() == ElemInfo && myMode->checkedId() == ElemMode )
+    selMode = CellSelection;
+  SMESH::SetPointRepresentation( selMode == NodeSelection );
+  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+    aViewWindow->SetSelectionMode( selMode );
 
-  QString oldID = myID->text().trimmed();
-  SMESH_Actor* oldActor = myActor;
+  SMESH::SelectionProxy previous = myProxy;
+  QString ids = myID->text().trimmed();
   myID->clear();
   
-  connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ));
+  connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
   updateInfo();
   
-  if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
-    myID->setText( oldID );
+  if ( myProxy && myProxy == previous && !ids.isEmpty() ) {
+    myID->setText( ids );
     idChanged();
   }
 }
 
 /*!
-  \brief Show help page
+  \brief Show documentation on selected dialog page.
 */
 void SMESHGUI_MeshInfoDlg::help()
 {
-  SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
-                       "mesh_infos.html#advanced-mesh-infos-anchor" : 
-                       "mesh_infos.html#mesh-element-info-anchor" );
-}
-
-/*!
-  \brief Show mesh information
-*/
-void SMESHGUI_MeshInfoDlg::updateInfo()
-{
-  SUIT_OverrideCursor wc;
-
-  SALOME_ListIO selected;
-  SMESHGUI::selectionMgr()->selectedObjects( selected );
-
-  if ( selected.Extent() == 1 ) {
-    Handle(SALOME_InteractiveObject) IO = selected.First();
-    showInfo( IO );
-  }
-  else {
-    showInfo( myIO );
+  QString helpPage = "mesh_infos.html";
+  switch ( myTabWidget->currentIndex() )
+  {
+  case BaseInfo:
+    helpPage += "#advanced-mesh-infos-anchor";
+    break;
+  case ElemInfo:
+    helpPage += "#mesh-element-info-anchor";
+    break;
+  case AddInfo:
+    helpPage += "#mesh-addition-info-anchor";
+    break;
+  case CtrlInfo:
+    helpPage += "#mesh-quality-info-anchor";
+    break;
+  default:
+    break;
   }
+  SMESH::ShowHelpFile( helpPage );
 }
 
 /*!
-  \brief Activate dialog box
-*/
-void SMESHGUI_MeshInfoDlg::activate()
-{
-  SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
-  SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
-  myTabWidget->setEnabled( true );
-  updateSelection();
-}
-
-/*!
-  \brief Deactivate dialog box
+  \brief Deactivate dialog box.
 */
 void SMESHGUI_MeshInfoDlg::deactivate()
 {
-  myTabWidget->setEnabled( false );
-  disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ));
+  disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
 }
 
 /*!
@@ -3166,6 +3307,7 @@ void SMESHGUI_MeshInfoDlg::deactivate()
 */
 void SMESHGUI_MeshInfoDlg::modeChanged()
 {
+  emit( switchMode( myMode->checkedId() == GroupMode ? 1 : 0 ) );
   myID->clear();
   updateSelection();
 }
@@ -3177,46 +3319,48 @@ void SMESHGUI_MeshInfoDlg::idChanged()
 {
   myIDPreview->SetPointsLabeled( false );
 
-  SVTK_Selector* selector = SMESH::GetSelector();
-  if ( myActor && selector ) {
-    Handle(SALOME_InteractiveObject) IO = myActor->getIO();
+  if ( myProxy ) {
     TColStd_MapOfInteger ID;
-    QSet<long>           ids;
+    QSet<uint>           ids;
     std::vector<int>     idVec;
     std::list< gp_XYZ >  aGrCentersXYZ;
+    SMESH::XYZ           xyz;
+    const bool           isElem = ( myMode->checkedId() == ElemMode );
     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
     foreach ( QString tid, idTxt ) {
-      long id = tid.trimmed().toLong();
-      const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ?
-        myActor->GetObject()->GetMesh()->FindElement( id ) :
-        myActor->GetObject()->GetMesh()->FindNode( id );
-      if ( e ) {
+      long id = tid.toUInt();
+      if ( isElem ? myProxy.hasElement( id ) : myProxy.hasNode( id ))
+      {
         ID.Add( id );
         ids << id;
-        if ( myMode->checkedId() == ElemMode )
+        if ( isElem && myProxy.actor() && myProxy.elementGravityCenter( id, xyz ))
         {
           idVec.push_back( id );
-          aGrCentersXYZ.push_back( myElemInfo->getGravityCenter( e ));
+          aGrCentersXYZ.push_back( xyz );
         }
       }
     }
-    selector->AddOrRemoveIndex( IO, ID, false );
-    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
-
-      if ( myMode->checkedId() == NodeMode )
-        myIDPreview->SetPointsData( myActor->GetObject()->GetMesh(), ID );
-      else
-        myIDPreview->SetElemsData( idVec, aGrCentersXYZ );
-
-      bool showIDs = ( !ID.IsEmpty() &&
-                       myIDPreviewCheck->isChecked() &&
-                       myTabWidget->currentIndex() == ElemInfo );
-      myIDPreview->SetPointsLabeled( showIDs, myActor->GetVisibility() );
-
-      aViewWindow->highlight( IO, true, true );
-      aViewWindow->Repaint();
+    SVTK_Selector* selector = SMESH::GetSelector();
+    if ( myProxy.actor() && selector ) {
+      Handle(SALOME_InteractiveObject) IO = myProxy.actor()->getIO();
+      selector->AddOrRemoveIndex( IO, ID, false );
+      if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      {
+        if ( myMode->checkedId() == NodeMode )
+          myIDPreview->SetPointsData( myProxy.actor()->GetObject()->GetMesh(), ID );
+        else
+          myIDPreview->SetElemsData( idVec, aGrCentersXYZ );
+
+        bool showIDs = ( !ID.IsEmpty() &&
+                         myIDPreviewCheck->isChecked() &&
+                         myTabWidget->currentIndex() == ElemInfo );
+        myIDPreview->SetPointsLabeled( showIDs, myProxy.actor()->GetVisibility() );
+
+        aViewWindow->highlight( IO, true, true );
+        aViewWindow->Repaint();
+      }
     }
-    myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
+    myElemInfo->showInfo( myProxy, ids, isElem );
   }
 }
 
@@ -3226,145 +3370,112 @@ void SMESHGUI_MeshInfoDlg::idChanged()
 void SMESHGUI_MeshInfoDlg::idPreviewChange( bool isOn )
 {
   myIDPreview->SetPointsLabeled( isOn && !myID->text().simplified().isEmpty() );
-  SMESHGUI::resourceMgr()->setValue("SMESH", id_preview_resource, isOn );
+  SMESHGUI::resourceMgr()->setValue("SMESH", "id_preview_resource", isOn );
   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
     aViewWindow->Repaint();
 }
 
-void SMESHGUI_MeshInfoDlg::showItemInfo( int id )
-{
-  if ( id > 0 &&  myActor->GetObject()->GetMesh()->FindNode( id )) {
-    myMode->button( NodeMode )->click();
-    myID->setText( QString::number( id ));
-  }
-}
-
-void SMESHGUI_MeshInfoDlg::showItemInfo( const QString& theStr )
+void SMESHGUI_MeshInfoDlg::showItemInfo( int type, const QString& ids )
 {
-  if ( !theStr.isEmpty() ) {
-    myMode->button( ElemMode )->click();
-    myID->setText( theStr );
+  if ( !ids.isEmpty() && ( type == NodeConnectivity || type == ElemConnectivity )) {
+    myMode->button( type - NodeConnectivity )->click();
+    myID->setText( ids );
   }
 }
 
+/*!
+  \brief Dump information to file.
+*/
 void SMESHGUI_MeshInfoDlg::dump()
 {
-  QStringList aFilters;
-  aFilters.append( tr( "TEXT_FILES" ));
-
-  bool anIsBase = true;
-  bool anIsElem = true;
-  bool anIsAdd  = true;
-  bool anIsCtrl = true;
-
-  if ( SUIT_ResourceMgr* aResourceMgr = SMESHGUI::resourceMgr() ) {
-    anIsBase = aResourceMgr->booleanValue( "SMESH", "info_dump_base", anIsBase );
-    anIsElem = aResourceMgr->booleanValue( "SMESH", "info_dump_elem", anIsElem );
-    anIsAdd  = aResourceMgr->booleanValue( "SMESH", "info_dump_add",  anIsAdd );
-    anIsCtrl = aResourceMgr->booleanValue( "SMESH", "info_dump_ctrl", anIsCtrl );
-  }
-
   DumpFileDlg fd( this );
-  fd.setWindowTitle( tr( "SAVE_INFO" ));
-  fd.setNameFilters( aFilters );
-  fd.myBaseChk->setChecked( anIsBase );
-  fd.myElemChk->setChecked( anIsElem );
-  fd.myAddChk ->setChecked( anIsAdd );
-  fd.myCtrlChk->setChecked( anIsCtrl );
+  fd.setWindowTitle( tr( "SAVE_INFO" ) );
+  fd.setNameFilters( QStringList() << tr( "TEXT_FILES" ) );
+  fd.setChecked( BaseInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_base", true ) );
+  fd.setChecked( ElemInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_elem", true ) );
+  fd.setChecked( AddInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_add", true ) );
+  fd.setChecked( CtrlInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_ctrl", true ) );
   if ( fd.exec() == QDialog::Accepted )
   {
-    QString aFileName = fd.selectedFile();
-
-    bool toBase = fd.myBaseChk->isChecked();
-    bool toElem = fd.myElemChk->isChecked();
-    bool toAdd  = fd.myAddChk->isChecked();
-    bool toCtrl = fd.myCtrlChk->isChecked();
-
-    if ( !aFileName.isEmpty() ) {
-      QFileInfo aFileInfo( aFileName );
-      if ( aFileInfo.isDir() )
+    QString fileName = fd.selectedFile();
+    if ( !fileName.isEmpty() ) {
+      QFile file( fileName );
+      if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
         return;
-      QFile aFile( aFileName );
-      if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ))
-        return;
-      
-      QTextStream out( &aFile );
-      
-      if ( toBase ) myBaseInfo->saveInfo( out );
-      if ( toElem ) myElemInfo->saveInfo( out );
-      if ( toAdd )  myAddInfo ->saveInfo( out );
-      if ( toCtrl ) myCtrlInfo->saveInfo( out );
+
+      QTextStream out( &file );
+      if ( fd.isChecked( BaseInfo ) ) myBaseInfo->saveInfo( out );
+      if ( fd.isChecked( ElemInfo ) ) myElemInfo->saveInfo( out );
+      if ( fd.isChecked( AddInfo ) )  myAddInfo->saveInfo( out );
+      if ( fd.isChecked( CtrlInfo ) ) myCtrlInfo->saveInfo( out );
     }
   }
 }
 
-/*!
-  \class SMESHGUI_CtrlInfo
-  \brief Class for the mesh controls information widget.
-*/
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_CtrlInfo
+/// \brief Show quality statistics information on selected object.
+///
+/// Displays quality controls statistics about selected object: mesh, sub-mesh,
+/// group or arbitrary ID source.
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
-  \brief Constructor
-  \param parent parent widget
+  \brief Constructor.
+  \param parent Parent widget. Defaults to 0.
 */
-SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
-  : QFrame( parent ), myPlot( 0 ), myPlot3D( 0 )
+SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent ): SMESHGUI_Info( parent )
 {
-  setFrameStyle( StyledPanel | Sunken );
+  QGridLayout* l = new QGridLayout( this );
+  l->setMargin( MARGIN );
+  l->setSpacing( SPACING );
 
-  myMainLayout = new QGridLayout( this );
-  myMainLayout->setMargin( MARGIN );
-  myMainLayout->setSpacing( SPACING );
+  QIcon aComputeIcon( SUIT_Session::session()->resourceMgr()->loadPixmap( "SMESH", tr( "ICON_COMPUTE" ) ) );
+  SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
 
   // name
-  QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this );
-  QLabel* aName = createField();
+  QLabel* aNameLab = createLabel( tr( "NAME_LAB" ), this, Bold );
+  QLabel* aName = createField( this, "ctrlName" );
   aName->setMinimumWidth( 150 );
   myWidgets << aName;
 
-  SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
-  QIcon aComputeIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_COMPUTE" )) );
-
-  SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
-
   // nodes info
-  QLabel* aNodesLab = new QLabel( tr( "NODES_INFO" ), this );
+  QLabel* aNodesLab = createLabel( tr( "NODES_INFO" ), this, Bold );
   QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this );
-  QLabel* aNodesFree = createField();
+  QLabel* aNodesFree = createField( this, "ctrlNodesFree" );
   myWidgets << aNodesFree;
   myPredicates << aFilterMgr->CreateFreeNodes();
   //
   QLabel* aNodesNbConnLab = new QLabel( tr( "MAX_NODE_CONNECTIVITY" ), this );
-  QLabel* aNodesNbConn = createField();
+  QLabel* aNodesNbConn = createField( this, "ctrlNodesCnty" );
   myWidgets << aNodesNbConn;
   myNodeConnFunctor = aFilterMgr->CreateNodeConnectivityNumber();
   //
   QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this );
-  QLabel* aNodesDouble = createField();
+  QLabel* aNodesDouble = createField( this, "ctrlNodesDouble" );
   myWidgets << aNodesDouble;
   myPredicates << aFilterMgr->CreateEqualNodes();
   QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this );
   myToleranceWidget = new SMESHGUI_SpinBox( this );
   myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" );
   myToleranceWidget->setAcceptNames( false );
-  myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ));
+  myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ) );
 
   // edges info
-  QLabel* anEdgesLab = new QLabel( tr( "EDGES_INFO" ),  this );
+  QLabel* anEdgesLab = createLabel( tr( "EDGES_INFO" ), this, Bold );
   QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ),     this );
-  QLabel* anEdgesDouble = createField();
+  QLabel* anEdgesDouble = createField( this, "ctrlEdgesDouble" );
   myWidgets << anEdgesDouble;
   myPredicates << aFilterMgr->CreateEqualEdges();
 
   // faces info
-  QLabel* aFacesLab = new QLabel( tr( "FACES_INFO" ), this );
+  QLabel* aFacesLab = createLabel( tr( "FACES_INFO" ), this, Bold );
   QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this );
-  QLabel* aFacesDouble = createField();
+  QLabel* aFacesDouble = createField( this, "ctrlFacesDouble" );
   myWidgets << aFacesDouble;
   myPredicates << aFilterMgr->CreateEqualFaces();
   QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
-  QLabel* aFacesOver = createField();
+  QLabel* aFacesOver = createField( this, "ctrlFacesOver" );
   myWidgets << aFacesOver;
   myPredicates << aFilterMgr->CreateOverConstrainedFace();
   QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this );
@@ -3372,13 +3483,13 @@ SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
   myAspectRatio = aFilterMgr->CreateAspectRatio();
  
   // volumes info
-  QLabel* aVolumesLab = new QLabel( tr( "VOLUMES_INFO" ), this );
+  QLabel* aVolumesLab = createLabel( tr( "VOLUMES_INFO" ), this, Bold );
   QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this );
-  QLabel* aVolumesDouble = createField();
+  QLabel* aVolumesDouble = createField( this, "ctrlVolumesDouble" );
   myWidgets << aVolumesDouble;
   myPredicates << aFilterMgr->CreateEqualVolumes();
   QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
-  QLabel* aVolumesOver = createField();
+  QLabel* aVolumesOver = createField( this, "ctrlVolumesOver" );
   myWidgets << aVolumesOver;
   myPredicates << aFilterMgr->CreateOverConstrainedVolume();
   QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this );
@@ -3425,112 +3536,77 @@ SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
   aComputeVolumeBtn->setIcon(aComputeIcon);
   myButtons << aComputeVolumeBtn;   //9
 
-  connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ));
-  connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ));
-  connect( aFreeNodesBtn,     SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ));
-  connect( aNodesNbConnBtn,   SIGNAL( clicked() ), this, SLOT( computeNodesNbConnInfo() ));
-  connect( aDoubleNodesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ));
-  connect( aDoubleEdgesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ));
-  connect( aDoubleFacesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ));
-  connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ));
-  connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ));
-  connect( aOverContVolumesBtn,SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ));
-  connect( myToleranceWidget, SIGNAL(valueChanged(double)), this, SLOT( setTolerance( double )));
-
-  setFontAttributes( aNameLab );
-  setFontAttributes( aNodesLab );
-  setFontAttributes( anEdgesLab );
-  setFontAttributes( aFacesLab );
-  setFontAttributes( aVolumesLab );
-
-  myMainLayout->addWidget( aNameLab,           0, 0 );       //0
-  myMainLayout->addWidget( aName,              0, 1, 1, 2 ); //1
-  myMainLayout->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
-  myMainLayout->addWidget( aNodesFreeLab,      2, 0 );       //3
-  myMainLayout->addWidget( aNodesFree,         2, 1 );       //4
-  myMainLayout->addWidget( aFreeNodesBtn,      2, 2 );       //5
-  myMainLayout->addWidget( aNodesNbConnLab,    3, 0 );       //6
-  myMainLayout->addWidget( aNodesNbConn,       3, 1 );       //7
-  myMainLayout->addWidget( aNodesNbConnBtn,    3, 2 );       //8
-  myMainLayout->addWidget( aNodesDoubleLab,    4, 0 );       //9
-  myMainLayout->addWidget( aNodesDouble,       4, 1 );       //10
-  myMainLayout->addWidget( aDoubleNodesBtn,    4, 2 );       //11
-  myMainLayout->addWidget( aToleranceLab,      5, 0 );       //12
-  myMainLayout->addWidget( myToleranceWidget,  5, 1 );       //13
-  myMainLayout->addWidget( anEdgesLab,         6, 0, 1, 3 ); //14
-  myMainLayout->addWidget( anEdgesDoubleLab,   7, 0 );       //15
-  myMainLayout->addWidget( anEdgesDouble,      7, 1 );       //16
-  myMainLayout->addWidget( aDoubleEdgesBtn,    7, 2 );       //17
-  myMainLayout->addWidget( aFacesLab,          8, 0, 1, 3 ); //18
-  myMainLayout->addWidget( aFacesDoubleLab,    9, 0 );       //19
-  myMainLayout->addWidget( aFacesDouble,       9, 1 );       //20
-  myMainLayout->addWidget( aDoubleFacesBtn,    9, 2 );       //21
-  myMainLayout->addWidget( aFacesOverLab,      10, 0 );      //22
-  myMainLayout->addWidget( aFacesOver,         10, 1 );      //23
-  myMainLayout->addWidget( aOverContFacesBtn,  10, 2 );      //24
-  myMainLayout->addWidget( anAspectRatioLab,   11, 0 );      //25
-  myMainLayout->addWidget( aComputeFaceBtn,    11, 2 );      //26
-  myMainLayout->addWidget( myPlot,             12, 0, 1, 3 );//27
-  myMainLayout->addWidget( aVolumesLab,        13, 0, 1, 3 );//28
-  myMainLayout->addWidget( aVolumesDoubleLab,  14, 0 );      //29
-  myMainLayout->addWidget( aVolumesDouble,     14, 1 );      //30
-  myMainLayout->addWidget( aDoubleVolumesBtn,  14, 2 );      //31
-  myMainLayout->addWidget( aVolumesOverLab,    15, 0 );      //32
-  myMainLayout->addWidget( aVolumesOver,       15, 1 );      //33
-  myMainLayout->addWidget( aOverContVolumesBtn,15, 2 );      //34
-  myMainLayout->addWidget( anAspectRatio3DLab, 16, 0 );      //35
-  myMainLayout->addWidget( aComputeVolumeBtn,  16, 2 );      //36
-  myMainLayout->addWidget( myPlot3D,           17, 0, 1, 3 );//37
+  connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ) );
+  connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ) );
+  connect( aFreeNodesBtn,     SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ) );
+  connect( aNodesNbConnBtn,   SIGNAL( clicked() ), this, SLOT( computeNodesNbConnInfo() ) );
+  connect( aDoubleNodesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) );
+  connect( aDoubleEdgesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) );
+  connect( aDoubleFacesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) );
+  connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ) );
+  connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ) );
+  connect( aOverContVolumesBtn,SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ) );
+  connect( myToleranceWidget, SIGNAL( valueChanged( double ) ), this, SLOT( setTolerance( double ) ) );
+
+  l->addWidget( aNameLab,           0, 0 );       //0
+  l->addWidget( aName,              0, 1, 1, 2 ); //1
+  l->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
+  l->addWidget( aNodesFreeLab,      2, 0 );       //3
+  l->addWidget( aNodesFree,         2, 1 );       //4
+  l->addWidget( aFreeNodesBtn,      2, 2 );       //5
+  l->addWidget( aNodesNbConnLab,    3, 0 );       //6
+  l->addWidget( aNodesNbConn,       3, 1 );       //7
+  l->addWidget( aNodesNbConnBtn,    3, 2 );       //8
+  l->addWidget( aNodesDoubleLab,    4, 0 );       //9
+  l->addWidget( aNodesDouble,       4, 1 );       //10
+  l->addWidget( aDoubleNodesBtn,    4, 2 );       //11
+  l->addWidget( aToleranceLab,      5, 0 );       //12
+  l->addWidget( myToleranceWidget,  5, 1 );       //13
+  l->addWidget( anEdgesLab,         6, 0, 1, 3 ); //14
+  l->addWidget( anEdgesDoubleLab,   7, 0 );       //15
+  l->addWidget( anEdgesDouble,      7, 1 );       //16
+  l->addWidget( aDoubleEdgesBtn,    7, 2 );       //17
+  l->addWidget( aFacesLab,          8, 0, 1, 3 ); //18
+  l->addWidget( aFacesDoubleLab,    9, 0 );       //19
+  l->addWidget( aFacesDouble,       9, 1 );       //20
+  l->addWidget( aDoubleFacesBtn,    9, 2 );       //21
+  l->addWidget( aFacesOverLab,      10, 0 );      //22
+  l->addWidget( aFacesOver,         10, 1 );      //23
+  l->addWidget( aOverContFacesBtn,  10, 2 );      //24
+  l->addWidget( anAspectRatioLab,   11, 0 );      //25
+  l->addWidget( aComputeFaceBtn,    11, 2 );      //26
+  l->addWidget( myPlot,             12, 0, 1, 3 );//27
+  l->addWidget( aVolumesLab,        13, 0, 1, 3 );//28
+  l->addWidget( aVolumesDoubleLab,  14, 0 );      //29
+  l->addWidget( aVolumesDouble,     14, 1 );      //30
+  l->addWidget( aDoubleVolumesBtn,  14, 2 );      //31
+  l->addWidget( aVolumesOverLab,    15, 0 );      //32
+  l->addWidget( aVolumesOver,       15, 1 );      //33
+  l->addWidget( aOverContVolumesBtn,15, 2 );      //34
+  l->addWidget( anAspectRatio3DLab, 16, 0 );      //35
+  l->addWidget( aComputeVolumeBtn,  16, 2 );      //36
+  l->addWidget( myPlot3D,           17, 0, 1, 3 );//37
  
-  myMainLayout->setColumnStretch(  0,  0 );
-  myMainLayout->setColumnStretch(  1,  5 );
-  myMainLayout->setRowStretch   ( 12,  5 );
-  myMainLayout->setRowStretch   ( 17,  5 );
-  myMainLayout->setRowStretch   ( 18,  1 );
+  l->setColumnStretch(  0,  0 );
+  l->setColumnStretch(  1,  5 );
+  l->setRowStretch   ( 12,  5 );
+  l->setRowStretch   ( 17,  5 );
+  l->setRowStretch   ( 18,  1 );
 
   clearInternal();
 }
 
 /*!
-  \brief Destructor
+  \brief Destructor.
 */
 SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo()
-{}
-
-/*!
-  \brief Change widget font attributes (bold, ...).
-  \param w widget
-  \param attr font attributes (XORed flags)
-*/
-void SMESHGUI_CtrlInfo::setFontAttributes( QWidget* w )
-{
-  if ( w ) {
-    QFont f = w->font();
-    f.setBold( true );
-    w->setFont( f );
-  }
-}
-
-/*!
-  \brief Create info field
-  \return new info field
-*/
-QLabel* SMESHGUI_CtrlInfo::createField()
 {
-  QLabel* lab = new QLabel( this );
-  lab->setFrameStyle( StyledPanel | Sunken );
-  lab->setAlignment( Qt::AlignCenter );
-  lab->setAutoFillBackground( true );
-  QPalette pal = lab->palette();
-  pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ));
-  lab->setPalette( pal );
-  lab->setMinimumWidth( 60 );
-  return lab;
 }
 
 /*!
-  \brief Create QwtPlot
-  \return new QwtPlot
+  \brief Create plot widget.
+  \param parent Parent widget.
+  \return New plot widget.
 */
 QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
 {
@@ -3547,17 +3623,20 @@ QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
 }
 
 /*!
-  \brief Show controls information on the selected object
+  \brief Show information on given object.
+  \param proxy Object to show information on (mesh, sub-mesh, group, ID source).
 */
-void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
+void SMESHGUI_CtrlInfo::showInfo( const SMESH::SelectionProxy& proxy )
 {
   clearInternal();
 
-  myObject = SMESH::SMESH_IDSource::_duplicate( obj );
-  if ( myObject->_is_nil() ) return;
+  if ( !proxy )
+    return;
+
+  myProxy = proxy;
+  SMESH::SMESH_IDSource_var obj = proxy.object();
 
-  if ( _PTR(SObject) aSO = SMESH::FindSObject( obj ))
-    myWidgets[0]->setText( aSO->GetName().c_str() );
+  myWidgets[0]->setText( proxy.name() );
 
   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
   if ( mesh->_is_nil() ) return;
@@ -3596,7 +3675,7 @@ void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
   }
   else {
     for( int i=2; i<=13; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
   }
 
   // edges info
@@ -3609,9 +3688,9 @@ void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
   }
   else {
     for( int i=14; i<=17; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
   }
+
   // faces info
   if ( nbElemsByType[ SMESH::FACE ] > 0 ) {
     if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) {
@@ -3629,12 +3708,12 @@ void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
     }
 #ifdef DISABLE_PLOT2DVIEWER
     for( int i=25; i<=27; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
 #endif
   }
   else {
     for( int i=18; i<=27; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
   }
 
   // volumes info
@@ -3654,12 +3733,12 @@ void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
     }
 #ifdef DISABLE_PLOT2DVIEWER
     for( int i=35; i<=37; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
 #endif
   }
   else {
     for( int i=28; i<=37; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
   }
 }
 
@@ -3676,15 +3755,19 @@ void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg )
 {
   myButtons[ iBut ]->setEnabled( false );
   myWidgets[ iWdg ]->setText( "" );
-  if ( myObject->_is_nil() ) return;
+
+  if ( !myProxy )
+    return;
 
   SUIT_OverrideCursor wc;
 
-  SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+  SMESH::SMESH_IDSource_var obj = myProxy.object();
+  SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
+
   if ( !mesh->_is_nil() && !mesh->IsLoaded() )
   {
     mesh->Load();
-    this->showInfo( myObject ); // try to show all values
+    showInfo( myProxy ); // try to show all values
     if ( !myWidgets[ iWdg ]->text().isEmpty() )
       return; // <ft> predicate already computed
   }
@@ -3692,8 +3775,8 @@ void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg )
   for ( int i = 0; i < myPredicates.count(); ++i )
     if ( myPredicates[i]->GetFunctorType() == ft )
     {
-      CORBA::Long nb = myPredicates[i]->NbSatisfying( myObject );
-      myWidgets[ iWdg ]->setText( QString::number( nb ));
+      CORBA::Long nb = myPredicates[i]->NbSatisfying( obj );
+      myWidgets[ iWdg ]->setText( QString::number( nb ) );
     }
 }
 
@@ -3736,20 +3819,27 @@ void SMESHGUI_CtrlInfo::computeNodesNbConnInfo()
 {
   myButtons[ 1 ]->setEnabled( false );
   myWidgets[ 2 ]->setText( "" );
-  SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
-  if ( mesh->_is_nil() ) return;
+
+  if ( !myProxy )
+    return;
+
+  SUIT_OverrideCursor wc;
+
+  SMESH::SMESH_IDSource_var obj = myProxy.object();
+  SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
+
   if ( !mesh->IsLoaded() )
   {
     mesh->Load();
-    this->showInfo( myObject ); // try to show all values
+    showInfo( myProxy ); // try to show all values
     if ( !myWidgets[ 2 ]->text().isEmpty() )
       return; // already computed
   }
   myNodeConnFunctor->SetMesh( mesh );
   SMESH::Histogram_var histogram =
-    myNodeConnFunctor->GetLocalHistogram( 1, /*isLogarithmic=*/false, myObject );
+    myNodeConnFunctor->GetLocalHistogram( 1, /*isLogarithmic=*/false, obj );
 
-  myWidgets[ 2 ]->setText( QString::number( histogram[0].max ));
+  myWidgets[ 2 ]->setText( QString::number( histogram[0].max ) );
 }
 
 void SMESHGUI_CtrlInfo::computeAspectRatio()
@@ -3757,10 +3847,14 @@ void SMESHGUI_CtrlInfo::computeAspectRatio()
 #ifndef DISABLE_PLOT2DVIEWER
   myButtons[6]->setEnabled( false );
 
-  if ( myObject->_is_nil() ) return;
+  if ( !myProxy )
+    return;
 
   SUIT_OverrideCursor wc;
 
+  SMESH::SMESH_IDSource_var obj = myProxy.object();
+  SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
+
   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio );
   if ( aHistogram && !aHistogram->isEmpty() ) {
     QwtPlotItem* anItem = aHistogram->createPlotItem();
@@ -3776,10 +3870,14 @@ void SMESHGUI_CtrlInfo::computeAspectRatio3D()
 #ifndef DISABLE_PLOT2DVIEWER
   myButtons[9]->setEnabled( false );
 
-  if ( myObject->_is_nil() ) return;
+  if ( !myProxy )
+    return;
 
   SUIT_OverrideCursor wc;
 
+  SMESH::SMESH_IDSource_var obj = myProxy.object();
+  SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
+
   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio3D );
   if ( aHistogram && !aHistogram->isEmpty() ) {
     QwtPlotItem* anItem = aHistogram->createPlotItem();
@@ -3796,7 +3894,7 @@ void SMESHGUI_CtrlInfo::computeAspectRatio3D()
 void SMESHGUI_CtrlInfo::clearInternal()
 {
   for( int i=0; i<=37; i++)
-    myMainLayout->itemAt(i)->widget()->setVisible( true );
+    dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( true );
   for( int i=0; i<=9; i++)
     myButtons[i]->setEnabled( false );
   myPlot->detachItems();
@@ -3818,14 +3916,17 @@ void SMESHGUI_CtrlInfo::setTolerance( double theTolerance )
 #ifndef DISABLE_PLOT2DVIEWER
 Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr aNumFun )
 {
-  SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
-  if ( mesh->_is_nil() ) return 0;
+  SUIT_OverrideCursor wc;
+
+  SMESH::SMESH_IDSource_var obj = myProxy.object();
+  SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
+
   if ( !mesh->IsLoaded() )
     mesh->Load();
   aNumFun->SetMesh( mesh );
 
   CORBA::Long cprecision = 6;
-  if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false )
+  if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) )
     cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
   aNumFun->SetPrecision( cprecision );
 
@@ -3833,9 +3934,9 @@ Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr a
 
   SMESH::Histogram_var histogramVar = aNumFun->GetLocalHistogram( nbIntervals,
                                                                   /*isLogarithmic=*/false,
-                                                                  myObject );
+                                                                  obj );
   Plot2d_Histogram* aHistogram = new Plot2d_Histogram();
-  aHistogram->setColor( palette().color( QPalette::Highlight ));
+  aHistogram->setColor( palette().color( QPalette::Highlight ) );
   if ( &histogramVar.in() )
   {
     for ( size_t i = 0, nb = histogramVar->length(); i < nb; i++ )
@@ -3847,28 +3948,35 @@ Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr a
 }
 #endif
 
-void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out ) {
-  out << QString( 20, '-' ) << "\n";
-  out << tr( "CTRL_INFO"  ) << "\n";
-  out << QString( 20, '-' ) << "\n";
-  out <<                                 tr( "NAME_LAB" )                       << "  " << myWidgets[0]->text() << "\n";
-  out <<                                 tr( "NODES_INFO" )                     << "\n";
-  out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_FREE_NODES" )       << ": " << myWidgets[1]->text() << "\n";
-  out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_NODES" )     << ": " << myWidgets[2]->text() << "\n";
-  out <<                                 tr( "EDGES_INFO" )                     << "\n";
-  out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_EDGES" )     << ": " << myWidgets[3]->text() << "\n";
-  out <<                                 tr( "FACES_INFO" )                     << "\n";
-  out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_FACES" )     << ": " << myWidgets[4]->text() << "\n";
-  out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[5]->text() << "\n";
-  out <<                                 tr( "VOLUMES_INFO" )                   << "\n";
-  out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" )   << ": " << myWidgets[6]->text() << "\n";
-  out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[7]->text() << "\n";
+void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out )
+{
+  // title
+  QString title = tr( "CTRL_INFO" );
+  out << ruler( title.size() ) << endl;
+  out << title << endl;
+  out << ruler( title.size() ) << endl;
+  out << endl;
+
+  // info
+  out << tr( "NAME_LAB" ) << "  " << myWidgets[0]->text() << endl;
+  out << tr( "NODES_INFO" ) << endl;
+  out << indent() << tr( "NUMBER_OF_THE_FREE_NODES" ) << ": " << myWidgets[1]->text() << endl;
+  out << indent() << tr( "NUMBER_OF_THE_DOUBLE_NODES" ) << ": " << myWidgets[2]->text() << endl;
+  out << tr( "EDGES_INFO" ) << endl;
+  out << indent() << tr( "NUMBER_OF_THE_DOUBLE_EDGES" ) << ": " << myWidgets[3]->text() << endl;
+  out << tr( "FACES_INFO" ) << endl;
+  out << indent() << tr( "NUMBER_OF_THE_DOUBLE_FACES" ) << ": " << myWidgets[4]->text() << endl;
+  out << indent() << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[5]->text() << endl;
+  out << tr( "VOLUMES_INFO" ) << endl;
+  out << indent() << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ) << ": " << myWidgets[6]->text() << endl;
+  out << indent() << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[7]->text() << endl;
 }
 
-/*!
-  \class SMESHGUI_CtrlInfoDlg
-  \brief Controls information dialog box
-*/
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_CtrlInfoDlg
+/// \brief Overall Mesh Quality dialog.
+/// \todo Add selection button to reactivate selection on move from other dlg.
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
   \brief Constructor
@@ -3878,7 +3986,7 @@ SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
   : QDialog( parent )
 {
   setAttribute( Qt::WA_DeleteOnClose, true );
-  setWindowTitle( tr( "CTRL_INFO" ));
+  setWindowTitle( tr( "CTRL_INFO" ) );
   setMinimumSize( 400, 600 );
 
   myCtrlInfo = new SMESHGUI_CtrlInfo( this );
@@ -3903,16 +4011,16 @@ SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
   btnLayout->addWidget( helpBtn );
 
   QVBoxLayout* l = new QVBoxLayout ( this );
-  l->setMargin( MARGIN );
+  l->setMargin( 0 );
   l->setSpacing( SPACING );
   l->addWidget( myCtrlInfo );
   l->addLayout( btnLayout );
 
-  connect( okBtn,   SIGNAL( clicked() ), this, SLOT( reject() ));
-  connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ));
-  connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ));
-  connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ));
-  connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ));
+  connect( okBtn,   SIGNAL( clicked() ), this, SLOT( reject() ) );
+  connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
+  connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
+  connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
+  connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
 
   updateSelection();
 }
@@ -3925,34 +4033,28 @@ SMESHGUI_CtrlInfoDlg::~SMESHGUI_CtrlInfoDlg()
 }
 
 /*!
-  \brief Show controls information
-  \param IO interactive object
+  \brief Show mesh quality information on given object.
+  \param io Interactive object.
 */
-void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
+void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& io )
 {  
-  if ( SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO ))
-    myCtrlInfo->showInfo( obj );
+  if ( !io.IsNull() )
+    showInfo( SMESH::SelectionProxy( io ) );
 }
 
 /*!
-  \brief Perform clean-up actions on the dialog box closing.
+  \brief Show mesh quality information on given object.
+  \param proxy Selection proxy.
 */
-void SMESHGUI_CtrlInfoDlg::reject()
+void SMESHGUI_CtrlInfoDlg::showInfo( const SMESH::SelectionProxy& proxy )
 {
-  SMESH::SetPointRepresentation( false );
-  QDialog::reject();
-}
+  SUIT_OverrideCursor wc;
 
-/*!
-  \brief Setup selection mode depending on the current dialog box state.
-*/
-void SMESHGUI_CtrlInfoDlg::updateSelection()
-{
-  LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
-  disconnect( selMgr, 0, this, 0 );
-  SMESH::SetPointRepresentation( false );  
-  connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ));
-  updateInfo();  
+  if ( !proxy )
+    return;
+
+  myProxy = proxy;
+  myCtrlInfo->showInfo( proxy );
 }
 
 /*!
@@ -3960,72 +4062,70 @@ void SMESHGUI_CtrlInfoDlg::updateSelection()
 */
 void SMESHGUI_CtrlInfoDlg::updateInfo()
 {
-  SUIT_OverrideCursor wc;
-
   SALOME_ListIO selected;
   SMESHGUI::selectionMgr()->selectedObjects( selected );
 
-  if ( selected.Extent() == 1 ) {
-    Handle(SALOME_InteractiveObject) IO = selected.First();
-    showInfo( IO );
-  }
+  if ( selected.Extent() == 1 )
+    showInfo( selected.First() );
+  else
+    showInfo( myProxy );
 }
 
 /*!
-  \brief Activate dialog box
+  \brief Perform clean-up actions on the dialog box closing.
 */
-void SMESHGUI_CtrlInfoDlg::activate()
+void SMESHGUI_CtrlInfoDlg::reject()
 {
-  SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
-  SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
-  updateSelection();
+  SMESH::SetPointRepresentation( false );
+  QDialog::reject();
+}
+
+/*!
+  \brief Setup selection mode depending on the current dialog box state.
+*/
+void SMESHGUI_CtrlInfoDlg::updateSelection()
+{
+  LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
+  disconnect( selMgr, 0, this, 0 );
+  SMESH::SetPointRepresentation( false );  
+  connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
+  updateInfo();  
 }
 
 /*!
-  \brief Deactivate dialog box
+  \brief Deactivate dialog box.
 */
 void SMESHGUI_CtrlInfoDlg::deactivate()
 {
-  disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ));
+  disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
 }
 
 /*!
- * \brief Dump contents into a file
- */
+  \brief Dump information to file.
+*/
 void SMESHGUI_CtrlInfoDlg::dump()
 {
-  QStringList aFilters;
-  aFilters.append( tr( "TEXT_FILES" ));
-
-  DumpFileDlg fd( this );
-  fd.setWindowTitle( tr( "SAVE_INFO" ));
-  fd.setNameFilters( aFilters );
-  fd.myBaseChk->hide();
-  fd.myElemChk->hide();
-  fd.myAddChk ->hide();
-  fd.myCtrlChk->hide();
+  DumpFileDlg fd( this, false );
+  fd.setWindowTitle( tr( "SAVE_INFO" ) );
+  fd.setNameFilters( QStringList() << tr( "TEXT_FILES" ) );
   if ( fd.exec() == QDialog::Accepted )
   {
-    QString aFileName = fd.selectedFile();
-    if ( !aFileName.isEmpty() ) {
-      QFileInfo aFileInfo( aFileName );
-      if ( aFileInfo.isDir() )
-        return;
-      QFile aFile( aFileName );
-      if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ))
+    QString fileName = fd.selectedFile();
+    if ( !fileName.isEmpty() ) {
+      QFile file( fileName );
+      if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
         return;
-      
-      QTextStream out( &aFile );
+
+      QTextStream out( &file );
       myCtrlInfo->saveInfo( out );
     }
   }
 }
 
 /*!
- * \brief Show help
- */
+  \brief Show documentation on dialog.
+*/
 void SMESHGUI_CtrlInfoDlg::help()
 {
-  SMESH::ShowHelpFile("mesh_infos.html#mesh_quality_info_anchor");
+  SMESH::ShowHelpFile( "mesh_infos.html#mesh-quality-info-anchor" );
 }
index 85edb60..cba1809 100644 (file)
 //
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
-//  File   : SMESHGUI_MeshInfo.h
-//  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
 
 #ifndef SMESHGUI_MESHINFO_H
 #define SMESHGUI_MESHINFO_H
 
 #include "SMESH_SMESHGUI.hxx"
-#include "SMESH_ControlsDef.hxx"
+#include "SMESHGUI_SelectionProxy.h"
 
 #ifndef DISABLE_PLOT2DVIEWER
   #include <Plot2d_Histogram.h>
   #include <qwt_plot.h>
 #endif
 
-#include <QFrame>
 #include <QDialog>
 #include <QList>
 #include <QMap>
 #include <QSet>
-#include <QTreeWidget>
-#include <QVector>
 
 #include <SALOMEconfig.h>
-#include CORBA_SERVER_HEADER(SMESH_Mesh)
-#include CORBA_SERVER_HEADER(SMESH_Group)
 #include CORBA_SERVER_HEADER(SMESH_Filter)
 
 #include <SALOME_InteractiveObject.hxx>
@@ -54,51 +47,65 @@ class QAbstractButton;
 class QButtonGroup;
 class QCheckBox;
 class QContextMenuEvent;
-class QGridLayout;
 class QLabel;
 class QLineEdit;
-class QPushButton;
 class QTabWidget;
 class QTextBrowser;
+class QTreeWidget;
+class QTreeWidgetItem;
 class SMDS_MeshElement;
 class SMDS_MeshNode;
 class SMESHGUI_IdPreview;
 class SMESHGUI_SpinBox;
-class SMESH_Actor;
 
 class ExtraWidget;
+class GroupCombo;
+class InfoWriter;
 
-class SMESHGUI_EXPORT SMESHGUI_MeshInfo : public QFrame
+class SMESHGUI_EXPORT SMESHGUI_Info : public QWidget
+{
+public:
+  SMESHGUI_Info( QWidget* = 0 );
+  virtual void saveInfo( QTextStream& ) = 0;
+};
+
+class SMESHGUI_EXPORT SMESHGUI_BaseInfo : public SMESHGUI_Info
 {
   Q_OBJECT;
   
-  enum {
-    iName,
+  enum
+  {
+    iStart,
+    iObjectStart = iStart,
+    iName = iObjectStart,
     iObject,
-    iNodesStart,
+    iObjectEnd,
+    iNodesStart = iObjectEnd,
     iNodes,
     iNodesEnd,
-    iElementsStart = iNodesEnd, 
-    iElements,
-    iNbStart,
-    iNb,
-    iNbEnd,
-    i0DStart = iNbEnd,
+    iElementsStart = iNodesEnd,
+    iElementsTitleStart = iElementsStart,
+    iElementsTitle,
+    iElementsTitleEnd,
+    iElementsTotalStart = iElementsTitleEnd,
+    iElementsTotal,
+    iElementsTotalEnd,
+    i0DStart = iElementsTotalEnd,
     i0D,
     i0DEnd,
     iBallsStart = i0DEnd,
     iBalls,
     iBallsEnd,
-    i1DStart       = iBallsEnd,
+    i1DStart = iBallsEnd,
     i1D,
     i1DEnd,
-    i2DStart       = i1DEnd,
+    i2DStart = i1DEnd,
     i2D,
     i2DTriangles,
     i2DQuadrangles,
     i2DPolygons,
     i2DEnd,
-    i3DStart       = i2DEnd,
+    i3DStart = i2DEnd,
     i3D,
     i3DTetrahedrons,
     i3DHexahedrons,
@@ -107,45 +114,49 @@ class SMESHGUI_EXPORT SMESHGUI_MeshInfo : public QFrame
     i3DHexaPrisms,
     i3DPolyhedrons,
     i3DEnd,
-    iElementsEnd   = i3DEnd
+    iElementsEnd = i3DEnd,
+    iEnd,
+    iOther = iEnd
   };
 
-  enum {
-    iSingle = 1,
-    iTotal  = iSingle,
+  enum
+  {
+    iLabel,
+    iSingle,
+    iTotal = iSingle,
     iLinear,
     iQuadratic,
-    iBiQuadratic
+    iBiQuadratic,
+    iNbColumns
   };
 
-  typedef QList<QWidget*> wlist;
-  typedef QVector<wlist>  iwlist;
+  typedef QMap<int, QWidget*> wlist;
+  typedef QMap<int, wlist> iwlist;
 
 public:
-  SMESHGUI_MeshInfo( QWidget* = 0 );
-  ~SMESHGUI_MeshInfo();
+  SMESHGUI_BaseInfo( QWidget* = 0 );
+  ~SMESHGUI_BaseInfo();
 
-  void     showInfo( SMESH::SMESH_IDSource_ptr );
-  void     clear();
-  void     saveInfo( QTextStream &out );
+  void showInfo( const SMESH::SelectionProxy& );
+  void clear();
+  void saveInfo( QTextStream& );
 
 private:
-  enum { Bold = 0x01, Italic = 0x02 };
-
-  QLabel*  createField();
-  QWidget* createLine();
-  void     setFontAttributes( QWidget*, int, bool = true );
-  void     setFieldsVisible( int, int, bool );
+  QWidget* addWidget( QWidget*, int, int, int = 1 );
+  QWidget* widget( int, int ) const;
+  QString value( int, int ) const;
+  void setFieldsVisible( int, int, bool );
 
 private slots:
+  void updateInfo();
   void loadMesh();
 
 private:
-  iwlist       myWidgets;
-  QPushButton* myLoadBtn;
+  iwlist myWidgets;
+  SMESH::SelectionProxy myProxy;
 };
 
-class SMESHGUI_EXPORT SMESHGUI_ElemInfo : public QWidget
+class SMESHGUI_EXPORT SMESHGUI_ElemInfo : public SMESHGUI_Info
 {
   Q_OBJECT;
 
@@ -153,74 +164,60 @@ public:
   SMESHGUI_ElemInfo( QWidget* = 0 );
   ~SMESHGUI_ElemInfo();
 
-  void         setSource( SMESH_Actor*, SMESH::SMESH_IDSource_var );
-  void         showInfo( long, bool );
-  void         showInfo( QSet<long>, bool );
-  void         clear();
-  virtual void saveInfo( QTextStream &out ) = 0;
-
-  gp_XYZ       getGravityCenter( const SMDS_MeshElement* e ) { return gravityCenter(e); }
+  void showInfo( const SMESH::SelectionProxy&, uint, bool );
+  void showInfo( const SMESH::SelectionProxy&, QSet<uint>, bool );
+  void showInfo( const SMESH::SelectionProxy& );
+  void clear();
+  void saveInfo( QTextStream& );
 
 protected:
-  struct XYZ
-  {
-    double myX, myY, myZ;
-    XYZ() { myX = myY = myZ = 0.0; }
-    XYZ(double x, double y, double z) { myX = x; myY = y; myZ = z; }
-    void add( double x, double y, double z ) { myX += x; myY += y; myZ += z; }
-    void divide( double a ) { if ( a != 0.) { myX /= a; myY /= a; myZ /= a; } }
-    double x() const  { return myX; }
-    double y() const  { return myY; }
-    double z() const  { return myZ; }
-    operator gp_XYZ() const { return gp_XYZ( myX, myY, myZ ); }
-  };
-  typedef QMap< int, QList<int> > Connectivity;
+  enum { ShowNone, ShowNodes, ShowElements };
 
-  QWidget*     frame() const;
-  SMESH_Actor* actor() const;
-  bool         isElements() const;
-  bool         hasShapeToMesh() const { return myMeshHasShape; }
+  QWidget* centralWidget() const;
 
-  virtual void information( const QList<long>& ) = 0;
-  virtual void clearInternal();
+  SMESH::SelectionProxy proxy() const;
+  int what() const;
 
-  Connectivity nodeConnectivity( const SMDS_MeshNode* );
-  QString      formatConnectivity( Connectivity, int );
-  XYZ          gravityCenter( const SMDS_MeshElement* );
-  XYZ          normal( const SMDS_MeshElement* );
+  QString type2str( int, bool = false );
+  QString stype2str( int );
+  QString etype2str( int );
+  QString ctrl2str( int );
+  void writeInfo( InfoWriter*, const QList<uint>& );
+  virtual void information( const QList<uint>& ) = 0;
+  virtual void clearInternal();
 
 signals:
-  void         itemInfo( int );
-  void         itemInfo( const QString& );
+  void itemInfo( int type, const QString& ids );
 
 private slots:
-  void         showPrevious();
-  void         showNext();
-  void         updateControls();
+  void showPrevious();
+  void showNext();
+  void updateControls();
 
 private:
-  SMESH_Actor*     myActor;
-  QList<long>      myIDs;
-  int              myIsElement;
-  QWidget*         myFrame;
-  ExtraWidget*     myExtra;
-  int              myIndex;
-  bool             myMeshHasShape;
+  QWidget* myFrame;
+  ExtraWidget* myExtra;
+  SMESH::SelectionProxy myProxy;
+  int myWhat;
+  QList<uint> myIDs;
+  int myIndex;
 };
 
 class SMESHGUI_EXPORT SMESHGUI_SimpleElemInfo : public SMESHGUI_ElemInfo
 {
-  Q_OBJECT
+  Q_OBJECT;
 
 public:
   SMESHGUI_SimpleElemInfo( QWidget* = 0 );
-  void          saveInfo( QTextStream &out );
 
 protected:
-  void          information( const QList<long>& );
-  void          clearInternal();
+  void information( const QList<uint>& );
+  void clearInternal();
 
-private:
+private slots:
+  void connectivityClicked(const QUrl &);
+
+ private:
   QTextBrowser* myInfo;
 };
 
@@ -229,85 +226,86 @@ class SMESHGUI_EXPORT SMESHGUI_TreeElemInfo : public SMESHGUI_ElemInfo
   Q_OBJECT;
 
   class ItemDelegate;
-
-  enum { Bold = 0x01, All = 0x80 };
+  class ItemCreator;
 
 public:
   SMESHGUI_TreeElemInfo( QWidget* = 0 );
-  void             saveInfo( QTextStream &out );
 
 protected:
-  void             contextMenuEvent( QContextMenuEvent* e );
-  void             information( const QList<long>& );
-  void             nodeInfo( const SMDS_MeshNode*, int, int, QTreeWidgetItem* );
-  void             clearInternal();
+  void contextMenuEvent( QContextMenuEvent* );
+  void information( const QList<uint>& );
+  void nodeInfo( const SMDS_MeshNode*, int, int, QTreeWidgetItem* );
+  void clearInternal();
 
 private slots:
-  void             itemDoubleClicked( QTreeWidgetItem*, int );
-  void             saveExpanded( QTreeWidgetItem* );
-  
+  void itemDoubleClicked( QTreeWidgetItem*, int );
+  void saveExpanded( QTreeWidgetItem* );
+
 private:
   QTreeWidgetItem* createItem( QTreeWidgetItem* = 0, int = 0 );
   QString          expandedResource( QTreeWidgetItem* );
   
 private:
-  QTreeWidget*     myInfo;
+  QTreeWidget* myInfo;
 };
 
-class GrpComputor: public QObject
+class InfoComputor: public QObject
 {
   Q_OBJECT;
 
 public:
-  GrpComputor( SMESH::SMESH_GroupBase_ptr, QTreeWidgetItem*, QObject*, bool = false);
-  QTreeWidgetItem* getItem() { return myItem; }
+  enum { GrpSize, GrpNbNodes };
+  
+  InfoComputor( QObject*, const SMESH::SelectionProxy&, int );
+
+signals:
+  void computed();
 
 public slots:
   void compute();
 
 private:
-  SMESH::SMESH_GroupBase_var myGroup;
-  QTreeWidgetItem*           myItem;
-  bool                       myToComputeSize;
+  SMESH::SelectionProxy myProxy;
+  int myOperation;
 };
 
-class SMESHGUI_EXPORT SMESHGUI_AddInfo : public QTreeWidget
+class SMESHGUI_EXPORT SMESHGUI_AddInfo : public SMESHGUI_Info
 {
   Q_OBJECT;
 
-  enum { Bold = 0x01, All = 0x80 };
-
 public:
   SMESHGUI_AddInfo( QWidget* = 0 );
   ~SMESHGUI_AddInfo();
 
-  void             showInfo( SMESH::SMESH_IDSource_ptr );
-  //  void             clear();
-  void             saveInfo( QTextStream &out );
+  void showInfo( const SMESH::SelectionProxy& );
+  void clear();
+  void saveInfo( QTextStream& );
 
 private slots:
-  void             changeLoadToCompute();
-  void             showPreviousGroups();
-  void             showNextGroups();
-  void             showPreviousSubMeshes();
-  void             showNextSubMeshes();
+  void updateInfo();
+  void showPreviousGroups();
+  void showNextGroups();
+  void showPreviousSubMeshes();
+  void showNextSubMeshes();
 
 private:
   QTreeWidgetItem* createItem( QTreeWidgetItem* = 0, int = 0 );
-  void             meshInfo( SMESH::SMESH_Mesh_ptr, QTreeWidgetItem* );
-  void             subMeshInfo( SMESH::SMESH_subMesh_ptr, QTreeWidgetItem* );
-  void             groupInfo( SMESH::SMESH_GroupBase_ptr, QTreeWidgetItem* );
+  void meshInfo( const SMESH::SelectionProxy&, QTreeWidgetItem* );
+  void subMeshInfo( const SMESH::SelectionProxy&, QTreeWidgetItem* );
+  void groupInfo( const SMESH::SelectionProxy&, QTreeWidgetItem* );
 
-  void             showGroups();
-  void             showSubMeshes();
+  void showGroups();
+  void showSubMeshes();
 
 private:
-  QList<GrpComputor*>      myComputors;
-  SMESH::ListOfGroups_var  myGroups;
-  SMESH::submesh_array_var mySubMeshes;
+  SMESH::SelectionProxy myProxy;
+  QTreeWidget* myTree;
+  QList<InfoComputor*> myComputors;
+  QList<SMESH::SelectionProxy> myGroups;
+  QList<SMESH::SelectionProxy> mySubMeshes;
 };
 
-class SMESHGUI_EXPORT SMESHGUI_CtrlInfo : public QFrame
+class SMESHGUI_EXPORT SMESHGUI_CtrlInfo : public SMESHGUI_Info
 {
   Q_OBJECT;
 
@@ -315,62 +313,59 @@ public:
   SMESHGUI_CtrlInfo( QWidget* = 0 );
   ~SMESHGUI_CtrlInfo();
 
-  void                  showInfo( SMESH::SMESH_IDSource_ptr );
-  void                  saveInfo( QTextStream &out );
+  void showInfo( const SMESH::SelectionProxy& );
+  void saveInfo( QTextStream& );
 
 private:
   enum ObjectType { Mesh, SubMesh, Group };
-  QLabel*               createField();
-  QwtPlot*              createPlot( QWidget* );
-  void                  setFontAttributes( QWidget* );
-  void                  clearInternal();
+  QwtPlot* createPlot( QWidget* );
+  void clearInternal();
 #ifndef DISABLE_PLOT2DVIEWER
-  Plot2d_Histogram*     getHistogram( SMESH::NumericalFunctor_ptr functor );
+  Plot2d_Histogram* getHistogram( SMESH::NumericalFunctor_ptr );
 #endif
-  void                  computeNb( int ft, int iBut, int iWdg );
+  void computeNb( int, int, int );
 
 private slots:
-  void                  computeAspectRatio();
-  void                  computeAspectRatio3D();
-  void                  computeFreeNodesInfo();
-  void                  computeNodesNbConnInfo();
-  void                  computeDoubleNodesInfo();
-  void                  computeDoubleEdgesInfo();
-  void                  computeDoubleFacesInfo();
-  void                  computeOverConstrainedFacesInfo();
-  void                  computeDoubleVolumesInfo();
-  void                  computeOverConstrainedVolumesInfo();
-  void                  setTolerance( const double theTolerance );
-  
+  void computeAspectRatio();
+  void computeAspectRatio3D();
+  void computeFreeNodesInfo();
+  void computeNodesNbConnInfo();
+  void computeDoubleNodesInfo();
+  void computeDoubleEdgesInfo();
+  void computeDoubleFacesInfo();
+  void computeOverConstrainedFacesInfo();
+  void computeDoubleVolumesInfo();
+  void computeOverConstrainedVolumesInfo();
+  void setTolerance( double );
 
 private:
-  typedef SALOME::GenericObj_wrap< SMESH::Predicate >        TPredicate;
+  typedef SALOME::GenericObj_wrap< SMESH::Predicate > TPredicate;
   typedef SALOME::GenericObj_wrap< SMESH::NumericalFunctor > TNumFunctor;
-  SMESH::SMESH_IDSource_var myObject;
-  ObjectType                myObjectType;
-  SMESHGUI_SpinBox*         myToleranceWidget;
-  QList<QLabel*>            myWidgets;
-  QGridLayout*              myMainLayout;
-  QwtPlot*                  myPlot;
-  QwtPlot*                  myPlot3D;
-  QList<QAbstractButton*>   myButtons;
-  QList<TPredicate>         myPredicates;
-  TNumFunctor               myAspectRatio, myAspectRatio3D, myNodeConnFunctor;
+  SMESH::SelectionProxy myProxy;
+  ObjectType myObjectType;
+  SMESHGUI_SpinBox* myToleranceWidget;
+  QList<QLabel*> myWidgets;
+  QwtPlot* myPlot;
+  QwtPlot* myPlot3D;
+  QList<QAbstractButton*> myButtons;
+  QList<TPredicate> myPredicates;
+  TNumFunctor myAspectRatio, myAspectRatio3D, myNodeConnFunctor;
 };
 
 class SMESHGUI_EXPORT SMESHGUI_MeshInfoDlg : public QDialog
 { 
   Q_OBJECT;
 
-  enum { NodeMode, ElemMode };
+  enum { NodeMode, ElemMode, GroupMode };
 
 public:
   //! Information type
-  enum { 
+  enum
+  { 
     BaseInfo,  //!< base mesh information
     ElemInfo,  //!< mesh element information
     AddInfo,   //!< additional information
-    CtrlInfo //!< controls information
+    CtrlInfo   //!< controls information
   };
 
   SMESHGUI_MeshInfoDlg( QWidget* = 0, int = BaseInfo );
@@ -381,33 +376,35 @@ public:
 
 protected:
   void keyPressEvent( QKeyEvent* );
-  void enterEvent( QEvent* );
+
+signals:
+  void switchMode( int );
 
 private slots:
   void help();
   void updateSelection();
   void updateInfo();
-  void activate();
   void deactivate();
   void modeChanged();
   void idChanged();
-  void idPreviewChange(bool);
-  void showItemInfo( int );
-  void showItemInfo( const QString& );
+  void idPreviewChange( bool );
+  void showItemInfo( int type, const QString& ids );
   void dump();
 
 private:
-  QTabWidget*                      myTabWidget;
-  SMESHGUI_MeshInfo*               myBaseInfo;
-  QButtonGroup*                    myMode;
-  QLineEdit*                       myID;
-  QCheckBox*                       myIDPreviewCheck;
-  SMESHGUI_IdPreview*              myIDPreview;
-  SMESHGUI_ElemInfo*               myElemInfo;   
-  SMESHGUI_AddInfo*                myAddInfo;
-  SMESHGUI_CtrlInfo*               myCtrlInfo;
-  SMESH_Actor*                     myActor;
-  Handle(SALOME_InteractiveObject) myIO;
+  void showInfo( const SMESH::SelectionProxy& );
+
+  SMESH::SelectionProxy myProxy;
+  QTabWidget* myTabWidget;
+  SMESHGUI_BaseInfo* myBaseInfo;
+  SMESHGUI_ElemInfo* myElemInfo;
+  SMESHGUI_AddInfo* myAddInfo;
+  SMESHGUI_CtrlInfo* myCtrlInfo;
+  QButtonGroup* myMode;
+  QLineEdit* myID;
+  QCheckBox* myIDPreviewCheck;
+  GroupCombo* myGroups;
+  SMESHGUI_IdPreview* myIDPreview;
 };
 
 class SMESHGUI_EXPORT SMESHGUI_CtrlInfoDlg : public QDialog
@@ -423,14 +420,16 @@ public:
 
 private slots:
   void updateInfo();
-  void activate();
   void deactivate();
   void updateSelection();
   void help();
   void dump();
 
 private:
-  SMESHGUI_CtrlInfo*  myCtrlInfo;
+  void showInfo( const SMESH::SelectionProxy& );
+
+  SMESH::SelectionProxy myProxy;
+  SMESHGUI_CtrlInfo* myCtrlInfo;
 };
 
 #endif // SMESHGUI_MESHINFO_H
index 19a08d1..5008c9c 100755 (executable)
@@ -1622,7 +1622,7 @@ SMESHGUI_SplitVolumesDlg::SMESHGUI_SplitVolumesDlg(SMESHGUI* theModule)
   }
   if ( myEntityTypeGrp )
   {
-    myEntityTypeGrp->button(0)->setText( tr("SMESH_TETRAS"));
+    myEntityTypeGrp->button(0)->setText( tr("SMESH_TETRAHEDRON"));
     myEntityTypeGrp->button(1)->setText( tr("SMESH_PRISM"));
     if ( QGroupBox* gb = qobject_cast< QGroupBox* >( myEntityTypeGrp->button(0)->parent() ))
       gb->setTitle( tr("TARGET_ELEM_TYPE"));
diff --git a/src/SMESHGUI/SMESHGUI_SelectionProxy.cxx b/src/SMESHGUI/SMESHGUI_SelectionProxy.cxx
new file mode 100644 (file)
index 0000000..8986852
--- /dev/null
@@ -0,0 +1,1585 @@
+// Copyright (C) 2007-2016  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, or (at your option) any later version.
+//
+// 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
+//
+
+#include "SMESHGUI_SelectionProxy.h"
+
+#include "SMDS_Mesh.hxx"
+#include "SMDS_VolumeTool.hxx"
+#include "SMESHGUI.h"
+#include "SMESHGUI_Utils.h"
+#include "SMESHGUI_VTKUtils.h"
+#include "SMESH_Actor.h"
+#include "SMESH_ControlsDef.hxx"
+
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(SMESH_Filter)
+#include CORBA_SERVER_HEADER(SMESH_Group)
+
+#include <SALOMEDSClient_Study.hxx>
+#include <SUIT_ResourceMgr.h>
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESH::SelectionProxy
+/// \brief Provide operations over the selected object.
+///
+/// The selection proxy class is aimed to use in dialogs to access mesh object
+/// data either from actor or directly from CORBA reference, depending on what
+/// of them is accessible.
+/// This is useful in situations when some information is needed, but an actor
+/// was not created yet.
+/// 
+/// Selection proxy can be constructed in two ways:
+/// - From interactive object: this performs full proxy initialization including
+///   pick-up of an actor from the current viewer if it exists.
+/// - From mesh source object (CORBA reference); for performance reasons in this
+///   case full initialization is not immediately done and performed only when
+///   needed.
+////////////////////////////////////////////////////////////////////////////////
+
+/*!
+  \brief Default constructor. Creates null proxy.
+*/
+SMESH::SelectionProxy::SelectionProxy(): myActor(0), myDirty(false)
+{
+}
+
+/*!
+  \brief Constructor.
+  \param io Interactive object.
+*/
+SMESH::SelectionProxy::SelectionProxy( const Handle(SALOME_InteractiveObject)& io ): myActor(0), myDirty(true)
+{
+  myObject = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( io );
+  init();
+}
+
+/*!
+  \brief Constructor.
+  \param object Mesh source.
+*/
+SMESH::SelectionProxy::SelectionProxy( SMESH::SMESH_IDSource_ptr object ): myActor(0), myDirty(true)
+{
+  if ( !CORBA::is_nil( object ) )
+    myObject = SMESH::SMESH_IDSource::_duplicate( object );
+}
+
+/*!
+  \brief Copy constructor.
+  \param other Proxy being copied.
+*/
+SMESH::SelectionProxy::SelectionProxy( const SelectionProxy& other )
+{
+  myIO = other.myIO;
+  myObject = other.myObject;
+  myActor = other.myActor;
+  myDirty = other.myDirty;
+}
+
+/*!
+  \brief Perform internal initialization.
+  \internal
+*/
+void SMESH::SelectionProxy::init()
+{
+  if ( myIO.IsNull() )
+    myIO = new SALOME_InteractiveObject(); // create dummy IO to avoid crashes when accesing it
+
+  if ( !CORBA::is_nil( myObject ) )
+  {
+    if ( !myIO->hasEntry() )
+    {
+      _PTR(SObject) sobj = SMESH::ObjectToSObject( myObject.in() );
+      if ( sobj )
+        myIO = new SALOME_InteractiveObject( sobj->GetID().c_str(), "SMESH", sobj->GetName().c_str() );
+    }
+    if ( !myActor && myIO->hasEntry() )
+      myActor = SMESH::FindActorByEntry( myIO->getEntry() );
+  }
+  myDirty = false;
+}
+
+/*!
+  \brief Assignment operator.
+  \param other Proxy being copied.
+*/
+SMESH::SelectionProxy& SMESH::SelectionProxy::operator= ( const SMESH::SelectionProxy& other )
+{
+  myIO = other.myIO;
+  myObject = other.myObject;
+  myActor = other.myActor;
+  myDirty = other.myDirty;
+  return *this;
+}
+
+/*!
+  \brief Equality comparison operator.
+  \param other Proxy to compare with.
+  \return \c true if two proxies are equal; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::operator== ( const SMESH::SelectionProxy& other )
+{
+  return !CORBA::is_nil( myObject ) && !CORBA::is_nil( other.myObject ) && 
+    myObject->_is_equivalent( other.myObject );
+}
+
+/*!
+  \brief Re-initialize proxy.
+*/
+void SMESH::SelectionProxy::refresh()
+{
+  init();
+}
+
+/*!
+  \brief Check if proxy is null.
+  \return \c true if proxy is null; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::isNull() const
+{
+  return CORBA::is_nil( myObject );
+}
+
+/*!
+  \brief Boolean conversion operator.
+  \return \c true if proxy is not null; \c false otherwise.
+*/
+SMESH::SelectionProxy::operator bool() const
+{
+  return !isNull();
+}
+
+/*!
+  \brief Get interactive object.
+  \return Interactive object referenced by proxy.
+*/
+const Handle(SALOME_InteractiveObject)& SMESH::SelectionProxy::io() const
+{
+  if ( myDirty )
+    const_cast<SMESH::SelectionProxy*>(this)->init();
+  return myIO;
+}
+
+/*!
+  \brief Get mesh object.
+  \return Mesh object (mesh, sub-mesh, group, etc.) referenced by proxy.
+*/
+SMESH::SMESH_IDSource_ptr SMESH::SelectionProxy::object() const
+{
+  return SMESH::SMESH_IDSource::_duplicate( myObject );
+}
+
+/*!
+  \brief Get actor.
+  \return Actor referenced by proxy.
+*/
+SMESH_Actor* SMESH::SelectionProxy::actor() const
+{
+  if ( myDirty )
+    const_cast<SMESH::SelectionProxy*>(this)->init();
+  return myActor;
+}
+
+/*!
+  \brief Get object's validity.
+
+  Mesh object is valid if it is not null and information stored in it is valid.
+
+  \return \c true if object is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::isValid() const
+{
+  return !isNull() && myObject->IsMeshInfoCorrect();
+}
+
+/*!
+  \brief Load mesh object from study file.
+*/
+void SMESH::SelectionProxy::load()
+{
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+    if ( !CORBA::is_nil( mesh ) )
+      mesh->Load();
+  }
+}
+
+/*!
+  \brief Get name.
+  \return Mesh object's name.
+*/
+QString SMESH::SelectionProxy::name() const
+{
+  QString value;
+  if ( !isNull() )
+    value = io()->getName();
+  return value;
+}
+
+/*!
+  \brief Get type.
+  \return Mesh object's type.
+*/
+SMESH::SelectionProxy::Type SMESH::SelectionProxy::type() const
+{
+  Type value = Unknown;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( myObject );
+    SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( myObject );
+    SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( myObject );
+    SMESH::SMESH_Group_var sGroup = SMESH::SMESH_Group::_narrow( myObject );
+    SMESH::SMESH_GroupOnGeom_var gGroup = SMESH::SMESH_GroupOnGeom::_narrow( myObject );
+    SMESH::SMESH_GroupOnFilter_var fGroup = SMESH::SMESH_GroupOnFilter::_narrow( myObject );
+    
+    if ( !CORBA::is_nil( mesh ) )
+      value = Mesh;
+    else if ( !CORBA::is_nil( submesh ) )
+      value = Submesh;
+    else if ( !CORBA::is_nil( sGroup ) )
+      value = GroupStd;
+    else if ( !CORBA::is_nil( gGroup ) )
+      value = GroupGeom;
+    else if ( !CORBA::is_nil( fGroup ) )
+      value = GroupFilter;
+    else if ( !CORBA::is_nil( group ) )
+      value = Group;
+  }
+  return value;
+}
+
+/*!
+  \brief Get mesh information.
+  \return Statistics on stored mesh object.
+*/
+SMESH::MeshInfo SMESH::SelectionProxy::meshInfo() const
+{
+  SMESH::MeshInfo info;
+  if ( !isNull() )
+  {
+    SMESH::long_array_var data = myObject->GetMeshInfo();
+    for ( uint type = SMESH::Entity_Node; type < SMESH::Entity_Last; type++ )
+    {
+      if ( type < data->length() )
+        info.addInfo( type, data[ type ] );
+    }
+  }
+  return info;
+}
+
+/*!
+  \brief Get parent mesh.
+  \return Proxy object that stores parent mesh object.
+  \note For proxy that stores a mesh, returns its copy.
+*/
+SMESH::SelectionProxy SMESH::SelectionProxy::mesh() const
+{
+  SMESH::SelectionProxy parent;
+  if ( !isNull() )
+    parent = SMESH::SelectionProxy( (SMESH::SMESH_Mesh_var) myObject->GetMesh() ); // cast to var to avoid leaks
+  return parent;
+}
+
+/*!
+  \brief Check if parent mesh has shape to mesh.
+  \return \c true if Parent mesh is built on a shape; \c false otherwise.
+  \note For group or submesh, this method checks that parent mesh has a shape.
+*/
+bool SMESH::SelectionProxy::hasShapeToMesh() const
+{
+  bool result = false;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+    if ( !CORBA::is_nil( mesh ) )
+      result = mesh->HasShapeToMesh();
+  }
+  return result;
+}
+
+/*!
+  \brief Get referenced GEOM object.
+  \return GEOM object referenced by selection proxy.
+
+  The result contains valid pointer only if proxy refers to mesh, sub-mesh
+  or group created on a geometry.
+*/
+GEOM::GEOM_Object_ptr SMESH::SelectionProxy::shape() const
+{
+  GEOM::GEOM_Object_var shape;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( myObject );
+    SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( myObject );
+    SMESH::SMESH_GroupOnGeom_var group = SMESH::SMESH_GroupOnGeom::_narrow( myObject );
+    if ( !CORBA::is_nil( mesh ) )
+      shape = mesh->GetShapeToMesh();
+    else if ( !CORBA::is_nil( submesh ) )
+      shape = submesh->GetSubShape();
+    else if ( !CORBA::is_nil( group ) )
+      shape = group->GetShape();
+  }
+  return shape._retn();
+}
+
+/*!
+  \brief Get name of referenced GEOM object.
+  \return Name of GEOM object referenced by selection proxy.
+
+  The result contains non-empty name only if proxy refers to mesh, sub-mesh
+  or group created on a geometry, and if that geometry has valid name.
+*/
+QString SMESH::SelectionProxy::shapeName() const
+{
+  QString name;
+  if ( !isNull() )
+  {
+    GEOM::GEOM_Object_var gobj = shape();
+    _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
+    if ( sobj )
+      name = QString::fromStdString( sobj->GetName() );
+  }
+  return name;
+}
+
+/*!
+  \brief Get type of referenced GEOM object.
+  \return Type of GEOM object referenced by selection proxy.
+
+  The result contains valid type only if proxy refers to mesh, sub-mesh
+  or group created on a geometry.
+*/
+int SMESH::SelectionProxy::shapeType() const
+{
+  int type = -1;
+  if ( !isNull() )
+  {
+    GEOM::GEOM_Object_var gobj = shape();
+    if ( !CORBA::is_nil( gobj ) )
+      type = gobj->GetShapeType();
+  }
+  return type;
+}
+
+/*!
+  \brief Check if mesh has been loaded from study file.
+  \return \c true if mesh was loaded; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::isMeshLoaded() const
+{
+  bool result = true; // set default to true to avoid side effects
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+    if ( !CORBA::is_nil( mesh ) )
+      result = mesh->IsLoaded();
+  }
+  return result;
+}
+
+/*!
+  \brief Check if node with given ID is present in the mesh.
+  \param id Mesh node ID.
+  \return \c true if mesh contains node; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::hasNode( int id )
+{
+  bool result = false;
+  if ( !isNull() )
+  {
+    if ( actor() )
+    {
+      const SMDS_MeshNode* node = actor()->GetObject()->GetMesh()->FindNode( id );
+      result = node != 0;
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        SMESH::double_array_var coords = mesh->GetNodeXYZ( id );
+        result = coords->length() >= 3;
+      }
+    }
+  }
+  return result; 
+}
+
+/*!
+  \brief Get node coordinates.
+  \param id Mesh node ID.
+  \param xyz Returned node coordinates.
+  \return \c true if result is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::nodeCoordinates( int id, SMESH::XYZ& xyz )
+{
+  bool result = false;
+  xyz = SMESH::XYZ();
+  
+  if ( !isNull() )
+  {
+    if ( actor() )
+    {
+      const SMDS_MeshNode* node = actor()->GetObject()->GetMesh()->FindNode( id );
+      if ( node )
+      {
+        xyz = SMESH::XYZ( node->X(), node->Y(), node->Z() );
+        result = true;
+      }
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        SMESH::double_array_var coords = mesh->GetNodeXYZ( id );
+        if ( coords->length() >= 3 )
+        {
+          xyz = SMESH::XYZ( coords[0], coords[1], coords[2] );
+          result = true;
+        }
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get node connectivity.
+  \param id Mesh node ID.
+  \param connectivity Returned node connectivity.
+  \return \c true if result is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::nodeConnectivity( int id, SMESH::Connectivity& connectivity )
+{
+  bool result = false;
+  connectivity.clear();
+  if ( !isNull() )
+  {
+    if ( actor() )
+    {
+      const SMDS_MeshNode* node = actor()->GetObject()->GetMesh()->FindNode( id );
+      if ( node )
+      {
+        SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
+        while ( it && it->more() )
+        {
+          const SMDS_MeshElement* ne = it->next();
+          connectivity[ ne->GetType() ] << ne->GetID();
+        }
+        result = true;
+      }
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        SMESH::long_array_var elements = mesh->GetNodeInverseElements( id, SMESH::ALL );
+        for ( int i = 0, n = elements->length(); i < n; i++ )
+        {
+          SMESH::ElementType type = mesh->GetElementType( elements[i], true );
+          connectivity[ type ] << elements[i];
+        }
+        result = true;
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get node position on a shape.
+  \param id Mesh node ID.
+  \param position Returned node position.
+  \return \c true if result is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::nodePosition( int id, Position& position )
+{
+  bool result = false;
+  position = Position();
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+    if ( !CORBA::is_nil( mesh ) )
+    {
+      SMESH::NodePosition_var pos = mesh->GetNodePosition( id );
+      position.setShapeId( pos->shapeID );
+      if ( pos->shapeID > 0 )
+      {
+        position.setShapeType( pos->shapeType );
+        if ( pos->shapeType == GEOM::EDGE && pos->params.length() > 0 )
+        {
+          position.setU( pos->params[0] );
+        }
+        if ( pos->shapeType == GEOM::FACE && pos->params.length() > 1 )
+        {
+          position.setU( pos->params[0] );
+          position.setV( pos->params[1] );
+        }
+        result = true;
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get groups given node belongs to.
+  \param id Mesh node ID.
+  \return List of groups containing given node.
+*/
+QList<SMESH::SelectionProxy> SMESH::SelectionProxy::nodeGroups( int id ) const
+{
+  QList<SMESH::SelectionProxy> result;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+    if ( !CORBA::is_nil( mesh ) )
+    {
+      SMESH::ListOfGroups_var groups = mesh->GetGroups();
+      for ( uint i = 0 ; i < groups->length(); i++ )
+      {
+        if ( groups[i]->GetType() == SMESH::NODE && groups[i]->Contains( id ) )
+        {
+          result << SMESH::SelectionProxy( groups[i].in() );
+        }
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Check if element with given ID is present in the mesh.
+  \param id Mesh element ID.
+  \return \c true if mesh contains element; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::hasElement( int id )
+{
+  bool result = false;
+  if ( !isNull() )
+  {
+    if ( actor() )
+    {
+      const SMDS_MeshElement* element = actor()->GetObject()->GetMesh()->FindElement( id );
+      result = element != 0;
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        SMESH::long_array_var nodes = mesh->GetElemNodes( id );
+        result = nodes->length() > 0;
+      }
+    }
+  }
+  return result; 
+}
+
+/*!
+  \brief Get type of given mesh element.
+  \param id Mesh element ID.
+  \return Element type.
+*/
+SMESH::ElementType SMESH::SelectionProxy::elementType( int id ) const
+{
+  SMESH::ElementType value = SMESH::ALL;
+  if ( !isNull() )
+  {
+    if ( actor() )
+    {
+      const SMDS_MeshElement* element = actor()->GetObject()->GetMesh()->FindElement( id );
+      if ( element )
+      {
+        value = (SMESH::ElementType)element->GetType();
+      }
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        value = mesh->GetElementType( id, true );
+      }
+    }
+  }
+  return value;
+}
+
+/*!
+  \brief Get entity type of given mesh element.
+  \param id Mesh element ID.
+  \return Entity type.
+*/
+int SMESH::SelectionProxy::elementEntityType( int id ) const
+{
+  SMESH::EntityType value = SMESH::Entity_Last;
+  if ( !isNull() )
+  {
+    if ( actor() )
+    {
+      const SMDS_MeshElement* element = actor()->GetObject()->GetMesh()->FindElement( id );
+      if ( element )
+      {
+        value = (SMESH::EntityType)element->GetEntityType();
+      }
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        value = mesh->GetElementGeomType( id );
+      }
+    }
+  }
+  return value;
+}
+
+/*!
+  \brief Get element connectivity.
+  \param id Mesh element ID.
+  \param connectivity Return element connectivity.
+  \return \c true if result is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::elementConnectivity( int id, Connectivity& connectivity )
+{
+  bool result = false;
+  connectivity.clear();
+  if ( !isNull() )
+  {
+    QSet<int> nodes; // order of nodes is important
+    if ( actor() )
+    {
+      const SMDS_MeshElement* element = actor()->GetObject()->GetMesh()->FindElement( id );
+      if ( element )
+        if ( SMDS_NodeIteratorPtr it = element->nodeIterator())
+        {
+          while ( it->more() )
+          {
+            int n = it->next()->GetID();
+            if ( !nodes.contains( n ))
+            {
+              connectivity[ SMDSAbs_Node ] << n;
+              nodes << n;
+            }
+          }
+          result = true;
+        }
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        SMESH::long_array_var nn = mesh->GetElemNodes( id );
+        for ( int i = 0, nb = nn->length(); i < nb; i++ )
+        {
+          if ( !nodes.contains( nn[i] ))
+          {
+            connectivity[ SMDSAbs_Node ] << nn[i];
+            nodes << nn[i];
+          }
+        }
+        result = true;
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get volume element connectivity.
+  \param id Mesh element ID.
+  \param connectivity Return nodal connectivity of each facet numbered from 1
+  \param nbNodes Return number of unique nodes.
+  \return \c true if result is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::perFaceConnectivity( int id, Connectivity& connectivity, int& nbNodes )
+{
+  bool result = false;
+  connectivity.clear();
+  nbNodes = 0;
+  if ( !isNull() )
+  {
+    QSet<int> nodeSet;
+    if ( actor() )
+    {
+      const SMDS_MeshElement* element = actor()->GetObject()->GetMesh()->FindElement( id );
+      SMDS_VolumeTool volTool;
+      if ( volTool.Set( element ))
+      {
+        for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
+        {
+          const SMDS_MeshNode** nn = volTool.GetFaceNodes( iF );
+          int nbN = volTool.NbFaceNodes( iF );
+          for ( int iN = 0; iN < nbN; ++iN )
+          {
+            connectivity[ iF+1 ] << ( nn[ iN ]->GetID() );
+            nodeSet << ( nn[ iN ]->GetID() );
+          }
+        }
+        result = true;
+      }
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        CORBA::Long nbFaces = mesh->ElemNbFaces( id );
+        for ( CORBA::Long iF = 0; iF < nbFaces; ++iF )
+        {
+          SMESH::long_array_var nodes = mesh->GetElemFaceNodes( id, iF );
+          for ( CORBA::ULong iN = 0; iN < nodes->length(); ++iN )
+          {
+            connectivity[ iF ] << nodes[iN];
+            nodeSet << nodes[iN];
+          }
+        }
+        result = ( nbFaces > 0 );
+      }
+    }
+    nbNodes = nodeSet.size();
+  }
+  return result;
+}
+
+/*!
+  \brief Get element position on a shape.
+  \param id Mesh element ID.
+  \param position Returned element position.
+  \return \c true if result is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::elementPosition( int id, Position& position )
+{
+  bool result = false;
+  position = Position();
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+    if ( !CORBA::is_nil( mesh ) )
+    {
+      SMESH::ElementPosition_var pos = mesh->GetElementPosition( id );
+      position.setShapeId( pos->shapeID );
+      if ( pos->shapeID > 0 )
+      {
+        position.setShapeType( pos->shapeType );
+        result = true;
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get gravity center of given element.
+  \param id Mesh element ID.
+  \param xyz Returned gravity center.
+  \return \c true if result is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::elementGravityCenter( int id, SMESH::XYZ& xyz )
+{
+  bool result = false;
+  xyz = SMESH::XYZ();
+  if ( !isNull() )
+  {
+    if ( actor() )
+    {
+      const SMDS_MeshElement* element = actor()->GetObject()->GetMesh()->FindElement( id );
+      if ( element )
+      {
+        SMDS_ElemIteratorPtr it = element->nodesIterator();
+        while ( it->more() )
+        {
+          const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( it->next() );
+          xyz.add( node->X(), node->Y(), node->Z() );
+        }
+        xyz.divide( element->NbNodes() );
+        result = true;
+      }
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        SMESH::long_array_var nodes = mesh->GetElemNodes( id );
+        for ( int i = 0, n = nodes->length(); i < n; i++ )
+        {
+          SMESH::double_array_var coords = mesh->GetNodeXYZ( nodes[i]  );
+          if ( coords->length() >= 3 )
+          {
+            xyz.add( coords[0], coords[1], coords[2] );
+          }
+        }
+        xyz.divide( nodes->length() );
+        result = true;
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get normal vector to given element (face).
+  \param id Mesh element ID.
+  \param xyz Returned normal vector.
+  \return \c true if result is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::elementNormal( int id, SMESH::XYZ& xyz )
+{
+  bool result = false;
+  xyz = SMESH::XYZ();
+  if ( !isNull() )
+  {
+    if ( actor() )
+    {
+      const SMDS_MeshElement* element = actor()->GetObject()->GetMesh()->FindElement( id );
+      if ( element && element->GetType() == SMDSAbs_Face )
+      {
+        xyz = SMESH::getNormale( SMDS_Mesh::DownCast<SMDS_MeshFace>( element ) );
+        result = true;
+      }
+    }
+    else
+    {
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !CORBA::is_nil( mesh ) )
+      {
+        SMESH::double_array_var normal = mesh->GetFaceNormal( id, true );
+        if ( normal->length() >= 3 )
+        {
+          xyz = SMESH::XYZ( normal[0], normal[1], normal[2] );
+          result = true;
+        }
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get quality control's value for given element.
+  \param id Mesh element ID.
+  \param control Quality control type.
+  \param precision Precision for control's value.
+  \param value Returned quality control's value.
+  \return \c true if result is valid; \c false otherwise.
+*/
+bool SMESH::SelectionProxy::elementControl( int id, int control, double precision, double& value ) const
+{
+  bool result = false;
+  value = 0.;
+  if ( !isNull() )
+  {
+    if ( actor() )
+    {
+      SMESH::Controls::NumericalFunctorPtr functor;
+      switch ( control )
+      {
+      case SMESH::FT_AspectRatio:
+        functor.reset( new SMESH::Controls::AspectRatio() );
+        break;
+      case SMESH::FT_AspectRatio3D:
+        functor.reset( new SMESH::Controls::AspectRatio3D() );
+        break;
+      case SMESH::FT_Warping:
+        functor.reset( new SMESH::Controls::Warping() );
+        break;
+      case SMESH::FT_MinimumAngle:
+        functor.reset( new SMESH::Controls::MinimumAngle() );
+        break;
+      case SMESH::FT_Taper:
+        functor.reset( new SMESH::Controls::Taper() );
+        break;
+      case SMESH::FT_Skew:
+        functor.reset( new SMESH::Controls::Skew() );
+        break;
+      case SMESH::FT_Area:
+        functor.reset(  new SMESH::Controls::Area() );
+        break;
+      case SMESH::FT_Volume3D:
+        functor.reset(  new SMESH::Controls::Volume() );
+        break;
+      case SMESH::FT_MaxElementLength2D:
+        functor.reset( new SMESH::Controls::MaxElementLength2D() );
+        break;
+      case SMESH::FT_MaxElementLength3D:
+        functor.reset(  new SMESH::Controls::MaxElementLength3D() );
+        break;
+      case SMESH::FT_Length:
+        functor.reset( new SMESH::Controls::Length() );
+        break;
+      case SMESH::FT_Length2D:
+        functor.reset( new SMESH::Controls::Length2D() );
+        break;
+      case SMESH::FT_Length3D:
+        functor.reset( new SMESH::Controls::Length3D() );
+        break;
+      case SMESH::FT_BallDiameter:
+        functor.reset( new SMESH::Controls::BallDiameter() );
+        break;
+      default:
+        break;
+      } 
+      const SMDS_MeshElement* element = actor()->GetObject()->GetMesh()->FindElement( id );
+      if ( element && functor && element->GetType() == functor->GetType() )
+      {
+        functor->SetMesh( actor()->GetObject()->GetMesh() );
+        if ( functor->IsApplicable( element ))
+        {
+          functor->SetPrecision( precision );
+          value = functor->GetValue( id );
+          result = true;
+        }
+      }
+    }
+    else
+    {
+      SMESH::SMESH_Gen_var smeshGen = SMESHGUI::GetSMESHGen();
+      if ( smeshGen->_is_nil() )
+        return false;
+      SMESH::FilterManager_var manager = smeshGen->CreateFilterManager();
+      if ( manager->_is_nil() )
+        return false;
+      SMESH::NumericalFunctor_var functor;
+      switch ( control )
+      {
+      case SMESH::FT_AspectRatio:
+        functor = manager->CreateAspectRatio();
+        break;
+      case SMESH::FT_AspectRatio3D:
+        functor = manager->CreateAspectRatio3D();
+        break;
+      case SMESH::FT_Warping:
+        functor = manager->CreateWarping();
+        break;
+      case SMESH::FT_MinimumAngle:
+        functor = manager->CreateMinimumAngle();
+        break;
+      case SMESH::FT_Taper:
+        functor = manager->CreateTaper();
+        break;
+      case SMESH::FT_Skew:
+        functor = manager->CreateSkew();
+        break;
+      case SMESH::FT_Area:
+        functor = manager->CreateArea();
+        break;
+      case SMESH::FT_Volume3D:
+        functor = manager->CreateVolume3D();
+        break;
+      case SMESH::FT_MaxElementLength2D:
+        functor = manager->CreateMaxElementLength2D();
+        break;
+      case SMESH::FT_MaxElementLength3D:
+        functor = manager->CreateMaxElementLength3D();
+        break;
+      case SMESH::FT_Length:
+        functor = manager->CreateLength();
+        break;
+      case SMESH::FT_Length2D:
+        functor = manager->CreateLength2D();
+        break;
+      case SMESH::FT_Length3D:
+        functor = manager->CreateLength3D();
+        break;
+      case SMESH::FT_BallDiameter:
+        functor = manager->CreateBallDiameter();
+        break;
+      default:
+        break;
+      }
+      SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+      if ( !functor->_is_nil() && !mesh->_is_nil() )
+      {
+        functor->SetMesh( mesh );
+        if ( functor->IsApplicable( id ))
+        {
+          functor->SetPrecision( precision );
+          value = functor->GetValue( id );
+          result = true;
+        }
+      }
+      manager->UnRegister();
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get groups given element belongs to.
+  \param id Mesh element ID.
+  \return List of groups containing element.
+*/
+QList<SMESH::SelectionProxy> SMESH::SelectionProxy::elementGroups( int id ) const
+{
+  QList<SMESH::SelectionProxy> result;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
+    if ( !CORBA::is_nil( mesh ) )
+    {
+      SMESH::ListOfGroups_var groups = mesh->GetGroups();
+      for ( uint i = 0 ; i < groups->length(); i++ )
+      {
+        if ( groups[i]->GetType() != SMESH::NODE && groups[i]->Contains( id ) )
+        {
+          result << SMESH::SelectionProxy( groups[i].in() );
+        }
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get MED file information.
+  \return MED file information.
+
+  The result contains valid data only if proxy refers to mesh object
+  which has been imported from the MED file.
+*/
+SMESH::MedInfo SMESH::SelectionProxy::medFileInfo() const
+{
+  SMESH::MedInfo info;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( myObject );
+    if ( !CORBA::is_nil( mesh ) )
+    {
+      SMESH::MedFileInfo_var inf = mesh->GetMEDFileInfo();
+      info.setFileName( inf->fileName.in() );
+      info.setSize( inf->fileSize );
+      info.setVersion( inf->major, inf->minor, inf->release );
+    }
+  }
+  return info;
+}
+
+/*!
+  \brief Get child sub-meshes.
+  \return List of sub-meshes for mesh object; empty list for other types.
+*/
+QList<SMESH::SelectionProxy> SMESH::SelectionProxy::submeshes() const
+{
+  QList<SMESH::SelectionProxy> lst;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( myObject );
+    if ( !CORBA::is_nil( mesh ) )
+    {
+      SMESH::submesh_array_var array = mesh->GetSubMeshes();
+      for ( uint i = 0 ; i < array->length(); i++ )
+        lst << SMESH::SelectionProxy( array[i].in() );
+    }
+  }
+  return lst;
+}
+
+/*!
+  \brief Get child groups.
+  \return List of groups for mesh object; empty list for other types.
+*/
+QList<SMESH::SelectionProxy> SMESH::SelectionProxy::groups() const
+{
+  QList<SMESH::SelectionProxy> lst;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( myObject );
+    if ( !CORBA::is_nil( mesh ) )
+    {
+      SMESH::ListOfGroups_var array = mesh->GetGroups();
+      for ( uint i = 0 ; i < array->length(); i++ )
+        lst << SMESH::SelectionProxy( array[i].in() );
+    }
+  }
+  return lst;
+}
+
+/*!
+  \brief Get element type (for group). For other mesh objects result is undefined.
+  \return Group's element type.
+*/
+SMESH::ElementType SMESH::SelectionProxy::groupElementType() const
+{
+  SMESH::ElementType value = SMESH::ALL;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( myObject );
+    if ( !CORBA::is_nil( group ) )
+      value = group->GetType();
+  }
+  return value;
+}
+
+/*!
+  \brief Get color (for group). For other mesh objects result is undefined.
+  \return Group's color.
+*/
+QColor SMESH::SelectionProxy::color() const
+{
+  QColor result;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( myObject );
+    if ( !CORBA::is_nil( group ) )
+    {
+      SALOMEDS::Color c = group->GetColor();
+      result = QColor::fromRgbF( c.R, c.G, c.B );
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get size (for group). For other mesh objects result is undefined.
+  \param autoCompute Compute size if it is unavailable. Defaults to \c false.
+  \return Group's size.
+*/
+int SMESH::SelectionProxy::size( bool autoCompute ) const
+{
+  // note: size is not computed for group on filter for performance reasons, see IPAL52831
+  int result = -1;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( myObject );
+    if ( !CORBA::is_nil( group ) )
+    {
+      if ( type() == GroupFilter )
+        // for group on filter we check if value is already computed and cached
+        autoCompute |= group->IsNodeInfoAvailable();
+      else
+        // for other groups we force autoCompute to true
+        autoCompute = true;
+      if ( autoCompute )
+        result = group->Size();
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get number of underlying nodes (for group of elements). For other
+  mesh objects result is undefined.
+  \param autoCompute Compute size if it is unavailable. Defaults to \c false.
+  \return Number of nodes contained in group.
+*/
+int SMESH::SelectionProxy::nbNodes( bool autoCompute ) const
+{
+  // note: nb of nodes is not computed automatically for performance reasons
+  int result = -1;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( myObject );
+    if ( !CORBA::is_nil( group ) && ( autoCompute || isMeshLoaded() ) )
+    {
+      int groupSize = size( autoCompute );
+      if ( groupSize >= 0 )
+      {
+        int limit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
+        if ( group->IsNodeInfoAvailable() || limit <= 0 || groupSize <= limit )
+          result = group->GetNumberOfNodes();
+      }
+    }
+  }
+  return result;
+}
+
+/*!
+  \brief Get list of nodes / elements IDs for the mesh group.
+  \return List of IDs for group object; empty list for other types.
+*/
+QSet<uint> SMESH::SelectionProxy::ids() const
+{
+  QSet<uint> result;
+  if ( !isNull() )
+  {
+    SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( myObject );
+    if ( !CORBA::is_nil( group ) )
+    {
+      SMESH::long_array_var seq = group->GetListOfID();
+      for ( int i = 0, n = seq->length(); i < n; i++ )
+        result << (uint)seq[i];
+    }
+  }
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESH::MeshInfo
+/// \brief Store statistics on mesh object.
+////////////////////////////////////////////////////////////////////////////////
+
+/*!
+  \brief Constructor.
+*/
+SMESH::MeshInfo::MeshInfo()
+{
+}
+
+/*!
+  \brief Add information on given entity type.
+  \param type Entity type.
+  \param value Number of entities.
+*/
+void SMESH::MeshInfo::addInfo( int type, long value )
+{
+  myInfo[type] = value;
+}
+
+/*!
+  \brief Get number of entities of given type.
+  \param type Entity type.
+  \return Number of entities.
+*/
+uint SMESH::MeshInfo::info( int type ) const
+{
+  return myInfo.value( type, 0U );
+}
+
+/*!
+  \brief Access operator.
+  \param type Entity type.
+  \return Number of entities.
+*/
+uint SMESH::MeshInfo::operator[] ( int type )
+{
+  return (uint)info( type );
+}
+
+/*!
+  \brief Get total number of entities for types in given range.
+  \param fromType Lower entity type.
+  \param toType Upper entity type.
+  \return Number of entities.
+*/
+uint SMESH::MeshInfo::count( int fromType, int toType ) const
+{
+  uint value = 0;
+  for ( int type = fromType; type <= toType; type++ )
+    value += info( type );
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESH::MedInfo
+/// \brief Provide operations over the selected object
+////////////////////////////////////////////////////////////////////////////////
+
+/*!
+  \brief Constructor.
+*/
+SMESH::MedI