Salome HOME
IPAL54521: [TC-9.3.0]: Mesh information: Additinal Info tab: 'Compute' button for...
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
index 7957b4fddef4eb9555e35f9246fb40f59ad5b336..192b1440d5500d5f583e3010c9a9df3277de258b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2019  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
 //
 // 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_IdValidator.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
+////////////////////////////////////////////////////////////////////////////////
 
-#include <SALOMEconfig.h>
-#include CORBA_SERVER_HEADER(GEOM_Gen)
+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 );
+}
 
-namespace {
+/*!
+  \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 );
+}
 
-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;
+////////////////////////////////////////////////////////////////////////////////
+/// \class TreeItemCreator
+/// \brief Generic tree item creator.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
 
-enum InfoRole {
-  TypeRole = Qt::UserRole + 10,
-  IdRole,
+class TreeItemCreator
+{
+public:
+  TreeItemCreator() {}
+  virtual ~TreeItemCreator() {}
+  virtual QTreeWidgetItem* createItem( QTreeWidgetItem*, int ) = 0;
 };
 
-enum InfoType {
-  NodeConnectivity = 100,
-  ElemConnectivity,
-};
-} // namesapce
+////////////////////////////////////////////////////////////////////////////////
+// General purpose services.
+////////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+  const int SPACING = 6;
+  const int MARGIN = 9;
+
+  enum
+  {
+    Bold = 0x01,
+    Italic = 0x02,
+    AllColumns = 0x04,
+    Expanded = 0x08,
+    Editable = 0x10
+  };
+
+  enum
+  {
+    GroupsId = 100,
+    SubMeshesId
+  };
+
+  enum
+  {
+    TypeRole = Qt::UserRole + 10,
+    IdRole,
+  };
+
+  enum
+  {
+    NodeConnectivity = 100,
+    ElemConnectivity,
+  };
+
+  /*!
+    \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 );
@@ -128,878 +462,1049 @@ 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*  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;
-  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( 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];
-    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];
-    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[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 nbElemLinerial    = 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( nbElemLinerial ) );
-    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 );
     }
   }
+  // hide 'Load' button
+  widget( iEnd, iSingle )->setVisible( false );
+}
+
+/*!
+  \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.
+*/
+QWidget* SMESHGUI_BaseInfo::addWidget( QWidget* w, int row, int column, int colspan )
+{
+  if ( !myWidgets.contains( row ) )
+    myWidgets[row] = wlist();
+  myWidgets[row][column] = w;
+  dynamic_cast<QGridLayout*>( layout() )->addWidget( w, row, column, 1, colspan );
+  return w;
 }
 
 /*!
-  \brief Reset the widget to the initial state (nullify all fields).
+  \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).
 */
-void SMESHGUI_MeshInfo::clear()
+QWidget* SMESHGUI_BaseInfo::widget( int row, int column ) const
 {
-  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.
+  return myWidgets.contains( row ) && myWidgets[row].contains( column ) ? myWidgets[row][column] : 0;
+}
+
+/*!
+  \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 Constructor
-  \param parent parent widget
+  \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() ) );
+
   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 )
+void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy, uint id, bool isElement )
 {
-  if ( myActor != actor ) {
-    myActor = actor;
-    myIsElement = -1;
-    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()
 {
@@ -1010,136 +1515,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.
+*/
+
+/*!
+  \brief Internal clean-up (reset panel).
+
+  Default implementation does nothing; the method has to be redefined
+  in sub-classes to perform internal clean-up.
 */
-SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::normal( const SMDS_MeshElement* element )
+void SMESHGUI_ElemInfo::clearInternal()
 {
-  gp_XYZ n = SMESH::getNormale( dynamic_cast<const 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()
 {
@@ -1147,442 +1999,53 @@ void SMESHGUI_ElemInfo::updateControls()
 }
 
 /*!
-  \class SMESHGUI_SimpleElemInfo
-  \brief Represents mesh element information in the simple text area.
-*/
-
-/*!
-  \brief Constructor
-  \param parent parent widget
+  \brief Write information from panel to ouput stream.
+  \param out Text stream output.
 */
-SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
-: SMESHGUI_ElemInfo( parent )
+void SMESHGUI_ElemInfo::saveInfo( QTextStream &out )
 {
-  myInfo = new QTextBrowser( frame() );
-  QVBoxLayout* l = new QVBoxLayout( frame() );
-  l->setMargin( 0 );
-  l->addWidget( myInfo );
+  // 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;
 }
 
-/*!
-  \brief Show mesh element information
-  \param ids mesh nodes / elements identifiers
-*/
-void SMESHGUI_SimpleElemInfo::information( const QList<long>& 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, v;
-            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:
-          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 = dynamic_cast<const 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 ) ) );
-          //Wraping 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() );
-          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_2D" ) ).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() ) );
-        }
+////////////////////////////////////////////////////////////////////////////////
+/// \class SMESHGUI_SimpleElemInfo
+/// \brief Show mesh element information in the simple text area.
+////////////////////////////////////////////////////////////////////////////////
 
-        // 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 ) );
-            }
-          }
-        }
+/*!
+  \brief Constructor.
+  \param parent Parent widget. Defaults to 0.
+*/
+SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
+  : SMESHGUI_ElemInfo( parent )
+{
+  myInfo = new QTextBrowser( centralWidget() );
+  QVBoxLayout* l = new QVBoxLayout( centralWidget() );
+  l->setMargin( 0 );
+  l->addWidget( myInfo );
 
-        // 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( "" );
-      }
-    }
-  }
+  connect( myInfo, SIGNAL( anchorClicked(QUrl)), this, SLOT( connectivityClicked( QUrl )));
+}
+
+/*!
+  \brief Show mesh element information.
+  \param ids Nodes / elements IDs.
+*/
+void SMESHGUI_SimpleElemInfo::information( const QList<uint>& ids )
+{
+  clearInternal();
+  TextWriter writer( myInfo );
+  writeInfo( &writer, ids );
 }
 
 /*!
@@ -1593,21 +2056,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:
@@ -1616,529 +2077,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 )
+  : SMESHGUI_ElemInfo( parent )
 {
-  myInfo = new QTreeWidget( frame() );
+  myInfo = new QTreeWidget( centralWidget() );
   myInfo->setColumnCount( 2 );
   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() );
+  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( 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, v;
-            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:
-          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 = dynamic_cast<const 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 {
-          const SMDS_VtkVolume* aVtkVolume = dynamic_cast<const SMDS_VtkVolume*>(e);
-          SMDS_ElemIteratorPtr nodeIt = aVtkVolume->uniqueNodesIterator();
-          QList<const SMDS_MeshElement*> uniqueNodes;
-          while ( nodeIt->more() )
-            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, aVtkVolume->NbUniqueNodes(), 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
-          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 ) ) );    
-          //AspectRatio2D
-          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 ) ) );    
-          //Wraping 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 ) ) );        
-          //Skew          
-          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 ) ) );       
-          //ElemDiam2D    
-          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 ) {
-          //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 ) ) );     
-        }
-
-        // 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 );
 }
 
 /*!
@@ -2151,66 +2182,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)
@@ -2222,29 +2253,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 );
+  QTreeWidgetItem* item = new QTreeWidgetItem( parent ? parent : myInfo->invisibleRootItem() );
+  setTreeItemAttributes( item, options | Expanded | Editable );
 
-  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 );
+  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;
 }
 
@@ -2254,495 +2278,554 @@ 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 )
+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 )) );
   }
 }
 
-void SMESHGUI_TreeElemInfo::saveInfo( QTextStream &out )
+void SMESHGUI_TreeElemInfo::saveExpanded( QTreeWidgetItem* theItem )
 {
-  out << QString( 12, '-' ) << "\n";
-  out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
-  out << QString( 12, '-' ) << "\n";
+  if ( theItem )
+    SMESHGUI::resourceMgr()->setValue("SMESH", expandedResource( theItem ), theItem->isExpanded() );
+}
 
-  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";
+QString SMESHGUI_TreeElemInfo::expandedResource( QTreeWidgetItem* theItem )
+{
+  return QString("Expanded_") + ( what()==ShowElements ? "E_" : "N_" ) + theItem->text(0);
 }
 
-/*!
-  \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.
-*/
+////////////////////////////////////////////////////////////////////////////////
+/// \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.
+////////////////////////////////////////////////////////////////////////////////
 
 /*!
-  \brief Contructor
+  \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
 */
-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 ) {
-    QTreeWidgetItem* item = myItem;
-    myItem = 0;
-    int nb = myToComputeSize ? myGroup->Size() : myGroup->GetNumberOfNodes();
-    item->treeWidget()->removeItemWidget( item, 1 );
-    item->setText( 1, QString::number( nb ));
+  if ( myProxy )
+  {
+    SUIT_OverrideCursor wc;
+    myProxy.load();
+    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 );
-  header()->setResizeMode( 0, QHeaderView::ResizeToContents );
-  header()->hide();
+  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)
+  myTree->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
+#else
+  myTree->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
+#endif
+  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 ) ) {
+  if ( !shapeName.isEmpty() )
+  {
     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() );
-    }
+    // shape
+    QTreeWidgetItem* gobjItem = createItem( parent, Bold );
+    gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
+    gobjItem->setText( 1, shapeName );
   }
-  else if ( strlen( (char*)inf->fileName ) > 0 ) {
+  else if ( inf.isValid() )
+  {
     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
-    QTreeWidgetItem* fileItem = createItem( typeItem );
+    // med file information
+    QTreeWidgetItem* fileItem = createItem( parent, Bold );
     fileItem->setText( 0, tr( "FILE_NAME" ) );
-    fileItem->setText( 1, (char*)inf->fileName );
+    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 {
+  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( 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( 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 ) ) {
+  if ( type == SMESH::SelectionProxy::GroupStd )
+  {
     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
   }
-  else if ( !CORBA::is_nil( aGeomGroup ) ) {
+  else if ( type == SMESH::SelectionProxy::GroupGeom )
+  {
     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() );
-    }
+    // shape
+    QTreeWidgetItem* gobjItem = createItem( parent, Bold );
+    gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
+    gobjItem->setText( 1, proxy.shapeName() );
   }
-  else if ( !CORBA::is_nil( aFltGroup ) ) {
+  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( 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 ) );
+  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 );
+  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->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() ) );
+
+    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 ); 
+    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;
+  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->GetType();
+    int grpType = grp.groupElementType();
 
-    if ( !itemGroups ) {
-      // create top-level groups container item
-      itemGroups = createItem( parent, Bold | All );
+    // 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, GROUPS_ID );
+      itemGroups->setData( 0, Qt::UserRole, GroupsId );
 
-      // total number of groups > 10, show extra widgets for info browsing
-      if ((int) myGroups->length() > MAXITEMS ) {
+      // 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 );
+        myTree->setItemWidget( itemGroups, 1, extra );
+        extra->updateControls( myGroups.count(), idx );
       }
     }
 
-    if ( grpItems.find( grpType ) == grpItems.end() ) {
-      grpItems[ grpType ] = createItem( itemGroups, Bold | All );
+    // 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 ] );
+      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 );
+    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, SUBMESHES_ID );
+      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 );
+        myTree->setItemWidget( itemSubMeshes, 1, extra );
+        extra->updateControls( mySubMeshes.count(), idx );
       }
     }
-         
-    if ( smItems.find( smType ) == smItems.end() ) {
-      smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
+
+    // create container item corresponding to particular shape type
+    if ( !smItems.contains( smType ) )
+    {
+      smItems[ smType ] = createItem( itemSubMeshes, Bold | AllColumns );
       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
+    // name
+    QTreeWidgetItem* nameItem = createItem( smItems[ smType ] );
+    nameItem->setText( 0, sm.name().trimmed() ); // trim name
     
     // submesh info
-    subMeshInfo( sm.in(), smNameItem );
+    subMeshInfo( sm, nameItem );
   }
 }
 
 /*!
- * \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") );
-    }
-  }
-}
-
+  \brief Show previous chunk of information on child groups.
+*/
 void SMESHGUI_AddInfo::showPreviousGroups()
 {
   int idx = property( "group_index" ).toInt();
@@ -2750,6 +2833,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();
@@ -2757,52 +2843,169 @@ void SMESHGUI_AddInfo::showNextGroups()
   showGroups();
 }
 
-void SMESHGUI_AddInfo::showPreviousSubMeshes()
+/*!
+  \brief Show previous chunk of information on child sub-meshes.
+*/
+void SMESHGUI_AddInfo::showPreviousSubMeshes()
+{
+  int idx = property( "submesh_index" ).toInt();
+  setProperty( "submesh_index", idx-1 );
+  showSubMeshes();
+}
+
+/*!
+  \brief Show next chunk of information on child sub-meshes.
+*/
+void SMESHGUI_AddInfo::showNextSubMeshes()
+{
+  int idx = property( "submesh_index" ).toInt();
+  setProperty( "submesh_index", idx+1 );
+  showSubMeshes();
+}
+
+/*!
+  \brief Write information from panel to ouput stream.
+  \param out Text stream output.
+*/
+void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
+{
+  // 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 << endl;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class GroupCombo
+/// \brief Customized combo box to manage list of mesh groups.
+/// \internal
+////////////////////////////////////////////////////////////////////////////////
+
+class GroupCombo: public QComboBox
 {
-  int idx = property( "submesh_index" ).toInt();
-  setProperty( "submesh_index", idx-1 );
-  showSubMeshes();
-}
+  class Item: public QStandardItem
+  {
+  public:
+    SMESH::SelectionProxy myGroup;
+    Item( const SMESH::SelectionProxy& group )
+    {
+      myGroup = group;
+      setText( myGroup.name() );
+    }
+    SMESH::SelectionProxy group()
+    {
+      return myGroup;
+    }
+  };
 
-void SMESHGUI_AddInfo::showNextSubMeshes()
+  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 )
 {
-  int idx = property( "submesh_index" ).toInt();
-  setProperty( "submesh_index", idx+1 );
-  showSubMeshes();
+  setModel( new QStandardItemModel( this ) );
 }
 
-void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
+/*!
+  \brief Set mesh source.
+  \param obj Mesh source.
+  \internal
+*/
+void GroupCombo::setSource( const SMESH::SelectionProxy& proxy )
 {
-  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();
+  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] ) );
+        }
       }
-      else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1);
-      out << "\n";
+      setCurrentIndex( -1 ); // for performance reasons
+    }
+    else if ( myProxy.type() >= SMESH::SelectionProxy::Group )
+    {
+      m->appendRow( new Item( myProxy ) );
+      setCurrentIndex( 0 );
     }
-    ++it;
   }
-  out << "\n";
+
+  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 );
@@ -2811,38 +3014,48 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
 
   myTabWidget = new QTabWidget( this );
 
-  // base info 
+  // base info
 
-  myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
+  myBaseInfo = new SMESHGUI_BaseInfo( myTabWidget );
   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
 
   // elem info 
-  
+
   QWidget* w = new QWidget( myTabWidget );
 
   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 ) );
+  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() ) );
 
   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
   mode = qMin( 1, qMax( 0, mode ) );
-  
-  if ( mode == 0 ) 
+
+  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( myElemInfo, 1, 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" ) );
 
   // additional info
@@ -2875,64 +3088,108 @@ 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 );
 
+  // 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( 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
+
+  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()
 {
+  delete myIDPreview;
 }
 
 /*!
-  \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 )
+{
+  if ( !io.IsNull() )
+    showInfo( SMESH::SelectionProxy( io ) );
+}
+
+/*!
+  \brief Show mesh information on given object.
+  \param proxy Selection proxy.
 */
-void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
+void SMESHGUI_MeshInfoDlg::showInfo( const SMESH::SelectionProxy& proxy )
 {
-  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)
-    myCtrlInfo->showInfo( obj );
+  SUIT_OverrideCursor wc;
 
-    myActor = SMESH::FindActorByEntry( IO->getEntry() );
+  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 ( myActor && selector ) {
-      nb = myMode->checkedId() == NodeMode ? 
-        SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
-        SMESH::GetNameOfSelectedNodes( selector, IO, ID );
+    if ( myProxy.actor() && selector ) { //todo: actor()?
+      nb = myMode->checkedId() == NodeMode ?
+        SMESH::GetNameOfSelectedElements( selector, myProxy.io(), ID ) :
+        SMESH::GetNameOfSelectedNodes( selector, myProxy.io(), ID );
     }
-    myElemInfo->setSource( myActor ) ;
     if ( nb > 0 ) {
       myID->setText( ID.trimmed() );
-      QSet<long> ids;
+      QSet<uint> ids;
       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
       foreach ( ID, idTxt )
-        ids << ID.trimmed().toLong();
-      myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
+        ids << ID.trimmed().toUInt();
+      myElemInfo->showInfo( proxy, ids, myMode->checkedId() == ElemMode );
     }
     else {
       myID->clear();
@@ -2942,21 +3199,36 @@ void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO
 }
 
 /*!
-  \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 );
 }
 
 /*!
-  \brief Process keyboard event
-  \param e key press event
+  \brief Process keyboard event.
+  \param e Key press event.
 */
 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
 {
@@ -2968,15 +3240,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()
 {
@@ -2985,85 +3249,59 @@ 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() ) );
   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_page.html#advanced_mesh_infos_anchor" : 
-                       "mesh_infos_page.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 );
+  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;
   }
-//   else {
-//     myBaseInfo->clear();
-//     myElemInfo->clear();
-//     myAddInfo->clear();
-//   }
-}
-
-/*!
-  \brief Activate dialog box
-*/
-void SMESHGUI_MeshInfoDlg::activate()
-{
-  SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
-  SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
-  myTabWidget->setEnabled( true );
-  updateSelection();
+  SMESH::ShowHelpFile( helpPage );
 }
 
 /*!
-  \brief Deactivate dialog box
+  \brief Deactivate dialog box.
 */
 void SMESHGUI_MeshInfoDlg::deactivate()
 {
-  myTabWidget->setEnabled( false );
   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
 }
 
@@ -3072,152 +3310,152 @@ void SMESHGUI_MeshInfoDlg::deactivate()
 */
 void SMESHGUI_MeshInfoDlg::modeChanged()
 {
+  emit( switchMode( myMode->checkedId() == GroupMode ? 1 : 0 ) );
   myID->clear();
   updateSelection();
 }
 
 /*!
-  \brief Caled when users prints mesh element ID in the corresponding field.
+  \brief Called when users prints mesh element ID in the corresponding field.
 */
 void SMESHGUI_MeshInfoDlg::idChanged()
 {
-  SVTK_Selector* selector = SMESH::GetSelector();
-  if ( myActor && selector ) {
-    Handle(SALOME_InteractiveObject) IO = myActor->getIO();
+  myIDPreview->SetPointsLabeled( false );
+
+  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 ( isElem && myProxy.actor() && myProxy.elementGravityCenter( id, xyz ))
+        {
+          idVec.push_back( id );
+          aGrCentersXYZ.push_back( xyz );
+        }
       }
     }
-    selector->AddOrRemoveIndex( IO, ID, false );
-    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
-      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 );
   }
 }
 
-void SMESHGUI_MeshInfoDlg::showItemInfo( int id )
+/*!
+ * \brief Show IDs clicked
+ */
+void SMESHGUI_MeshInfoDlg::idPreviewChange( bool isOn )
 {
-  if ( id > 0 &&  myActor->GetObject()->GetMesh()->FindNode( id ) ) {
-    myMode->button( NodeMode )->click();
-    myID->setText( QString::number( id ) );
-  }
+  myIDPreview->SetPointsLabeled( isOn && !myID->text().simplified().isEmpty() );
+  SMESHGUI::resourceMgr()->setValue("SMESH", "id_preview_resource", isOn );
+  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+    aViewWindow->Repaint();
 }
 
-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()
 {
-  SUIT_Application* app = SUIT_Session::session()->activeApplication();
-  if ( !app ) return;
-  SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
-  if ( !appStudy ) return;
-  _PTR( Study ) aStudy = appStudy->studyDS();
-
-  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.setFilters( aFilters );
-  fd.myBaseChk->setChecked( anIsBase );
-  fd.myElemChk->setChecked( anIsElem );
-  fd.myAddChk ->setChecked( anIsAdd );
-  fd.myCtrlChk->setChecked( anIsCtrl );
+  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() )
-        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 );
-      
-      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( 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 );
@@ -3227,20 +3465,20 @@ SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
   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 );
@@ -3248,13 +3486,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 );
@@ -3265,140 +3503,113 @@ SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
   aFreeNodesBtn->setIcon(aComputeIcon);
   myButtons << aFreeNodesBtn;       //0
 
+  QToolButton* aNodesNbConnBtn = new QToolButton( this );
+  aNodesNbConnBtn->setIcon(aComputeIcon);
+  myButtons << aNodesNbConnBtn;     //1
+
   QToolButton* aDoubleNodesBtn = new QToolButton( this );
   aDoubleNodesBtn->setIcon(aComputeIcon);
-  myButtons << aDoubleNodesBtn;     //1
+  myButtons << aDoubleNodesBtn;     //2
 
   QToolButton* aDoubleEdgesBtn = new QToolButton( this );
   aDoubleEdgesBtn->setIcon(aComputeIcon);
-  myButtons << aDoubleEdgesBtn;     //2
+  myButtons << aDoubleEdgesBtn;     //3
 
   QToolButton* aDoubleFacesBtn = new QToolButton( this );
   aDoubleFacesBtn->setIcon(aComputeIcon);
-  myButtons << aDoubleFacesBtn;     //3
+  myButtons << aDoubleFacesBtn;     //4
 
   QToolButton* aOverContFacesBtn = new QToolButton( this );
   aOverContFacesBtn->setIcon(aComputeIcon);
-  myButtons << aOverContFacesBtn;   //4
+  myButtons << aOverContFacesBtn;   //5
 
   QToolButton* aComputeFaceBtn = new QToolButton( this );
   aComputeFaceBtn->setIcon(aComputeIcon);
-  myButtons << aComputeFaceBtn;     //5
+  myButtons << aComputeFaceBtn;     //6
 
   QToolButton* aDoubleVolumesBtn = new QToolButton( this );
   aDoubleVolumesBtn->setIcon(aComputeIcon);
-  myButtons << aDoubleVolumesBtn;   //6
+  myButtons << aDoubleVolumesBtn;   //7
 
   QToolButton* aOverContVolumesBtn = new QToolButton( this );
   aOverContVolumesBtn->setIcon(aComputeIcon);
-  myButtons << aOverContVolumesBtn; //7
+  myButtons << aOverContVolumesBtn; //8
 
   QToolButton* aComputeVolumeBtn = new QToolButton( this );
   aComputeVolumeBtn->setIcon(aComputeIcon);
-  myButtons << aComputeVolumeBtn;   //8
+  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( aDoubleNodesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) );
-  connect( aDoubleEdgesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) );
-  connect( aDoubleFacesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) );
+  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( aNodesDoubleLab,    3, 0 );       //6
-  myMainLayout->addWidget( aNodesDouble,       3, 1 );       //7
-  myMainLayout->addWidget( aDoubleNodesBtn,    3, 2 );       //8
-  myMainLayout->addWidget( aToleranceLab,      4, 0 );       //9
-  myMainLayout->addWidget( myToleranceWidget,  4, 1 );       //10
-  myMainLayout->addWidget( anEdgesLab,         5, 0, 1, 3 ); //11
-  myMainLayout->addWidget( anEdgesDoubleLab,   6, 0 );       //12
-  myMainLayout->addWidget( anEdgesDouble,      6, 1 );       //13
-  myMainLayout->addWidget( aDoubleEdgesBtn,    6, 2 );       //14
-  myMainLayout->addWidget( aFacesLab,          7, 0, 1, 3 ); //15
-  myMainLayout->addWidget( aFacesDoubleLab,    8, 0 );       //16
-  myMainLayout->addWidget( aFacesDouble,       8, 1 );       //17
-  myMainLayout->addWidget( aDoubleFacesBtn,    8, 2 );       //18
-  myMainLayout->addWidget( aFacesOverLab,      9, 0 );       //19
-  myMainLayout->addWidget( aFacesOver,         9, 1 );       //20
-  myMainLayout->addWidget( aOverContFacesBtn,  9, 2 );       //21
-  myMainLayout->addWidget( anAspectRatioLab,   10, 0 );      //22
-  myMainLayout->addWidget( aComputeFaceBtn,    10, 2 );      //23
-  myMainLayout->addWidget( myPlot,             11, 0, 1, 3 );//24
-  myMainLayout->addWidget( aVolumesLab,        12, 0, 1, 3 );//25
-  myMainLayout->addWidget( aVolumesDoubleLab,  13, 0 );      //26
-  myMainLayout->addWidget( aVolumesDouble,     13, 1 );      //27
-  myMainLayout->addWidget( aDoubleVolumesBtn,  13, 2 );      //28
-  myMainLayout->addWidget( aVolumesOverLab,    14, 0 );      //28
-  myMainLayout->addWidget( aVolumesOver,       14, 1 );      //30
-  myMainLayout->addWidget( aOverContVolumesBtn,14, 2 );      //31
-  myMainLayout->addWidget( anAspectRatio3DLab, 15, 0 );      //32
-  myMainLayout->addWidget( aComputeVolumeBtn,  15, 2 );      //33
-  myMainLayout->addWidget( myPlot3D,           16, 0, 1, 3 );//34
+  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   ( 11,  5 );
-  myMainLayout->setRowStretch   ( 16,  5 );
-  myMainLayout->setRowStretch   ( 17,  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 )
 {
@@ -3415,17 +3626,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;
 
-  if ( _PTR(SObject) aSO = SMESH::FindSObject( obj ))
-    myWidgets[0]->setText( aSO->GetName().c_str() );
+  myProxy = proxy;
+  SMESH::SMESH_IDSource_var obj = proxy.object();
+
+  myWidgets[0]->setText( proxy.name() );
 
   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
   if ( mesh->_is_nil() ) return;
@@ -3444,25 +3658,27 @@ void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
 
   // nodes info
   const CORBA::Long nbNodes =   nbElemsByType[ SMESH::NODE ];
-  const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
-                                nbElemsByType[ SMESH::FACE ] +
-                                nbElemsByType[ SMESH::VOLUME ] );
-  if ( nbNodes + nbElems > 0 ) {
-    if ( Max( (int)nbNodes, (int)nbElems ) <= ctrlLimit ) {
+  // const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
+  //                               nbElemsByType[ SMESH::FACE ] +
+  //                               nbElemsByType[ SMESH::VOLUME ] );
+  if ( nbNodes > 0 ) {
+    if ( nbNodes <= ctrlLimit ) {
       // free nodes
       computeFreeNodesInfo();
+      // node connectivity number
+      computeNodesNbConnInfo();
       // double nodes
-      if ( Max( (int)mesh->NbNodes(), (int)mesh->NbElements() ) <= ctrlLimit )
-        computeDoubleNodesInfo();
+      computeDoubleNodesInfo();
     }
     else {
       myButtons[0]->setEnabled( true );
       myButtons[1]->setEnabled( true );
+      myButtons[2]->setEnabled( true );
     }
   }
   else {
-    for( int i=2; i<=10; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+    for( int i=2; i<=13; i++)
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
   }
 
   // edges info
@@ -3471,13 +3687,13 @@ void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
     if( nbElemsByType[ SMESH::EDGE ] <= ctrlLimit )
       computeDoubleEdgesInfo();
     else
-      myButtons[2]->setEnabled( true );
+      myButtons[3]->setEnabled( true );
   }
   else {
-    for( int i=11; i<=14; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+    for( int i=14; i<=17; i++)
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
   }
+
   // faces info
   if ( nbElemsByType[ SMESH::FACE ] > 0 ) {
     if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) {
@@ -3489,20 +3705,18 @@ void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
       computeAspectRatio();
     }
     else {
-      myButtons[3]->setEnabled( true );
       myButtons[4]->setEnabled( true );
       myButtons[5]->setEnabled( true );
+      myButtons[6]->setEnabled( true );
     }
 #ifdef DISABLE_PLOT2DVIEWER
-    myMainLayout->setRowStretch(11,0);
-    for( int i=22; i<=24; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+    for( int i=25; i<=27; i++)
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
 #endif
   }
   else {
-    myMainLayout->setRowStretch(11,0);
-    for( int i=15; i<=24; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+    for( int i=18; i<=27; i++)
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
   }
 
   // volumes info
@@ -3514,22 +3728,20 @@ void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
       computeOverConstrainedVolumesInfo();
       // aspect Ratio 3D histogram
       computeAspectRatio3D();
-     }
-     else {
-       myButtons[6]->setEnabled( true );
-       myButtons[7]->setEnabled( true );
-       myButtons[8]->setEnabled( true );
-     }
+    }
+    else {
+      myButtons[7]->setEnabled( true );
+      myButtons[8]->setEnabled( true );
+      myButtons[9]->setEnabled( true );
+    }
 #ifdef DISABLE_PLOT2DVIEWER
-    myMainLayout->setRowStretch(16,0);
-    for( int i=32; i<=34; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+    for( int i=35; i<=37; i++)
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
 #endif
   }
   else {
-    myMainLayout->setRowStretch(16,0);
-    for( int i=25; i<=34; i++)
-      myMainLayout->itemAt(i)->widget()->setVisible( false );
+    for( int i=28; i<=37; i++)
+      dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
   }
 }
 
@@ -3546,15 +3758,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
   }
@@ -3562,8 +3778,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 ) );
     }
 }
 
@@ -3574,43 +3790,74 @@ void SMESHGUI_CtrlInfo::computeFreeNodesInfo()
 
 void SMESHGUI_CtrlInfo::computeDoubleNodesInfo()
 {
-  computeNb( SMESH::FT_EqualNodes, 1, 2 );
+  computeNb( SMESH::FT_EqualNodes, 2, 3 );
 }
 
 void SMESHGUI_CtrlInfo::computeDoubleEdgesInfo()
 {
-  computeNb( SMESH::FT_EqualEdges, 2, 3 );
+  computeNb( SMESH::FT_EqualEdges, 3, 4 );
 }
 
 void SMESHGUI_CtrlInfo::computeDoubleFacesInfo()
 {
-  computeNb( SMESH::FT_EqualFaces, 3, 4 );
+  computeNb( SMESH::FT_EqualFaces, 4, 5 );
 }
 
 void SMESHGUI_CtrlInfo::computeOverConstrainedFacesInfo()
 {
-  computeNb( SMESH::FT_OverConstrainedFace, 4, 5 );
+  computeNb( SMESH::FT_OverConstrainedFace, 5, 6 );
 }
 
 void SMESHGUI_CtrlInfo::computeDoubleVolumesInfo()
 {
-  computeNb( SMESH::FT_EqualVolumes, 6, 6 );
+  computeNb( SMESH::FT_EqualVolumes, 7, 7 );
 }
 
 void SMESHGUI_CtrlInfo::computeOverConstrainedVolumesInfo()
 {
-  computeNb( SMESH::FT_OverConstrainedVolume, 7, 7 );
+  computeNb( SMESH::FT_OverConstrainedVolume, 8, 8 );
+}
+
+void SMESHGUI_CtrlInfo::computeNodesNbConnInfo()
+{
+  myButtons[ 1 ]->setEnabled( false );
+  myWidgets[ 2 ]->setText( "" );
+
+  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();
+    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, obj );
+
+  myWidgets[ 2 ]->setText( QString::number( histogram[0].max ) );
 }
 
 void SMESHGUI_CtrlInfo::computeAspectRatio()
 {
 #ifndef DISABLE_PLOT2DVIEWER
-  myButtons[5]->setEnabled( false );
+  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();
@@ -3624,12 +3871,16 @@ void SMESHGUI_CtrlInfo::computeAspectRatio()
 void SMESHGUI_CtrlInfo::computeAspectRatio3D()
 {
 #ifndef DISABLE_PLOT2DVIEWER
-  myButtons[8]->setEnabled( false );
+  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();
@@ -3645,9 +3896,9 @@ void SMESHGUI_CtrlInfo::computeAspectRatio3D()
 */
 void SMESHGUI_CtrlInfo::clearInternal()
 {
-  for( int i=0; i<=34; i++)
-    myMainLayout->itemAt(i)->widget()->setVisible( true );
-  for( int i=0; i<=8; i++)
+  for( int i=0; i<=37; i++)
+    dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( true );
+  for( int i=0; i<=9; i++)
     myButtons[i]->setEnabled( false );
   myPlot->detachItems();
   myPlot3D->detachItems();
@@ -3656,8 +3907,6 @@ void SMESHGUI_CtrlInfo::clearInternal()
   myWidgets[0]->setText( QString() );
   for ( int i = 1; i < myWidgets.count(); i++ )
     myWidgets[i]->setText( "" );
-  myMainLayout->setRowStretch(11,5);
-  myMainLayout->setRowStretch(16,5);
 }
 
 void SMESHGUI_CtrlInfo::setTolerance( double theTolerance )
@@ -3670,14 +3919,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 );
 
@@ -3685,7 +3937,7 @@ 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 ) );
   if ( &histogramVar.in() )
@@ -3699,36 +3951,42 @@ 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
   \param parent parent widget
-  \param page specifies the dialog page to be shown at the start-up
 */
 SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
-: QDialog( parent )
+  : QDialog( parent )
 {
   setAttribute( Qt::WA_DeleteOnClose, true );
   setWindowTitle( tr( "CTRL_INFO" ) );
@@ -3756,7 +4014,7 @@ 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 );
@@ -3778,34 +4036,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 );
 }
 
 /*!
@@ -3813,29 +4065,38 @@ 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()
 {
@@ -3843,48 +4104,31 @@ void SMESHGUI_CtrlInfoDlg::deactivate()
 }
 
 /*!
- * \brief Dump contents into a file
- */
+  \brief Dump information to file.
+*/
 void SMESHGUI_CtrlInfoDlg::dump()
 {
-  SUIT_Application* app = SUIT_Session::session()->activeApplication();
-  if ( !app ) return;
-  SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
-  if ( !appStudy ) return;
-  _PTR( Study ) aStudy = appStudy->studyDS();
-
-  QStringList aFilters;
-  aFilters.append( tr( "TEXT_FILES" ) );
-
-  DumpFileDlg fd( this );
+  DumpFileDlg fd( this, false );
   fd.setWindowTitle( tr( "SAVE_INFO" ) );
-  fd.setFilters( aFilters );
-  fd.myBaseChk->hide();
-  fd.myElemChk->hide();
-  fd.myAddChk ->hide();
-  fd.myCtrlChk->hide();
+  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_page.html#mesh_quality_info_anchor");
+  SMESH::ShowHelpFile( "mesh_infos.html#mesh-quality-info-anchor" );
 }