Salome HOME
Merge from V6_5_BR 05/06/2012
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
index 255951008d61b34e164fef509623fdf3f1ce6537..95e214d31b1bcc3253a9d84d8c6901e009e2c5ee 100644 (file)
@@ -1,23 +1,23 @@
-//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2012  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
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 //
-//  This library is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU Lesser General Public
-//  License as published by the Free Software Foundation; either
-//  version 2.1 of the License.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
 //
-//  This library is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-//  Lesser General Public License for more details.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
 //
-//  You should have received a copy of the GNU Lesser General Public
-//  License along with this library; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+// See http://www.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 <QRadioButton>
 #include <QTabWidget>
 #include <QTextBrowser>
-#include <QTreeWidget>
 #include <QVBoxLayout>
 
 #include "utilities.h"
 
 #include <SALOMEconfig.h>
-#include CORBA_SERVER_HEADER(SMESH_Group)
+#include CORBA_SERVER_HEADER(GEOM_Gen)
 
-const int SPACING = 6;
-const int MARGIN  = 9;
+const int SPACING  = 6;
+const int MARGIN   = 9;
+const int MAXITEMS = 10;
 
 /*!
   \class SMESHGUI_MeshInfo
@@ -169,6 +169,8 @@ SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent )
   QLabel*  a3DPriTotal = createField();
   QLabel*  a3DPriLin   = createField();
   QLabel*  a3DPriQuad  = createField();
+  QLabel*  a3DHexPriLab   = new QLabel( tr( "HEX_PRISMS_LAB" ), this );
+  QLabel*  a3DHexPriTotal = createField();
   QLabel*  a3DPolLab   = new QLabel( tr( "POLYHEDRONS_LAB" ), this );
   QLabel*  a3DPolTotal = createField();
   myWidgets[15] << a3DLine;
@@ -177,8 +179,13 @@ SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent )
   myWidgets[18] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad;
   myWidgets[19] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad;
   myWidgets[20] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad;
-  myWidgets[21] << a3DPolLab << a3DPolTotal;
+  myWidgets[21] << a3DHexPriLab << a3DHexPriTotal;
+  myWidgets[22] << 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 );
@@ -247,13 +254,16 @@ SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent )
   l->addWidget( a3DPriTotal, 20, 1 );
   l->addWidget( a3DPriLin,   20, 2 );
   l->addWidget( a3DPriQuad,  20, 3 );
-  l->addWidget( a3DPolLab,   21, 0 );
-  l->addWidget( a3DPolTotal, 21, 1 );
+  l->addWidget( a3DHexPriLab,   21, 0 );
+  l->addWidget( a3DHexPriTotal, 21, 1 );
+  l->addWidget( a3DPolLab,   22, 0 );
+  l->addWidget( a3DPolTotal, 22, 1 );
+  l->addWidget( myLoadBtn,   23, 1, 1, 3 );
   l->setColumnStretch( 0, 0 );
   l->setColumnStretch( 1, 5 );
   l->setColumnStretch( 2, 5 );
   l->setColumnStretch( 3, 5 );
-  l->setRowStretch( 22, 5 );
+  l->setRowStretch( 23, 5 );
 
   clear();
 }
@@ -273,7 +283,7 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
 {
   clear();
   if ( !CORBA::is_nil( obj ) ) {
-    _PTR(SObject) sobj = ObjectToSObject( 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 );
@@ -289,69 +299,177 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
       QString objType;
       switch( aGroup->GetType() ) {
       case SMESH::NODE:
-       objType = tr( "OBJECT_GROUP_NODES" );
-       break;
+        objType = tr( "OBJECT_GROUP_NODES" );
+        break;
       case SMESH::EDGE:
-       objType = tr( "OBJECT_GROUP_EDGES" );
-       break;
+        objType = tr( "OBJECT_GROUP_EDGES" );
+        break;
       case SMESH::FACE:
-       objType = tr( "OBJECT_GROUP_FACES" );
-       break;
+        objType = tr( "OBJECT_GROUP_FACES" );
+        break;
       case SMESH::VOLUME:
-       objType = tr( "OBJECT_GROUP_VOLUMES" );
-       break;
+        objType = tr( "OBJECT_GROUP_VOLUMES" );
+        break;
       case SMESH::ELEM0D:
-       objType = tr( "OBJECT_GROUP_0DELEMS" );
-       break;
+        objType = tr( "OBJECT_GROUP_0DELEMS" );
+        break;
       default:
-       objType = tr( "OBJECT_GROUP" );
-       break;
+        objType = tr( "OBJECT_GROUP" );
+        break;
       }
       myWidgets[iObject][iSingle]->setProperty( "text", objType );
     }
     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[iNodes][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Node] ) );
+    myWidgets[i0D][iTotal]    ->setProperty( "text", QString::number( info[SMDSEntity_0D] ) );
     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][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];
-    long nbQuadrangles = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle];
+    long nbQuadrangles = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
     long nb2DLinear    = info[SMDSEntity_Triangle] + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon];
-    long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_Quad_Quadrangle];
-    myWidgets[i2D][iTotal]->setProperty( "text", QString::number( nb2DLinear + nb2DQuadratic ) );
-    myWidgets[i2D][iLinear]->setProperty( "text", QString::number( nb2DLinear ) );
-    myWidgets[i2D][iQuadratic]->setProperty( "text", QString::number( nb2DQuadratic ) );
-    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[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[i2DPolygons][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) );
+    long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
+    myWidgets[i2D][iTotal]               ->setProperty( "text", QString::number( nb2DLinear + nb2DQuadratic ) );
+    myWidgets[i2D][iLinear]              ->setProperty( "text", QString::number( nb2DLinear ) );
+    myWidgets[i2D][iQuadratic]           ->setProperty( "text", QString::number( nb2DQuadratic ) );
+    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[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] + info[SMDSEntity_BiQuad_Quadrangle] ));
+    myWidgets[i2DPolygons][iTotal]       ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) );
     long nbTetrahedrons = info[SMDSEntity_Tetra]   + info[SMDSEntity_Quad_Tetra];
-    long nbHexahedrons  = info[SMDSEntity_Hexa]    + info[SMDSEntity_Quad_Hexa];
+    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];
-    long nb3DLinear     = info[SMDSEntity_Tetra] + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra];
-    long nb3DQuadratic  = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta];
-    myWidgets[i3D][iTotal]->setProperty( "text", QString::number( nb3DLinear + nb3DQuadratic ) );
-    myWidgets[i3D][iLinear]->setProperty( "text", QString::number( nb3DLinear ) );
-    myWidgets[i3D][iQuadratic]->setProperty( "text", QString::number( nb3DQuadratic ) );
-    myWidgets[i3DTetrahedrons][iTotal]->setProperty( "text", QString::number( nbTetrahedrons ) );
-    myWidgets[i3DTetrahedrons][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ) );
+    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_TriQuad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta];
+    myWidgets[i3D][iTotal]                ->setProperty( "text", QString::number( nb3DLinear + nb3DQuadratic ) );
+    myWidgets[i3D][iLinear]               ->setProperty( "text", QString::number( nb3DLinear ) );
+    myWidgets[i3D][iQuadratic]            ->setProperty( "text", QString::number( nb3DQuadratic ) );
+    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[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[i3DPolyhedrons][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) );
+    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] + 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[i3DHexaPrisms][iTotal]      ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ) );
+    myWidgets[i3DPolyhedrons][iTotal]     ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) );
+
+    // 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 )
+    {
+      // 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
+      {
+        if ( nb2DLinear + nb2DQuadratic > 0 )
+        {
+          myWidgets[i2D][iLinear]              ->setProperty( "text", "?" );
+          myWidgets[i2D][iQuadratic]           ->setProperty( "text", "?" );
+          myWidgets[i2DTriangles][iTotal]      ->setProperty( "text", "?" );
+          myWidgets[i2DTriangles][iLinear]     ->setProperty( "text", "?" );
+          myWidgets[i2DTriangles][iQuadratic]  ->setProperty( "text", "?" );
+          myWidgets[i2DQuadrangles][iTotal]    ->setProperty( "text", "?" );
+          myWidgets[i2DQuadrangles][iLinear]   ->setProperty( "text", "?" );
+          myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", "?" );
+          myWidgets[i2DPolygons][iTotal]       ->setProperty( "text", "?" );
+        }
+        else if ( nb3DLinear + nb3DQuadratic > 0 )
+        {
+          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[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", "?" );
+        }
+      }
+      else
+      {
+        myWidgets[iNodes][iTotal]             ->setProperty( "text", "?" );
+        myWidgets[i0D][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[i2DTriangles][iTotal]       ->setProperty( "text", "?" );
+        myWidgets[i2DTriangles][iLinear]      ->setProperty( "text", "?" );
+        myWidgets[i2DTriangles][iQuadratic]   ->setProperty( "text", "?" );
+        myWidgets[i2DQuadrangles][iTotal]     ->setProperty( "text", "?" );
+        myWidgets[i2DQuadrangles][iLinear]    ->setProperty( "text", "?" );
+        myWidgets[i2DQuadrangles][iQuadratic] ->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[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", "?" );
+      }
+    }
+  }
+}
+
+/*!
+  \brief Load mesh from a study file
+*/
+void SMESHGUI_MeshInfo::loadMesh()
+{
+  SUIT_OverrideCursor wc;
+
+  SALOME_ListIO selected;
+  SMESHGUI::selectionMgr()->selectedObjects( selected );
+
+  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 );
+      }
+    }
   }
 }
 
@@ -392,6 +510,7 @@ void SMESHGUI_MeshInfo::clear()
   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 ) );
 }
 
@@ -465,8 +584,29 @@ void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on )
   \param parent parent widget
 */
 SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent )
-: QWidget( parent ), myActor( 0 ), myID( 0 ), myIsElement( -1 )
+: QWidget( parent ), myActor( 0 ), myIsElement( -1 )
 {
+  myFrame = new QWidget( this );
+  myExtra = new QWidget( this );
+  myCurrent = new QLabel( "10/43 items shown", myExtra );
+  myCurrent->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
+  myPrev = new QPushButton( tr( "<<" ), myExtra );
+  myNext = new QPushButton( tr( ">>" ), myExtra );
+  QHBoxLayout* hbl = new QHBoxLayout( myExtra );
+  hbl->setContentsMargins( 0, SPACING, 0, 0 );
+  hbl->setSpacing( SPACING );
+  hbl->addStretch();
+  hbl->addWidget( myCurrent );
+  hbl->addWidget( myPrev );
+  hbl->addWidget( myNext );
+  QVBoxLayout* vbl = new QVBoxLayout( this );
+  vbl->setMargin( 0 );
+  vbl->setSpacing( 0 );
+  vbl->addWidget( myFrame );
+  vbl->addWidget( myExtra );
+  connect( myPrev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) );
+  connect( myNext, SIGNAL( clicked() ), this, SLOT( showNext() ) );
+  clear();
 }
 
 /*!
@@ -484,7 +624,6 @@ void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor )
 {
   if ( myActor != actor ) {
     myActor = actor;
-    myID = 0;
     myIsElement = -1;
     clear();
   }
@@ -492,19 +631,87 @@ void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor )
 
 /*!
   \brief Show mesh element information
-  \param long id mesh node / element ID
+  \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 )
 {
-  myID = id;
+  QSet<long> ids;
+  ids << id;
+  showInfo( ids, isElem );
+}
+
+/*!
+  \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
+*/
+void SMESHGUI_ElemInfo::showInfo( QSet<long> ids, bool isElem )
+{
+  QList<long> newIds = ids.toList();
+  qSort( newIds );
+  if ( myIDs == newIds && myIsElement == isElem ) return;
+
+  myIDs = newIds;
   myIsElement = isElem;
+  myIndex = 0;
+  updateControls();
+  information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
 }
 
 /*!
-  \fn void SMESHGUI_ElemInfo::clear()
   \brief Clear mesh element information widget
 */
+void SMESHGUI_ElemInfo::clear()
+{
+  myIDs.clear();
+  myIndex = 0;
+  clearInternal();
+  updateControls();
+}
+
+/*!
+  \brief Get central area widget
+  \return central widget
+*/
+QWidget* SMESHGUI_ElemInfo::frame() const
+{
+  return myFrame;
+}
+
+/*!
+  \brief Get actor
+  \return actor being used
+*/
+SMESH_Actor* SMESHGUI_ElemInfo::actor() const
+{
+  return myActor;
+}
+
+/*!
+  \brief Get current info mode.
+  \return \c true if mesh element information is shown or \c false if node information is shown
+*/
+bool SMESHGUI_ElemInfo::isElements() const
+{
+  return myIsElement;
+}
+
+/*!
+  \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 Internal clean-up (reset widget)
+*/
+void SMESHGUI_ElemInfo::clearInternal()
+{
+}
 
 /*!
   \brief Get node connectivity
@@ -560,6 +767,39 @@ SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement*
   return xyz;
 }
 
+/*!
+  \brief This slot is called from "Show Previous" button click.
+  Shows information on the previous group of the items.
+*/
+void SMESHGUI_ElemInfo::showPrevious()
+{
+  myIndex = qMax( 0, myIndex-1 );
+  updateControls();
+  information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
+}
+
+/*!
+  \brief This slot is called from "Show Next" button click.
+  Shows information on the next group of the items.
+*/
+void SMESHGUI_ElemInfo::showNext()
+{
+  myIndex = qMin( myIndex+1, myIDs.count() / MAXITEMS );
+  updateControls();
+  information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
+}
+
+/*!
+  \brief Update widgets state
+*/
+void SMESHGUI_ElemInfo::updateControls()
+{
+  myExtra->setVisible( myIDs.count() > MAXITEMS );
+  myCurrent->setText( tr( "X_FROM_Y_ITEMS_SHOWN" ).arg( myIndex*MAXITEMS+1 ).arg(qMin(myIndex*MAXITEMS+MAXITEMS, myIDs.count())).arg( myIDs.count() ) );
+  myPrev->setEnabled( myIndex > 0 );
+  myNext->setEnabled( (myIndex+1)*MAXITEMS < myIDs.count() );
+}
+
 /*!
   \class SMESHGUI_SimpleElemInfo
   \brief Represents mesh element information in the simple text area.
@@ -572,178 +812,183 @@ SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement*
 SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
 : SMESHGUI_ElemInfo( parent )
 {
-  myInfo = new QTextBrowser( this );
-  QVBoxLayout* l = new QVBoxLayout( this );
+  myInfo = new QTextBrowser( frame() );
+  QVBoxLayout* l = new QVBoxLayout( frame() );
   l->setMargin( 0 );
   l->addWidget( myInfo );
 }
 
 /*!
   \brief Show mesh element information
-  \param long id mesh node / element ID
-  \param isElem show mesh element information if \c true or mesh node information if \c false
+  \param ids mesh nodes / elements identifiers
 */
-void SMESHGUI_SimpleElemInfo::showInfo( long id, bool isElem )
+void SMESHGUI_SimpleElemInfo::information( const QList<long>& ids )
 {
-  if ( myID == id && myIsElement == isElem ) return;
-
-  SMESHGUI_ElemInfo::showInfo( id, isElem );
-
-  clear();
+  clearInternal();
   
-  if ( myActor ) {
+  if ( actor() ) {
     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
-    if ( !isElem ) {
-      //
-      // show node info
-      //
-      const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindNode( id );
-      if ( !e ) return;
-      const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
-      
-      // node ID
-      myInfo->append( QString( "<b>%1 #%2</b>" ).arg( tr( "NODE" ) ).arg( id ) );
-      // separator
-      myInfo->append( "" );
-      // coordinates
-      myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( 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( tr( "CONNECTIVITY" ) ) );
-       QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
-       if ( !con.isEmpty() )
-         myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) );
-       con = formatConnectivity( connectivity, SMDSAbs_Edge );
-       if ( !con.isEmpty() )
-         myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "EDGES" ) ).arg( con ) );
-       con = formatConnectivity( connectivity, SMDSAbs_Face );
-       if ( !con.isEmpty() )
-         myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "FACES" ) ).arg( con ) );
-       con = formatConnectivity( connectivity, SMDSAbs_Volume );
-       if ( !con.isEmpty() )
-         myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUMES" ) ).arg( con ) );
+    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
+        myInfo->append( QString( "<b>%1 #%2</b>" ).arg( tr( "NODE" ) ).arg( id ) );
+        // separator
+        myInfo->append( "" );
+        // coordinates
+        myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( 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( tr( "CONNECTIVITY" ) ) );
+          QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
+          if ( !con.isEmpty() )
+            myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) );
+          con = formatConnectivity( connectivity, SMDSAbs_Edge );
+          if ( !con.isEmpty() )
+            myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "EDGES" ) ).arg( con ) );
+          con = formatConnectivity( connectivity, SMDSAbs_Face );
+          if ( !con.isEmpty() )
+            myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "FACES" ) ).arg( con ) );
+          con = formatConnectivity( connectivity, SMDSAbs_Volume );
+          if ( !con.isEmpty() )
+            myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUMES" ) ).arg( con ) );
+        }
+        else {
+          myInfo->append( QString( "<b>%1</b>" ).arg( tr( "FREE_NODE" ) ).arg( id ) );
+        }
       }
       else {
-       myInfo->append( QString( "<b>%1</b>" ).arg( tr( "FREE_NODE" ) ).arg( id ) );
-      }
-    }
-    else {
-      //
-      // show element info
-      // 
-      const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindElement( id );
-      if ( !e ) return;
-
-      // element ID && type
-      QString stype;
-      switch( e->GetType() ) {
-      case SMDSAbs_0DElement:
-       stype = tr( "0D ELEMENT" ); break;
-      case SMDSAbs_Edge:
-       stype = tr( "EDGE" ); break;
-      case SMDSAbs_Face:
-       stype = tr( "FACE" ); break;
-      case SMDSAbs_Volume:
-       stype = tr( "VOLUME" ); break;
-      default: 
-       break;
+        //
+        // show element info
+        // 
+        const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
+        if ( !e ) return;
+        
+        // element ID && type
+        QString stype;
+        switch( e->GetType() ) {
+        case SMDSAbs_0DElement:
+          stype = tr( "0D ELEMENT" ); break;
+        case SMDSAbs_Edge:
+          stype = tr( "EDGE" ); break;
+        case SMDSAbs_Face:
+          stype = tr( "FACE" ); break;
+        case SMDSAbs_Volume:
+          stype = 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:
+          gtype = tr( "TRIANGLE" ); break;
+        case SMDSEntity_Quadrangle:
+        case SMDSEntity_Quad_Quadrangle:
+        case SMDSEntity_BiQuad_Quadrangle:
+          gtype = tr( "QUADRANGLE" ); break;
+        case SMDSEntity_Polygon:
+        case SMDSEntity_Quad_Polygon:
+          gtype = tr( "POLYGON" ); break;
+        case SMDSEntity_Tetra:
+        case SMDSEntity_Quad_Tetra:
+          gtype = tr( "TETRAHEDRON" ); break;
+        case SMDSEntity_Pyramid:
+        case SMDSEntity_Quad_Pyramid:
+          gtype = tr( "PYRAMID" ); break;
+        case SMDSEntity_Hexa:
+        case SMDSEntity_Quad_Hexa:
+        case SMDSEntity_TriQuad_Hexa:
+          gtype = tr( "HEXAHEDRON" ); break;
+        case SMDSEntity_Penta:
+        case SMDSEntity_Quad_Penta:
+          gtype = tr( "PRISM" ); break;
+        case SMDSEntity_Hexagonal_Prism:
+          gtype = tr( "HEX_PRISM" ); break;
+        case SMDSEntity_Polyhedra:
+        case SMDSEntity_Quad_Polyhedra:
+          gtype = tr( "POLYHEDRON" ); break;
+        default: 
+          break;
+        }
+        if ( !gtype.isEmpty() )
+          myInfo->append( QString( "<b>%1:</b> %2" ).arg( tr( "TYPE" ) ).arg( gtype ) );
+        // quadratic flag and gravity center (any element except 0D)
+        if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) {
+          // quadratic flag
+          myInfo->append( QString( "<b>%1?</b> %2" ).arg( tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ) );
+          // separator
+          myInfo->append( "" );
+          // gravity center
+          XYZ gc = gravityCenter( e );
+          myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) );
+        }
+        // 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( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) );
+          // node coordinates
+          myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( 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( tr( "CONNECTIVITY" ) ) );
+            QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
+            if ( !con.isEmpty() )
+              myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) );
+            con = formatConnectivity( connectivity, SMDSAbs_Edge );
+            if ( !con.isEmpty() )
+              myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "EDGES" ) ).arg( con ) );
+            con = formatConnectivity( connectivity, SMDSAbs_Face );
+            if ( !con.isEmpty() )
+              myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "FACES" ) ).arg( con ) );
+            con = formatConnectivity( connectivity, SMDSAbs_Volume );
+            if ( !con.isEmpty() )
+              myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUMES" ) ).arg( con ) );
+          }
+          else {
+            myInfo->append( QString( "<b>%1</b>" ).arg( tr( "FREE_NODE" ) ).arg( id ) );
+          }
+        }
       }
-      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:
-       gtype = tr( "TRIANGLE" ); break;
-      case SMDSEntity_Quadrangle:
-      case SMDSEntity_Quad_Quadrangle:
-       gtype = tr( "QUADRANGLE" ); break;
-      case SMDSEntity_Polygon:
-      case SMDSEntity_Quad_Polygon:
-       gtype = tr( "POLYGON" ); break;
-      case SMDSEntity_Tetra:
-      case SMDSEntity_Quad_Tetra:
-       gtype = tr( "TETRAHEDRON" ); break;
-      case SMDSEntity_Pyramid:
-      case SMDSEntity_Quad_Pyramid:
-       gtype = tr( "PYRAMID" ); break;
-      case SMDSEntity_Hexa:
-      case SMDSEntity_Quad_Hexa:
-       gtype = tr( "HEXAHEDRON" ); break;
-      case SMDSEntity_Penta:
-      case SMDSEntity_Quad_Penta:
-       gtype = tr( "PRISM" ); break;
-      case SMDSEntity_Polyhedra:
-      case SMDSEntity_Quad_Polyhedra:
-       gtype = tr( "POLYHEDRON" ); break;
-      default: 
-       break;
-      }
-      if ( !gtype.isEmpty() )
-       myInfo->append( QString( "<b>%1:</b> %2" ).arg( tr( "TYPE" ) ).arg( gtype ) );
-      // quadratic flag and gravity center (any element except 0D)
-      if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) {
-       // quadratic flag
-       myInfo->append( QString( "<b>%1?</b> %2" ).arg( tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ) );
-       // separator
-       myInfo->append( "" );
-       // gravity center
-       XYZ gc = gravityCenter( e );
-       myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) );
-      }
-      // 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( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) );
-       // node coordinates
-       myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( 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( tr( "CONNECTIVITY" ) ) );
-         QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
-         if ( !con.isEmpty() )
-           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) );
-         con = formatConnectivity( connectivity, SMDSAbs_Edge );
-         if ( !con.isEmpty() )
-           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "EDGES" ) ).arg( con ) );
-         con = formatConnectivity( connectivity, SMDSAbs_Face );
-         if ( !con.isEmpty() )
-           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "FACES" ) ).arg( con ) );
-         con = formatConnectivity( connectivity, SMDSAbs_Volume );
-         if ( !con.isEmpty() )
-           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUMES" ) ).arg( con ) );
-       }
-       else {
-         myInfo->append( QString( "<b>%1</b>" ).arg( tr( "FREE_NODE" ) ).arg( id ) );
-       }
-       // separator
-       myInfo->append( "" );
+      if ( ids.count() > 1 ) {
+        myInfo->append( "" );
+        myInfo->append( "------" );
+        myInfo->append( "" );
       }
     }
   }
 }
 
 /*!
-  \brief Clear mesh element information widget
+  \brief Internal clean-up (reset widget)
 */
-void SMESHGUI_SimpleElemInfo::clear()
+void SMESHGUI_SimpleElemInfo::clearInternal()
 {
   myInfo->clear();
 }
@@ -791,240 +1036,233 @@ QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, con
 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
 : SMESHGUI_ElemInfo( parent )
 {
-  myInfo = new QTreeWidget( this );
+  myInfo = new QTreeWidget( frame() );
   myInfo->setColumnCount( 2 );
   myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
   myInfo->header()->setStretchLastSection( true );
   myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
   myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
-  QVBoxLayout* l = new QVBoxLayout( this );
+  QVBoxLayout* l = new QVBoxLayout( frame() );
   l->setMargin( 0 );
   l->addWidget( myInfo );
 }
 
 /*!
   \brief Show mesh element information
-  \param long id mesh node / element ID
-  \param isElem show mesh element information if \c true or mesh node information if \c false
+  \param ids mesh nodes / elements identifiers
 */
-void SMESHGUI_TreeElemInfo::showInfo( long id, bool isElem )
+void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
 {
-  if ( myID == id && myIsElement == isElem ) return;
-
-  SMESHGUI_ElemInfo::showInfo( id, isElem );
+  clearInternal();
 
-  clear();
-  
-  if ( myActor ) {
+  if ( actor() ) {
     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
-    if ( !isElem ) {
-      //
-      // show node info
-      //
-      const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindNode( id );
-      if ( !e ) return;
-      const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
+    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, -1 );
-      nodeItem->setText( 0, tr( "NODE" ) );
-      nodeItem->setText( 1, QString( "#%1" ).arg( id ) );
-      nodeItem->setExpanded( true );
-      // coordinates
-      QTreeWidgetItem* coordItem = createItem( nodeItem, 0 );
-      coordItem->setText( 0, tr( "COORDINATES" ) );
-      coordItem->setExpanded( true );
-      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, 0 );
-      conItem->setText( 0, tr( "CONNECTIVITY" ) );
-      conItem->setExpanded( true );
-      Connectivity connectivity = nodeConnectivity( node );
-      if ( !connectivity.isEmpty() ) {
-       QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
-       if ( !con.isEmpty() ) {
-         QTreeWidgetItem* i = createItem( conItem );
-         i->setText( 0, tr( "0D_ELEMENTS" ) );
-         i->setText( 1, con );
-       }
-       con = formatConnectivity( connectivity, SMDSAbs_Edge );
-       if ( !con.isEmpty() ) {
-         QTreeWidgetItem* i = createItem( conItem );
-         i->setText( 0, tr( "EDGES" ) );
-         i->setText( 1, con );
-       }
-       con = formatConnectivity( connectivity, SMDSAbs_Face );
-       if ( !con.isEmpty() ) {
-         QTreeWidgetItem* i = createItem( conItem );
-         i->setText( 0, tr( "FACES" ) );
-         i->setText( 1, con );
-       }
-       con = formatConnectivity( connectivity, SMDSAbs_Volume );
-       if ( !con.isEmpty() ) {
-         QTreeWidgetItem* i = createItem( conItem );
-         i->setText( 0, tr( "VOLUMES" ) );
-         i->setText( 1, con );
-       }
+        // node ID
+        QTreeWidgetItem* nodeItem = createItem( 0, Bold | All );
+        nodeItem->setText( 0, tr( "NODE" ) );
+        nodeItem->setText( 1, QString( "#%1" ).arg( id ) );
+        // coordinates
+        QTreeWidgetItem* coordItem = createItem( nodeItem, Bold );
+        coordItem->setText( 0, 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, 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, tr( "0D_ELEMENTS" ) );
+            i->setText( 1, con );
+          }
+          con = formatConnectivity( connectivity, SMDSAbs_Edge );
+          if ( !con.isEmpty() ) {
+            QTreeWidgetItem* i = createItem( conItem );
+            i->setText( 0, tr( "EDGES" ) );
+            i->setText( 1, con );
+          }
+          con = formatConnectivity( connectivity, SMDSAbs_Face );
+          if ( !con.isEmpty() ) {
+            QTreeWidgetItem* i = createItem( conItem );
+            i->setText( 0, tr( "FACES" ) );
+            i->setText( 1, con );
+          }
+          con = formatConnectivity( connectivity, SMDSAbs_Volume );
+          if ( !con.isEmpty() ) {
+            QTreeWidgetItem* i = createItem( conItem );
+            i->setText( 0, tr( "VOLUMES" ) );
+            i->setText( 1, con );
+          }
+        }
+        else {
+          conItem->setText( 1, tr( "FREE_NODE" ) );
+        }
       }
       else {
-       conItem->setText( 1, tr( "FREE_NODE" ) );
-      }
-    }
-    else {
-      //
-      // show element info
-      // 
-      const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindElement( id );
-      if ( !e ) return;
-
-      // element ID && type
-      QString stype;
-      switch( e->GetType() ) {
-      case SMDSAbs_0DElement:
-       stype = tr( "0D ELEMENT" ); break;
-      case SMDSAbs_Edge:
-       stype = tr( "EDGE" ); break;
-      case SMDSAbs_Face:
-       stype = tr( "FACE" ); break;
-      case SMDSAbs_Volume:
-       stype = tr( "VOLUME" ); break;
-      default: 
-       break;
-      }
-      if ( stype.isEmpty() ) return;
-      QTreeWidgetItem* elemItem = createItem( 0, -1 );
-      elemItem->setText( 0, stype );
-      elemItem->setText( 1, QString( "#%1" ).arg( id ) );
-      elemItem->setExpanded( true );
-      // geometry type
-      QString gtype;
-      switch( e->GetEntityType() ) {
-      case SMDSEntity_Triangle:
-      case SMDSEntity_Quad_Triangle:
-       gtype = tr( "TRIANGLE" ); break;
-      case SMDSEntity_Quadrangle:
-      case SMDSEntity_Quad_Quadrangle:
-       gtype = tr( "QUADRANGLE" ); break;
-      case SMDSEntity_Polygon:
-      case SMDSEntity_Quad_Polygon:
-       gtype = tr( "POLYGON" ); break;
-      case SMDSEntity_Tetra:
-      case SMDSEntity_Quad_Tetra:
-       gtype = tr( "TETRAHEDRON" ); break;
-      case SMDSEntity_Pyramid:
-      case SMDSEntity_Quad_Pyramid:
-       gtype = tr( "PYRAMID" ); break;
-      case SMDSEntity_Hexa:
-      case SMDSEntity_Quad_Hexa:
-       gtype = tr( "HEXAHEDRON" ); break;
-      case SMDSEntity_Penta:
-      case SMDSEntity_Quad_Penta:
-       gtype = tr( "PRISM" ); break;
-      case SMDSEntity_Polyhedra:
-      case SMDSEntity_Quad_Polyhedra:
-       gtype = tr( "POLYHEDRON" ); break;
-      default: 
-       break;
-      }
-      if ( !gtype.isEmpty() ) {
-       QTreeWidgetItem* typeItem = createItem( elemItem, 0 );
-       typeItem->setText( 0, tr( "TYPE" ) );
-       typeItem->setText( 1, gtype );
-      }
-      // quadratic flag and gravity center (any element except 0D)
-      if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) {
-       // quadratic flag
-       QTreeWidgetItem* quadItem = createItem( elemItem, 0 );
-       quadItem->setText( 0, tr( "QUADRATIC" ) );
-       quadItem->setText( 1, e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) );
-       // gravity center
-       XYZ gc = gravityCenter( e );
-       QTreeWidgetItem* gcItem = createItem( elemItem, 0 );
-       gcItem->setText( 0, tr( "GRAVITY_CENTER" ) );
-       gcItem->setExpanded( true );
-       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 ) ) );
-      }
-      // connectivity
-      QTreeWidgetItem* conItem = createItem( elemItem, 0 );
-      conItem->setText( 0, tr( "CONNECTIVITY" ) );
-      conItem->setExpanded( true );
-      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
-       QTreeWidgetItem* nodeItem = createItem( conItem, 0 );
-       nodeItem->setText( 0, QString( "%1 %2/%3" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) );
-       nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) );
-       //nodeItem->setExpanded( true );
-       // node coordinates
-       QTreeWidgetItem* coordItem = createItem( nodeItem );
-       coordItem->setText( 0, tr( "COORDINATES" ) );
-       coordItem->setExpanded( true );
-       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, tr( "CONNECTIVITY" ) );
-       nconItem->setExpanded( true );
-       Connectivity connectivity = nodeConnectivity( node );
-       if ( !connectivity.isEmpty() ) {
-         QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
-         if ( !con.isEmpty() ) {
-           QTreeWidgetItem* i = createItem( nconItem );
-           i->setText( 0, tr( "0D_ELEMENTS" ) );
-           i->setText( 1, con );
-         }
-         con = formatConnectivity( connectivity, SMDSAbs_Edge );
-         if ( !con.isEmpty() ) {
-           QTreeWidgetItem* i = createItem( nconItem );
-           i->setText( 0, tr( "EDGES" ) );
-           i->setText( 1, con );
-         }
-         con = formatConnectivity( connectivity, SMDSAbs_Face );
-         if ( !con.isEmpty() ) {
-           QTreeWidgetItem* i = createItem( nconItem );
-           i->setText( 0, tr( "FACES" ) );
-           i->setText( 1, con );
-         }
-         con = formatConnectivity( connectivity, SMDSAbs_Volume );
-         if ( !con.isEmpty() ) {
-           QTreeWidgetItem* i = createItem( nconItem );
-           i->setText( 0, tr( "VOLUMES" ) );
-           i->setText( 1, con );
-         }
-       }
+        //
+        // show element info
+        // 
+        const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
+        if ( !e ) return;
+        
+        // element ID && type
+        QString stype;
+        switch( e->GetType() ) {
+        case SMDSAbs_0DElement:
+          stype = tr( "0D ELEMENT" ); break;
+        case SMDSAbs_Edge:
+          stype = tr( "EDGE" ); break;
+        case SMDSAbs_Face:
+          stype = tr( "FACE" ); break;
+        case SMDSAbs_Volume:
+          stype = tr( "VOLUME" ); break;
+        default: 
+          break;
+        }
+        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:
+          gtype = tr( "TRIANGLE" ); break;
+        case SMDSEntity_Quadrangle:
+        case SMDSEntity_Quad_Quadrangle:
+        case SMDSEntity_BiQuad_Quadrangle:
+          gtype = tr( "QUADRANGLE" ); break;
+        case SMDSEntity_Polygon:
+        case SMDSEntity_Quad_Polygon:
+          gtype = tr( "POLYGON" ); break;
+        case SMDSEntity_Tetra:
+        case SMDSEntity_Quad_Tetra:
+          gtype = tr( "TETRAHEDRON" ); break;
+        case SMDSEntity_Pyramid:
+        case SMDSEntity_Quad_Pyramid:
+          gtype = tr( "PYRAMID" ); break;
+        case SMDSEntity_Hexa:
+        case SMDSEntity_Quad_Hexa:
+        case SMDSEntity_TriQuad_Hexa:
+          gtype = tr( "HEXAHEDRON" ); break;
+        case SMDSEntity_Penta:
+        case SMDSEntity_Quad_Penta:
+          gtype = tr( "PRISM" ); break;
+        case SMDSEntity_Hexagonal_Prism:
+          gtype = tr( "HEX_PRISM" ); break;
+        case SMDSEntity_Polyhedra:
+        case SMDSEntity_Quad_Polyhedra:
+          gtype = tr( "POLYHEDRON" ); break;
+        default: 
+          break;
+        }
+        if ( !gtype.isEmpty() ) {
+          QTreeWidgetItem* typeItem = createItem( elemItem, Bold );
+          typeItem->setText( 0, tr( "TYPE" ) );
+          typeItem->setText( 1, gtype );
+        }
+        // quadratic flag and gravity center (any element except 0D)
+        if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) {
+          // quadratic flag
+          QTreeWidgetItem* quadItem = createItem( elemItem, Bold );
+          quadItem->setText( 0, tr( "QUADRATIC" ) );
+          quadItem->setText( 1, e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) );
+          // gravity center
+          XYZ gc = gravityCenter( e );
+          QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
+          gcItem->setText( 0, 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 ) ) );
+        }
+        // connectivity
+        QTreeWidgetItem* conItem = createItem( elemItem, Bold );
+        conItem->setText( 0, tr( "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
+          QTreeWidgetItem* nodeItem = createItem( conItem, Bold );
+          nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) );
+          nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) );
+          nodeItem->setExpanded( false );
+          // node coordinates
+          QTreeWidgetItem* coordItem = createItem( nodeItem );
+          coordItem->setText( 0, 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, 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, tr( "0D_ELEMENTS" ) );
+              i->setText( 1, con );
+            }
+            con = formatConnectivity( connectivity, SMDSAbs_Edge );
+            if ( !con.isEmpty() ) {
+              QTreeWidgetItem* i = createItem( nconItem );
+              i->setText( 0, tr( "EDGES" ) );
+              i->setText( 1, con );
+            }
+            con = formatConnectivity( connectivity, SMDSAbs_Face );
+            if ( !con.isEmpty() ) {
+              QTreeWidgetItem* i = createItem( nconItem );
+              i->setText( 0, tr( "FACES" ) );
+              i->setText( 1, con );
+            }
+            con = formatConnectivity( connectivity, SMDSAbs_Volume );
+            if ( !con.isEmpty() ) {
+              QTreeWidgetItem* i = createItem( nconItem );
+              i->setText( 0, tr( "VOLUMES" ) );
+              i->setText( 1, con );
+            }
+          }
+        }
       }
     }
   }
 }
 
 /*!
-  \brief Clear mesh element information widget
+  \brief Internal clean-up (reset widget)
 */
-void SMESHGUI_TreeElemInfo::clear()
+void SMESHGUI_TreeElemInfo::clearInternal()
 {
   myInfo->clear();
   myInfo->repaint();
@@ -1032,11 +1270,11 @@ void SMESHGUI_TreeElemInfo::clear()
 
 /*!
   \brief Create new tree item.
-  \param parnt parent tree widget item
-  \param column item column to be set bold, if it is -1, bold font will be set for all columns
+  \param parent parent tree widget item
+  \param flags item flag
   \return new tree widget item
 */
-QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int column )
+QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int flags )
 {
   QTreeWidgetItem* item;
   if ( parent )
@@ -1048,16 +1286,379 @@ QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int
 
   QFont f = item->font( 0 );
   f.setBold( true );
-  if ( column >= 0 && column < myInfo->columnCount() ) {
-    item->setFont( column, f );
+  for ( int i = 0; i < myInfo->columnCount(); i++ ) {
+    if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
+      item->setFont( i, f );
+  }
+
+  item->setExpanded( true );
+  return item;
+}
+
+/*!
+  \class GrpComputor
+  \brief Mesh information computer
+  \internal
+  
+  The class is created for different computation operation. Currently it is used
+  to compute number of underlying nodes for the groups.
+*/
+
+/*!
+  \brief Contructor
+*/
+GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* item, QObject* parent )
+  : QObject( parent ), myItem( item )
+{
+  myGroup = SMESH::SMESH_GroupBase::_narrow( grp );
+}
+
+/*!
+  \brief Compute function
+*/
+void GrpComputor::compute()
+{
+  if ( !CORBA::is_nil( myGroup ) && myItem ) {
+    QTreeWidgetItem* item = myItem;
+    myItem = 0;
+    int nbNodes = myGroup->GetNumberOfNodes();
+    item->treeWidget()->removeItemWidget( item, 1 );
+    item->setText( 1, QString::number( nbNodes ));
   }
-  else if ( column == -1 ) {
-    for ( int i = 0; i < myInfo->columnCount(); i++ )
+}
+
+/*!
+  \class SMESHGUI_AddInfo
+  \brief The wigdet shows additional information on the mesh object.
+*/
+
+/*!
+  \brief Constructor
+  \param parent parent widget
+*/
+SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
+: QTreeWidget( parent )
+{
+  setColumnCount( 2 );
+  header()->setStretchLastSection( true );
+  header()->setResizeMode( 0, QHeaderView::ResizeToContents );
+  header()->hide();
+}
+
+/*!
+  \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)
+*/
+void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
+{
+  myComputors.clear();
+
+  clear();
+
+  if ( CORBA::is_nil( obj ) ) return;
+
+  _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
+  if ( !sobj ) return;
+
+  // 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 );
+}
+
+/*!
+  \brief Create new tree item.
+  \param parent parent tree widget item
+  \param flags item flag
+  \return new tree widget item
+*/
+QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
+{
+  QTreeWidgetItem* item;
+
+  if ( parent )
+    item = new QTreeWidgetItem( parent );
+  else
+    item = new QTreeWidgetItem( this );
+
+  //item->setFlags( item->flags() | Qt::ItemIsEditable );
+
+  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 );
   }
+
+  item->setExpanded( true );
   return item;
 }
 
+/*!
+  \brief Show mesh info
+  \param mesh mesh object
+  \param parent parent tree item
+*/
+void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
+{
+  // type
+  GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
+  SALOME_MED::MedFileInfo* 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() );
+    }
+  }
+  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 {
+    typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
+  }
+  
+  // groups
+  SMESH::ListOfGroups_var groups = mesh->GetGroups();
+  QTreeWidgetItem* itemGroups  = 0;
+  QMap<int, QTreeWidgetItem*> grpItems;
+  for ( int i = 0; i < groups->length(); i++ ) {
+    SMESH::SMESH_GroupBase_var grp = groups[i];
+    if ( CORBA::is_nil( grp ) ) continue;
+    _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
+    if ( !grpSObj ) continue;
+
+    int grpType = grp->GetType();
+
+    if ( !itemGroups ) {
+      itemGroups = createItem( parent, Bold | All );
+      itemGroups->setText( 0, tr( "GROUPS" ) );
+    }
+
+    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 ] );
+    }
+  
+    // group name
+    QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
+    grpNameItem->setText( 0, grpSObj->GetName().c_str() );
+
+    // group info
+    groupInfo( grp.in(), grpNameItem );
+  }
+
+  // sub-meshes
+  SMESH::submesh_array_var subMeshes = mesh->GetSubMeshes();
+  QTreeWidgetItem* itemSubMeshes = 0;
+  QMap<int, QTreeWidgetItem*> smItems;
+  for ( int i = 0; i < subMeshes->length(); i++ ) {
+    SMESH::SMESH_subMesh_var sm = subMeshes[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;
+    
+    int smType = gobj->GetShapeType();
+    if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
+
+    if ( !itemSubMeshes ) {
+      itemSubMeshes = createItem( parent, Bold | All );
+      itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
+    }
+         
+    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, smSObj->GetName().c_str() );
+    
+    // submesh info
+    subMeshInfo( sm.in(), smNameItem );
+  }
+}
+
+/*!
+  \brief Show sub-mesh info
+  \param subMesh sub-mesh object
+  \param parent parent tree item
+*/
+void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
+{
+  bool isShort = parent->parent() != 0;
+
+  if ( !isShort ) {
+    // parent mesh
+    _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
+    if ( sobj ) {
+      QTreeWidgetItem* nameItem = createItem( parent, Bold );
+      nameItem->setText( 0, tr( "PARENT_MESH" ) );
+      nameItem->setText( 1, sobj->GetName().c_str() );
+    }
+  }
+  
+  // shape
+  GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
+  _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
+  if ( sobj ) {
+    QTreeWidgetItem* gobjItem = createItem( parent, Bold );
+    gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
+    gobjItem->setText( 1, sobj->GetName().c_str() );
+  }
+}
+
+/*!
+  \brief Show group info
+  \param grp mesh group object
+  \param parent parent tree item
+*/
+void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
+{
+  bool isShort = parent->parent() != 0;
+
+  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 );
+
+  if ( !isShort ) {
+    // parent mesh
+    _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
+    if ( sobj ) {
+      QTreeWidgetItem* nameItem = createItem( parent, Bold );
+      nameItem->setText( 0, tr( "PARENT_MESH" ) );
+      nameItem->setText( 1, sobj->GetName().c_str() );
+    }
+  }
+
+  // type : group on geometry, standalone group, group on filter
+  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() );
+    }
+  }
+  else if ( !CORBA::is_nil( aFltGroup ) ) {
+    typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
+  }
+
+  if ( !isShort ) {
+    // entity type
+    QString etype = tr( "UNKNOWN" );
+    switch( grp->GetType() ) {
+    case SMESH::NODE:
+      etype = tr( "NODE" );
+      break;
+    case SMESH::EDGE:
+      etype = tr( "EDGE" );
+      break;
+    case SMESH::FACE:
+      etype = tr( "FACE" );
+      break;
+    case SMESH::VOLUME:
+      etype = tr( "VOLUME" );
+      break;
+    case SMESH::ELEM0D:
+      etype = tr( "0DELEM" );
+      break;
+    default:
+      break;
+    }
+    QTreeWidgetItem* etypeItem = createItem( parent, Bold );
+    etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
+    etypeItem->setText( 1, etype );
+  }
+
+  // size
+  QTreeWidgetItem* sizeItem = createItem( parent, Bold );
+  sizeItem->setText( 0, tr( "SIZE" ) );
+  sizeItem->setText( 1, QString::number( grp->Size() ) );
+
+  // 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.) ) );
+
+  // nb of underlying nodes
+  if ( grp->GetType() != SMESH::NODE) {
+    QTreeWidgetItem* nodesItem = createItem( parent, Bold );
+    nodesItem->setText( 0, tr( "NB_NODES" ) );
+    int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
+    SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
+    bool meshLoaded = mesh->IsLoaded();
+    bool toShowNodes = ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || grp->Size() <= nbNodesLimit );
+    if ( toShowNodes && meshLoaded ) {
+      // already calculated and up-to-date
+      nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
+    }
+    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() ) );
+      myComputors.append( comp );
+      if ( !meshLoaded )
+        connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
+    }
+  }
+}
+
+/*!
+ * \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() )
+    {
+      if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 )))
+        btn->setText( tr("COMPUTE"));
+    }
+  }
+}
+
 /*!
   \class SMESHGUI_MeshInfoDlg
   \brief Mesh information dialog box
@@ -1092,7 +1693,7 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
   myMode->button( NodeMode )->setChecked( true );
   myID = new QLineEdit( w );
-  myID->setValidator( new SMESHGUI_IdValidator( this, 1 ) );
+  myID->setValidator( new SMESHGUI_IdValidator( this ) );
 
   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
   mode = qMin( 1, qMax( 0, mode ) );
@@ -1112,6 +1713,13 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
   
   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
 
+  // additional info
+
+  myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
+  myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
+
+  // buttons
+
   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
   okBtn->setAutoDefault( true );
   okBtn->setDefault( true );
@@ -1131,7 +1739,6 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
   l->setMargin( MARGIN );
   l->setSpacing( SPACING );
   l->addWidget( myTabWidget );
-  l->addStretch();
   l->addLayout( btnLayout );
 
   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
@@ -1163,20 +1770,25 @@ void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO
   SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
   if ( !CORBA::is_nil( obj ) ) {
     myBaseInfo->showInfo( obj );
-    
+    myAddInfo->showInfo( obj );
+
     myActor = SMESH::FindActorByEntry( IO->getEntry() );
     SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
     QString ID;
     int nb = 0;
     if ( myActor && selector ) {
       nb = myMode->checkedId() == NodeMode ? 
-       SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
-       SMESH::GetNameOfSelectedNodes( selector, IO, ID );
+        SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
+        SMESH::GetNameOfSelectedNodes( selector, IO, ID );
     }
-    if ( nb == 1 ) {
+    myElemInfo->setSource( myActor ) ;
+    if ( nb > 0 ) {
       myID->setText( ID.trimmed() );
-      myElemInfo->setSource( myActor ) ;
-      myElemInfo->showInfo( ID.toLong(), myMode->checkedId() == ElemMode );
+      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();
@@ -1229,7 +1841,7 @@ void SMESHGUI_MeshInfoDlg::updateSelection()
   disconnect( selMgr, 0, this, 0 );
   selMgr->clearFilters();
 
-  if ( myTabWidget->currentIndex() == BaseInfo ) {
+  if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) {
     SMESH::SetPointRepresentation( false );
     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
       aViewWindow->SetSelectionMode( ActorSelection );
@@ -1238,24 +1850,24 @@ void SMESHGUI_MeshInfoDlg::updateSelection()
     if ( myMode->checkedId() == NodeMode ) {
       SMESH::SetPointRepresentation( true );
       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
-       aViewWindow->SetSelectionMode( NodeSelection );
+        aViewWindow->SetSelectionMode( NodeSelection );
     }
     else {
       SMESH::SetPointRepresentation( false );
       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
-       aViewWindow->SetSelectionMode( CellSelection );
+        aViewWindow->SetSelectionMode( CellSelection );
     }
   }
 
-  int oldID = myID->text().toLong();
+  QString oldID = myID->text().trimmed();
   SMESH_Actor* oldActor = myActor;
   myID->clear();
   
   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
   updateInfo();
   
-  if ( oldActor == myActor && myActor && oldID ) {
-    myID->setText( QString::number( oldID ) );
+  if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
+    myID->setText( oldID );
     idChanged();
   }
 }
@@ -1265,9 +1877,9 @@ void SMESHGUI_MeshInfoDlg::updateSelection()
 */
 void SMESHGUI_MeshInfoDlg::help()
 {
-  SMESH::ShowHelpFile( myTabWidget->currentIndex() == BaseInfo ?
-                      "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
-                      "mesh_infos_page.html#mesh_element_info_anchor" );
+  SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
+                       "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
+                       "mesh_infos_page.html#mesh_element_info_anchor" );
 }
 
 /*!
@@ -1287,6 +1899,7 @@ void SMESHGUI_MeshInfoDlg::updateInfo()
 //   else {
 //     myBaseInfo->clear();
 //     myElemInfo->clear();
+//     myAddInfo->clear();
 //   }
 }
 
@@ -1328,10 +1941,21 @@ void SMESHGUI_MeshInfoDlg::idChanged()
   if ( myActor && selector ) {
     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
     TColStd_MapOfInteger ID;
-    ID.Add( myID->text().toLong() );
+    QSet<long> ids;
+    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 ) {
+        ID.Add( id );
+        ids << id;
+      }
+    }
     selector->AddOrRemoveIndex( IO, ID, false );
     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
       aViewWindow->highlight( IO, true, true );
-    myElemInfo->showInfo( myID->text().toLong(), myMode->checkedId() == ElemMode );
+    myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
   }
 }